public void ServerApplication()
        {
            while (true)
            {
                // check to see if we have any live Incoming messages..

                while (_apm.pktQueueToApplication.Count > 0)
                {
                    try
                    {
                        // process the incoming queue

                        BACnetPacket bacpkt = _apm.pktQueueToApplication.Dequeue();

                        if (bacpkt.npdu.isNPDUmessage)
                        {
                            switch (bacpkt.npdu.function)
                            {
                            case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_I_AM_ROUTER_TO_NETWORK:
                                // find the site, establish the device, make sure that it is marked as a router, save the information
                                _apm.MessageTodo("I am router received");
                                break;

                            case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_INIT_RT_TABLE_ACK:
                                // find the site, establish the device, make sure that it is marked as a router, save the information
                                _apm.MessageTodo("Init rt table ack received");
                                break;

                            case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_WHO_IS_ROUTER_TO_NETWORK:
                                _apm.MessageTodo("m0053 - ----- Implementing  " + bacpkt.npdu.function.ToString());
                                break;
                            }
                        }
                        else
                        {
                            // todo - a certain amount of redundancy exists below, resolve.
                            BACnetLibraryCL.RespondToAPDU(_apm, _bnm, bacpkt);
                        }
                    }
                    catch (Exception ex)
                    {
                        _apm.MessagePanic("m0052 - Router application layer fault" + ex.ToString());
                    }
                }

                System.Threading.Thread.Sleep(10);
            }
        }
