/// <summary> /// Get the network HART device that is /// a wireless Gateway, IO System, or protocol bridge device /// from devices list. /// </summary> /// <returns><see cref="HartDevice"/></returns> public HartDevice GetNetworkHARTIPDevice() { HartDevice Dev = null; HartDevice[] HDevices = null; int nCount; lock (SyncRoot) { m_Error = String.Empty; nCount = m_DeviceList.Count; if (nCount > 0) { HDevices = new HartDevice[nCount]; m_DeviceList.CopyTo(HDevices, 0); } } if (HDevices != null) { for (int i = 0; i < HDevices.Length; i++) { // find the network HART device if (HDevices[i].IsBridgeDevice) { Dev = HDevices[i]; break; } } } return(Dev); }
/// <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> /// Send HART-IP Device the command 84s. /// </summary> /// <param name="Dev"><see cref="HartDevice"/></param> /// <returns>bool returns true if success. Otherwise, false.</returns> private bool SendCmd84s(HartDevice Dev) { bool bSuccess = false; ushort usStartDeviceIndex = 1; ushort usNumOfSubDevices = 0; if (Dev != null) { usNumOfSubDevices = Dev.NumOfSubDevices; while (usStartDeviceIndex <= usNumOfSubDevices) { HartDevice HDevice = SendCmd84(Dev, usStartDeviceIndex); if (HDevice != null) { m_DeviceList.Add(HDevice); usStartDeviceIndex += 1; // found all the HART device's sub-devices if (usStartDeviceIndex > usNumOfSubDevices) { bSuccess = true; break; } } else { break; } } } return(bSuccess); }
/// <summary> /// HartDevice Contructor /// </summary> /// <param name="usDeviceType">ushort device type</param> /// <param name="uiDeviceId">uint device id</param> /// <param name="cUniversalRev">byte universal revision</param> /// <param name="Parent">HartDevice</param> public HartDevice(ushort usDeviceType, uint uiDeviceId, byte cUniversalRev, HartDevice Parent) { m_Device = new DeviceData(String.Empty, usDeviceType, uiDeviceId, cUniversalRev); m_Parent = Parent; m_usNumOfSubDevices = 0; m_IOCard = 0; m_Channel = 0; m_Profile = DeviceProfile.UNKNOWN_PROFILE; m_FlagAssignment = DeviceFlagAssignment.UNDEFINED; }
/// <summary> /// Send HART Device a flush dr command. /// </summary> internal void SendFlushDrCmd() { HartDevice Dev = GetNetworkHARTIPDevice(); if (Dev != null) { SendHartRequest(Dev.DeviceType, Dev.DeviceId, HARTIPMessage.CMD_FLUSH_DELAYED_RESPONSES); } }
/// <summary> /// Get the network HART Device connected devices. /// </summary> /// <param name="Dev"><see cref="HartDevice"/></param> /// <returns>bool returns true if success. Otherwise, false.</returns> private bool GetConnectedDevices(HartDevice Dev) { bool bSuccess = false; if (Dev != null) { if (Dev.UniversalRev >= 7) { bSuccess = SendCmd84s(Dev); } } return(bSuccess); }
/// <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 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> /// 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); }
/// <summary> /// If the HART-IP devices is a wireless Gateway, IO System, or Protocol bridge device, /// it gets all devices that include Gateway, IO System, or Protocol bridge device /// into devices list for the network connection. Otherwise, just has the network /// HART-IP device in the list. /// </summary> /// <returns>bool returns true if success. Otherwise, false.</returns> public bool GetDeviceList() { bool bSuccess = false; do { lock (SyncRoot) { m_Error = String.Empty; // Check if the device list is filled. if (m_DeviceList.Count > 0) { break; } // Check if it has a connection if ((m_HartIPConn != null) && m_HartIPConn.IsConnected) { // poll for the HART Device HartDevice Dev = null; for (byte polladdr = 0; polladdr < 64; polladdr++) { Dev = DiscoverHartDevice(polladdr); if (Dev != null) { // presume only one device at this HART-IP address m_PollingAddr = polladdr; break; } } if (Dev != null) { // this is the IO device m_DeviceList.Add(Dev); // Get the HART device's Tag String Tag = GetDeviceTag(Dev.DeviceType, Dev.DeviceId, (byte)HARTIPMessage.CMD_READ_LONG_TAG); if (String.IsNullOrEmpty(Tag)) { ushort usDeviceType = Dev.DeviceType; uint nDeviceId = Dev.DeviceId; Tag = String.Format("Unknown (00-1B-1E-{0:X2}-{1:X2}-{2:X2}-{3:X2}-{4:X2})", new object[] { (usDeviceType >> 8), (usDeviceType & 0x0ff), (nDeviceId >> 16 & 0x0ff), (nDeviceId >> 8 & 0x0ff), (nDeviceId & 0x0ff) }); } Dev.Name = Tag; // check if the device has sub-devices, or Flag assignment is Protocol Bridge Device if (Dev.IsBridgeDevice) { // Get the HART Device's IO info bSuccess = GetHartDeviceIO(Dev); if (bSuccess && (Dev.NumOfSubDevices > 0)) { // get sub-devices bSuccess = GetConnectedDevices(Dev); } } else { bSuccess = true; } } } } } 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); }