// TODO: Refactor read into something smaller /// <inheritdoc /> public bool Read(IResponseReader reader) { if (IsOpen) { throw new InvalidOperationException("Attempting to read set before it has been prepared."); } if (reader.Count == 0) { throw new InvalidOperationException("Invalid response. Response was completely empty."); } uint reportId = reader.ReadByte(); if (reader.Count < 1) { throw new InvalidOperationException("No data was returned"); } uint startFlag = reader.ReadByte(); uint destination; uint source; if (startFlag == (byte)FrameCommands.EXTENDED_START_FLAG) { if (reader.Count < 4) { throw new InvalidOperationException("Improperly formatted frame."); } destination = reader.ReadByte(); source = reader.ReadByte(); } else if (startFlag != (byte)FrameCommands.STANDARD_START_FLAG) { throw new InvalidOperationException("No start flag was found"); } int stopFrameFlagIndex = reader.Position; uint checksum; stopFrameFlagIndex = ((List <uint>)reader).IndexOf((byte)FrameCommands.STOP_FRAME_FLAG, stopFrameFlagIndex + 1); if (stopFrameFlagIndex == -1) { InvalidOperationException exception = new ("Improperly formatted frame. No stop flag was found."); _logger.LogError(exception, "No stop flag found."); throw exception; } // Unstuff bytes for (int index = reader.Position; index < stopFrameFlagIndex - 1; index++) { if (reader[index] == 0xF3) { reader.RemoveAt(index); stopFrameFlagIndex--; reader[index] += 0xF0; } } checksum = reader.Skip(reader.Position).Take(stopFrameFlagIndex - reader.Position - 1).Aggregate <uint, uint>(0, _calculateChecksum); if (checksum != reader[stopFrameFlagIndex - 1]) { InvalidOperationException exception = new("Improperly formatted frame. Checksum did not match."); _logger.LogError(exception, "Checksum did not match."); throw exception; } // Remove checksum and end flag reader.Truncate(stopFrameFlagIndex - 1); if (reader.Position == reader.Size) { return(true); } uint status = reader.ReadByte(); int listHighWaterMark = 0; do { uint commandCode = reader.ReadByte(); if (_wrapperCommands.Contains(commandCode)) { uint size = reader.ReadByte(); int startIndex = reader.Position; while (reader.Position < startIndex + size) { uint proprietaryCommandCode = reader.ReadByte(); ICommand wrappedCommand = this.Skip(listHighWaterMark).First(command => command.Code == proprietaryCommandCode && command.Wrapper == commandCode); listHighWaterMark = IndexOf(wrappedCommand) + 1; if (wrappedCommand is GetCommand) { try { wrappedCommand.Read(reader); } catch (Exception e) { _logger.LogError(e, "Exception occurred while reading command [{CommandName}]", wrappedCommand.Name); throw; } } } continue; } ICommand command = this.Skip(listHighWaterMark).First(command => command.Code == commandCode && command.Wrapper == null); listHighWaterMark = IndexOf(command) + 1; if (command is GetCommand) { try { command.Read(reader); } catch (Exception e) { _logger.LogError(e, "Exception occurred while reading command [{CommandName}]", command.Name); throw; } } } while (reader.Position < reader.Size); // Ensure whole response has been read bool success = reader.Position == reader.Size; return(success); }