Esempio n. 1
0
        /// <summary>
        /// Send short frame command 0 to discover the HART Device that is
        /// connected to the network.
        /// </summary>
        /// <returns><see cref="HartDevice"/></returns>
        private HartDevice DiscoverHartDevice(byte polladdr)
        {
            HartIPResponse Rsp = null;

            byte[]     Params = new byte[5];
            HartDevice Dev    = null;

            // short frame
            Params[0] = 0x02;
            // Device's polling address in short frame
            Params[1] = (byte)((polladdr & 0x3F) | 0x80);
            // cmd 0
            Params[2] = HARTIPMessage.CMD_READ_UID;
            // byte count is zero
            Params[3] = 0x00;
            // get check sum byte
            Params[4] = HartUtil.GetCheckSum(Params, 4);

            Rsp = SendHartRequest(Params, 5, HARTIPConnect.IO_SOCKET_TIMEOUT);
            if (Rsp != null)
            {
                try
                {
                    Dev = HartUtil.CreateHartDevice(Rsp, null);
                }
                catch (Exception e)
                {
                    m_Error = "DiscoverHartDevice Exception: " + e.Message;
                    Logger.Log(m_Error, true);
                }
            }

            return(Dev);
        }
 /// <summary>
 /// Contructor
 /// </summary>
 /// <param name="Req">HartIPRequest</param>
 /// <param name="nNumOfRetries">uint</param>
 /// <param name="nRetryDelay">uint</param>
 public RequestTask(HartIPRequest Req, uint nNumOfRetries,
                    uint nRetryDelay)
 {
     this.HartIPReq        = Req;
     this.HartIPRsp        = null;
     this.nNumberOfRetries = nNumOfRetries;
     this.nDrRetries       = 0;
     this.nRetryDelay      = nRetryDelay;
     this.bIsCompleted     = false;
 }
Esempio n. 3
0
        /// <summary>
        /// Receive a HART-IP Response from the network connection.
        /// </summary>
        /// <returns><see cref="HartIPResponse"/></returns>
        protected override HartIPResponse GetResponse()
        {
            HartIPResponse Rsp      = null;
            BinaryReader   breader  = null;
            MemoryStream   inStream = null;

            do
            {
                if (m_socket == null)
                {
                    break;
                }

                try
                {
                    byte[]     RspMsg       = new byte[HARTIPMessage.MAX_HARTMSG_LENGTH];
                    int        nRecvLen     = 0;
                    IPEndPoint sender       = new IPEndPoint(/*m_HostIp*/ IPAddress.Any, 0);
                    EndPoint   senderRemote = (EndPoint)sender;
                    nRecvLen = m_socket.ReceiveFrom(RspMsg, ref senderRemote);
                    if (nRecvLen == 0)
                    {
                        break;
                    }

                    String TimeStamp = HartUtil.GetTimeStamp();
                    inStream = new System.IO.MemoryStream(RspMsg);
                    breader  = new System.IO.BinaryReader(inStream);
                    // set position to the beginning of the stream
                    breader.BaseStream.Position = 0;

                    int nRecvPort = ((IPEndPoint)senderRemote).Port;
                    if (m_nSendPort != nRecvPort)
                    {
                        m_nSendPort = ((IPEndPoint)senderRemote).Port;
                    }

                    Rsp = new HartIPResponse(breader, TimeStamp);
                }
                finally
                {
                    if (breader != null)
                    {
                        breader.Close();
                    }
                    if (inStream != null)
                    {
                        inStream.Close();
                        inStream.Dispose();
                    }
                }
            } while (false);

            return(Rsp);
        }
        /// <summary>
        /// Receive a HART-IP Response from the network connection.
        /// </summary>
        /// <returns><see cref="HartIPResponse"/></returns>
        protected override HartIPResponse GetResponse()
        {
            HartIPResponse Rsp = null;

            if (m_breader != null)
            {
                Rsp = new HartIPResponse(m_breader, null);
            }

            return(Rsp);
        }
