Пример #1
0
        public void Decode(byte[] buffer, ref int pos)
        {
            networkNumber  = (uint)buffer[pos++] << 8;
            networkNumber |= buffer[pos++];

            MACaddress.length = buffer[pos++];

            switch (MACaddress.length)
            {
            case 0:
                // indicates a broadcast, perfectly legal.
                break;

            case 1:
                MACaddress.uintMACaddress = buffer[pos++];
                break;

            case 6:
                // extract the IP address
                myIPEndPoint ipep = new myIPEndPoint();
                ipep.Decode(buffer, pos);
                MACaddress.ipMACaddress = ipep;
                pos += 6;
                break;

            default:
                BACnetLibraryCL.Panic("Illegal MAC address length??");
                break;
            }
        }
Пример #2
0
        public bool Equals(MACaddress madr)
        {
            if (length != madr.length)
            {
                return(false);
            }

            switch (length)
            {
            case 0:
                break;

            case 1:
                if (madr.uintMACaddress != uintMACaddress)
                {
                    return(false);
                }
                break;

            case 6:
                if (ipMACaddress.Equals(madr.ipMACaddress) != true)
                {
                    return(false);
                }
                break;

            default:
                BACnetLibraryCL.Panic("Illegal MAC address length??");
                return(false);
            }
            return(true);
        }
Пример #3
0
        public bool seenOnRouterInit;           // These flags help us establish that.

        public bool Decode(byte[] buf, ref int iptr)
        {
            networkNumber = BACnetLibraryCL.ExtractUint16(buf, ref iptr);
            ID            = buf[iptr++];
            portInfoLen   = buf[iptr++];
            if (portInfoLen != 0)
            {
                // we are not ready to handle this.
                BACnetLibraryCL.Panic("todo");
            }
            iptr += (int)portInfoLen;
            return(true);
        }
Пример #4
0
        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);
            }
        }
Пример #5
0
        public override string ToString()
        {
            switch (length)
            {
            case 0:
                return("Broadcast");

            case 1:
                return(uintMACaddress.ToString());

            case 6:
                return(ipMACaddress.ToString());

            default:
                BACnetLibraryCL.Panic("Illegal MAC length");
                return("Illegal MAC address");
            }
        }
Пример #6
0
        // Build the 'header' part of the BACnet Packet
        private static int InsertReadPropertyResponse(AppManager apm, BACnetPacket requestBACpkt, BACnetPacket responseCRP, byte[] outbuf, BACnetEnums.BACNET_PROPERTY_ID pID)
        {
            int optr;

            optr = responseCRP.apdu_offset;

            // build APDU to provide services supported.

            responseCRP.EncodeNPDU(outbuf, ref optr);

            BACnetLibraryCL.InsertPDU(outbuf, ref optr, BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_COMPLEX_ACK, requestBACpkt.invokeID, requestBACpkt.confirmedServiceChoice);

            requestBACpkt.objectID.EncodeContextTag(outbuf, ref optr, 0);

            BACnetLibraryCL.InsertContextTag(outbuf, ref optr, 1, (int)pID);

            return(optr);
        }
