/// <summary> /// Send a Hart-IP Request /// </summary> /// <param name="Request"><see cref="HartIPRequest"></see></param> /// <para>see the HartIPRequest.Command for HART specification references.</para> /// <returns>bool true if the request is sent success.</returns> private bool SendHartIPRequest(HartIPRequest Request) { bool bSuccess = false; lock (SyncRoot) { m_Error = String.Empty; try { bSuccess = SendRequest(Request); LogMsg.Instance.Log(Request.ToString()); } catch (SocketException se) { m_Error = String.Format("SendHartIPRequest SocketException: ErrorCode:{0}. {1}", se.ErrorCode, se.Message); LogMsg.Instance.Log("Error, " + m_Error, true); } catch (Exception e) { m_Error = String.Format("SendHartIPRequest Exception: {0}", e.Message); LogMsg.Instance.Log("Error, " + m_Error, true); } } return(bSuccess); }
/// <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> /// 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> /// Send a Hart-IP Request /// </summary> /// <param name="Request"><see cref="HartIPRequest"></see></param> /// <param name="MsgRsp"><see cref="MsgResponse"></see></param> /// <para>see the HartIPRequest.Command for HART specification references.</para> /// <returns>bool if it is success</returns> public bool SendHartRequest(HartIPRequest Request, MsgResponse MsgRsp) { bool bSuccess = false; if (Request == null) { throw new ArgumentException("Invalid argument in SendHartRequest."); } lock (SyncRoot) { m_Error = String.Empty; try { if (m_RspMsgReader == null) { // Create a thread that is constantly reading on the input stream m_bStopped = false; m_RspMsgReader = new Thread(new ThreadStart(this.ReceiveMsg)); m_RspMsgReader.Name = "HartIPConnection"; m_RspMsgReader.Start(); } // add the request object into the m_Requests list MsgRequest MsgReq = new MsgRequest(Request.TransactionId, MsgRsp); m_Requests.Add(MsgReq); // send the request bSuccess = SendRequest(Request); LogMsg.Instance.Log(Request.ToString()); } catch (SocketException se) { m_Error = String.Format("SendHartRequest SocketException: ErrorCode:{0}. {1}", se.ErrorCode, se.Message); LogMsg.Instance.Log("Error, " + m_Error, true); } catch (Exception e) { m_Error = String.Format("SendHartRequest Exception: {0}", e.Message); LogMsg.Instance.Log("Error, " + m_Error, true); } if (!bSuccess) { LogMsg.Instance.Log("Error, Failed sending Request: " + Request.ToString(), true); DequeueRequest(Request.TransactionId); } } return(bSuccess); }
/// <summary> /// Send a Hart request to connected network HART-IP device. /// </summary> /// <param name="Request"><see cref="HartIPRequest"/></param> /// <returns>bool True if it is success to send the HART request.</returns> protected override bool SendRequest(HartIPRequest Request) { bool bSuccess = false; String TimeStamp = HartUtil.GetTimeStamp(); if (m_socket != null) { m_socket.Send(Request.Message); Request.TimeStamp = TimeStamp; bSuccess = true; } else { m_Error = "SendRequest Error: Socket is already closed."; LogMsg.Instance.Log("Error, Socket is already closed in SendRequest.", true); } return(bSuccess); }
/// <summary> /// Initiate a HART Session request /// </summary> /// <param name="usTranId">ushort Transaction Id</param> /// <param name="InactivityCloseTime">uint Session inactivity close time</param> /// <returns><see cref="HartIPRequest"> initiate session request</see></returns> public static HartIPRequest InitiateSession(ushort usTranId, uint InactivityCloseTime) { // create message header for this request HartIPRequest request = new HartIPRequest(MessageId.SESSION_INITIATE, usTranId); byte[] Params = new byte[5]; Params[0] = HARTIPMessage.HART_SESSION_MASTER_TYPE; // swap the InactivityCloseTime bytes to 'host to network order' Params[1] = (byte)((InactivityCloseTime >> 24) & 0x0ff); Params[2] = (byte)((InactivityCloseTime >> 16) & 0x0ff); Params[3] = (byte)((InactivityCloseTime >> 8) & 0x0ff); Params[4] = (byte)(InactivityCloseTime & 0x0ff); // set it into request member variable request.HARTCommand = Params; // set the request's byte count request.m_HartCmdSize = 5; return(request); }
/// <summary> /// Create a HART Close Session Request, send it to the Gateway, /// and close the socket. /// </summary> /// <param name="Result"><see cref="HARTMsgResult">HARTMsgResult</see></param> public void CloseSession(HARTMsgResult Result) { HartIPRequest Req = null; do { Req = HartIPRequest.CloseSession(TransactionId); MsgResponse MsgRsp = new MsgResponse(HARTIPConnect.USE_SOCKET_TIMEOUT_DEFAULT); if (SendHartRequest(Req, MsgRsp)) { try { // wait for the object return or timeout if (MsgRsp.GetResponse() == false) { Result.AddMessage("Close Session failed: No response was received.", false, true); break; } if (!MsgRsp.ResponseMsg.IsValidResponse) { Result.AddMessage("Close Session failed: Received an invalid response msg type.", false, true); break; } LogMsg.Instance.Log(MsgRsp.ResponseMsg.ToString()); } catch { Result.AddMessage("Close Session failed.", false, true); break; } } else { Result.AddMessage("Close Session failed.", false, true); break; } } while (false); /* ONCE */ Close(); Result.AddMessage("Closed the HPort socket.", false, true); }
/// <summary> /// Create a HART Command Request /// </summary> /// <param name="usTranId">ushort Transaction Id</param> /// <param name="Command">byte[] Command byte array /// <para>Array should have frame, device address, command, byte count, /// data, and checksum bytes.</para> /// <para>device address is the device type and device id 5 bytes with expanded type mask</para> /// <remarks>See HART specification 081r8.2.pdf section 5.1, 5.2, and 5.3 for frame, /// address, expansion, data, and checksum bytes information. /// </remarks> /// </param> /// <param name="usByteCount">ushort the specified Command array byte count</param> /// <returns><see cref="HartIPRequest"> request</see></returns> public static HartIPRequest HartCommandRequest(ushort usTranId, byte[] Command, ushort usByteCount, int Timeout = HARTIPConnect.USE_SOCKET_TIMEOUT_DEFAULT) { if (usByteCount > HARTIPMessage.MAX_REQUEST_MSG_LEN) { throw new ArgumentException(String.Format("HartCommandRequest Error: Invalid cmd length: {0}.", usByteCount)); } HartIPRequest Request = new HartIPRequest(MessageId.HART_WIRED_PDU, usTranId); Request.m_Timeout = Timeout; // if command has data if (usByteCount > 0) { Request.m_HartCmdSize = usByteCount; Request.HARTCommand = Command; } return(Request); }
/// <summary> /// Build a Hart-IP request /// </summary> /// <param name="Command">byte[] request Command byte array /// <para>Array should include the frame, device address, command, byte count, /// data, and checksum bytes.</para>para</param> /// <param name="usByteCount">ushort the specified Command array byte count</param> /// <returns><see cref="HartIPRequest"/></returns> public HartIPRequest BuildHartRequest(byte[] Command, ushort usByteCount) { return(HartIPRequest.HartCommandRequest(TransactionId, Command, usByteCount)); }
/// <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-IP request to network HART-IP device. /// </summary> /// <param name="Request">HartIPRequest</param> /// <returns>bool True if it is success to send the HART-IP request.</returns> protected abstract bool SendRequest(HartIPRequest Request);
/// <summary> /// Keep Alive Request /// </summary> /// <param name="usTranId">ushort Transaction Id</param> /// <returns><see cref="HartIPRequest"> keep alive request</see></returns> public static HartIPRequest KeepAlive(ushort usTranId) { HartIPRequest Request = new HartIPRequest(MessageId.KEEP_ALIVE, usTranId); return(Request); }
/// <summary> /// Close Session Request /// </summary> /// <param name="usTranId">ushort Transaction Id</param> /// <returns><see cref="HartIPRequest">HartIPRequest close session request</see></returns> public static HartIPRequest CloseSession(ushort usTranId) { HartIPRequest HRequest = new HartIPRequest(MessageId.SESSION_CLOSE, usTranId); return(HRequest); }
/// <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 a Hart Request and handle Delay Retry. /// If no more dr retry, it sends nerwork HART device a flush Dr cmd. /// </summary> /// <param name="Request">byte[] a request byte array</param> /// <param name="ByteCount">ushort request array byte count</param> /// <param name="Timeout">int request timeout in ms</param> /// <returns><see cref="HartIPResponse"/></returns> public HartIPResponse SendHartRequest(byte[] Request, ushort ByteCount, int Timeout = HARTIPConnect.USE_SOCKET_TIMEOUT_DEFAULT) { HartIPRequest Req = HartIPRequest.HartCommandRequest(m_HartIPConn.TransactionId, Request, ByteCount, Timeout); return(SendHartRequest(Req)); }
/// <summary> /// Build a HartIP Request using the specified request command, request message, /// device type, and device id. It will have frame, device address, command, byte count, /// data, and checksum bytes in the returned HartIPRequest.Command. /// </summary> /// <param name="usReqCmd">ushort Request command</param> /// <param name="ReqMsg">String Request message in Hex string</param> /// <param name="usDeviceType">ushort Device Type</param> /// <param name="nDeviceId">uint Device ID</param> /// <returns><see cref="HartIPRequest"/></returns> public HartIPRequest BuildHartIPRequest(ushort usReqCmd, String ReqMsg, ushort usDeviceType, uint nDeviceId) { String Msg; HartIPRequest HRequest = null; int nDataLen = 0; if (m_HartIPConn == null) { throw new Exception("Call Connect to initialize the network connection first."); } if ((uint)(usReqCmd) > 65536) { Msg = "Invalid HARTIP Request Command."; throw new ArgumentException(Msg); } if (!String.IsNullOrEmpty(ReqMsg)) { ReqMsg = ReqMsg.Replace(" ", ""); nDataLen = ReqMsg.Length; if ((nDataLen > 0) && (nDataLen % 2) != 0) { Msg = "Multiple contiguous bytes must define an even number of hex digits."; throw new ArgumentException(Msg); } } // Check if it is extended command bool bExtendedCmd = (usReqCmd > HARTIPMessage.MAX_SINGLE_BYTE_CMD) ? true : false; byte cCmd = (byte)(bExtendedCmd ? HARTIPMessage.CMD_EXTENDED_CMD : usReqCmd); byte cbyteCount = 9; byte cDataByteCount = 0; int nIndex = 0; int nSubCmdByteCountIndex; // Request bytes byte[] Data = new byte[HARTIPMessage.MAX_REQUEST_MSG_LEN]; Array.Clear(Data, 0, Data.Length); if (nDataLen > 0) { cbyteCount += (byte)(nDataLen / 2); cDataByteCount = (byte)(nDataLen / 2); } // form a request Data[nIndex++] = 0x82; // long frame Data[nIndex++] = (byte)(((usDeviceType >> 8) & 0x3F) | 0x80); Data[nIndex++] = (byte)(usDeviceType & 0x0ff); Data[nIndex++] = (byte)((nDeviceId >> 16) & 0x0ff); Data[nIndex++] = (byte)((nDeviceId >> 8) & 0x0ff); Data[nIndex++] = (byte)(nDeviceId & 0x0ff); Data[nIndex++] = cCmd; // cmd nSubCmdByteCountIndex = nIndex; // skip the byte count nIndex += 1; // if it is extended cmd, put the cmd two bytes in data field first if (bExtendedCmd) { Data[nIndex++] = (byte)((usReqCmd >> 8) & 0x0ff); Data[nIndex++] = (byte)(usReqCmd & 0x0ff); cbyteCount += 2; cDataByteCount += 2; } // set the data byte count value Data[nSubCmdByteCountIndex] = cDataByteCount; int n = 0; byte cY, cW; while (n < nDataLen) { if (HartUtil.HexCharToNibble(ReqMsg[n], out cY)) { if (HartUtil.HexCharToNibble(ReqMsg[n + 1], out cW)) { Data[nIndex++] = (byte)(cY * 16 + cW); n += 2; } else { Msg = String.Format("The character: '{0}' is not allowed in the request data byte value.", ReqMsg[n + 1]); throw new ArgumentException(Msg); } } else { Msg = String.Format("The character: '{0}' is not allowed in the request data byte value.", ReqMsg[n]); throw new ArgumentException(Msg); } } // tunnel messages to attached devices if (RootDevice.DeviceType != usDeviceType && RootDevice.DeviceId != nDeviceId && RootDevice.IsBridgeDevice) { // message is routed into an attached device // wrap the message with command 77 to tunnel to attached device byte[] Data77 = new byte[HARTIPMessage.MAX_REQUEST_MSG_LEN]; Array.Clear(Data77, 0, Data.Length); // command 77 request data HartDevice dev = FindDevice(nDeviceId); Data77[0] = dev.IOCard; Data77[1] = dev.Channel; Data77[2] = 5; // transmit preamble count Array.Copy(Data, 0, Data77, 3, nIndex); nIndex += 3; // send the command 77 to the root device (a gateway or IO) string hex = BitConverter.ToString(Data77).Replace("-", string.Empty); hex = hex.Substring(0, nIndex * 2); return(BuildHartIPRequest(77, hex, RootDevice.DeviceType, RootDevice.DeviceId)); } // Get check sum byte and send the request Data[nIndex] = HartUtil.GetCheckSum(Data, (byte)(cbyteCount - 1)); HRequest = HartIPRequest.HartCommandRequest(m_HartIPConn.TransactionId, Data, cbyteCount); return(HRequest); }