/// <summary> /// Decodes the response PDU. /// </summary> public virtual bool DecodeRespPDU(byte[] buffer, int offset, int length, out string errMsg) { errMsg = ""; bool result = false; byte respFuncCode = buffer[offset]; if (respFuncCode == FuncCode) { if (length == RespPduLen) { result = true; } else { errMsg = ModbusPhrases.IncorrectPduLength; } } else if (respFuncCode == ExcFuncCode) { errMsg = length == 2 ? ModbusPhrases.DeviceError + ": " + ModbusUtils.GetExcDescr(buffer[offset + 1]) : ModbusPhrases.IncorrectPduLength; } else { errMsg = ModbusPhrases.IncorrectPduFuncCode; } return(result); }
private string reqDescr; // the request description /// <summary> /// Initializes a new instance of the class. /// </summary> public ElemGroup(DataBlock dataBlock) : base(dataBlock) { reqDescr = ""; Elems = new List <Elem>(); ElemData = null; StartTagIdx = -1; SetFuncCode(ModbusUtils.GetReadFuncCode(dataBlock)); }
/// <summary> /// Gets the element value according to its type, converted to double. /// </summary> public double GetElemVal(int elemIdx) { Elem elem = Elems[elemIdx]; byte[] elemData = ElemData[elemIdx]; byte[] buf; // order bytes if needed if (elem.ByteOrder == null) { buf = elemData; } else { buf = new byte[elemData.Length]; ModbusUtils.ApplyByteOrder(elemData, buf, elem.ByteOrder); } // calculate value switch (elem.ElemType) { case ElemType.UShort: return(BitConverter.ToUInt16(buf, 0)); case ElemType.Short: return(BitConverter.ToInt16(buf, 0)); case ElemType.UInt: return(BitConverter.ToUInt32(buf, 0)); case ElemType.Int: return(BitConverter.ToInt32(buf, 0)); case ElemType.ULong: // possible data loss return(BitConverter.ToUInt64(buf, 0)); case ElemType.Long: // possible data loss return(BitConverter.ToInt64(buf, 0)); case ElemType.Float: return(BitConverter.ToSingle(buf, 0)); case ElemType.Double: return(BitConverter.ToDouble(buf, 0)); case ElemType.Bool: return(buf[0] > 0 ? 1.0 : 0.0); default: return(0.0); } }
/// <summary> /// Initializes the request ADU and calculates the response length. /// </summary> public virtual void InitReqADU(byte devAddr, TransMode transMode) { if (ReqPDU == null) { return; } int pduLen = ReqPDU.Length; switch (transMode) { case TransMode.RTU: ReqADU = new byte[pduLen + 3]; ReqADU[0] = devAddr; Buffer.BlockCopy(ReqPDU, 0, ReqADU, 1, ReqPDU.Length); ushort crc = ModbusUtils.CRC16(ReqADU, 0, pduLen + 1); ReqADU[pduLen + 1] = (byte)(crc % 256); ReqADU[pduLen + 2] = (byte)(crc / 256); RespAduLen = RespPduLen + 3; break; case TransMode.ASCII: byte[] aduBuf = new byte[pduLen + 2]; aduBuf[0] = devAddr; Buffer.BlockCopy(ReqPDU, 0, aduBuf, 1, ReqPDU.Length); aduBuf[pduLen + 1] = ModbusUtils.LRC(aduBuf, 0, pduLen + 1); StringBuilder sbADU = new StringBuilder(); foreach (byte b in aduBuf) { sbADU.Append(b.ToString("X2")); } ReqADU = Encoding.ASCII.GetBytes(sbADU.ToString()); ReqStr = ModbusUtils.Colon + sbADU; RespAduLen = RespPduLen + 2; break; default: // TransModes.TCP ReqADU = new byte[pduLen + 7]; ReqADU[0] = 0; ReqADU[1] = 0; ReqADU[2] = 0; ReqADU[3] = 0; ReqADU[4] = (byte)((pduLen + 1) / 256); ReqADU[5] = (byte)((pduLen + 1) % 256); ReqADU[6] = devAddr; Buffer.BlockCopy(ReqPDU, 0, ReqADU, 7, ReqPDU.Length); RespAduLen = RespPduLen + 7; break; } }
private string reqDescr; // the command description /// <summary> /// Initializes a new instance of the class. /// </summary> public ModbusCmd(DataBlock dataBlock, bool multiple) : base(dataBlock) { if (dataBlock != DataBlock.Coils && dataBlock != DataBlock.HoldingRegisters && dataBlock != DataBlock.Custom) { throw new InvalidOperationException(ModbusPhrases.IllegalDataBlock); } reqDescr = ""; Multiple = multiple; ElemType = ElemType.Undefined; ElemCnt = 1; ByteOrder = null; CmdNum = 0; CmdCode = ""; Value = 0; Data = null; SetFuncCode(ModbusUtils.GetWriteFuncCode(dataBlock, multiple)); }
/// <summary> /// Initializes the request PDU and calculates the response length. /// </summary> public override void InitReqPDU() { if (DataBlock == DataBlock.Custom) { // build PDU for custom command int dataLength = Data == null ? 0 : Data.Length; ReqPDU = new byte[1 + dataLength]; ReqPDU[0] = FuncCode; if (dataLength > 0) { Buffer.BlockCopy(Data, 0, ReqPDU, 1, dataLength); } RespPduLen = ReqPDU.Length; // assuming echo } else if (Multiple) { // build PDU for WriteMultipleCoils and WriteMultipleRegisters commands int quantity; // quantity of registers int dataLength; // data length in bytes if (DataBlock == DataBlock.Coils) { quantity = ElemCnt; dataLength = (ElemCnt % 8 == 0) ? ElemCnt / 8 : ElemCnt / 8 + 1; } else { quantity = ElemCnt * ModbusUtils.GetQuantity(ElemType); dataLength = quantity * 2; } ReqPDU = new byte[6 + dataLength]; ReqPDU[0] = FuncCode; ReqPDU[1] = (byte)(Address / 256); ReqPDU[2] = (byte)(Address % 256); ReqPDU[3] = (byte)(quantity / 256); ReqPDU[4] = (byte)(quantity % 256); ReqPDU[5] = (byte)dataLength; ModbusUtils.ApplyByteOrder(Data, 0, ReqPDU, 6, dataLength, ByteOrder, false); // set response length RespPduLen = 5; } else { // build PDU for WriteSingleCoil and WriteSingleRegister commands int dataLength = DataBlock == DataBlock.Coils ? 2 : ModbusUtils.GetDataLength(ElemType); ReqPDU = new byte[3 + dataLength]; ReqPDU[0] = FuncCode; ReqPDU[1] = (byte)(Address / 256); ReqPDU[2] = (byte)(Address % 256); if (DataBlock == DataBlock.Coils) { ReqPDU[3] = Value > 0 ? (byte)0xFF : (byte)0x00; ReqPDU[4] = 0x00; } else { byte[] data = dataLength == 2 ? new byte[] // standard Modbus { (byte)(Value / 256), (byte)(Value % 256) } : Data; ModbusUtils.ApplyByteOrder(data, 0, ReqPDU, 3, dataLength, ByteOrder, false); } // set response length RespPduLen = ReqPDU.Length; // echo } }
/// <summary> /// Performs a request in the ASCII mode. /// </summary> protected bool AsciiRequest(DataUnit dataUnit) { bool result = false; // send request log.WriteLine(dataUnit.ReqDescr); Connection.WriteLine(dataUnit.ReqStr, out string logText); log.WriteLine(logText); // receive response string line = Connection.ReadLine(Timeout, out logText); log.WriteLine(logText); int lineLen = line == null ? 0 : line.Length; if (lineLen >= 3) { int aduLen = (lineLen - 1) / 2; if (aduLen == dataUnit.RespAduLen && lineLen % 2 == 1) { // receive response ADU byte[] aduBuf = new byte[aduLen]; bool parseOK = true; for (int i = 0, j = 1; i < aduLen && parseOK; i++, j += 2) { try { aduBuf[i] = byte.Parse(line.Substring(j, 2), NumberStyles.HexNumber); } catch { log.WriteLine(ModbusPhrases.IncorrectSymbol); parseOK = false; } } if (parseOK) { if (aduBuf[aduLen - 1] == ModbusUtils.LRC(aduBuf, 0, aduLen - 1)) { // decode response if (dataUnit.DecodeRespPDU(aduBuf, 1, aduLen - 2, out string errMsg)) { log.WriteLine(ModbusPhrases.OK); result = true; } else { log.WriteLine(errMsg + "!"); } } else { log.WriteLine(ModbusPhrases.LrcError); } } } else { log.WriteLine(ModbusPhrases.IncorrectAduLength); } } else { log.WriteLine(ModbusPhrases.CommErrorWithExclamation); } return(result); }
/// <summary> /// Performs a request in the PDU mode. /// </summary> protected bool RtuRequest(DataUnit dataUnit) { bool result = false; // send request log.WriteLine(dataUnit.ReqDescr); Connection.Write(dataUnit.ReqADU, 0, dataUnit.ReqADU.Length, ProtocolFormat.Hex, out string logText); log.WriteLine(logText); // receive response // partial read to calculate PDU length const int FirstCount = 2; int readCnt = Connection.Read(InBuf, 0, FirstCount, Timeout, ProtocolFormat.Hex, out logText); log.WriteLine(logText); if (readCnt != FirstCount) { log.WriteLine(ModbusPhrases.CommErrorWithExclamation); } else if (InBuf[0] != dataUnit.ReqADU[0]) // validate device address { log.WriteLine(ModbusPhrases.IncorrectDevAddr); } else if (!(InBuf[1] == dataUnit.FuncCode || InBuf[1] == dataUnit.ExcFuncCode)) // validate function code { log.WriteLine(ModbusPhrases.IncorrectPduFuncCode); } else { int pduLen; int count; if (InBuf[1] == dataUnit.FuncCode) { pduLen = dataUnit.RespPduLen; count = dataUnit.RespAduLen - FirstCount; } else // exception received { pduLen = 2; count = 3; } // read rest of response readCnt = Connection.Read(InBuf, FirstCount, count, Timeout, ProtocolFormat.Hex, out logText); log.WriteLine(logText); if (readCnt != count) { log.WriteLine(ModbusPhrases.CommErrorWithExclamation); } else if (InBuf[pduLen + 1] + InBuf[pduLen + 2] * 256 != ModbusUtils.CRC16(InBuf, 0, pduLen + 1)) { log.WriteLine(ModbusPhrases.CrcError); } else if (dataUnit.DecodeRespPDU(InBuf, 1, pduLen, out string errMsg)) { log.WriteLine(ModbusPhrases.OK); result = true; } else { log.WriteLine(errMsg + "!"); } } return(result); }