Пример #7
0
        // Create a new Application Tag

        public BACnetObjectIdentifier(byte[] buf, ref int offset, BACnetEnums.TAG tagType, BACnetEnums.BACNET_APPLICATION_TAG appTag)
        {
            // is the next parameter even an application tag
            if ((buf[offset] & 0x08) != 0x00)
            {
                // we have an unexpected context tag, sort this out
                BACnetLibraryCL.Panic("Not a context tag");
                // todo, now is there a way to avoid creating the object? Have to flag it at least...
                return;
            }

            if ((BACnetEnums.BACNET_APPLICATION_TAG)(((buf[offset] & 0xf0) >> 4)) != appTag)
            {
                // we have an unexpected context tag, sort this out
                BACnetLibraryCL.Panic("Unexpected application tag");
                // todo, now is there a way to avoid creating the object? Have to flag it at least...
                return;
            }

            int contextTagSize = buf[offset] & 0x07;

            offset++;

            switch (appTag)
            {
            case BACnetEnums.BACNET_APPLICATION_TAG.BACNET_APPLICATION_TAG_OBJECT_ID:
                if (contextTagSize != 4)
                {
                    // we dont have a legal object ID!
                    BACnetLibraryCL.Panic("Illegal length");
                    return;
                }

                this.objectType = (BACnetEnums.BACNET_OBJECT_TYPE)(((uint)buf[offset] << 2) | ((uint)buf[offset + 1] >> 6));

                objectInstance  = ((uint)buf[offset + 1] & 0x3f) << 16;
                objectInstance |= ((uint)buf[offset + 2]) << 8;
                objectInstance |= ((uint)buf[offset + 3]);

                offset += 4;
                return;
            }
        }
Пример #8
0
        // Create a new Context Tag

        public BACnetObjectIdentifier(byte[] buf, ref int offset, BACnetEnums.TAG tagType, int tagValue)
        {
            // is the next parameter even a context tag
            if ((buf[offset] & 0x08) != 0x08)
            {
                // we have an unexpected context tag, sort this out
                BACnetLibraryCL.Panic("Not a context tag");
                // todo, now is there a way to avoid creating the object? Have to flag it at least...
                return;
            }

            if ((buf[offset] & 0xf0) != (tagValue << 4))
            {
                // we have an unexpected context tag, sort this out
                BACnetLibraryCL.Panic("Unexpected context tag");
                // todo, now is there a way to avoid creating the object? Have to flag it at least...
                return;
            }

            int contextTagSize = buf[offset] & 0x07;

            // the length of a bacnet object identifier better be 4

            if (contextTagSize != 4)
            {
                // we have an unexpected context tag, sort this out
                BACnetLibraryCL.Panic("Unbelievable length of object identifier");
                // todo, now is there a way to avoid creating the object? Have to flag it at least...
                return;
            }


            objectType = (BACnetEnums.BACNET_OBJECT_TYPE)(((uint)buf[offset + 1] << 2) | ((uint)buf[offset + 2] >> 6));

            objectInstance  = ((uint)buf[offset + 2] & 0x3f) << 16;
            objectInstance |= ((uint)buf[offset + 3]) << 8;
            objectInstance |= ((uint)buf[offset + 4]);

            offset += 5;
        }
Пример #9
0
        public void Encode(byte[] buffer, ref int pos)
        {
            buffer[pos++] = (byte)(this.networkNumber >> 8);
            buffer[pos++] = (byte)(this.networkNumber & 0xff);

            buffer[pos++] = (byte)MACaddress.length;

            switch (MACaddress.length)
            {
            case 1:
                buffer[pos++] = (byte)MACaddress.uintMACaddress;
                break;

            case 6:
                MACaddress.ipMACaddress.Encode(buffer, ref pos);
                break;

            default:
                BACnetLibraryCL.Panic("Illegal MAC address length??");
                break;
            }
        }
