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)); }
protected override void OnResponseReady(int frameLength) { _serialPort.Write(this.FrameBuffer.Buffer, 0, frameLength); }