/// <summary> /// Add a request or response message string /// </summary> /// <param name="Msg">string a message to add</param> /// <param name="bRequest">bool true is added to request message</param> /// <param name="bAddTimeStamp">bool true is added a timestamp in front of the specified string</param> public void AddMessage(string Msg, bool bRequest, bool bAddTimeStamp) { string Output = string.Empty; if (bAddTimeStamp) { Output = string.Format("{0} {1}", HartUtil.GetTimeStamp(), Msg); } else { Output = Msg; } if (bRequest) { if (m_Request.Length > 0) { m_Request += "\r\n"; } m_Request += Output; } else { if (m_Response.Length > 0) { m_Response += "\r\n"; } m_Response += Output; } }
/// <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> /// 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> /// Write message in debug console and/or write into a file. /// </summary> /// <param name="msg">String message to write</param> /// <param name="bAddTimeStamp">bool true to add timestamp in front of message</param> /// <param name="bAddEmptyLine">bool true to add empty line after the message</param> /// <remark>It will write a message to debug console console screen, /// and/or write to log file.</remark> public void Log(String msg, bool bAddTimeStamp, bool bAddEmptyLine) { do { lock (SyncRoot) { String strOutput; if (bAddTimeStamp) { String TimeStamp = HartUtil.GetTimeStamp(); strOutput = String.Format("{0}, {1}", TimeStamp, msg); } else { strOutput = msg; } // Check if display output string to screen if (m_bOutputToScreen) { Console.WriteLine(strOutput); Console.WriteLine(); } if (m_bLogToFile) { if (m_Count >= m_Limit) { AddTimeStampInFileName(); m_Count = 0; } WriteMsgToFile(m_strFileName, strOutput, bAddEmptyLine); m_Count++; } else { System.Diagnostics.Debug.WriteLine(strOutput); } } } while (false); /* ONCE */ }
/// <summary> /// HartIPResponse /// </summary> /// <param name="inBuffer">BinaryReader</param> /// <param name="TimeStamp">String response timestamp</param> internal HartIPResponse(BinaryReader inBuffer, String TimeStamp) : base("Rx") { byte Version, MsgType, MsgId, Status; ushort usMsgByteCount; Version = inBuffer.ReadByte(); if (Version != HARTIPMessage.HART_UDP_TCP_MSG_VERSION) { throw new ArgumentException(String.Format("HartIPResponse Error: Unsupported Response Message Version: {0}.", Version)); } // If the input timestamp is null or empty, get the current time as timestamp if ((TimeStamp != null) && (TimeStamp.Length > 0)) { m_TimeStamp = TimeStamp; } else { m_TimeStamp = HartUtil.GetTimeStamp(); } MsgType = inBuffer.ReadByte(); MsgId = inBuffer.ReadByte(); Status = inBuffer.ReadByte(); // Create message header MsgHeader = new HartIPMessageHeader(MsgType, (MessageId)MsgId, Status); // transaction id m_TransactionId = (ushort)IPAddress.NetworkToHostOrder((short)inBuffer.ReadUInt16()); // byte count usMsgByteCount = (ushort)IPAddress.NetworkToHostOrder((short)inBuffer.ReadUInt16()); // message body byte count m_HartCmdSize = (ushort)(usMsgByteCount - HARTIPMessage.HART_MSG_HEADER_SIZE); if (m_HartCmdSize > HARTIPMessage.MAX_HARTMSG_LENGTH) { m_HartCmdSize = HARTIPMessage.MAX_HARTMSG_LENGTH; } // get data bytes if message has data if (m_HartCmdSize > 0) { ushort usExtra; int nIndex; int j, i; // get the message bytes for (i = MsgHeader.ByteCount, j = 0; i < usMsgByteCount; i++, j++) { m_HartCmd[j] = inBuffer.ReadByte(); } // if the message is the ACK or BACK (notify) type if (MsgType == HARTIPMessage.HART_ACK || MsgType == HARTIPMessage.HART_PUBLISH_NOTIFY) { // Check if response is initiate session if (MsgHeader.MsgId == MessageId.SESSION_INITIATE) { nIndex = 0; m_cDataCount = (byte)m_HartCmdSize; m_cRspcode = MsgHeader.Status; } // Check if it is a long frame else if ((m_HartCmd[0] & 0x80) == 0x80) { // get the extra usExtra = (ushort)((m_HartCmd[0] & 0x60) >> 5); nIndex = 6 + usExtra; m_cCmd = m_HartCmd[nIndex++]; m_cDataCount = m_HartCmd[nIndex++]; // subtract response code and device status bytes m_cDataCount -= 2; // get respsone code and device status bytes m_cRspcode = m_HartCmd[nIndex++]; m_cDeviceStatus = m_HartCmd[nIndex++]; } else { // it is a short frame nIndex = 2; m_cCmd = m_HartCmd[nIndex++]; m_cDataCount = m_HartCmd[nIndex++]; m_cRspcode = m_HartCmd[nIndex++]; m_cDeviceStatus = m_HartCmd[nIndex++]; // subtract response code and device status bytes m_cDataCount -= 2; } // Get the rest of response data bytes and store them in the data array m_Data = new byte[m_cDataCount]; for (i = nIndex, j = 0; j < m_cDataCount; i++, j++) { m_Data[j] = m_HartCmd[i]; } } } else { m_cRspcode = MsgHeader.Status; } }
/// <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); }