Esempio n. 5
0
        /// <summary>
        /// Send HART-IP request
        /// </summary>
        /// <param name="Request"><see cref="HartIPRequest"/></param>
        /// <returns><see cref="HartIPResponse"/></returns>
        private HartIPResponse SendRequest(HartIPRequest Request)
        {
            HartIPResponse Rsp = null;

            do
            {
                try
                {
                    if (m_HartIPConn != null)
                    {
                        MsgResponse MsgRsp = new MsgResponse(Request.m_Timeout);
                        if (!m_HartIPConn.SendHartRequest(Request, MsgRsp))
                        {
                            m_Error = m_HartIPConn.LastError;
                            break;
                        }

                        // wait for the object return or timeout
                        if (MsgRsp.GetResponse())
                        {
                            Rsp = MsgRsp.ResponseMsg;
                        }
                    }

                    if (Rsp == null)
                    {
                        if ((m_HartIPConn != null) && (m_HartIPConn.LastError.Length > 0))
                        {
                            m_Error = m_HartIPConn.LastError;
                        }
                        else
                        {
                            m_Error = "Waiting Hart-IP Request waiting response timeout.";
                        }

                        Logger.Log(m_Error, false);
                        break;
                    }
                }
                catch (ThreadInterruptedException Ex)
                {
                    m_Error = "Send Hart Request Exception: " + Ex.Message;
                    Logger.Log(m_Error, true);
                }
                catch (ThreadStateException TSEx)
                {
                    m_Error = "Send Hart Request Exception: " + TSEx.Message;
                    Logger.Log(m_Error, true);
                }
            } while (false); /* ONCE */

            return(Rsp);
        }
Esempio n. 6
0
        /// <summary>
        /// Create a HARTDevice object from the HART response command 0.
        /// </summary>
        /// <param name="Rsp"><see cref="HartIPResponse">HartIPResponse</see></param>
        /// <param name="HParent"><see cref="HartDevice">HartDevice device parent</see></param>
        /// <returns>HartDevice object if success. Otherwise return NULL.</returns>
        public static HartDevice CreateHartDevice(HartIPResponse Rsp, HartDevice HParent)
        {
            HartDevice HDevice = null;
            ushort     usDeviceType;
            uint       uiDeviceId = 0;
            byte       cUnivCmdRev;
            byte       cDataCount;

            if (Rsp == null)
            {
                throw new ArgumentException("CreateHartDevice Error: Invalid arguments.");
            }

            if (Rsp.ResponseCode != HARTIPMessage.RSP_SUCCESS)
            {
                throw new ArgumentException("CreateHartDevice Error: Response code=" +
                                            Rsp.ResponseCode);
            }

            cDataCount = Rsp.DataCount;
            // check if data btye count less than 12 or cmd is equal to 0
            if ((cDataCount < 12) || (Rsp.Command != HARTIPMessage.CMD_READ_UID))
            {
                throw new ArgumentException("CreateHartDevice Error: Invalid Command Response.");
            }

            // Copy the response data
            byte[] Data = new byte[cDataCount];
            Data = Rsp.Data;

            // check if it is HART5 or above device
            if (Data[0] != 254)
            {
                throw new ArgumentException("CreateHartDevice Error: Invalid Target Hart Device.");
            }

            //  convert network to host byte order
            usDeviceType = (ushort)((Data[1] << 8) + (Data[2] & 0x0ff));
            uiDeviceId   = (uint)((Data[9] << 16) | (Data[10] << 8) | (Data[11] & 0x0ff));
            cUnivCmdRev  = Data[4];

            HDevice = new HartDevice(usDeviceType, uiDeviceId, cUnivCmdRev, HParent);
            HDevice.FlagAssignment = (DeviceFlagAssignment)Data[8];

            if ((cUnivCmdRev >= 7) && (cDataCount >= 22))
            {
                HDevice.Profile = (DeviceProfile)Data[21];
            }

            return(HDevice);
        }