Exemple #2
0
        public bool DecodeBACnet(byte[] buffer, int totalMessageLength)
        {
            int offset = 0;

            try
            {
                // this whole section http://www.bacnetwiki.com/wiki/index.php?title=BACnet_Virtual_Link_Control
                ADR sadr = null;

                if (buffer[offset] != BACnetEnums.BACNET_BVLC_TYPE_BIP)
                {
                    // todo3, panic log
                    _apm.MessageProtocolError("m0013 - Not a BACnet/IP message");
                    return(false);
                }

                // we could receive an original broadcast, a unicast, a forwarded here...
                // BVLC Function Types. See http://www.bacnetwiki.com/wiki/index.php?title=BVLC_Function

                switch ((BACnetEnums.BACNET_BVLC_FUNCTION)buffer[offset + 1])
                {
                case BACnetEnums.BACNET_BVLC_FUNCTION.BVLC_FORWARDED_NPDU:
                    npdu_offset = offset + 10;
                    break;

                case BACnetEnums.BACNET_BVLC_FUNCTION.BVLC_ORIGINAL_UNICAST_NPDU:
                case BACnetEnums.BACNET_BVLC_FUNCTION.BVLC_ORIGINAL_BROADCAST_NPDU:
                    // all these OK
                    npdu_offset = offset + 4;
                    break;

                default:
                    BACnetLibraryCL.Panic("m0012 nosuch bvlc function");
                    break;
                }


                // Investigate the NPDU
                // http://www.bacnetwiki.com/wiki/index.php?title=NPDU

                if (buffer[npdu_offset] != BACnetEnums.BACNET_PROTOCOL_VERSION)
                {
                    // we have a major problem, microprotocol version has changed. http://www.bacnetwiki.com/wiki/index.php?title=BACnet_Virtual_Link_Control
                    BACnetLibraryCL.Panic("m0011 BVLC microprotocol problem");
                    return(false);
                }

                // expecting reply?

                if ((buffer[npdu_offset + 1] & 0x04) == 0x04)
                {
                    npdu.expectingReply = true;
                }


                // destination address present?
                // http://www.bacnetwiki.com/wiki/index.php?title=NPCI

                if ((buffer[npdu_offset + 1] & 0x20) == 0x20)
                {
                    //da_present = true;
                    dadr = new ADR();

                    // dnet, dadr and hop count present

                    int dAddrOffset = npdu_offset + 2;
                    dadr.Decode(buffer, ref dAddrOffset);

                    if (dadr.MACaddress.length == 0)
                    {
                        npdu.isBroadcast = true;

                        // broadcast, but check the DNET
                        if (dadr.networkNumber != 0xffff)
                        {
                            throw new Exception("m0010 - Broadcast according to DLEN, but DNET not 0xffff");
                            // todo, this means directed broadcast, need to deal with this still
                        }
                    }
                    if (dadr.MACaddress.length != 1 && dadr.MACaddress.length != 6 && dadr.MACaddress.length != 0)
                    {
                        // panic
                        throw new Exception("m0009 - Unexpected DADR len");
                    }
                    // todo, pick up variable length destination address
                }


                // Source address present?
                // http://www.bacnetwiki.com/wiki/index.php?title=NPCI

                if ((buffer[npdu_offset + 1] & 0x08) == 0x08)
                {
                    //sa_present = true;

                    sadr = new ADR();

                    int sa_offset = npdu_offset + 2;

                    // however, if there is a destination address, move the sa_offset up appropriate amount

                    if (dadr != null)
                    {
                        sa_offset = npdu_offset + 2 + 3 + (int)dadr.MACaddress.length;
                    }

                    // means SADR, SNET present

                    sadr.Decode(buffer, ref sa_offset);

                    // SA exists (included MAC and so this means the received IP address needs to be the fromBIP
                }
                else
                {
                    // at this point, if SADR not discovered within the NPDU, then the SADR MAC address is the Ethernet/IP fromaddress
                    // and the device can (must) be considered 'direcly connected'
                    if (directlyConnectedIPEndPointOfDevice != null)
                    {
                        // and even though the device is directly connected, because we are a router, we have an allocated network number to provide
                        // the network number is available outside this class, and will be filled in by the calling function if it is relevant.
                        srcDevice.adr = new ADR(0, directlyConnectedIPEndPointOfDevice);
                    }
                    else
                    {
                        throw new Exception("m0063 - No From-Address can be determined");
                    }
                }



                if (dadr != null)
                {
                    if (sadr != null)
                    {
                        hopcount = (uint)(buffer[npdu_offset + 2 + 2 + 1 + dadr.MACaddress.length + 2 + 1 + sadr.MACaddress.length]);
                    }
                    else
                    {
                        hopcount = (uint)(buffer[npdu_offset + 2 + 2 + 1 + dadr.MACaddress.length]);
                    }
                    // true broadcast, but check the hopcount

                    if (hopcount == 0)
                    {
                        // out of hops, should never happen to us, so sound a warning
                        // todo, remove this for a functioning systems
                        System.Windows.Forms.MessageBox.Show("m0008 Hopcount of 0 detected");
                        return(false);
                    }
                }

                // finished resolving sadr, and dadr. Now populate our devices as required

                if (sadr != null)
                {
                    if (srcDevice.adr != null)
                    {
                        // means this adr was partially populated elsewhere.
                        srcDevice.adr.networkNumber = sadr.networkNumber;
                        srcDevice.adr.MACaddress    = sadr.MACaddress;
                    }
                    else
                    {
                        srcDevice.adr = sadr;
                    }
                }



                if ((buffer[npdu_offset + 1] & 0x80) == 0x80)  // todo magic number
                {
                    // NSDU contains Network Layer Message
                    // http://www.bacnetwiki.com/wiki/index.php?title=Network_Layer_Protocol_Control_Information

                    apdu_present       = false;
                    npdu.isNPDUmessage = true;

                    // calculate offset to the NSDU

                    nsdu_offset = npdu_offset + 2;

                    if (sadr != null)
                    {
                        nsdu_offset += 2 + 1 + (int)sadr.MACaddress.length;
                    }
                    if (dadr != null)
                    {
                        nsdu_offset += 2 + 1 + (int)dadr.MACaddress.length + 1;
                    }

                    npdu.function = (BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE)buffer[nsdu_offset];

                    switch (npdu.function)
                    {
                    case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_I_AM_ROUTER_TO_NETWORK:
                        // there may be a list of network numbers after the header

                        if ((length - nsdu_offset >= 3))
                        {
                            numberList = new List <uint>();
                        }

                        for (int i = 0; i < (length - nsdu_offset - 1) / 2; i++)
                        {
                            int tref = nsdu_offset + 1 + i * 2;
                            numberList.Add(BACnetLibraryCL.ExtractUint16(buffer, ref tref));
                        }
                        break;

                    case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_INIT_RT_TABLE_ACK:
                        int tiptr    = nsdu_offset + 1;
                        int numPorts = buffer[tiptr++];
                        routerPortList = new List <RouterPort>();

                        for (int i = 0; i < numPorts; i++)
                        {
                            RouterPort rp = new RouterPort();
                            rp.Decode(buffer, ref tiptr);
                            routerPortList.Add(rp);
                        }
                        break;

                    default:
                        // todo
                        break;
                    }
                }
                else
                {
                    // NSDU contains APDU
                    // http://www.bacnetwiki.com/wiki/index.php?title=Network_Layer_Protocol_Control_Information

                    // determine if SNET, SLEN, SADR present

                    apdu_present = true;

                    apdu_offset = npdu_offset + 2;

                    if (sadr != null)
                    {
                        apdu_offset += 2 + 1 + (int)sadr.MACaddress.length;
                    }
                    if (dadr != null)
                    {
                        apdu_offset += 2 + 1 + (int)dadr.MACaddress.length + 1;
                    }

                    apdu_length = length - apdu_offset;
                    if (apdu_length < 0)
                    {
                        _apm.MessagePanic("m0006 Illegal APDU length");
                        return(false);
                    }

                    // todo - need to extract the apdu for others to refer to. However, APDUs may be customer specific, so extract this as a buffer
                    // only for now, and do some spot checks for relevant functions such as I-Am and Who-Is.

                    apdu_buf = new byte[2000];

                    Buffer.BlockCopy(buffer, apdu_offset, apdu_buf, 0, apdu_length);

                    // the offset here is the APDU. Start parsing APDU.
                    // todo, decided to leave the enum values unshifted today 11/27/09
                    pduType = (BACnetEnums.BACNET_PDU_TYPE)(buffer[apdu_offset] & 0xf0);

                    // make sure that we can handle the rest of the packet

                    //if ((buffer[apdu_offset] & 0x0f) != 0 )
                    //{
                    //    throw new Exception("m0056 - Cannot handle segmented messages yet");
                    //}

                    int tptr = apdu_offset + 1;

                    if (pduType == BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
                    {
                        // some PDUs have max segs here
                        tptr++;
                    }

                    //_apm.MessageTodo("Remove apdu++");
                    //apdu_offset++;
                    //apdu_offset++;

                    // now the next byte is the invoke ID

                    invokeID = buffer[tptr++];

                    switch (pduType)
                    {
                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
                        // todo, offset is not always 1, depends on the flags in the first byte.
                        DecodeUnconfirmedService(apdu_buf, apdu_length);
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
                        DecodeConfirmedService(apdu_buf);
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_SIMPLE_ACK:
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_COMPLEX_ACK:
                        confirmedServiceChoice = (BACnetEnums.BACNET_CONFIRMED_SERVICE)buffer[apdu_offset + 2];
                        DecodeComplexACK(buffer, apdu_offset);
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_SEGMENT_ACK:
                        _apm.MessageTodo("m0093 - Segment ACK");
                        errorFlag = true;
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_ERROR:
                        _apm.MessageTodo("m0064 - Error");
                        errorFlag = true;
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_REJECT:
                        pduRejectReason = (BACnetEnums.BACNET_BACNET_REJECT_REASON)buffer[apdu_offset++];
                        errorFlag       = true;
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_ABORT:
                        _apm.MessageTodo("m0066 - PDU abort");
                        errorFlag = true;
                        break;

                    default:
                        throw new Exception("m0003 - Illegal PDU type");
                    }
                }
            }
            catch (Exception ex)
            {
                _apm.MessagePanic("m0001 - BACnet Decode Failed " + ex.ToString());
            }
            return(true);
        }
Exemple #3
0
        // This method that will be called when the thread is started
        public void BACnetInsideListener()
        {
            while (true)
            {
                // Byte[] received = new Byte[2000];
                BACnetPacket packet = new BACnetPacket(_apm);

                // Create an IPEndPoint to capture the identity of the sending host.
                IPEndPoint sender       = new IPEndPoint(IPAddress.Any, 0);
                EndPoint   senderRemote = (EndPoint)sender;

                try
                {
                    // bacnet_listen_socket.Receive(received);
                    packet.length = listen_socket.ReceiveFrom(packet.buffer, ref senderRemote);

                    // Console.WriteLine("This message was sent from " + ((IPEndPoint)senderRemote).Address.ToString() + "  Port " + ((IPEndPoint)senderRemote).Port.ToString());
                    // packet.fromBIP = (IPEndPoint) senderRemote;
                    packet.directlyConnectedIPEndPointOfDevice         = new myIPEndPoint();
                    packet.directlyConnectedIPEndPointOfDevice.Port    = ((IPEndPoint)senderRemote).Port;
                    packet.directlyConnectedIPEndPointOfDevice.Address = ((IPEndPoint)senderRemote).Address;

                    // if the packet is from ourselves, discard
                    if (listen_socket.detect_echo_packet(bnm, packet) == true)
                    {
                        continue;
                    }

                    // todo - one day, we will be able to see if this packet was addressed to this host in a broadcast packet, and mark the dadr accordingly, that is, if we care.

                    // todo - remove directlyconnected
                    //packet.srcDevice.adr = new ADR ( packet.directlyConnectedIPEndPointOfDevice ) ;

                    // Make an undecoded copy of the packet for the application layer. This is to ease debugging in the asynch application layer.
                    BACnetPacket appPkt = (BACnetPacket)packet.Clone();

                    // packet.buffer = received;
                    packet.DecodeBACnet();

                    // extract some information from the packet for our caches

                    if (packet.sAdr != null)
                    {
                        lock (_apm.internalRouterInfo)
                        {
                            _apm.internalRouterInfo.AddRoutingTableEntry(packet.sAdr.networkNumber);
                        }
                    }
                    if (packet.routerTableList != null)
                    {
                        lock (_apm.internalRouterInfo)
                        {
                            foreach (RoutingTableEntry re in packet.routerTableList)
                            {
                                // surrounding this because we know of at least one router out there that has illegal network numbers
                                try
                                {
                                    _apm.internalRouterInfo.AddRoutingTableEntry(re.networkNumber);
                                }
                                catch (ProtocolException pe)
                                {
                                    pe.DumpException(_apm);
                                }
                            }
                        }
                    }


                    // display the decoded packet in the UI treeview
                    bnm.newPacketQueue.myEnqueue(packet);

                    // todo, if diagnostics are not running, then this queue will overflow.... hence the check.. find a cleaner method..
                    if (_apm.pktQueueToApplication.Count < 1000)
                    {
                        _apm.pktQueueToApplication.myEnqueue(appPkt);   // notice, this is not a copy of the packet, it is a pointer to the same packet.... kick me if there are problems one day
                    }
                }
                catch (ProtocolException pe)
                {
                    pe.DumpException(_apm);
                }
                catch (SocketException)
                {
                    // need to catch the inevitable exception when this blocking call is cancelled by the shutdown code
                    // ignore, they will happen on shutdown
                }
                catch (ThreadAbortException)
                {
                }
                catch (Exception efe)
                {
                    _apm.MessagePanic(efe.ToString());
                }
            }
        }
        // This method that will be called when the thread is started
        public void BACnetListenerMethod()
        {
            Console.WriteLine("Thread starting for port " + Convert.ToString(BACnet_port));

            while (true)
            {
                Byte[]       received          = new Byte[2000];
                BACnetPacket incomingCRPpacket = new BACnetPacket(_apm, _bnm);

                // Create an IPEndPoint to capture the identity of the sending host.
                IPEndPoint sender       = new IPEndPoint(IPAddress.Any, 0);
                EndPoint   senderRemote = (EndPoint)sender;

                try
                {
                    incomingCRPpacket.length = _bnm.bacnet_listen_socket.ReceiveFrom(received, ref senderRemote);

                    Console.WriteLine("This message was sent from " + ((IPEndPoint)senderRemote).Address.ToString() + "  Port " + ((IPEndPoint)senderRemote).Port.ToString());

                    incomingCRPpacket.directlyConnectedIPEndPointOfDevice = new myIPEndPoint(senderRemote);
                    incomingCRPpacket.buffer = received;

                    // Decode the packet
                    bool decodeOK = incomingCRPpacket.DecodeBACnet(received, incomingCRPpacket.length);

                    if (!decodeOK)
                    {
                        continue;
                    }

                    // log this data
                    PacketLog pkt = new PacketLog(false, (IPEndPoint)senderRemote, incomingCRPpacket);
                    pkt.BACnetPacket = (BACnetPacket)incomingCRPpacket;
                    _bnm.BACnetMessageLog.Enqueue(pkt);


                    // did packet Decode fail to create a device? If so, we are not interested. e.g. Who-Is.

                    if (incomingCRPpacket.srcDevice == null)
                    {
                        _apm.MessageTodo("m0039 - Device not created by packet decode");
                        continue;
                    }


                    _apm.pktQueueToApplication.Enqueue(incomingCRPpacket);
                }
                catch (SocketException)
                {
                    // we expect a socket exception when shutting down
                    System.Console.WriteLine("socket exception occurred");
                }
                catch (System.Threading.ThreadAbortException)
                {
                    System.Console.WriteLine("Thread abort exception occurred (shutting down)");
                }
                catch (Exception efe)
                {
                    // need to catch the inevitable exception when this blocking call is cancelled by the shutdown code
                    _apm.MessagePanic(efe.ToString());
                }
            }
        }
Exemple #5
0
        public void UpdateDeviceTreeView(BACnetManager bnm, BACnetPacket pkt)
        {
            if (!pkt.apdu_present)
            {
                // means that this packet must be a NPDU message. Treat it differently

                switch (pkt.npdu.function)
                {
                case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_I_AM_ROUTER_TO_NETWORK:
                    //if (pkt.numberList.Count > 0)
                    //{
                    // means we had a response from a router - establish the router in our tree.
                    myTreeNode mtnd = EstablishTreeNodeDevice(bnm, pkt);

                    if (mtnd != null)
                    {
                        // found, or established, the treenode matching the device,
                        // now add the objects to it.

                        // update the type of device - we now know it is a router (even if we did not know before).

                        mtnd.device.type = BACnetEnums.DEVICE_TYPE.Router;
                        mtnd.Text        = "Router";

                        if (pkt.numberList != null)
                        {
                            foreach (int bno in pkt.numberList)
                            {
                                bool found = false;

                                for (int i = 0; i < mtnd.Nodes.Count; i++)
                                {
                                    if (mtnd.Nodes[i].GetType() == typeof(myTreeNode))
                                    {
                                        myTreeNode mtnObj = (myTreeNode)mtnd.Nodes[i];
                                        if (mtnObj.type == myTreeNode.TREENODE_OBJ_TYPE.NetworkNumber && mtnObj.networkNumber == bno)
                                        {
                                            // if we get here, the object already exists in the list and we must not add it again.
                                            mtnObj.networkNumberFromWhoIsRouter = true;
                                            found = true;
                                            break;
                                        }
                                    }
                                }

                                if (!found)
                                {
                                    //// not found, so add
                                    myTreeNode ntn = mtnd.AddMyTreeNodeObject(myTreeNode.TREENODE_OBJ_TYPE.NetworkNumber, "Network " + bno.ToString());
                                    ntn.networkNumber = (uint)bno;
                                    ntn.networkNumberFromWhoIsRouter = true;
                                    ntn.ToolTipText = "Do not right click on this item, it has no effect";
                                    mtnd.Expand();
                                }
                            }
                        }
                        else
                        {
                            _apm.MessageTodo("m0032");
                        }
                    }

                    //}
                    break;

                case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_INIT_RT_TABLE_ACK:

                    myTreeNode mtnrt = EstablishTreeNodeDevice(bnm, pkt);

                    if (mtnrt != null)
                    {
                        // found, or established, the treenode matching the device,
                        // now add the objects to it.
                        // update the type of device - we now know it is a router (even if we did not know before).

                        mtnrt.device.type = BACnetEnums.DEVICE_TYPE.Router;
                        mtnrt.Text        = "Router";

                        foreach (RouterPort rp in pkt.routerPortList)
                        {
                            bool found = false;

                            for (int i = 0; i < mtnrt.Nodes.Count; i++)
                            {
                                if (mtnrt.Nodes[i].GetType() == typeof(myTreeNode))
                                {
                                    myTreeNode mtnObj = (myTreeNode)mtnrt.Nodes[i];
                                    if (mtnObj.type == myTreeNode.TREENODE_OBJ_TYPE.NetworkNumber && mtnObj.networkNumber == rp.networkNumber)
                                    {
                                        // if we get here, the object already exists in the list and we must not add it again.
                                        found = true;
                                        mtnObj.networkNumberFromInitRouterTable = true;
                                        break;
                                    }
                                }
                            }

                            if (!found)
                            {
                                //// not found, so add
                                myTreeNode ntn = mtnrt.AddMyTreeNodeObject(myTreeNode.TREENODE_OBJ_TYPE.NetworkNumber, "Network " + rp.networkNumber.ToString());
                                ntn.networkNumber = rp.networkNumber;
                                ntn.networkNumberFromInitRouterTable = true;
                                // ntn.ToolTipText = "Do not right click on this item, it has no effect";
                                mtnrt.Expand();
                            }
                        }
                    }

                    break;
                }

                return;
            }

            switch (pkt.pduType)
            {
            case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
                switch (pkt.unconfirmedServiceChoice)
                {
                case BACnetEnums.BACNET_UNCONFIRMED_SERVICE.SERVICE_UNCONFIRMED_I_AM:
                    pkt.srcDevice.directlyConnectedIPEndPointOfDevice = pkt.directlyConnectedIPEndPointOfDevice;           // was fromBIP

                    // todo, not sure where I use this - check
                    bnm.deviceList.Add(pkt.srcDevice);

                    AddDeviceToTreeNode(bnm, pkt);
                    // bnm.newPacketQueue.Enqueue(packet);
                    break;

                case BACnetEnums.BACNET_UNCONFIRMED_SERVICE.SERVICE_UNCONFIRMED_WHO_IS:
                    // ignore reflected who-is messages
                    break;

                default:
                    BACnetLibraryCL.Panic("Todo");
                    break;
                }
                break;

            case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_COMPLEX_ACK:
                switch (pkt.confirmedServiceChoice)
                {
                case BACnetEnums.BACNET_CONFIRMED_SERVICE.SERVICE_CONFIRMED_READ_PROPERTY:
                    switch (pkt.propertyID)
                    {
                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_OBJECT_LIST:
                        // what we need to do here is list the objects on the treeview...

                        // find the device in the tree
                        // add the objects to it

                        myTreeNode mtn = findTreeNodeDevice(bnm, pkt);

                        if (mtn != null)
                        {
                            // found the treenode matching the device, add the objects to it.

                            if (pkt.objectList != null)
                            {
                                foreach (BACnetObjectIdentifier bno in pkt.objectList)
                                {
                                    // does it exist? if so, ignore
                                    if (findTreeNodeObject(mtn, bno) == null)
                                    {
                                        // not found, so add
                                        myTreeNode ntn = new myTreeNode();
                                        ntn.oID         = bno;
                                        ntn.type        = myTreeNode.TREENODE_OBJ_TYPE.BACnetObject;
                                        ntn.Text        = bno.objectType.ToString() + "   Instance: " + bno.objectInstance.ToString();
                                        ntn.ToolTipText = "Do not right click on this item, it has no effect";
                                        mtn.Nodes.Add(ntn);
                                    }
                                }
                            }

                            // now remove the object list??? (but it will be removed when packet is destroyed....
                        }

                        break;

                    default:
                        _apm.MessagePanic("m0030 " + pkt.propertyID.ToString());
                        break;
                    }
                    break;

                default:
                    _apm.MessagePanic("m0029");
                    break;
                }
                break;


            case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
            case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_REJECT:
                // These messages do not affect the Device TreeView, so we will ignore them..
                break;

            default:
                _apm.MessageTodo("m0027 - Device Treeview needs to parse this message still: " + pkt.pduType.ToString());
                break;
            }
        }