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}"); } }
internal bool TestCommunicationCircuit() { if (!Port.IsOpen) { return(false); } lock (synLocker) { byte[] data = new byte[8]; data[0] = addr; data[1] = 0x08; data[2] = 0x00; data[3] = 0x00; data[4] = 0x17; data[5] = 0x70; byte[] crc = Checksum.CRC16(data, 6); data[6] = crc[0]; data[7] = crc[1]; if (InitTransArgs(8)) { Port.Write(data, 0, 8); if (WaitForResponse(1000)) { byte[] recvData = new byte[8]; Port.Read(recvData, 0, 8); return(recvData[1] == 0x08); } } return(false); } }
internal bool WriteOneRegisterValue(ushort address, ushort value) { if (!Port.IsOpen) { return(false); } lock (synLocker) { byte[] data = new byte[8]; data[0] = addr; data[1] = 0x06; data[2] = (byte)(address >> 8 & 0xFF); data[3] = (byte)(address & 0xFF); data[4] = (byte)(value >> 8 & 0xFF); data[5] = (byte)(value & 0xFF); byte[] crc = Checksum.CRC16(data, 6); data[6] = crc[0]; data[7] = crc[1]; if (InitTransArgs(8)) { Port.Write(data, 0, 8); if (WaitForResponse(2000)) { byte[] recvData = new byte[8]; Port.Read(recvData, 0, 8); return(BitConverter.ToUInt64(recvData, 0) == BitConverter.ToUInt64(data, 0)); } } return(false); } }
internal bool ReadRegisterValues(ushort address, out ushort[] value, int num = 1) { if (num > 20) { num = 20; } value = new ushort[num]; if (!Port.IsOpen) { return(false); } lock (synLocker) { byte[] data = new byte[8]; data[0] = addr; data[1] = 0x03; data[2] = (byte)(address >> 8 & 0xFF); data[3] = (byte)(address & 0xFF); data[4] = (byte)(num >> 8 & 0xFF); data[5] = (byte)(num & 0xFF); byte[] crc = Checksum.CRC16(data, 6); data[6] = crc[0]; data[7] = crc[1]; waitFlag = true; if (InitTransArgs(5 + num * 2)) { Port.Write(data, 0, 8); if (WaitForResponse(500 * num)) { byte[] recvData = new byte[readBufferNum]; Port.Read(recvData, 0, readBufferNum); if (recvData[2] == 2 * num) { for (int i = 0; i < num; i++) { value[i] = recvData[3 + i * 2]; value[i] <<= 8; value[i] += recvData[4 + i * 2]; } return(true); } } } return(false); } }
internal bool WriteMultipleRegisterValues(ushort address, ushort[] value, int num) { if (!Port.IsOpen) { return(false); } if (value.Length < num) { num = value.Length; } lock (synLocker) { byte[] data = new byte[9 + num * 2]; data[0] = addr; data[1] = 0x10; data[2] = (byte)(address >> 8 & 0xFF); data[3] = (byte)(address & 0xFF); data[4] = 0x00; data[5] = (byte)(num); data[6] = (byte)(data[5] * 2); for (int i = 0; i < data[6]; i += 2) { data[7 + i] = (byte)(value[i / 2] >> 8 & 0xFF); data[8 + i] = (byte)(value[i / 2] & 0xFF); } byte[] crc = Checksum.CRC16(data, 7 + num * 2); data[7 + num * 2] = crc[0]; data[8 + num * 2] = crc[1]; if (InitTransArgs(8)) { Port.Write(data, 0, data.Length); if (WaitForResponse(2000)) { byte[] recvData = new byte[8]; Port.Read(recvData, 0, 8); return(BitConverter.ToUInt32(data, 2) == BitConverter.ToUInt32(recvData, 2)); } } return(false); } }
/// <summary> /// Serializes the request ready to send via serial. /// </summary> /// <returns></returns> public byte[] Serialize() { var buffer = new DataBuffer(2); buffer.SetByte(0, DeviceId); buffer.SetByte(1, (byte)Function); switch (Function) { case FunctionCode.ReadCoils: case FunctionCode.ReadDiscreteInputs: case FunctionCode.ReadHoldingRegisters: case FunctionCode.ReadInputRegisters: buffer.AddUInt16(Address); buffer.AddUInt16(Count); break; case FunctionCode.WriteMultipleCoils: case FunctionCode.WriteMultipleRegisters: buffer.AddUInt16(Address); buffer.AddUInt16(Count); if (Data?.Length > 0) { buffer.AddBytes(Data.Buffer); } break; case FunctionCode.WriteSingleCoil: case FunctionCode.WriteSingleRegister: buffer.AddUInt16(Address); if (Data?.Length > 0) { buffer.AddBytes(Data.Buffer); } break; case FunctionCode.EncapsulatedInterface: buffer.AddByte((byte)MEIType); switch (MEIType) { case MEIType.CANOpenGeneralReference: if (Data?.Length > 0) { buffer.AddBytes(Data.Buffer); } break; case MEIType.ReadDeviceInformation: buffer.AddByte((byte)MEICategory); buffer.AddByte((byte)MEIObject); break; default: throw new NotImplementedException(); } break; default: throw new NotImplementedException(); } byte[] crc = Checksum.CRC16(buffer.Buffer); buffer.AddBytes(crc); return(buffer.Buffer); }
private void Deserialize(byte[] bytes) { // Response timed out => device not available if (bytes.All(b => b == 0)) { IsTimeout = true; return; } var buffer = new DataBuffer(bytes); var crcBuff = buffer.GetBytes(buffer.Length - 2, 2); var 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)."); } DeviceId = buffer.GetByte(0); var fn = buffer.GetByte(1); if ((fn & Consts.ErrorMask) > 0) { Function = (FunctionCode)(fn ^ Consts.ErrorMask); ErrorCode = (ErrorCode)buffer.GetByte(2); } else { Function = (FunctionCode)fn; switch (Function) { case FunctionCode.ReadCoils: case FunctionCode.ReadDiscreteInputs: case FunctionCode.ReadHoldingRegisters: case FunctionCode.ReadInputRegisters: var len = buffer.GetByte(2); if (buffer.Length != len + 3 + 2) // following bytes + 3 byte head + 2 byte CRC { throw new ArgumentException("Response incomplete"); } Data = new DataBuffer(buffer.GetBytes(3, buffer.Length - 5)); break; case FunctionCode.WriteMultipleCoils: case FunctionCode.WriteMultipleRegisters: Address = buffer.GetUInt16(2); Count = buffer.GetUInt16(4); 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(2); switch (MEIType) { case MEIType.CANOpenGeneralReference: Data = new DataBuffer(buffer.Buffer.Skip(3).ToArray()); break; case MEIType.ReadDeviceInformation: MEICategory = (DeviceIDCategory)buffer.GetByte(3); ConformityLevel = buffer.GetByte(4); MoreRequestsNeeded = buffer.GetByte(5) > 0; NextObjectId = buffer.GetByte(6); ObjectCount = buffer.GetByte(7); Data = new DataBuffer(buffer.Buffer.Skip(8).ToArray()); break; default: throw new NotImplementedException(); } break; default: throw new NotImplementedException(); } } }
internal byte[] Serialize() { var buffer = new DataBuffer(2); buffer.SetByte(0, DeviceId); var fn = (byte)Function; if (IsError) { fn = (byte)(fn & Consts.ErrorMask); buffer.AddByte((byte)ErrorCode); } else { switch (Function) { case FunctionCode.ReadCoils: case FunctionCode.ReadDiscreteInputs: case FunctionCode.ReadHoldingRegisters: case FunctionCode.ReadInputRegisters: buffer.AddByte((byte)Data.Length); buffer.AddBytes(Data.Buffer); break; case FunctionCode.WriteMultipleCoils: case FunctionCode.WriteMultipleRegisters: buffer.AddUInt16(Address); buffer.AddUInt16(Count); break; case FunctionCode.WriteSingleCoil: case FunctionCode.WriteSingleRegister: buffer.AddUInt16(Address); buffer.AddBytes(Data.Buffer); break; case FunctionCode.EncapsulatedInterface: buffer.AddByte((byte)MEIType); switch (MEIType) { case MEIType.CANOpenGeneralReference: if (Data?.Length > 0) { buffer.AddBytes(Data.Buffer); } break; case MEIType.ReadDeviceInformation: buffer.AddByte((byte)MEICategory); buffer.AddByte(ConformityLevel); buffer.AddByte((byte)(MoreRequestsNeeded ? 0xFF : 0x00)); buffer.AddByte(NextObjectId); buffer.AddByte(ObjectCount); buffer.AddBytes(Data.Buffer); break; default: throw new NotImplementedException(); } break; default: throw new NotImplementedException(); } } buffer.SetByte(1, fn); var crc = Checksum.CRC16(buffer.Buffer); buffer.AddBytes(crc); return(buffer.Buffer); }