Esempio n. 7
0
        /// <summary>
        /// Get the HART Device Tag from HART Response command 13 or 20
        /// </summary>
        /// <param name="Rsp"><see cref="HartIPResponse">HartIPResponse</see></param>
        /// <returns>String device tag</returns>
        public static String GetHARTDeviceTag(HartIPResponse Rsp)
        {
            String strTag = String.Empty;
            byte   cDataCount, cCmd;

            if (Rsp == null)
            {
                throw new ArgumentException("GetHARTDeviceTag Error: Invalid arguments.");
            }

            cCmd       = Rsp.Command;
            cDataCount = Rsp.DataCount;

            // check if we receive the collect cmd and data byte count
            if (((cCmd != (byte)HARTIPMessage.CMD_READ_LONG_TAG) && (cCmd != (byte)HARTIPMessage.CMD_READ_TAG_DESC_DATE)) ||
                ((cCmd == (byte)HARTIPMessage.CMD_READ_LONG_TAG) && (cDataCount < HARTIPMessage.MAX_LONG_TAG_LENGTH)) ||
                ((cCmd == (byte)HARTIPMessage.CMD_READ_TAG_DESC_DATE) && (cDataCount < HARTIPMessage.MAX_SHORT_TAG_LENGTH)))
            {
                throw new ArgumentException("GetHARTDeviceTag Error: Invalid Command Response.");
            }

            byte[] Data = new byte[cDataCount];
            Data = Rsp.Data;

            // if it is cmd 20
            if (cCmd == HARTIPMessage.CMD_READ_LONG_TAG)
            {
                for (int i = 0; i < HARTIPMessage.MAX_LONG_TAG_LENGTH; i++)
                {
                    char ch = (char)(Data[i] & 0x00ff);
                    if (ch == 0)
                    {
                        break;
                    }

                    strTag += ch;
                }
            }
            else
            {
                // it is cmd 13
                strTag = UnpackAscii(Data, (byte)HARTIPMessage.MAX_SHORT_TAG_LENGTH);
            }

            return(strTag);
        }
Esempio n. 8
0
 /// <summary>
 /// Release the lock signal.
 /// </summary>
 /// <param name="RspMsg"><see cref="HartIPResponse"/>returned
 /// response message</param>
 public void SetResponse(HartIPResponse RspMsg)
 {
     lock (this)
     {
         this.m_RspMsg  = RspMsg;
         m_bResponse    = true;
         m_bResponseSet = true;
         try
         {
             // release the waiting lock
             Monitor.Pulse(this);
         }
         catch (ThreadStateException)
         {
             throw;
         }
     }
 }
Esempio n. 9
0
        /// <summary>
        /// Get the network HART Device IO info.
        /// </summary>
        /// <param name="Dev"><see cref="HartDevice"/></param>
        /// <returns>bool returns true if success. Otherwise, false.</returns>
        private bool GetHartDeviceIO(HartDevice Dev)
        {
            byte   cCmd;
            ushort usNumOfDevices = 0;
            bool   bSuccess       = false;

            if (Dev != null)
            {
                cCmd = (byte)((Dev.UniversalRev >= 7) ? HARTIPMessage.CMD_READ_IO_SYSTEM_CAPABILITIES :
                              HARTIPMessage.CMD_READ_HARTPORT_PARAMETERS);
                HartIPResponse Rsp = SendHartRequest(Dev.DeviceType, Dev.DeviceId, cCmd);
                if (Rsp != null)
                {
                    try
                    {
                        usNumOfDevices = HartUtil.GetHIPDeviceNumOfDevices(Rsp);
                        bSuccess       = true;
                    }
                    catch (Exception e)
                    {
                        m_Error = "GetHartDeviceIO Exception: " + e.Message;
                        Logger.Log(m_Error, true);
                    }

                    if (bSuccess && (usNumOfDevices > 0))
                    {
                        // Hart7 device cmd 74 rsp num of devices include HART-IP device itself.
                        if (Dev.UniversalRev >= 7)
                        {
                            Dev.NumOfSubDevices = (ushort)(usNumOfDevices - 1);
                        }
                        else
                        {
                            Dev.NumOfSubDevices = usNumOfDevices;
                        }
                    }
                }
            }

            return(bSuccess);
        }
