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