private async Task <bool> InternalReceiveRequestAsync()
        {
            this.Length = 0;

            try
            {
                while (true)
                {
                    this.Length += await _serialPort.ReadAsync(this.FrameBuffer.Buffer, this.Length, this.FrameBuffer.Buffer.Length - this.Length, this.CTS.Token);

                    // full frame received
                    if (ModbusUtils.DetectFrame(255, this.FrameBuffer.Buffer.AsMemory(0, this.Length)))
                    {
                        this.FrameBuffer.Reader.BaseStream.Seek(0, SeekOrigin.Begin);

                        // read unit identifier
                        this.UnitIdentifier = this.FrameBuffer.Reader.ReadByte();

                        break;
                    }
                    else
                    {
                        // reset length because one or more chunks of data were received and written to
                        // the buffer, but no valid Modbus frame could be detected and now the buffer is full
                        if (this.Length == this.FrameBuffer.Buffer.Length)
                        {
                            this.Length = 0;
                        }
                    }
                }
            }
            catch (TimeoutException)
            {
                this.Length = 0;
            }

            // make sure that the incoming frame is actually adressed to this server
            if (this.UnitIdentifier == this.ModbusRtuServer.UnitIdentifier)
            {
                this.LastRequest.Restart();
                return(true);
            }
            else
            {
                return(false);
            }
        }
