diff --git a/bacnet-stack/address.c b/bacnet-stack/address.c index cd4d3163..03639b0c 100644 --- a/bacnet-stack/address.c +++ b/bacnet-stack/address.c @@ -47,6 +47,7 @@ static struct Address_Cache_Entry { bool valid; + bool bind_request; uint32_t device_id; unsigned max_apdu; BACNET_ADDRESS address; @@ -83,7 +84,8 @@ void address_remove_device( for (i = 0; i < MAX_ADDRESS_CACHE; i++) { - if (Address_Cache[i].valid && + if ((Address_Cache[i].valid || + Address_Cache[i].bind_request) && (Address_Cache[i].device_id == device_id)) { Address_Cache[i].valid = false; @@ -101,6 +103,7 @@ void address_init(void) for (i = 0; i < MAX_ADDRESS_CACHE; i++) { Address_Cache[i].valid = false; + Address_Cache[i].bind_request = false; } return; @@ -168,6 +171,92 @@ void address_add( return; } +// returns true if device is already bound +// also returns the address and max apdu if already bound +bool address_bind_request( + uint32_t device_id, + unsigned *max_apdu, + BACNET_ADDRESS *src) +{ + unsigned i; + bool found = false; // return value + + // existing device - update address + for (i = 0; i < MAX_ADDRESS_CACHE; i++) + { + if (Address_Cache[i].valid && + (Address_Cache[i].device_id == device_id)) + { + found = true; + address_copy(src, &Address_Cache[i].address); + *max_apdu = Address_Cache[i].max_apdu; + break; + } + // already have a bind request active for this puppy + else if (Address_Cache[i].bind_request && + (Address_Cache[i].device_id == device_id)) + { + return found; + } + } + + if (!found) + { + for (i = 0; i < MAX_ADDRESS_CACHE; i++) + { + if (!(Address_Cache[i].bind_request || Address_Cache[i].valid)) + { + Address_Cache[i].bind_request = true; + Address_Cache[i].device_id = device_id; + // now would be a good time to do a Who-Is request + break; + } + } + } + + return found; +} + +void address_add_binding( + uint32_t device_id, + unsigned max_apdu, + BACNET_ADDRESS *src) +{ + unsigned i; + bool found = false; // return value + + // existing device - update address + for (i = 0; i < MAX_ADDRESS_CACHE; i++) + { + if (Address_Cache[i].valid && + (Address_Cache[i].device_id == device_id)) + { + address_copy(&Address_Cache[i].address,src); + Address_Cache[i].max_apdu = max_apdu; + found = true; + break; + } + } + // add new device - but only if bind requested + if (!found) + { + for (i = 0; i < MAX_ADDRESS_CACHE; i++) + { + if (!Address_Cache[i].valid && Address_Cache[i].bind_request) + { + Address_Cache[i].valid = true; + Address_Cache[i].bind_request = false; + Address_Cache[i].device_id = device_id; + Address_Cache[i].max_apdu = max_apdu; + address_copy(&Address_Cache[i].address,src); + break; + } + } + } + + return; +} + bool address_get_by_index( unsigned index, uint32_t *device_id, diff --git a/bacnet-stack/address.h b/bacnet-stack/address.h index 5fda75b4..50e5391f 100644 --- a/bacnet-stack/address.h +++ b/bacnet-stack/address.h @@ -69,5 +69,15 @@ unsigned address_count(void); bool address_match( BACNET_ADDRESS *dest, BACNET_ADDRESS *src); + +bool address_bind_request( + uint32_t device_id, + unsigned *max_apdu, + BACNET_ADDRESS *src); + +void address_add_binding( + uint32_t device_id, + unsigned max_apdu, + BACNET_ADDRESS *src); #endif diff --git a/bacnet-stack/apdu.c b/bacnet-stack/apdu.c index 2b9b4cdc..100ce492 100644 --- a/bacnet-stack/apdu.c +++ b/bacnet-stack/apdu.c @@ -40,6 +40,7 @@ #include "bacdcode.h" #include "bacenum.h" #include "tsm.h" +#include "iam.h" // Confirmed Function Handlers // If they are not set, they are handled by a reject message @@ -66,7 +67,11 @@ void apdu_set_unrecognized_service_handler_handler( // Unconfirmed Function Handlers // If they are not set, they are not handled static unconfirmed_function -Unconfirmed_Function[MAX_BACNET_UNCONFIRMED_SERVICE]; +Unconfirmed_Function[MAX_BACNET_UNCONFIRMED_SERVICE] = +{ + iam_handler, + NULL +}; void apdu_set_unconfirmed_handler( BACNET_UNCONFIRMED_SERVICE service_choice, diff --git a/bacnet-stack/handlers.c b/bacnet-stack/handlers.c index 09814665..b3843f17 100644 --- a/bacnet-stack/handlers.c +++ b/bacnet-stack/handlers.c @@ -37,7 +37,6 @@ #include "ao.h" #include "rp.h" #include "wp.h" -#include "iam.h" #include "whois.h" #include "reject.h" #include "abort.h" @@ -95,43 +94,10 @@ void UnrecognizedServiceHandler( fprintf(stderr,"Failed to Send Reject (%s)!\n", strerror(errno)); } -// FIXME: if we handle multiple ports, then a port neutral version -// of this would be nice. Then it could be moved into iam.c void Send_IAm(void) { - int pdu_len = 0; - BACNET_ADDRESS dest; - int bytes_sent = 0; - - // I-Am is a global broadcast - datalink_get_broadcast_address(&dest); - - // encode the NPDU portion of the packet - pdu_len = npdu_encode_apdu( - &Tx_Buf[0], - &dest, - NULL, - false, // true for confirmed messages - MESSAGE_PRIORITY_NORMAL); - - // encode the APDU portion of the packet - pdu_len += iam_encode_apdu( - &Tx_Buf[pdu_len], - Device_Object_Instance_Number(), - MAX_APDU, - SEGMENTATION_NONE, - Device_Vendor_Identifier()); - - bytes_sent = datalink_send_pdu( - &dest, // destination address - &Tx_Buf[0], - pdu_len); // number of bytes of data - if (bytes_sent > 0) - fprintf(stderr,"Sent I-Am Request!\n"); - else - fprintf(stderr,"Failed to Send I-Am Request (%s)!\n", strerror(errno)); + iam_send(&Tx_Buf[0]); } - void Send_WhoIs(void) { int pdu_len = 0; @@ -253,34 +219,6 @@ void WhoIsHandler( return; } -void IAmHandler( - uint8_t *service_request, - uint16_t service_len, - BACNET_ADDRESS *src) -{ - int len = 0; - uint32_t device_id = 0; - unsigned max_apdu = 0; - int segmentation = 0; - uint16_t vendor_id = 0; - - (void)src; - (void)service_len; - len = iam_decode_service_request( - service_request, - &device_id, - &max_apdu, - &segmentation, - &vendor_id); - fprintf(stderr,"Received I-Am Request"); - if (len != -1) - fprintf(stderr," from %u!\n",device_id); - else - fprintf(stderr,"!\n"); - - return; -} - void ReadPropertyAckHandler( uint8_t *service_request, uint16_t service_len, diff --git a/bacnet-stack/handlers.h b/bacnet-stack/handlers.h index b6829d96..9fde8944 100644 --- a/bacnet-stack/handlers.h +++ b/bacnet-stack/handlers.h @@ -42,19 +42,14 @@ void UnrecognizedServiceHandler( BACNET_ADDRESS *dest, BACNET_CONFIRMED_SERVICE_DATA *service_data); -void Send_IAm(void); void Send_WhoIs(void); +void Send_IAm(void); void WhoIsHandler( uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS *src); -void IAmHandler( - uint8_t *service_request, - uint16_t service_len, - BACNET_ADDRESS *src); - void ReadPropertyAckHandler( uint8_t *service_request, uint16_t service_len, diff --git a/bacnet-stack/iam.c b/bacnet-stack/iam.c index 983c59b7..77bc3307 100755 --- a/bacnet-stack/iam.c +++ b/bacnet-stack/iam.c @@ -33,7 +33,12 @@ ####COPYRIGHTEND####*/ #include #include "bacenum.h" +#include "bacdef.h" +#include "npdu.h" +#include "datalink.h" +#include "device.h" #include "bacdcode.h" +#include "address.h" // encode I-Am service int iam_encode_apdu( @@ -161,6 +166,65 @@ int iam_decode_apdu( return apdu_len; } +int iam_send(uint8_t *buffer) +{ + int pdu_len = 0; + BACNET_ADDRESS dest; + int bytes_sent = 0; + + // I-Am is a global broadcast + datalink_get_broadcast_address(&dest); + + // encode the NPDU portion of the packet + pdu_len = npdu_encode_apdu( + &buffer[0], + &dest, + NULL, + false, // true for confirmed messages + MESSAGE_PRIORITY_NORMAL); + + // encode the APDU portion of the packet + pdu_len += iam_encode_apdu( + &buffer[pdu_len], + Device_Object_Instance_Number(), + MAX_APDU, + SEGMENTATION_NONE, + Device_Vendor_Identifier()); + + bytes_sent = datalink_send_pdu( + &dest, // destination address + &buffer[0], + pdu_len); // number of bytes of data + + return bytes_sent; +} + +void iam_handler( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src) +{ + int len = 0; + uint32_t device_id = 0; + unsigned max_apdu = 0; + int segmentation = 0; + uint16_t vendor_id = 0; + + (void)service_len; + len = iam_decode_service_request( + service_request, + &device_id, + &max_apdu, + &segmentation, + &vendor_id); + // only add address if requested to bind + address_add_binding(device_id, + max_apdu, + src); + + return; +} + #ifdef TEST #include #include diff --git a/bacnet-stack/iam.h b/bacnet-stack/iam.h index 04c8b552..6fefb534 100644 --- a/bacnet-stack/iam.h +++ b/bacnet-stack/iam.h @@ -57,6 +57,13 @@ int iam_decode_apdu( unsigned *pMax_apdu, int *pSegmentation, uint16_t *pVendor_id); + +void iam_handler( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src); + +int iam_send(uint8_t *buffer); #ifdef TEST void testIAm(Test * pTest); diff --git a/bacnet-stack/ports/rtos32/main.c b/bacnet-stack/ports/rtos32/main.c index a76b7c3b..9f7cfef3 100644 --- a/bacnet-stack/ports/rtos32/main.c +++ b/bacnet-stack/ports/rtos32/main.c @@ -87,9 +87,6 @@ static void Init_Service_Handlers(void) apdu_set_unconfirmed_handler( SERVICE_UNCONFIRMED_WHO_IS, WhoIsHandler); - apdu_set_unconfirmed_handler( - SERVICE_UNCONFIRMED_I_AM, - IAmHandler); // set the handler for all the services we don't implement // It is required to send the proper reject message... apdu_set_unrecognized_service_handler_handler( diff --git a/bacnet-stack/ports/rtos32/makefile.mak b/bacnet-stack/ports/rtos32/makefile.mak index 996ee2a6..777604da 100644 --- a/bacnet-stack/ports/rtos32/makefile.mak +++ b/bacnet-stack/ports/rtos32/makefile.mak @@ -40,6 +40,7 @@ SRCS = init.c main.c ethernet.c bip.c \ ..\..\device.c \ ..\..\ai.c \ ..\..\ao.c \ + ..\..\datalink.c \ ..\..\tsm.c \ ..\..\address.c \ ..\..\abort.c \