Esempio n. 1
0
        private void Deserialize(byte[] bytes)
        {
            var buffer = new DataBuffer(bytes);

            DeviceId = buffer.GetByte(0);
            Function = (FunctionCode)buffer.GetByte(1);

            byte[] crcBuff = buffer.GetBytes(buffer.Length - 3, 2);
            byte[] crcCalc = Checksum.CRC16(bytes, 0, bytes.Length - 2);

            if (crcBuff[0] != crcCalc[0] || crcBuff[1] != crcCalc[1])
            {
                throw new InvalidOperationException("Data not valid (CRC check failed).");
            }

            switch (Function)
            {
            case FunctionCode.ReadCoils:
            case FunctionCode.ReadDiscreteInputs:
            case FunctionCode.ReadHoldingRegisters:
            case FunctionCode.ReadInputRegisters:
                Address = buffer.GetUInt16(2);
                Count   = buffer.GetUInt16(4);
                break;

            case FunctionCode.WriteMultipleCoils:
            case FunctionCode.WriteMultipleRegisters:
                Address = buffer.GetUInt16(2);
                Count   = buffer.GetUInt16(4);
                Data    = new DataBuffer(buffer.GetBytes(6, buffer.Length - 8));
                break;

            case FunctionCode.WriteSingleCoil:
            case FunctionCode.WriteSingleRegister:
                Address = buffer.GetUInt16(2);
                Data    = new DataBuffer(buffer.GetBytes(4, buffer.Length - 6));
                break;

            case FunctionCode.EncapsulatedInterface:
                MEIType = (MEIType)buffer.GetByte(8);
                switch (MEIType)
                {
                case MEIType.CANOpenGeneralReference:
                    Data = new DataBuffer(buffer.Buffer.Skip(9).ToArray());
                    break;

                case MEIType.ReadDeviceInformation:
                    MEICategory = (DeviceIDCategory)buffer.GetByte(9);
                    MEIObject   = (DeviceIDObject)buffer.GetByte(10);
                    break;

                default:
                    throw new NotImplementedException($"Unknown MEI type: {MEIType}");
                }
                break;

            default:
                throw new NotImplementedException($"Unknown function code: {Function}");
            }
        }
 public RequestExtendedStruct(FunctionType functionCode, MEIType mei, DeviceIDCategory deviceIdCat, DeviceIDObject deviceIdObj)
 {
     FunctionCode = functionCode;
     MEI          = mei;
     DeviceIdCat  = deviceIdCat;
     DeviceIdObj  = deviceIdObj;
 }
Esempio n. 3
0
        /// <summary>
        /// Reads device information. (Modbus function 43).
        /// </summary>
        /// <param name="deviceId">The id to address the device (slave).</param>
        /// <param name="categoryId">The category to read (basic, regular, extended, individual).</param>
        /// <param name="objectId">The first object id to read.</param>
        /// <returns>A map of device information and their content as raw bytes.</returns>>
        public async Task <Dictionary <byte, byte[]> > ReadDeviceInformationRaw(byte deviceId, DeviceIDCategory categoryId, DeviceIDObject objectId = DeviceIDObject.VendorName)
        {
            logger?.LogTrace($"ModbusClient.ReadDeviceInformation({deviceId}, {categoryId}, {objectId})");
            if (isDisposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }

            if (deviceId < Consts.MinDeviceIdRtu || Consts.MaxDeviceId < deviceId)
            {
                throw new ArgumentOutOfRangeException(nameof(deviceId));
            }

            try
            {
                var request = new Request
                {
                    DeviceId    = deviceId,
                    Function    = FunctionCode.EncapsulatedInterface,
                    MEIType     = MEIType.ReadDeviceInformation,
                    MEICategory = categoryId,
                    MEIObject   = objectId
                };
                var response = await SendRequest(request);

                if (response.IsTimeout)
                {
                    throw new IOException("Request timed out");
                }
                if (response.IsError)
                {
                    throw new ModbusException(response.ErrorMessage);
                }

                var dict = new Dictionary <byte, byte[]>();
                for (int i = 0, idx = 0; i < response.ObjectCount && idx < response.Data.Length; i++)
                {
                    byte objId = response.Data.GetByte(idx);
                    idx++;
                    byte len = response.Data.GetByte(idx);
                    idx++;
                    byte[] data = response.Data.GetBytes(idx, len);
                    idx += len;

                    dict.Add(objId, data);
                }

                if (response.MoreRequestsNeeded)
                {
                    var transDict = await ReadDeviceInformationRaw(deviceId, categoryId, (DeviceIDObject)response.NextObjectId);

                    foreach (var kvp in transDict)
                    {
                        dict.Add(kvp.Key, kvp.Value);
                    }
                }

                return(dict);
            }
            catch (IOException ex)
            {
                logger?.LogWarning(ex, "Reading device information. Reconnecting.");
                ConnectingTask = Task.Run((Action)Reconnect);
            }

            return(null);
        }