Esempio n. 10
0
        /// <summary>
        /// Send 13 or 20 command to get HART device tag.
        /// </summary>
        /// <param name="usDeviceType">ushort</param>
        /// <param name="nDeviceId">uint</param>
        /// <param name="cCmd">byte</param>
        /// <returns>string device's Tag</returns>
        private string GetDeviceTag(ushort usDeviceType, uint nDeviceId, byte cCmd)
        {
            string         Tag = String.Empty;
            HartIPResponse Rsp = SendHartRequest(usDeviceType, nDeviceId, cCmd);

            if (Rsp != null)
            {
                try
                {
                    Tag = HartUtil.GetHARTDeviceTag(Rsp);
                    Tag = Tag.TrimEnd();
                }
                catch (Exception e)
                {
                    m_Error = "GetDeviceTag Exception: " + e.Message;
                    Logger.Log(m_Error, true);
                }
            }

            return(Tag);
        }
Esempio n. 11
0
        /// <summary>
        /// Get HIPDevice's number of sub-devices from the response
        /// Hart-5 command 128 or Hart-7 command 74.
        /// </summary>
        /// <param name="Rsp"><see cref="HartIPResponse">HartIPResponse object to parse</see></param>
        /// <returns>ushort number of sub-devices in HIPDevice.</returns>
        public static ushort GetHIPDeviceNumOfDevices(HartIPResponse Rsp)
        {
            String strTag = String.Empty;

            byte   cDataCount, cCmd;
            ushort usNumOfDevices;

            if (Rsp == null)
            {
                throw new ArgumentException("GetHARTDeviceTag Error: Invalid arguments.");
            }

            cDataCount = Rsp.DataCount;
            cCmd       = Rsp.Command;

            // check if we receive the collect cmd and data byte count
            if ((Rsp.ResponseCode != HARTIPMessage.RSP_SUCCESS) &&
                (((cCmd == (byte)HARTIPMessage.CMD_READ_HARTPORT_PARAMETERS) && (cDataCount < 18)) ||
                 ((cCmd == (byte)HARTIPMessage.CMD_READ_IO_SYSTEM_CAPABILITIES) && (cDataCount < 8))))
            {
                throw new ArgumentException("GetHIPDeviceNumOfDevices Error: Invalid Command Response.");
            }

            byte[] Data = new byte[cDataCount];
            Data = Rsp.Data;

            if (cCmd == HARTIPMessage.CMD_READ_HARTPORT_PARAMETERS)
            {
                usNumOfDevices = (ushort)((Data[8] << 8) + (Data[9] & 0x0ff));
            }
            else
            {
                usNumOfDevices = (ushort)((Data[3] << 8) + (Data[4] & 0x0ff));
            }

            return(usNumOfDevices);
        }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="Rsp"><see cref="HartIPResponse"/></param>
 internal HartIPResponseArg(HartIPResponse Rsp)
 {
     this.m_Rsp = Rsp;
 }
        /// <summary>
        /// Continue get Hart-IP Response from the connected stream.
        /// Remove the received request from the list and release the
        /// MsgResponse lock signal.
        /// </summary>
        private void ReceiveMsg()
        {
            bool stoploop;

            lock (SyncRoot)
            {
                stoploop = m_bStopped;
            }

            while (!stoploop)
            {
                try
                {
                    HartIPResponse Rsp = GetResponse();
                    if (Rsp == null)
                    {
                        continue;
                    }

                    m_lLastActivityTime = DateTime.Now.Ticks;
                    if (Rsp.MessageType == HARTIPMessage.HART_ACK)
                    {
                        MsgRequest Req = DequeueRequest(Rsp.TransactionId);
                        if (Req != null)
                        {
                            Req.Response.SetResponse(Rsp);
                        }
                        else
                        {
                            // just in case can't find the request in the list
                            LogMsg.Instance.Log(Rsp.ToString());
                        }
                    }
                    else
                    {
                        if ((Rsp.MessageType == HARTIPMessage.HART_PUBLISH_NOTIFY) &&
                            (PublishedCmdNotify != null))
                        {
                            HartIPResponseArg Arg = new HartIPResponseArg(Rsp);
                            PublishedCmdNotify(this, Arg);
                        }
                        else
                        {
                            LogMsg.Instance.Log(Rsp.ToString());
                        }
                    }
                }
                catch (SocketException se)
                {
                    int nErrorCode = se.ErrorCode;
                    // socket receive timeout
                    if ((nErrorCode == 10060) || (nErrorCode == 10035))
                    {
                        if (m_nConnection != UDP)
                        {
                            break;
                        }
                    }
                    // socket closed, server close the connection or interrupted
                    else if ((nErrorCode == 995) || (nErrorCode == 10004) || (nErrorCode == 10054))
                    {
                        break;
                    }
                    else
                    {
                        LogMsg.Instance.Log("Error, ReceiveMsg SocketException: ErrorCode:" +
                                            nErrorCode + ". " + se.Message, true);
                        break;
                    }
                }
                catch (EndOfStreamException e)
                {
                    LogMsg.Instance.Log("Error, ReceiveMsg EndOfStreamException: " + e.Message, true);
                    break;
                }
                catch (IOException io)
                {
                    if (m_nConnection != TCP)
                    {
                        LogMsg.Instance.Log("Error, ReceiveMsg IOException: " + io.Message, true);
                        break;
                    }
                }
                catch (ObjectDisposedException obex)
                {
                    LogMsg.Instance.Log("Error, ReceiveMsg Expection :" + obex.Message, true);
                    break;
                }
                catch (ThreadStateException tsEx)
                {
                    // caller failed to release the lock signal and it will timeout
                    LogMsg.Instance.Log("Error, ReceiveMsg ThreadStateException: " + tsEx.Message, true);
                }
            }

            ClearRequests();
        }
        /// <summary>
        /// Initiate session with the network HART-IP device.
        /// </summary>
        /// <returns>bool</returns>
        private bool InitSession()
        {
            bool           bSuccess = false;
            HartIPResponse Response = null;

            do
            {
                // create init session request
                HartIPRequest Request = HartIPRequest.InitiateSession(TransactionId, m_InactivityCloseTime);
                if (!SendHartIPRequest(Request))
                {
                    LogMsg.Instance.Log("Error, sending InitSession request failure.", true);
                    Close();
                    break;
                }

                try
                {
                    Response = GetResponse();
                }
                catch (SocketException se)
                {
                    m_Error = String.Format("InitSession SocketException: ErrorCode:{0}. {1}.",
                                            se.ErrorCode, se.Message);
                    LogMsg.Instance.Log("Error, " + m_Error, true);
                    Close();
                    break;
                }
                catch (Exception ex)
                {
                    m_Error = String.Format("InitSession Exception: {0}", ex.Message);
                    LogMsg.Instance.Log("Error, " + m_Error, true);
                    Close();
                    break;
                }

                if (Response == null)
                {
                    m_Error = "Initiate Session failed getting response.";
                    LogMsg.Instance.Log("Error, " + m_Error, true);
                    Close();
                    break;
                }
                else if (0 != Response.ResponseCode)
                {
                    m_Error = "InitSession received an error response code: " +
                              Response.ResponseCode.ToString() + "  " +
                              GetSessionInitStatusCode(Response.ResponseCode);

                    LogMsg.Instance.Log("Error, " + m_Error, true);
                    LogMsg.Instance.Log(Response.ToString());
                    Close();
                    break;
                }
                else if (!Response.IsValidResponse)
                {
                    m_Error = "InitSession received an invalid response Msg Type.";
                    LogMsg.Instance.Log("Error, " + m_Error, true);
                    LogMsg.Instance.Log(Response.ToString());
                    Close();
                    break;
                }

                LogMsg.Instance.Log(Response.ToString());
                bSuccess = (Response.Status == HARTIPMessage.RSP_SUCCESS ||
                            Response.Status == HARTIPMessage.RSP_SET_TO_NEAREST_POSSIBLE_VALUE) ? true : false;
            } while (false); /* ONCE */

            return(bSuccess);
        }