Пример #10
0
        public void EncodeBACnetNew(byte[] outbuf, ref int optr)
        {
            int startBACnetPacket = optr;

            // BVLC Part
            // http://www.bacnetwiki.com/wiki/index.php?title=BACnet_Virtual_Link_Control

            outbuf[optr++] = BACnetEnums.BACNET_BVLC_TYPE_BIP;

            if (npdu.isBroadcast)
            {
                outbuf[optr++] = (byte)BACnetEnums.BACNET_BVLC_FUNCTION.BVLC_ORIGINAL_BROADCAST_NPDU;
            }
            else
            {
                outbuf[optr++] = (byte)BACnetEnums.BACNET_BVLC_FUNCTION.BVLC_ORIGINAL_UNICAST_NPDU;
            }

            int store_length_here = optr;

            optr += 2;

            // Start of NPDU
            // http://www.bacnetwiki.com/wiki/index.php?title=NPDU

            outbuf[optr++] = 0x01;        // Always 1

            int store_NPCI = optr;

            outbuf[optr++] = 0x00;        // Control

            if (npdu.isNPDUmessage)
            {
                outbuf[store_NPCI] |= 0x80;     // Indicating Network Layer Message
            }

            if (npdu.expectingReply)
            {
                outbuf[store_NPCI] |= 0x04;     // todo- magic number
            }

            if (npdu.isBroadcast)
            {
                outbuf[store_NPCI] |= 0x20;     // Control byte - indicate DADR present
                outbuf[optr++]      = 0xff;     // DNET Network - B'cast
                outbuf[optr++]      = 0xff;
                outbuf[optr++]      = 0x00;     // DLEN
            }
            else
            {
                // insert dadr - but only if the device is NOT directly coupled. See page 59. If the device is directly coupled
                // then the ethernet address in the packet will suffice.
                if (!dadr.directlyConnected)
                {
                    // need to insert destination DADR here
                    outbuf[store_NPCI] |= 0x20;         // Control byte - indidate DADR present
                    dadr.Encode(outbuf, ref optr);
                }
            }

            // we are a router, so we need to add source address under most circumstances. (not broadcast who-is)
            if (srcDevice.adr != null)
            {
                outbuf[store_NPCI] |= 0x08;                 // Control byte - indidate SADR present
                srcDevice.adr.Encode(outbuf, ref optr);
            }

            if (npdu.isBroadcast || !dadr.directlyConnected)
            {
                // insert hopcount here.
                hopcount      -= 10;
                outbuf[optr++] = (byte)hopcount;
            }

            // APDU start
            // http://www.bacnetwiki.com/wiki/index.php?title=APDU

            if (apdu_present)
            {
                // APDU start
                // http://www.bacnetwiki.com/wiki/index.php?title=APDU

                for (int i = 0; i < apdu_length; i++)
                {
                    outbuf[optr++] = buffer[apdu_offset + i];        // Encoded APDU type == 01 == Unconfirmed Request
                }
            }
            else if (npdu.isNPDUmessage)
            {
                // Build the Nsdu
                // http://www.bacnetwiki.com/wiki/index.php?title=Network_Layer_Message

                outbuf[optr++] = (byte)npdu.function;

                switch (npdu.function)
                {
                case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_WHO_IS_ROUTER_TO_NETWORK:
                    break;

                case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_INIT_RT_TABLE:
                    outbuf[optr++] = 0x00;            // Number of port mappings
                    break;

                case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_I_AM_ROUTER_TO_NETWORK:
                    if (numberList != null)
                    {
                        foreach (uint i in numberList)
                        {
                            BACnetLibraryCL.InsertUint16(outbuf, ref optr, i);
                        }
                    }
                    break;

                default:
                    _apm.MessageTodo("m0023 Implement " + npdu.function.ToString());
                    break;
                }
            }
            else
            {
                // build an APDU.
                switch (this.pduType)
                {
                case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
                    switch (this.unconfirmedServiceChoice)
                    {
                    case BACnetEnums.BACNET_UNCONFIRMED_SERVICE.SERVICE_UNCONFIRMED_I_AM:
                        // APDU start
                        // http://www.bacnetwiki.com/wiki/index.php?title=APDU

                        outbuf[optr++] = 0x10;                // Encoded APDU type == 01 == Unconfirmed Request
                        outbuf[optr++] = 0x00;                // Unconfirmed Service Choice: I-Am

                        // object identifier, device object

                        BACnetObjectIdentifier bnoid = new BACnetObjectIdentifier();

                        bnoid.SetType(BACnetEnums.BACNET_OBJECT_TYPE.OBJECT_DEVICE);
                        _apm.MessageTodo("m0038 - Establish a mechanism to determine our OWN Device ID");
                        bnoid.SetInstance(_apm.ourDeviceId);
                        bnoid.EncodeApplicationTag(outbuf, ref optr);

                        // Maximum APDU length (Application Tag, Integer)
                        Unsigned apdulen = new Unsigned(1476);
                        apdulen.Encode(outbuf, ref optr);

                        // Segmentation supported, (Application Tag, Enum)
                        BACnetSegmentation bsg = new BACnetSegmentation();

                        bsg.Encode(outbuf, ref optr);

                        // Vendor ID, (Application Tag, Integer)
                        BACnetLibraryCL.InsertApplicationTagUint16(outbuf, ref optr, _apm.ourVendorID);
                        break;

                    default:
                        _apm.MessageTodo("m0022 Build missing service type");
                        break;
                    }
                    break;

                default:
                    _apm.MessageTodo("m0021 Build missing PDU type");
                    break;
                }
            }
            outbuf[store_length_here]     = (byte)(((optr - startBACnetPacket) >> 8) & 0xff);
            outbuf[store_length_here + 1] = (byte)((optr - startBACnetPacket) & 0xff);
        }
