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