Example #2
0
        private protected override Span <byte> TransceiveFrame(byte unitIdentifier, ModbusFunctionCode functionCode, Action <ExtendedBinaryWriter> extendFrame)
        {
            int    messageLength;
            int    frameLength;
            byte   rawFunctionCode;
            ushort crc;
            int    mbapHeaderLength = 4;

            // build request
            if (!(0 <= unitIdentifier && unitIdentifier <= 247))
            {
                throw new ModbusException(ErrorMessage.ModbusClient_InvalidUnitIdentifier);
            }

            // special case: broadcast (only for write commands)
            if (unitIdentifier == 0)
            {
                switch (functionCode)
                {
                case ModbusFunctionCode.WriteMultipleRegisters:
                case ModbusFunctionCode.WriteSingleCoil:
                case ModbusFunctionCode.WriteSingleRegister:
                case ModbusFunctionCode.WriteMultipleCoils:
                case ModbusFunctionCode.WriteFileRecord:
                case ModbusFunctionCode.MaskWriteRegister:
                    break;

                default:
                    throw new ModbusException(ErrorMessage.Modbus_InvalidUseOfBroadcast);
                }
            }

            _frameBuffer.Writer.Seek(0, SeekOrigin.Begin);
            _frameBuffer.Writer.Write(unitIdentifier);                                      // 00     Unit Identifier
            extendFrame(_frameBuffer.Writer);
            frameLength = (int)_frameBuffer.Writer.BaseStream.Position;

            // add CRC
            crc = ModbusUtils.CalculateCRC(_frameBuffer.Buffer.AsMemory().Slice(0, frameLength));
            _frameBuffer.Writer.Write(crc);
            frameLength = (int)_frameBuffer.Writer.BaseStream.Position;

            // build message
            _messageBuffer.Writer.Seek(0, SeekOrigin.Begin);
            if (!SwapBytes)
            {
                _messageBuffer.Writer.WriteReverse(ProtocolIdentifier);  //2b
                _messageBuffer.Writer.WriteReverse((ushort)frameLength); //2b
            }
            else
            {
                _messageBuffer.Writer.Write(ProtocolIdentifier);              //2b
                _messageBuffer.Writer.Write((ushort)frameLength);             //2b
            }
            _messageBuffer.Writer.Write(_frameBuffer.Buffer, 0, frameLength); //framelength
            messageLength = frameLength + mbapHeaderLength;

            // send request
            _serialPort.Write(_messageBuffer.Buffer, 0, messageLength);

            // special case: broadcast (only for write commands)
            if (unitIdentifier == 0)
            {
                return(_messageBuffer.Buffer.AsSpan(0, 0));
            }

            // wait for and process response
            messageLength = 0;
            _messageBuffer.Reader.BaseStream.Seek(0, SeekOrigin.Begin);

            while (true)
            {
                messageLength += _serialPort.Read(_messageBuffer.Buffer, messageLength, _messageBuffer.Buffer.Length - messageLength);

                if (ModbusUtils.DetectFrame(unitIdentifier, _messageBuffer.Buffer.AsMemory().Slice(mbapHeaderLength, messageLength - mbapHeaderLength)))
                {
                    break;
                }
                else
                {
                    // reset length because one or more chunks of data were received and written to
                    // the buffer, but no valid Modbus frame could be detected and now the buffer is full
                    if (messageLength == _messageBuffer.Buffer.Length)
                    {
                        messageLength = 0;
                    }
                }
            }

            //write message content to framebuffer
            _frameBuffer.Writer.BaseStream.Seek(0, SeekOrigin.Begin);
            _frameBuffer.Writer.Write(_messageBuffer.Buffer.AsSpan().Slice(mbapHeaderLength).ToArray(), 0, messageLength - mbapHeaderLength);
            frameLength = messageLength - mbapHeaderLength;

            unitIdentifier  = _frameBuffer.Reader.ReadByte();
            rawFunctionCode = _frameBuffer.Reader.ReadByte();

            if (rawFunctionCode == (byte)ModbusFunctionCode.Error + (byte)functionCode)
            {
                this.ProcessError(functionCode, (ModbusExceptionCode)_frameBuffer.Buffer[2]);
            }

            else if (rawFunctionCode != (byte)functionCode)
            {
                throw new ModbusException(ErrorMessage.ModbusClient_InvalidResponseFunctionCode);
            }

            return(_frameBuffer.Buffer.AsSpan(1, frameLength - 3));
        }
        private protected override async Task <Memory <byte> > TransceiveFrameAsync(byte unitIdentifier, ModbusFunctionCode functionCode, Action <ExtendedBinaryWriter> extendFrame, CancellationToken cancellationToken = default)
        {
            int    frameLength;
            byte   rawFunctionCode;
            ushort crc;

            // build request
            if (!(0 <= unitIdentifier && unitIdentifier <= 247))
            {
                throw new ModbusException(ErrorMessage.ModbusClient_InvalidUnitIdentifier);
            }

            // special case: broadcast (only for write commands)
            if (unitIdentifier == 0)
            {
                switch (functionCode)
                {
                case ModbusFunctionCode.WriteMultipleRegisters:
                case ModbusFunctionCode.WriteSingleCoil:
                case ModbusFunctionCode.WriteSingleRegister:
                case ModbusFunctionCode.WriteMultipleCoils:
                case ModbusFunctionCode.WriteFileRecord:
                case ModbusFunctionCode.MaskWriteRegister:
                    break;

                default:
                    throw new ModbusException(ErrorMessage.Modbus_InvalidUseOfBroadcast);
                }
            }

            _frameBuffer.Writer.Seek(0, SeekOrigin.Begin);
            _frameBuffer.Writer.Write(unitIdentifier);                                      // 00     Unit Identifier
            extendFrame(_frameBuffer.Writer);
            frameLength = (int)_frameBuffer.Writer.BaseStream.Position;

            // add CRC
            crc = ModbusUtils.CalculateCRC(_frameBuffer.Buffer.AsMemory().Slice(0, frameLength));
            _frameBuffer.Writer.Write(crc);
            frameLength = (int)_frameBuffer.Writer.BaseStream.Position;

            // send request
            await _serialPort.WriteAsync(_frameBuffer.Buffer, 0, frameLength, cancellationToken).ConfigureAwait(false);

            // special case: broadcast (only for write commands)
            if (unitIdentifier == 0)
            {
                return(_frameBuffer.Buffer.AsMemory(0, 0));
            }

            // wait for and process response
            frameLength = 0;
            _frameBuffer.Reader.BaseStream.Seek(0, SeekOrigin.Begin);

            while (true)
            {
                frameLength += await _serialPort.ReadAsync(_frameBuffer.Buffer, frameLength, _frameBuffer.Buffer.Length - frameLength, cancellationToken).ConfigureAwait(false);

                if (ModbusUtils.DetectFrame(unitIdentifier, _frameBuffer.Buffer.AsMemory().Slice(0, frameLength)))
                {
                    break;
                }
                else
                {
                    // reset length because one or more chunks of data were received and written to
                    // the buffer, but no valid Modbus frame could be detected and now the buffer is full
                    if (frameLength == _frameBuffer.Buffer.Length)
                    {
                        frameLength = 0;
                    }
                }
            }

            unitIdentifier  = _frameBuffer.Reader.ReadByte();
            rawFunctionCode = _frameBuffer.Reader.ReadByte();

            if (rawFunctionCode == (byte)ModbusFunctionCode.Error + (byte)functionCode)
            {
                this.ProcessError(functionCode, (ModbusExceptionCode)_frameBuffer.Buffer[2]);
            }

            else if (rawFunctionCode != (byte)functionCode)
            {
                throw new ModbusException(ErrorMessage.ModbusClient_InvalidResponseFunctionCode);
            }

            return(_frameBuffer.Buffer.AsMemory(1, frameLength - 3));
        }