Esempio n. 4
0
        /// <summary>
        /// Reads device information. (Modbus function 43).
        /// </summary>
        /// <param name="deviceId">The id to address the device (slave).</param>
        /// <param name="categoryId">The category to read (basic, regular, extended, individual).</param>
        /// <param name="objectId">The first object id to read.</param>
        /// <returns>A map of device information and their content as string.</returns>
        public async Task <Dictionary <DeviceIDObject, string> > ReadDeviceInformation(byte deviceId, DeviceIDCategory categoryId, DeviceIDObject objectId = DeviceIDObject.VendorName)
        {
            var raw = await ReadDeviceInformationRaw(deviceId, categoryId, objectId);

            if (raw == null)
            {
                return(null);
            }

            var dict = new Dictionary <DeviceIDObject, string>();

            foreach (var kvp in raw)
            {
                dict.Add((DeviceIDObject)kvp.Key, Encoding.ASCII.GetString(kvp.Value));
            }
            return(dict);
        }
Esempio n. 5
0
        private void Deserialize(ReadOnlySpan <byte> bytes)
        {
            TransactionId = BinaryPrimitives.ReadUInt16BigEndian(bytes.Slice(0, 2));
            var ident = BinaryPrimitives.ReadUInt16BigEndian(bytes.Slice(2, 2));

            if (ident != 0)
            {
                throw new ArgumentException("Protocol ident not valid");
            }
            var length = BinaryPrimitives.ReadUInt16BigEndian(bytes.Slice(4, 2));

            if (length + 6 != bytes.Length)
            {
                throw new ArgumentException("Data incomplete");
            }
            DeviceId = bytes[6];
            Function = (FunctionCode)bytes[7];

            switch (Function)
            {
            case FunctionCode.ReadCoils:
            case FunctionCode.ReadDiscreteInputs:
            case FunctionCode.ReadHoldingRegisters:
            case FunctionCode.ReadInputRegisters:
                Address = BinaryPrimitives.ReadUInt16BigEndian(bytes.Slice(8, 2));
                Count   = BinaryPrimitives.ReadUInt16BigEndian(bytes.Slice(10, 2));
                break;

            case FunctionCode.WriteMultipleCoils:
            case FunctionCode.WriteMultipleRegisters:
                Address = BinaryPrimitives.ReadUInt16BigEndian(bytes.Slice(8, 2));
                Count   = BinaryPrimitives.ReadUInt16BigEndian(bytes.Slice(10, 2));
                Data    = new DataBuffer(bytes.Slice(12).ToArray());
                break;

            case FunctionCode.WriteSingleCoil:
            case FunctionCode.WriteSingleRegister:
                Address = BinaryPrimitives.ReadUInt16BigEndian(bytes.Slice(8, 2));
                Data    = new DataBuffer(bytes.Slice(10).ToArray());
                break;

            case FunctionCode.EncapsulatedInterface:
                MEIType = (MEIType)bytes[8];
                switch (MEIType)
                {
                case MEIType.CANOpenGeneralReference:
                    Data = new DataBuffer(bytes.Slice(9).ToArray());
                    break;

                case MEIType.ReadDeviceInformation:
                    MEICategory = (DeviceIDCategory)bytes[9];
                    MEIObject   = (DeviceIDObject)bytes[10];
                    break;

                default:
                    throw new NotImplementedException();
                }
                break;

            default:
                throw new NotImplementedException();
            }
        }