Esempio n. 15
0
        /// <summary>
        /// Send a Hart Request and it handles Delay Retry.
        /// If no more dr retry, it sends nerwork HART device a flush Dr cmd.
        /// </summary>
        /// <param name="Request"><see cref="HartIPRequest"/></param>
        /// <returns><see cref="HartIPResponse"/></returns>
        public HartIPResponse SendHartRequest(HartIPRequest Request)
        {
            HartIPResponse Rsp = null;

            if (Request == null)
            {
                throw new ArgumentException("HartIPRequest is null");
            }

            if ((m_HartIPConn == null) || !m_HartIPConn.IsConnected)
            {
                throw new Exception("Call Connect to initialize the network connection first.");
            }

            lock (SyncRoot)
            {
                m_Error = String.Empty;

                // send the first request
                Rsp = SendRequest(Request);

                if (Rsp != null)
                {
                    Logger.Log(Rsp.ToString());
                }

                if ((Rsp != null) &&
                    ((Rsp.ResponseCode == HARTIPMessage.RSP_DR_INITIATE) ||
                     (Rsp.ResponseCode == HARTIPMessage.RSP_DR_CONFLICT) ||
                     (Rsp.ResponseCode == HARTIPMessage.RSP_DR_RUNNING) ||
                     (Rsp.ResponseCode == HARTIPMessage.RSP_DEVICE_BUSY)))
                {
                    if (m_nDrRetries > 0)
                    {
                        Rsp = null;
                        // Create a request task to store the request and retries values.
                        RequestTask ReqTask = new RequestTask(Request, m_nDrRetries,
                                                              m_nDrRetryDelay);

                        // Create a request worker to do the task with the callback to handles the retries.
                        RequestWorker ReqWorker = new RequestWorker(ReqTask,
                                                                    new RequestWorker.HandleSendRequestDelegate(HandleSendHARTIPRequest));
                        try
                        {
                            // start the task
                            ReqWorker.Perform();
                            Rsp = ReqTask.HartIPRsp;
                        }
                        catch (UserCancelException)
                        {
                            // user canceled action
                            m_Error = "User canceled sending retries command.";
                        }
                    }
                    else
                    {
                        SendFlushDrCmd();
                    }
                }
            }

//           if (Rsp.Command == 77)
//           { // unwrap the HART PDU in the response data
//                 Rsp
//           }

            return(Rsp);
        }
