예제 #1
0
        // 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);
        }