Esempio n. 6
0
        private void Deserialize(byte[] bytes)
        {
            var buffer = new DataBuffer(bytes);

            TransactionId = buffer.GetUInt16(0);
            var ident = buffer.GetUInt16(2);

            if (ident != 0)
            {
                throw new ArgumentException("Protocol ident not valid");
            }
            var length = buffer.GetUInt16(4);

            if (length + 6 != buffer.Length)
            {
                throw new ArgumentException("Data incomplete");
            }
            DeviceId = buffer.GetByte(6);
            Function = (FunctionCode)buffer.GetByte(7);

            switch (Function)
            {
            case FunctionCode.ReadCoils:
            case FunctionCode.ReadDiscreteInputs:
            case FunctionCode.ReadHoldingRegisters:
            case FunctionCode.ReadInputRegisters:
                Address = buffer.GetUInt16(8);
                Count   = buffer.GetUInt16(10);
                break;

            case FunctionCode.WriteMultipleCoils:
            case FunctionCode.WriteMultipleRegisters:
                Address = buffer.GetUInt16(8);
                Count   = buffer.GetUInt16(10);
                Data    = new DataBuffer(buffer.Buffer.Skip(12).ToArray());
                break;

            case FunctionCode.WriteSingleCoil:
            case FunctionCode.WriteSingleRegister:
                Address = buffer.GetUInt16(8);
                Data    = new DataBuffer(buffer.Buffer.Skip(10).ToArray());
                break;

            case FunctionCode.EncapsulatedInterface:
                MEIType = (MEIType)buffer.GetByte(8);
                switch (MEIType)
                {
                case MEIType.CANOpenGeneralReference:
                    Data = new DataBuffer(buffer.Buffer.Skip(9).ToArray());
                    break;

                case MEIType.ReadDeviceInformation:
                    MEICategory = (DeviceIDCategory)buffer.GetByte(9);
                    MEIObject   = (DeviceIDObject)buffer.GetByte(10);
                    break;

                default:
                    throw new NotImplementedException();
                }
                break;

            default:
                throw new NotImplementedException();
            }
        }
