Esempio n. 1
0
        public static bool DetectFrame(byte unitIdentifier, Memory <byte> frame)
        {
            byte newUnitIdentifier;

            /* Correct response frame (min. 6 bytes)
             * 00 Unit Identifier
             * 01 Function Code
             * 02 Byte count
             * 03 Minimum of 1 byte
             * 04 CRC Byte 1
             * 05 CRC Byte 2
             */

            /* Error response frame (5 bytes)
             * 00 Unit Identifier
             * 01 Function Code + 0x80
             * 02 Exception Code
             * 03 CRC Byte 1
             * 04 CRC Byte 2
             */

            var span = frame.Span;

            if (span.Length < 5)
            {
                return(false);
            }

            if (unitIdentifier != 255) // 255 means "skip unit identifier check"
            {
                newUnitIdentifier = span[0];

                if (newUnitIdentifier != unitIdentifier)
                {
                    return(false);
                }
            }

            // CRC check
            var crcBytes    = span.Slice(span.Length - 2, 2);
            var actualCRC   = unchecked ((ushort)((crcBytes[1] << 8) + crcBytes[0]));
            var expectedCRC = ModbusUtils.CalculateCRC(frame.Slice(0, frame.Length - 2));

            if (actualCRC != expectedCRC)
            {
                return(false);
            }

            return(true);
        }
        protected override int WriteFrame(Action extendFrame)
        {
            int    frameLength;
            ushort crc;

            this.FrameBuffer.Writer.Seek(0, SeekOrigin.Begin);

            // add unit identifier
            this.FrameBuffer.Writer.Write(this.UnitIdentifier);

            // add PDU
            extendFrame();

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

            return(frameLength + 2);
        }
Esempio n. 3
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));
        }