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); } }
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)); }