コード例 #1
0
        /// <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);
        }
コード例 #2
0
ファイル: ElemGroup.cs プロジェクト: RapidScada/scada-v6
        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));
        }
コード例 #3
0
ファイル: ElemGroup.cs プロジェクト: RapidScada/scada-v6
        /// <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);
            }
        }
コード例 #4
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;
            }
        }
コード例 #5
0
ファイル: ModbusCmd.cs プロジェクト: RapidScada/scada-v6
        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));
        }
コード例 #6
0
ファイル: ModbusCmd.cs プロジェクト: RapidScada/scada-v6
        /// <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
            }
        }
コード例 #7
0
        /// <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);
        }
コード例 #8
0
        /// <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);
        }