Esempio n. 7
0
        private void Deserialize(IEnumerable <byte> bytes)
        {
            var buffer = new DataBuffer(bytes);

            TransactionId = buffer.GetUInt16(0);
            ushort ident = buffer.GetUInt16(2);

            if (ident != 0)
            {
                throw new ArgumentException("Protocol identifier not valid.");
            }

            ushort length = buffer.GetUInt16(4);

            if (buffer.Length < length + 6)
            {
                throw new ArgumentException("Too less data.");
            }

            if (buffer.Length > length + 6)
            {
                if (buffer.Buffer.Skip(length + 6).Any(b => b != 0))
                {
                    throw new ArgumentException("Too many data.");
                }

                buffer = new DataBuffer(bytes.Take(length + 6));
            }

            DeviceId = buffer.GetByte(6);
            Function = (FunctionCode)buffer.GetByte(7);

            switch (Function)
            {
            case FunctionCode.ReadCoils:
            case FunctionCode.ReadDiscreteInputs:
            case FunctionCode.ReadHoldingRegisters:
            case FunctionCode.ReadInputRegisters:
                Address = buffer.GetUInt16(8);
                Count   = buffer.GetUInt16(10);
                break;

            case FunctionCode.WriteMultipleCoils:
            case FunctionCode.WriteMultipleRegisters:
                Address = buffer.GetUInt16(8);
                Count   = buffer.GetUInt16(10);
                Data    = new DataBuffer(buffer.Buffer.Skip(12));
                break;

            case FunctionCode.WriteSingleCoil:
            case FunctionCode.WriteSingleRegister:
                Address = buffer.GetUInt16(8);
                Data    = new DataBuffer(buffer.Buffer.Skip(10));
                break;

            case FunctionCode.EncapsulatedInterface:
                MEIType = (MEIType)buffer.GetByte(8);
                switch (MEIType)
                {
                case MEIType.CANOpenGeneralReference:
                    Data = new DataBuffer(buffer.Buffer.Skip(9));
                    break;

                case MEIType.ReadDeviceInformation:
                    MEICategory = (DeviceIDCategory)buffer.GetByte(9);
                    MEIObject   = (DeviceIDObject)buffer.GetByte(10);
                    break;

                default:
                    throw new NotImplementedException($"Unknown MEI type: {MEIType}.");
                }
                break;

            default:
                throw new NotImplementedException($"Unknown function code: {Function}.");
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Reads device information. (Modbus function 43).
        /// </summary>
        /// <param name="deviceId">The id to address the device (slave).</param>
        /// <param name="categoryId">The category to read (basic, regular, extended, individual).</param>
        /// <param name="objectId">The first object id to read.</param>
        /// <returns>A map of device information and their content as raw bytes.</returns>
        public async Task <Dictionary <byte, byte[]> > ReadDeviceInformationRaw(byte deviceId, DeviceIDCategory categoryId, DeviceIDObject objectId = DeviceIDObject.VendorName)
        {
            logger?.LogTrace($"ModbusClient.ReadDeviceInformation({deviceId}, {categoryId}, {objectId})");

            if (deviceId < Consts.MinDeviceIdTcp || Consts.MaxDeviceId < deviceId)
            {
                throw new ArgumentOutOfRangeException(nameof(deviceId));
            }

            try
            {
                var request = new Request
                {
                    DeviceId    = deviceId,
                    Function    = FunctionCode.EncapsulatedInterface,
                    MEIType     = MEIType.ReadDeviceInformation,
                    MEICategory = categoryId,
                    MEIObject   = objectId
                };
                var response = await SendRequest(request, mainCts.Token);

                if (response.IsTimeout)
                {
                    throw new SocketException((int)SocketError.TimedOut);
                }
                if (response.IsError)
                {
                    throw new ModbusException(response.ErrorMessage)
                          {
                              ErrorCode = response.ErrorCode
                          };
                }
                if (request.TransactionId != response.TransactionId)
                {
                    throw new ModbusException(nameof(response.TransactionId) + " does not match");
                }

                var dict = new Dictionary <byte, byte[]>();
                for (int i = 0, idx = 0; i < response.ObjectCount && idx < response.Data.Length; i++)
                {
                    byte objId = response.Data.GetByte(idx);
                    idx++;
                    byte len = response.Data.GetByte(idx);
                    idx++;
                    byte[] bytes = response.Data.GetBytes(idx, len);
                    idx += len;

                    dict.Add(objId, bytes);
                }

                if (response.MoreRequestsNeeded)
                {
                    var transDict = await ReadDeviceInformationRaw(deviceId, categoryId, (DeviceIDObject)response.NextObjectId);

                    foreach (var kvp in transDict)
                    {
                        dict.Add(kvp.Key, kvp.Value);
                    }
                }

                return(dict);
            }
            catch (SocketException ex)
            {
                logger?.LogWarning(ex, "ModbusClient.ReadDeviceInformation failed. Reconnecting.");
                Task.Run(() => Reconnect(mainCts.Token)).Forget();
                ConnectingTask = GetWaitTask(mainCts.Token);
            }
            catch (IOException ex)
            {
                logger?.LogWarning(ex, "ModbusClient.ReadDeviceInformation failed. Reconnecting.");
                Task.Run(() => Reconnect(mainCts.Token)).Forget();
                ConnectingTask = GetWaitTask(mainCts.Token);
            }

            return(null);
        }