Esempio n. 16
0
        /// <summary>
        /// Send HART device a command 84.
        /// </summary>
        /// <param name="Dev"><see cref="HartDevice"/></param>
        /// <param name="usDeviceIndex">ushort</param>
        /// <returns><see cref="HartDevice"/></returns>
        private HartDevice SendCmd84(HartDevice Dev, ushort usDeviceIndex)
        {
            HartDevice HDevice = null;
            ushort     usDeviceType;
            uint       nDeviceId;

            byte[]         Req = new byte[11];
            HartIPResponse Rsp = null;

            if (Dev != null)
            {
                usDeviceType = Dev.DeviceType;
                nDeviceId    = Dev.DeviceId;

                // send cmd to HART Device get the device list
                Req[0]  = 0x82; // long frame
                Req[1]  = (byte)(((usDeviceType >> 8) & 0x3F) | 0x80);
                Req[2]  = (byte)(usDeviceType & 0x0ff);
                Req[3]  = (byte)((nDeviceId >> 16) & 0x0ff);
                Req[4]  = (byte)((nDeviceId >> 8) & 0x0ff);
                Req[5]  = (byte)(nDeviceId & 0x0ff);
                Req[6]  = HARTIPMessage.CMD_READ_SUB_DEVICE_IDENTITY; // cmd byte
                Req[7]  = 2;                                          // byte count
                Req[8]  = (byte)((usDeviceIndex >> 8) & 0x0ff);
                Req[9]  = (byte)(usDeviceIndex & 0x0ff);
                Req[10] = HartUtil.GetCheckSum(Req, 10); // get check sum byte

                Rsp = SendHartRequest(Req, 11);
                if (Rsp != null)
                {
                    byte cDataCount = Rsp.DataCount;
                    if ((Rsp.ResponseCode != HARTIPMessage.RSP_SUCCESS) &&
                        (Rsp.Command != HARTIPMessage.CMD_READ_SUB_DEVICE_IDENTITY) ||
                        (cDataCount < 44))
                    {
                        m_Error = String.Format("{0} Received Cmd 84 invalid response from HART device.\r\n{1}",
                                                HartUtil.GetTimeStamp(), Rsp.ToString());
                        Logger.Log(m_Error);
                    }
                    else
                    {
                        byte   cIOCard, cChannel, cUniversalCmdRev;
                        byte[] Data = new byte[cDataCount];
                        Data = Rsp.Data;
                        int    nIndex = 2;
                        ushort usSubDeviceType;
                        uint   nSubDeviceId;
                        String Tag = String.Empty;

                        cIOCard  = Data[nIndex++];
                        cChannel = Data[nIndex++];
                        // skip the MfgId (2 bytes)
                        nIndex += 2;

                        // get the device type
                        usSubDeviceType = (ushort)((Data[nIndex] << 8) + (Data[nIndex + 1] & 0x0ff));
                        nIndex         += 2;

                        // get the device id
                        nSubDeviceId = (uint)((Data[nIndex] << 16) + (Data[nIndex + 1] << 8) +
                                              (Data[nIndex + 2] & 0x0ff));
                        nIndex += 3;

                        // get the universal cmd rev
                        cUniversalCmdRev = Data[nIndex++];

                        // get the tag
                        for (int i = nIndex; i < (nIndex + HARTIPMessage.MAX_LONG_TAG_LENGTH); i++)
                        {
                            char ch = (char)(Data[i] & 0x00ff);
                            if (ch == 0)
                            {
                                break;
                            }

                            Tag += ch;
                        }

                        Tag = Tag.TrimEnd();
                        // if tag is empty, set it to 'Unknown' with its device type and device id similar to MAC address
                        if (Tag.Length == 0)
                        {
                            String strOUI = (cUniversalCmdRev >= 7) ? "00-1B-1E" : "00-00-00";

                            Tag = String.Format("Unknown ({0}-{1:X2}-{2:X2}-{3:X2}-{4:X2}-{5:X2})",
                                                new object[] { strOUI,
                                                               (usSubDeviceType >> 8),
                                                               (usSubDeviceType & 0x0ff),
                                                               (nSubDeviceId >> 16 & 0x0ff),
                                                               (nSubDeviceId >> 8 & 0x0ff),
                                                               (nSubDeviceId & 0x0ff) });
                        }

                        // Create sub-device
                        HDevice         = new HartDevice(usSubDeviceType, nSubDeviceId, cUniversalCmdRev, Dev);
                        HDevice.Name    = Tag;
                        HDevice.IOCard  = cIOCard;
                        HDevice.Channel = cChannel;
                    }
                }
            }

            return(HDevice);
        }