From 7664b744d9c7b614b6cf0d0fb05e09bfa11853b1 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Fri, 2 Apr 2021 14:12:49 -0500 Subject: [PATCH] Fix the gateway example routing and lookups. Thanks, Sam! (#163) Co-authored-by: Steve Karg --- apps/gateway/main.c | 117 +++++++++++--------- src/bacnet/basic/npdu/h_routed_npdu.c | 8 +- src/bacnet/basic/object/gateway/gw_device.c | 62 ++++++++--- src/bacnet/config.h | 2 +- 4 files changed, 117 insertions(+), 72 deletions(-) diff --git a/apps/gateway/main.c b/apps/gateway/main.c index 64c70804..aef22479 100644 --- a/apps/gateway/main.c +++ b/apps/gateway/main.c @@ -82,6 +82,9 @@ int DNET_list[2] = { /* current version of the BACnet stack */ static const char *BACnet_Version = BACNET_VERSION_TEXT; +/* routed devices - I-Am on startup */ +static unsigned Routed_Device_Index; + /** Initialize the Device Objects and each of the child Object instances. * @param first_object_instance Set the first (gateway) Device to this instance number, and subsequent devices to incremented values. @@ -107,6 +110,59 @@ static void Devices_Init(uint32_t first_object_instance) } } +/** Initialize the BACnet Device Addresses for each Device object. + * The gateway has already gotten the normal address (eg, PC's IP for BIP) and + * the remote devices get + * - For BIP, the IP address reversed, and 4th byte equal to index. + * (Eg, 11.22.33.44 for the gateway becomes 44.33.22.01 for the first remote + * device.) This is sure to be unique! The port number stays the same. + * - For MS/TP, [Steve inserts a good idea here] + */ +static void Initialize_Device_Addresses(void) +{ + int i = 0; /* First entry is Gateway Device */ + uint32_t virtual_mac = 0; + BACNET_ADDRESS virtual_address = {0}; + DEVICE_OBJECT_DATA *pDev = NULL; + /* Setup info for the main gateway device first */ + pDev = Get_Routed_Device_Object(i); + + /* we can't use datalink_get_my_address() since it is + mapped to routed_get_my_address() in this app + to get the parent device address */ +#if defined(BACDL_BIP) + bip_get_my_address(&virtual_address); +#elif defined(BACDL_MSTP) + dlmstp_get_my_address(&virtual_address); +#elif defined(BACDL_ARCNET) + arcnet_get_my_address(&virtual_address); +#elif defined(BACDL_ETHERNET) + ethernet_get_my_address(&virtual_address); +#elif defined(BACDL_BIP6) + bip6_get_my_address(&virtual_address); +#else +#error "No support for this Data Link Layer type " +#endif + bacnet_address_copy(&pDev->bacDevAddr, &virtual_address); + /* broadcast an I-Am on startup */ + Send_I_Am(&Handler_Transmit_Buffer[0]); + + for (i = 1; i < MAX_NUM_DEVICES; i++) { + pDev = Get_Routed_Device_Object(i); + if (pDev == NULL) { + continue; + } + /* start with the router address */ + bacnet_address_copy(&pDev->bacDevAddr, &virtual_address); + /* add the network number to each gateway device */ + pDev->bacDevAddr.net = VIRTUAL_DNET; + /* use a virtual MAC for each gateway device */ + virtual_mac = pDev->bacObj.Object_Instance_Number; + encode_unsigned24(&pDev->bacDevAddr.adr[0], virtual_mac); + pDev->bacDevAddr.len = 3; + } +} + /** Initialize the handlers we will utilize. * @see Device_Init, apdu_set_unconfirmed_handler, apdu_set_confirmed_handler */ @@ -158,54 +214,6 @@ static void Init_Service_Handlers(uint32_t first_object_instance) handler_device_communication_control); } -/** Initialize the BACnet Device Addresses for each Device object. - * The gateway has already gotten the normal address (eg, PC's IP for BIP) and - * the remote devices get - * - For BIP, the IP address reversed, and 4th byte equal to index. - * (Eg, 11.22.33.44 for the gateway becomes 44.33.22.01 for the first remote - * device.) This is sure to be unique! The port number stays the same. - * - For MS/TP, [Steve inserts a good idea here] - */ -static void Initialize_Device_Addresses() -{ - int i = 0; /* First entry is Gateway Device */ - uint32_t virtual_mac = 0; - DEVICE_OBJECT_DATA *pDev = NULL; - /* Setup info for the main gateway device first */ - pDev = Get_Routed_Device_Object(i); - - /* we can't use datalink_get_my_address() since it is - mapped to routed_get_my_address() in this app - to get the parent device address */ -#if defined(BACDL_BIP) - bip_get_my_address(&pDev->bacDevAddr); -#elif defined(BACDL_MSTP) - dlmstp_get_my_address(&pDev->bacDevAddr); -#elif defined(BACDL_ARCNET) - arcnet_get_my_address(&pDev->bacDevAddr); -#elif defined(BACDL_ETHERNET) - ethernet_get_my_address(&pDev->bacDevAddr); -#elif defined(BACDL_BIP6) - bip6_get_my_address&pDev->bacDevAddr); -#else -#error "No support for this Data Link Layer type " -#endif - /* broadcast an I-Am on startup */ - Send_I_Am(&Handler_Transmit_Buffer[0]); - - for (i = 1; i < MAX_NUM_DEVICES; i++) { - pDev = Get_Routed_Device_Object(i); - if (pDev == NULL) { - continue; - } - virtual_mac = pDev->bacObj.Object_Instance_Number; - encode_unsigned24(&pDev->bacDevAddr.adr[0], virtual_mac); - pDev->bacDevAddr.len = 3; - /* broadcast an I-Am for each routed Device now */ - Send_I_Am(&Handler_Transmit_Buffer[0]); - } -} - /** Main function of server demo. * * @see Device_Set_Object_Instance_Number, dlenv_init, Send_I_Am, @@ -248,8 +256,9 @@ int main(int argc, char *argv[]) printf("BACnet Router Demo\n" "BACnet Stack Version %s\n" "BACnet Device ID: %u\n" - "Max APDU: %d\n", - BACnet_Version, first_object_instance, MAX_APDU); + "Max APDU: %d\n" + "Max Devices: %d\n", + BACnet_Version, first_object_instance, MAX_APDU, MAX_NUM_DEVICES); Init_Service_Handlers(first_object_instance); dlenv_init(); atexit(datalink_cleanup); @@ -293,8 +302,12 @@ int main(int argc, char *argv[]) } handler_cov_task(); /* output */ - - /* blink LEDs, Turn on or off outputs, etc */ + if (Routed_Device_Index < MAX_NUM_DEVICES) { + Routed_Device_Index++; + Get_Routed_Device_Object(Routed_Device_Index); + /* broadcast an I-Am for each routed Device now */ + Send_I_Am(&Handler_Transmit_Buffer[0]); + } } /* Dummy return */ return 0; diff --git a/src/bacnet/basic/npdu/h_routed_npdu.c b/src/bacnet/basic/npdu/h_routed_npdu.c index bcff248d..af185341 100644 --- a/src/bacnet/basic/npdu/h_routed_npdu.c +++ b/src/bacnet/basic/npdu/h_routed_npdu.c @@ -206,6 +206,7 @@ static void routed_apdu_handler(BACNET_ADDRESS *src, /* If wasn't unicast to us, must have been one of the bcast types. * Drop it. */ if (bvlc_get_function_code() != BVLC_ORIGINAL_UNICAST_NPDU) { + debug_printf("NPDU: not unicast - dropped!\n"); return; } #endif @@ -216,7 +217,10 @@ static void routed_apdu_handler(BACNET_ADDRESS *src, if (dest->len > 0) { Send_Reject_Message_To_Network( src, NETWORK_REJECT_NO_ROUTE, dest->net); - } /* else, silently drop it */ + } else { + /* silently drop it */ + debug_printf("NPDU: broadcast - dropped!\n"); + } return; } @@ -229,6 +233,7 @@ static void routed_apdu_handler(BACNET_ADDRESS *src, } if (!bGotOne) { /* Just silently drop this packet. */ + debug_printf("NPDU: dest not found - dropped!\n"); } } @@ -278,6 +283,7 @@ void routing_npdu_handler( network_control_handler(src, DNET_list, &npdu_data, &pdu[apdu_offset], (uint16_t)(pdu_len - apdu_offset)); } else { + debug_printf("NPDU: message for our router? Discarded!\n"); /* The DNET is set, but we don't support downstream routers, * so we just silently drop this network layer message, * since only routers can handle it (even if for our DNET) */ diff --git a/src/bacnet/basic/object/gateway/gw_device.c b/src/bacnet/basic/object/gateway/gw_device.c index ebb3f557..e7b4d0bd 100644 --- a/src/bacnet/basic/object/gateway/gw_device.c +++ b/src/bacnet/basic/object/gateway/gw_device.c @@ -220,24 +220,24 @@ void routed_get_my_address(BACNET_ADDRESS *my_address) * Else False if no match or invalid idx is given. */ bool Routed_Device_Address_Lookup( - int idx, uint8_t address_len, uint8_t *mac_adress) + int idx, uint8_t dlen, uint8_t *dadr) { bool result = false; DEVICE_OBJECT_DATA *pDev = &Devices[idx]; int i; if ((idx >= 0) && (idx < MAX_NUM_DEVICES)) { - if (address_len == 0) { + if (dlen == 0) { /* Automatic match */ iCurrent_Device_Idx = idx; result = true; - } else if (mac_adress != NULL) { - for (i = 0; i < address_len; i++) { - if (pDev->bacDevAddr.mac[i] != mac_adress[i]) { + } else if (dadr != NULL) { + for (i = 0; i < dlen; i++) { + if (pDev->bacDevAddr.adr[i] != dadr[i]) { break; } } - if (i == address_len) { /* Success! */ + if (i == dlen) { /* Success! */ iCurrent_Device_Idx = idx; result = true; } @@ -370,25 +370,51 @@ uint32_t Routed_Device_Index_To_Instance(unsigned index) return Devices[iCurrent_Device_Idx].bacObj.Object_Instance_Number; } -/** See if the requested Object instance matches that for the currently - * indexed Device Object. - * iCurrent_Device_Idx must have been set to point to this Device Object - * before this function is called. - * @param object_id [in] Object ID of the desired Device object. - * If the wildcard value (BACNET_MAX_INSTANCE), always - * matches. - * @return True if Object ID matches the present Device, else False. +/** + * For a given object instance-number, determines a 1..N-1 index + * of Device objects where N is MAX_NUM_DEVICES + * + * @param object_instance - object-instance number of the object + * @return index for the given instance-number, or 0 if not valid. + */ +static uint32_t Routed_Device_Instance_To_Index( + uint32_t Instance_Number) +{ + int i; + + + for ( i=0; i < MAX_NUM_DEVICES; i++) { + if (Devices[i].bacObj.Object_Instance_Number == Instance_Number) + { + /* Found Instance, so return the Device Index Number */ + return i; + } + } + + /* We did not find instance... so simply return an Index of 0 + All gateways will have at least a single root Device Object */ + return 0; + +} + +/** + * Determines if a given Device instance is valid + * + * @param object_id - object-instance number of the object + * @return true if the instance is valid, and false if not */ bool Routed_Device_Valid_Object_Instance_Number(uint32_t object_id) { - bool bResult = false; - DEVICE_OBJECT_DATA *pDev = &Devices[iCurrent_Device_Idx]; + bool valid = false; + DEVICE_OBJECT_DATA *pDev = NULL; + iCurrent_Device_Idx = Routed_Device_Instance_To_Index(object_id); + pDev = &Devices[iCurrent_Device_Idx]; if (pDev->bacObj.Object_Instance_Number == object_id) { - bResult = true; + valid = true; } - return bResult; + return valid; } bool Routed_Device_Name( diff --git a/src/bacnet/config.h b/src/bacnet/config.h index f4e68e24..0946dadc 100644 --- a/src/bacnet/config.h +++ b/src/bacnet/config.h @@ -62,7 +62,7 @@ /* Enable the Gateway (Routing) functionality here, if desired. */ #if !defined(MAX_NUM_DEVICES) #ifdef BAC_ROUTING -#define MAX_NUM_DEVICES 3 /* Eg, Gateway + two remote devices */ +#define MAX_NUM_DEVICES 32 /* Eg, Gateway + 31 remote devices */ #else #define MAX_NUM_DEVICES 1 /* Just the one normal BACnet Device Object */ #endif