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