Пример #11
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);
        }
Пример #12
0
        public static void RespondToAPDU(AppManager apm, BACnetManager bnm, BACnetPacket incomingPacket)
        {
            byte[]    outbuf = new byte[2000];
            int       optr;
            PacketLog pktlog;

            BACnetPacket outgoingBACpacket = new BACnetPacket(apm, bnm);

            // fill in some CRP parameters for packet log display
            outgoingBACpacket.confirmedServiceChoice       = incomingPacket.confirmedServiceChoice;
            outgoingBACpacket.apduConfirmedServiceTypeFlag = incomingPacket.apduConfirmedServiceTypeFlag;
            outgoingBACpacket.propertyID = incomingPacket.propertyID;
            outgoingBACpacket.apduUnconfirmedServiceFlag = incomingPacket.apduUnconfirmedServiceFlag;
            outgoingBACpacket.pduType = incomingPacket.pduType;
            outgoingBACpacket.unconfirmedServiceChoice            = incomingPacket.unconfirmedServiceChoice;
            outgoingBACpacket.directlyConnectedIPEndPointOfDevice = incomingPacket.directlyConnectedIPEndPointOfDevice;

            BACnetPacket incomingBACpacket = (BACnetPacket)incomingPacket;

            if (incomingBACpacket.apduConfirmedServiceTypeFlag == true)
            {
                switch (incomingBACpacket.confirmedServiceChoice)
                {
                case BACnetEnums.BACNET_CONFIRMED_SERVICE.SERVICE_CONFIRMED_READ_PROPERTY:

                    switch (incomingBACpacket.propertyID)
                    {
                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_OBJECT_NAME:
                        // supply the first (and only) (device) object
                        optr = InsertReadPropertyResponse(apm, incomingBACpacket, outgoingBACpacket, outbuf, incomingBACpacket.propertyID);
                        // Device Object ID
                        InsertContextOpeningTag(outbuf, ref optr, 3);
                        InsertApplicationTagString(outbuf, ref optr, apm.ourDeviceName);
                        InsertContextClosingTag(outbuf, ref optr, 3);
                        // Send it off
                        SendOffPacket(apm, outgoingBACpacket, outbuf, optr);
                        break;

                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED:
                        optr = InsertReadPropertyResponse(apm, incomingBACpacket, outgoingBACpacket, outbuf, incomingBACpacket.propertyID);
                        BACnetLibraryCL.InsertContextOpeningTag(outbuf, ref optr, 3);

                        // hardcode the bitstring until we see where else it can be used, then generalized.

                        outbuf[optr++] = 0x83;          // Assume length = 3, including unused bits byte
                        // outbuf[optr++] = 0x03;
                        outbuf[optr++] = 0x06;          // trailing bits not used

                        InsertBitString(outbuf, optr, 2, (int)BACnetEnums.BACNET_OBJECT_TYPE.OBJECT_DEVICE);
                        optr += 2;

                        BACnetLibraryCL.InsertContextClosingTag(outbuf, ref optr, 3);

                        SendOffPacket(apm, outgoingBACpacket, outbuf, optr);
                        break;

                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_PROTOCOL_SERVICES_SUPPORTED:

                        optr = InsertReadPropertyResponse(apm, incomingBACpacket, outgoingBACpacket, outbuf, incomingBACpacket.propertyID);

                        BACnetLibraryCL.InsertContextOpeningTag(outbuf, ref optr, 3);


                        //List<BACnetEnums.BACNET_SERVICES_SUPPORTED> servicesList = new List<BACnetEnums.BACNET_SERVICES_SUPPORTED>();

                        //servicesList.Add(BACnetEnums.BACNET_SERVICES_SUPPORTED.SERVICE_SUPPORTED_READ_PROPERTY);
                        //// servicesList.Add(BACnetEnums.BACNET_SERVICES_SUPPORTED.SERVICE_SUPPORTED_WRITE_PROPERTY);
                        //servicesList.Add(BACnetEnums.BACNET_SERVICES_SUPPORTED.SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL);
                        ////servicesList.Add(BACnetEnums.BACNET_SERVICES_SUPPORTED.SERVICE_SUPPORTED_REINITIALIZE_DEVICE);
                        //servicesList.Add(BACnetEnums.BACNET_SERVICES_SUPPORTED.SERVICE_SUPPORTED_TIME_SYNCHRONIZATION);
                        //servicesList.Add(BACnetEnums.BACNET_SERVICES_SUPPORTED.SERVICE_SUPPORTED_WHO_IS);
                        //// todo, what about i-am ?
                        //BACnetLibraryCL.InsertApplicationTagString(outbuf, ref optr, servicesList );

                        // hardcode the bitstring until we see where else it can be used, then generalized.

                        outbuf[optr++] = 0x85;          // Assume length = 6
                        outbuf[optr++] = 0x06;          // Length, including the next byte
                        outbuf[optr++] = 0x05;          // 5 trailing bits not used

                        InsertBitString(outbuf, optr, 5, (int)BACnetEnums.BACNET_SERVICES_SUPPORTED.SERVICE_SUPPORTED_READ_PROPERTY);
                        InsertBitString(outbuf, optr, 5, (int)BACnetEnums.BACNET_SERVICES_SUPPORTED.SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL);
                        InsertBitString(outbuf, optr, 5, (int)BACnetEnums.BACNET_SERVICES_SUPPORTED.SERVICE_SUPPORTED_TIME_SYNCHRONIZATION);
                        InsertBitString(outbuf, optr, 5, (int)BACnetEnums.BACNET_SERVICES_SUPPORTED.SERVICE_SUPPORTED_WHO_IS);

                        InsertBitString(outbuf, optr, 5, (int)BACnetEnums.BACNET_SERVICES_SUPPORTED.SERVICE_SUPPORTED_WRITE_PROPERTY);
                        InsertBitString(outbuf, optr, 5, (int)BACnetEnums.BACNET_SERVICES_SUPPORTED.SERVICE_SUPPORTED_REINITIALIZE_DEVICE);

                        optr += 5;

                        BACnetLibraryCL.InsertContextClosingTag(outbuf, ref optr, 3);

                        SendOffPacket(apm, outgoingBACpacket, outbuf, optr);
                        break;

                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_OBJECT_LIST:
                        // Only respond if array index specified
                        if (!incomingPacket.arrayIndexDecoded)
                        {
                            throw new Exception("m0058 - Not expecting open object list");
                        }

                        if (incomingPacket.arrayIndex == 0)
                        {
                            optr = InsertReadPropertyResponse(apm, incomingBACpacket, outgoingBACpacket, outbuf, incomingBACpacket.propertyID);

                            // arrayIndex 0
                            InsertContextTag(outbuf, ref optr, 2, 0);

                            // Object count
                            InsertContextOpeningTag(outbuf, ref optr, 3);
                            InsertApplicationTag(outbuf, ref optr, BACnetEnums.BACNET_APPLICATION_TAG.BACNET_APPLICATION_TAG_UNSIGNED_INT, 1);
                            InsertContextClosingTag(outbuf, ref optr, 3);

                            // Send it off
                            SendOffPacket(apm, outgoingBACpacket, outbuf, optr);
                            break;

                            // supply the number of objects
                        }
                        else if (incomingPacket.arrayIndex == 1)
                        {
                            // supply the first (and only) (device) object
                            optr = InsertReadPropertyResponse(apm, incomingBACpacket, outgoingBACpacket, outbuf, incomingBACpacket.propertyID);

                            // arrayIndex 1
                            InsertContextTag(outbuf, ref optr, 2, 1);

                            // Device Object ID
                            InsertContextOpeningTag(outbuf, ref optr, 3);
                            incomingPacket.objectID.EncodeApplicationTag(outbuf, ref optr);
                            InsertContextClosingTag(outbuf, ref optr, 3);

                            // Send it off
                            SendOffPacket(apm, outgoingBACpacket, outbuf, optr);
                        }
                        else
                        {
                            throw new Exception("m0059 - Illegal object list index");
                        }
                        break;

                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_OBJECT_TYPE:
                        // supply the first (and only) (device) object
                        optr = InsertReadPropertyResponse(apm, incomingBACpacket, outgoingBACpacket, outbuf, incomingBACpacket.propertyID);
                        // Device Object ID
                        InsertContextOpeningTag(outbuf, ref optr, 3);
                        InsertApplicationTag(outbuf, ref optr, BACnetEnums.BACNET_APPLICATION_TAG.BACNET_APPLICATION_TAG_ENUMERATED, (uint)BACnetEnums.BACNET_OBJECT_TYPE.OBJECT_DEVICE);
                        InsertContextClosingTag(outbuf, ref optr, 3);
                        // Send it off
                        SendOffPacket(apm, outgoingBACpacket, outbuf, optr);
                        break;

                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_SYSTEM_STATUS:
                        // supply the first (and only) (device) object
                        optr = InsertReadPropertyResponse(apm, incomingBACpacket, outgoingBACpacket, outbuf, incomingBACpacket.propertyID);
                        // Device Object ID
                        InsertContextOpeningTag(outbuf, ref optr, 3);
                        InsertApplicationTag(outbuf, ref optr, BACnetEnums.BACNET_APPLICATION_TAG.BACNET_APPLICATION_TAG_ENUMERATED, (uint)BACnetEnums.BACNET_DEVICE_STATUS.STATUS_OPERATIONAL);
                        InsertContextClosingTag(outbuf, ref optr, 3);
                        // Send it off
                        SendOffPacket(apm, outgoingBACpacket, outbuf, optr);
                        break;

                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_OBJECT_IDENTIFIER:
                        // supply the first (and only) (device) object
                        optr = InsertReadPropertyResponse(apm, incomingBACpacket, outgoingBACpacket, outbuf, incomingBACpacket.propertyID);
                        // Device Object ID
                        InsertContextOpeningTag(outbuf, ref optr, 3);
                        incomingPacket.objectID.EncodeApplicationTag(outbuf, ref optr);
                        InsertContextClosingTag(outbuf, ref optr, 3);
                        // Send it off
                        SendOffPacket(apm, outgoingBACpacket, outbuf, optr);
                        break;

                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_VENDOR_NAME:
                        // supply the first (and only) (device) object
                        optr = InsertReadPropertyResponse(apm, incomingBACpacket, outgoingBACpacket, outbuf, incomingBACpacket.propertyID);
                        // Device Object ID
                        InsertContextOpeningTag(outbuf, ref optr, 3);
                        InsertApplicationTagString(outbuf, ref optr, apm.ourVendorName);
                        InsertContextClosingTag(outbuf, ref optr, 3);
                        // Send it off
                        SendOffPacket(apm, outgoingBACpacket, outbuf, optr);
                        break;

                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_MODEL_NAME:
                        // supply the first (and only) (device) object
                        optr = InsertReadPropertyResponse(apm, incomingBACpacket, outgoingBACpacket, outbuf, incomingBACpacket.propertyID);
                        // Device Object ID
                        InsertContextOpeningTag(outbuf, ref optr, 3);
                        InsertApplicationTagString(outbuf, ref optr, apm.ourModelName);
                        InsertContextClosingTag(outbuf, ref optr, 3);
                        // Send it off
                        SendOffPacket(apm, outgoingBACpacket, outbuf, optr);
                        break;

                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_FIRMWARE_REVISION:
                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_APPLICATION_SOFTWARE_VERSION:
                        RespondReadPropertyWithString(apm, incomingBACpacket, outgoingBACpacket, outbuf, apm.ourFirmwareRevision);
                        break;

                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_VENDOR_IDENTIFIER:
                        RespondReadPropertyWithUint(apm, incomingBACpacket, outgoingBACpacket, outbuf, apm.ourVendorID);
                        break;

                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_PROTOCOL_VERSION:
                        RespondReadPropertyWithUint(apm, incomingBACpacket, outgoingBACpacket, outbuf, 1);
                        break;

                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_PROTOCOL_REVISION:
                        RespondReadPropertyWithUint(apm, incomingBACpacket, outgoingBACpacket, outbuf, 4);
                        break;

                    default:
                        apm.MessageTodo("m0046 - Implement read property " + incomingBACpacket.propertyID.ToString());
                        break;
                    }
                    break;

                default:
                    apm.MessageTodo("m0044 - Implement confirmed service " + incomingBACpacket.confirmedServiceChoice.ToString());
                    break;
                }
            }

            if (incomingBACpacket.apduUnconfirmedServiceFlag == true)
            {
                switch (incomingBACpacket.pduType)
                {
                case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
                    switch (incomingBACpacket.unconfirmedServiceChoice)
                    {
                    case BACnetEnums.BACNET_UNCONFIRMED_SERVICE.SERVICE_UNCONFIRMED_WHO_IS:

                        // we need to respond

                        // ONLY if we are in the range, and if not, ignore.

                        if (incomingBACpacket.lowRange != 0 || incomingBACpacket.highRange != 0)
                        {
                            if (apm.ourDeviceId < incomingBACpacket.lowRange || apm.ourDeviceId > incomingBACpacket.highRange)
                            {
                                // This packet not for us
                                apm.MessageLog("m0034 - Ranged Who-Is not addressed to us, ignoring");
                                break;
                            }
                        }

                        // Compose the response (I-am)

                        outgoingBACpacket.BACnetPort = incomingPacket.BACnetPort;

                        outgoingBACpacket.npdu.isBroadcast = true;
                        outgoingBACpacket.hopcount         = 256;

                        // destination address of the BACnet packet. (Must either be b'cast or directlyConnectedIPEP

                        optr = 0;

                        outgoingBACpacket.npdu.isNPDUmessage       = false;   // makes it an APDU
                        outgoingBACpacket.pduType                  = BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
                        outgoingBACpacket.unconfirmedServiceChoice = BACnetEnums.BACNET_UNCONFIRMED_SERVICE.SERVICE_UNCONFIRMED_I_AM;

                        outgoingBACpacket.EncodeBACnetNew(outbuf, ref optr);

                        // send the message

                        // if there is no available adapter, this try will throw
                        try
                        {
                            apm.bnm.bacnet_listen_socket.SendTo(outbuf, optr, SocketFlags.None, incomingPacket.directlyConnectedIPEndPointOfDevice);

                            pktlog = new PacketLog(true, incomingPacket.directlyConnectedIPEndPointOfDevice, outgoingBACpacket);
                            pktlog.BACnetPacket = (BACnetPacket)outgoingBACpacket;
                            apm.bnm.BACnetMessageLog.Enqueue(pktlog);
                        }
                        catch (SocketException)
                        {
                            apm.MessageTodo("Either the network cable is unplugged, or there is no configured Ethernet Port on this computer");
                        }
                        break;

                    case BACnetEnums.BACNET_UNCONFIRMED_SERVICE.SERVICE_UNCONFIRMED_I_AM:
                        break;

                    default:
                        apm.MessageTodo("Implement " + incomingBACpacket.unconfirmedServiceChoice.ToString());
                        break;
                    }
                    break;

                default:
                    apm.MessageTodo("Implement " + incomingBACpacket.pduType.ToString());
                    break;
                }
            }
        }
