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; }
/// <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); }
/// <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); }
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(); } }
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(); } }
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}."); } }
/// <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); }