/// <summary> /// I-Am. /// </summary> /// <param name="network">The network.</param> /// <param name="objectid">The objectid.</param> /// <returns></returns> public bool GetIAm(int network, uint objectid) { // Wait for I-Am packet var found = false; try { var sock = receiveUdp.Client; var remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0); // Process receive packets if (sock.Available > 0) { var recvBytes = receiveUdp.Receive(ref remoteIpEndPoint); { // Parse the packet - is it IAm? var npduOffset = Bvlc.Parse(recvBytes, 0); var apduOffset = Npdu.Parse(recvBytes, npduOffset); if (Apdu.ParseIAm(recvBytes, apduOffset) > 0) { if ((network == Npdu.Snet) && (objectid == Apdu.ObjectId)) { // Found it! found = true; } } } } } catch (Exception e) { Log.Error(e.Message); return(false); } return(found); }
/// <summary> /// Write Property. /// </summary> /// <param name="recipient">The receipient.</param> /// <param name="arrayidx">The arrayidx.</param> /// <param name="objtype">The objtype.</param> /// <param name="objprop">The objprop.</param> /// <param name="property">The property.</param> /// <param name="priority">The priority.</param> /// <returns></returns> public bool SendWriteProperty( Device recipient, int arrayidx, BacnetEnums.BacnetObjectType objtype, BacnetEnums.BacnetPropertyId objprop, Property property, int priority) { // Create and send an Confirmed Request if (recipient == null) { return(false); } if (property == null) { return(false); } var sendBytes = new byte[50]; // BVLL var len = Bvlc.Fill(ref sendBytes, Bvlc.BacnetBvlcFuncUnicastNpdu, 0); // NPDU sendBytes[len++] = BacnetEnums.BacnetProtocolVersion; if (recipient.SourceLength == 0) { sendBytes[len++] = 0x04; // Control flags, no destination address } else { sendBytes[len++] = 0x24; // Control flags, with broadcast or destination } if (recipient.SourceLength > 0) { // Get the (MSTP) Network number (2001) //sendBytes[6] = 0x07; // Destination network address (2001) //sendBytes[7] = 0xD1; var temp2 = BitConverter.GetBytes(recipient.Network); sendBytes[len++] = temp2[1]; sendBytes[len++] = temp2[0]; // Get the MAC address (0x0D) //sendBytes[8] = 0x01; // MAC address length //sendBytes[9] = 0x0D; // Destination MAC layer address var temp4 = BitConverter.GetBytes(recipient.MacAddress); sendBytes[len++] = 0x01; // MAC address length - adjust for other lengths ... sendBytes[len++] = temp4[0]; sendBytes[len++] = 0xFF; // Hop count = 255 } // APDU sendBytes[len++] = 0x00; // Control flags sendBytes[len++] = 0x05; // Max APDU length (1476) // Create invoke counter //sendBytes[len++] = InvokeCounter++; // Invoke ID sendBytes[len++] = (byte)(invokeCounter); invokeCounter = ((invokeCounter + 1) & 0xFF); sendBytes[len++] = 0x0F; // Service Choice: Write Property request // Service Request (var part of APDU): // Set up Object ID (Context Tag) len = Apdu.SetObjectId(ref sendBytes, len, objtype, recipient.Instance); // Set up Property ID (Context Tag) len = Apdu.SetPropertyId(ref sendBytes, len, objprop); // Optional array index goes here if (arrayidx >= 0) { len = Apdu.SetArrayIdx(ref sendBytes, len, arrayidx); } // Set the value to send len = Apdu.SetProperty(ref sendBytes, len, property); //PEP Optional array index goes here // Set priority if (priority > 0) { len = Apdu.SetPriority(ref sendBytes, len, priority); } // Fix the BVLL length sendBytes[3] = (byte)len; var count = 0; var getResponse = false; while (count < BacnetUnicastRequestRepeatCount && !getResponse) { sendUdp.EnableBroadcast = false; sendUdp.Send(sendBytes, (int)len, recipient.ServerEp); while (!getResponse) { if (sendUdp.Client.Available <= 0) { continue; } //recvBytes = SendUDP.Receive(ref RemoteEP); var sendTo = recipient.ServerEp; var recvBytes = sendUdp.Receive(ref sendTo); var apduOffset = Npdu.Parse(recvBytes, 4); // BVLL is always 4 bytes // Check for APDU response, and decide what to do // 0x - Confirmed Request // 1x - Un-Confirmed Request // 2x - Simple ACK // 3x - Complex ACK // 4x - Segment ACK // 5x - Error // 6x - Reject // 7x - Abort if (recvBytes[apduOffset] != 0x20) { continue; } // Verify the Invoke ID is the same var ic = (byte)(invokeCounter == 0 ? 255 : invokeCounter - 1); if (ic == recvBytes[apduOffset + 1]) { getResponse = true; // This will still execute the finally } } count++; } return(getResponse); // This will still execute the finally }
/// <summary> /// Read Property. /// </summary> /// <param name="recipient">The recipient.</param> /// <param name="arrayidx">The arrayidx.</param> /// <param name="objtype">The objtype.</param> /// <param name="objprop">The objprop.</param> /// <param name="property">The property.</param> /// <returns></returns> public bool SendReadProperty( Device recipient, int arrayidx, BacnetEnums.BacnetObjectType objtype, BacnetEnums.BacnetPropertyId objprop, Property property) { // Create and send an Confirmed Request //value = "(none)"; if (recipient == null) { return(false); } if (property == null) { return(false); } //uint instance = BACnetData.Devices[deviceidx].Instance; var sendBytes = new byte[50]; // BVLL sendBytes[0] = Bvlc.BacnetBvlcTypeBip; sendBytes[1] = Bvlc.BacnetBvlcFuncUnicastNpdu; sendBytes[2] = 0x00; sendBytes[3] = 0x00; // BVLL Length, fix later (24?) // NPDU sendBytes[4] = BacnetEnums.BacnetProtocolVersion; if (recipient.SourceLength == 0) { sendBytes[5] = 0x04; // Control flags, no destination address } else { sendBytes[5] = 0x24; // Control flags, with broadcast or destination address } uint len = 6; if (recipient.SourceLength > 0) { // Get the (MSTP) Network number (2001) var temp2 = BitConverter.GetBytes(recipient.Network); sendBytes[len++] = temp2[1]; sendBytes[len++] = temp2[0]; // Get the MAC address (0x0D) var temp4 = BitConverter.GetBytes(recipient.MacAddress); sendBytes[len++] = 0x01; // MAC address length - adjust for other lengths ... sendBytes[len++] = temp4[0]; sendBytes[len++] = 0xFF; // Hop count = 255 } // APDU sendBytes[len++] = 0x00; // Control flags sendBytes[len++] = 0x05; // Max APDU length (1476) // Create invoke counter sendBytes[len++] = (byte)(invokeCounter); invokeCounter = ((invokeCounter + 1) & 0xFF); sendBytes[len++] = 0x0C; // Service Choice: Read Property request // Service Request (var part of APDU): // Set up Object ID (Context Tag) len = Apdu.SetObjectId(ref sendBytes, len, objtype, recipient.Instance); // Set up Property ID (Context Tag) len = Apdu.SetPropertyId(ref sendBytes, len, objprop); // Optional array index goes here if (arrayidx >= 0) { len = Apdu.SetArrayIdx(ref sendBytes, len, arrayidx); } // Fix the BVLL length sendBytes[3] = (byte)len; var getResponse = false; var count = 0; while (count < BacnetUnicastRequestRepeatCount && !getResponse) { sendUdp.EnableBroadcast = false; sendUdp.Send(sendBytes, (int)len, recipient.ServerEp); while (!getResponse) { if (sendUdp.Client.Available <= 0) { continue; } //recvBytes = SendUDP.Receive(ref RemoteEP); var sendTo = recipient.ServerEp; var recvBytes = sendUdp.Receive(ref sendTo); var apduOffset = Npdu.Parse(recvBytes, Bvlc.BacnetBvlcHeaderLen); // BVLL is always 4 bytes // Check for APDU response // 0x - Confirmed Request // 1x - Un-Confirmed Request // 2x - Simple ACK // 3x - Complex ACK // 4x - Segment ACK // 5x - Error // 6x - Reject // 7x - Abort if (recvBytes[apduOffset] != 0x30) { continue; } // Verify the Invoke ID is the same var ic = (byte)(invokeCounter == 0 ? 255 : invokeCounter - 1); if (ic != recvBytes[apduOffset + 1]) { continue; } Apdu.ParseProperty(ref recvBytes, apduOffset, property); getResponse = true; // This will still execute the finally } count++; } return(getResponse); }
/// <summary> /// Collect Who-Is information from a single IP address. /// @todo: Use exceptions for timeout. /// </summary> /// <param name="bIpAddress">IP host address of suspected BACnet device.</param> /// <param name="milliseconds">I-Am receive timeout in milliseconds.</param> /// <returns>A BACnet Device object representation MAYBE with filled properties.</returns> public Device UnicastWhoIsOnSingleIp(IPEndPoint bIpAddress, int milliseconds) { var sendBytes = new byte[12]; var device = new Device(); try { //PEP Use NPDU.Create and APDU.Create (when written) sendBytes[0] = Bvlc.BacnetBvlcTypeBip; sendBytes[1] = Bvlc.BacnetBvlcFuncUnicastNpdu; sendBytes[2] = 0; sendBytes[3] = 12; sendBytes[4] = BacnetEnums.BacnetProtocolVersion; sendBytes[5] = 0x20; // Control flags sendBytes[6] = 0xFF; // Destination network address (65535) sendBytes[7] = 0xFF; sendBytes[8] = 0; // Destination MAC layer address length, 0 = Broadcast sendBytes[9] = 0xFF; // Hop count = 255 sendBytes[10] = (byte)BacnetEnums.BacnetPduType.PduTypeUnconfirmedServiceRequest; sendBytes[11] = (byte)BacnetEnums.BacnetUnconfirmedService.ServiceUnconfirmedWhoIs; sendUdp.EnableBroadcast = false; sendUdp.Send(sendBytes, 12, bIpAddress); var watch = new Stopwatch(); watch.Start(); while (true) { if (watch.Elapsed.TotalMilliseconds >= milliseconds) { break; } // Process the response packets //if (WinSockRecvReady() > 0) //{ // if (WinSockRecvFrom(recvBytes, ref count, ref ipaddr) > 0) // Process the response packets if (sendUdp.Client.Available > 0) { var recvBytes = sendUdp.Receive(ref bIpAddress); { // Parse and save the BACnet data var npduOffset = Bvlc.Parse(recvBytes, 0); var apduOffset = Npdu.Parse(recvBytes, npduOffset); if (Apdu.ParseIAm(recvBytes, apduOffset) <= 0) { continue; } device.Name = "Device"; device.SourceLength = Npdu.Slen; device.ServerEp = bIpAddress; device.Network = Npdu.Snet; device.MacAddress = Npdu.SAddress; device.Instance = Apdu.ObjectId; // We should now have enough info to read/write properties for this device } } } watch.Stop(); } catch (Exception e) { Log.ErrorFormat("Error on UnicastWhoIsOnSingleIp {0}", e.Message); } return(device); }
/// <summary> /// Who-Is, and collect the device about who answers /// </summary> /// <param name="milliseconds"></param> /// <returns></returns> public List <Device> GetDevices(int milliseconds) { // Get the host data, send a Who-Is, accept responses and save in the DeviceList var sendBytes = new byte[12]; devices.Clear(); // Send the request try { //PEP Use NPDU.Create and APDU.Create (when written) sendBytes[0] = Bvlc.BacnetBvlcTypeBip; sendBytes[1] = Bvlc.BacnetBvlcFuncUnicastNpdu; sendBytes[2] = 0; sendBytes[3] = 12; sendBytes[4] = BacnetEnums.BacnetProtocolVersion; sendBytes[5] = 0x20; // Control flags sendBytes[6] = 0xFF; // Destination network address (65535) sendBytes[7] = 0xFF; sendBytes[8] = 0; // Destination MAC layer address length, 0 = Broadcast sendBytes[9] = 0xFF; // Hop count = 255 sendBytes[10] = (byte)BacnetEnums.BacnetPduType.PduTypeUnconfirmedServiceRequest; sendBytes[11] = (byte)BacnetEnums.BacnetUnconfirmedService.ServiceUnconfirmedWhoIs; sendUdp.EnableBroadcast = false; sendUdp.Send(sendBytes, 12, broadcastEp); var watch = new Stopwatch(); watch.Start(); while (true) { if (watch.Elapsed.TotalMilliseconds >= milliseconds) { break; } var remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0); if (sendUdp.Client.Available > 0) { var recvBytes = sendUdp.Receive(ref remoteIpEndPoint); // Parse and save the BACnet data var npduOffset = Bvlc.Parse(recvBytes, 0); var apduOffset = Npdu.Parse(recvBytes, npduOffset); if (Apdu.ParseIAm(recvBytes, apduOffset) <= 0) { continue; } var device = new Device { Name = "Device", SourceLength = Npdu.Slen, ServerEp = remoteIpEndPoint, Network = Npdu.Snet, MacAddress = Npdu.SAddress, Instance = Apdu.ObjectId }; if (!devices.Contains(device)) { devices.Add(device); } } } watch.Stop(); } catch (Exception ex) { Log.ErrorFormat("Error GetDevices {0}", ex.Message); } return(devices); }