Пример #13
0
        public static void ReadPropertyObjectList(BACnetManager bnm, Device device)
        {
            byte[] data = new byte[1024];
            int    optr = 0;

            // BVLC Part
            // http://www.bacnetwiki.com/wiki/index.php?title=BACnet_Virtual_Link_Control

            data[optr++] = BACnetEnums.BACNET_BVLC_TYPE_BIP;                                  // 81
            data[optr++] = (byte)BACnetEnums.BACNET_BVLC_FUNCTION.BVLC_ORIGINAL_UNICAST_NPDU; //0a

            int store_length_here = optr;

            optr += 2;

            // Start of NPDU
            // http://www.bacnetwiki.com/wiki/index.php?title=NPDU

            data[optr++] = 0x01;            //  Version
            data[optr++] = 0x24;            //  NCPI - Dest present, expecting reply

            if (device.adr != null)
            {
                device.adr.Encode(data, ref optr);
            }
            else
            {
                // this means we have an ethernet/IP address for a MAC address. At present
                // we then dont know the network number
                // todo - resolve the network number issue
                ADR tempAdr = new ADR(0, device.directlyConnectedIPEndPointOfDevice);
                tempAdr.Encode(data, ref optr);
            }

            data[optr++] = 0xff;            // Hopcount


            // APDU start
            // http://www.bacnetwiki.com/wiki/index.php?title=APDU


            // Unconfirmed Request
            // Structure described here http://www.bacnetwiki.com/wiki/index.php?title=BACnet-Confirmed-Request-PDU

            data[optr++] = 0x02;            //  PDU Type=0 and SA=1
            data[optr++] = 0x04;            //  Max Resp (Encoded)

            data[optr++] = 0x01;            //  Invoke ID

            data[optr++] = 0x0c;            //  Service Choice 12 = ReadProperty

            // Service Request

            // Object type, instance (Device Object) (Encode as context tag 0)
            device.deviceObjectID.EncodeContextTag(data, ref optr, 0);

            // Property Identifier (Object List)
            InsertContextTag(data, ref optr, 1, (int)BACnetEnums.BACNET_PROPERTY_ID.PROP_OBJECT_LIST);

            // todo, why is this not context encoded?

            BACnetLibraryCL.InsertInt16(data, ref store_length_here, optr);

            // todo bnm.insidesocket.MySend(data, optr, device.packet.fromBIP);
        }
Пример #14
0
        public void EncodeApplicationTag(byte[] buffer, ref int pos)
        {
            UInt32 objid = ((UInt32)objectType << 22) | (objectInstance & 0x3ffffff);

            BACnetLibraryCL.InsertApplicationTag(buffer, ref pos, BACnetEnums.BACNET_APPLICATION_TAG.BACNET_APPLICATION_TAG_OBJECT_ID, objid);
        }
Пример #15
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;
            }
        }