Fix the gateway example routing and lookups. Thanks, Sam! (#163)
Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
+65
-52
@@ -82,6 +82,9 @@ int DNET_list[2] = {
|
|||||||
/* current version of the BACnet stack */
|
/* current version of the BACnet stack */
|
||||||
static const char *BACnet_Version = BACNET_VERSION_TEXT;
|
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.
|
/** Initialize the Device Objects and each of the child Object instances.
|
||||||
* @param first_object_instance Set the first (gateway) Device to this
|
* @param first_object_instance Set the first (gateway) Device to this
|
||||||
instance number, and subsequent devices to incremented values.
|
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.
|
/** Initialize the handlers we will utilize.
|
||||||
* @see Device_Init, apdu_set_unconfirmed_handler, apdu_set_confirmed_handler
|
* @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);
|
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.
|
/** Main function of server demo.
|
||||||
*
|
*
|
||||||
* @see Device_Set_Object_Instance_Number, dlenv_init, Send_I_Am,
|
* @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"
|
printf("BACnet Router Demo\n"
|
||||||
"BACnet Stack Version %s\n"
|
"BACnet Stack Version %s\n"
|
||||||
"BACnet Device ID: %u\n"
|
"BACnet Device ID: %u\n"
|
||||||
"Max APDU: %d\n",
|
"Max APDU: %d\n"
|
||||||
BACnet_Version, first_object_instance, MAX_APDU);
|
"Max Devices: %d\n",
|
||||||
|
BACnet_Version, first_object_instance, MAX_APDU, MAX_NUM_DEVICES);
|
||||||
Init_Service_Handlers(first_object_instance);
|
Init_Service_Handlers(first_object_instance);
|
||||||
dlenv_init();
|
dlenv_init();
|
||||||
atexit(datalink_cleanup);
|
atexit(datalink_cleanup);
|
||||||
@@ -293,8 +302,12 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
handler_cov_task();
|
handler_cov_task();
|
||||||
/* output */
|
/* output */
|
||||||
|
if (Routed_Device_Index < MAX_NUM_DEVICES) {
|
||||||
/* blink LEDs, Turn on or off outputs, etc */
|
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 */
|
/* Dummy return */
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -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.
|
/* If wasn't unicast to us, must have been one of the bcast types.
|
||||||
* Drop it. */
|
* Drop it. */
|
||||||
if (bvlc_get_function_code() != BVLC_ORIGINAL_UNICAST_NPDU) {
|
if (bvlc_get_function_code() != BVLC_ORIGINAL_UNICAST_NPDU) {
|
||||||
|
debug_printf("NPDU: not unicast - dropped!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -216,7 +217,10 @@ static void routed_apdu_handler(BACNET_ADDRESS *src,
|
|||||||
if (dest->len > 0) {
|
if (dest->len > 0) {
|
||||||
Send_Reject_Message_To_Network(
|
Send_Reject_Message_To_Network(
|
||||||
src, NETWORK_REJECT_NO_ROUTE, dest->net);
|
src, NETWORK_REJECT_NO_ROUTE, dest->net);
|
||||||
} /* else, silently drop it */
|
} else {
|
||||||
|
/* silently drop it */
|
||||||
|
debug_printf("NPDU: broadcast - dropped!\n");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,6 +233,7 @@ static void routed_apdu_handler(BACNET_ADDRESS *src,
|
|||||||
}
|
}
|
||||||
if (!bGotOne) {
|
if (!bGotOne) {
|
||||||
/* Just silently drop this packet. */
|
/* 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,
|
network_control_handler(src, DNET_list, &npdu_data,
|
||||||
&pdu[apdu_offset], (uint16_t)(pdu_len - apdu_offset));
|
&pdu[apdu_offset], (uint16_t)(pdu_len - apdu_offset));
|
||||||
} else {
|
} else {
|
||||||
|
debug_printf("NPDU: message for our router? Discarded!\n");
|
||||||
/* The DNET is set, but we don't support downstream routers,
|
/* The DNET is set, but we don't support downstream routers,
|
||||||
* so we just silently drop this network layer message,
|
* so we just silently drop this network layer message,
|
||||||
* since only routers can handle it (even if for our DNET) */
|
* since only routers can handle it (even if for our DNET) */
|
||||||
|
|||||||
@@ -220,24 +220,24 @@ void routed_get_my_address(BACNET_ADDRESS *my_address)
|
|||||||
* Else False if no match or invalid idx is given.
|
* Else False if no match or invalid idx is given.
|
||||||
*/
|
*/
|
||||||
bool Routed_Device_Address_Lookup(
|
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;
|
bool result = false;
|
||||||
DEVICE_OBJECT_DATA *pDev = &Devices[idx];
|
DEVICE_OBJECT_DATA *pDev = &Devices[idx];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if ((idx >= 0) && (idx < MAX_NUM_DEVICES)) {
|
if ((idx >= 0) && (idx < MAX_NUM_DEVICES)) {
|
||||||
if (address_len == 0) {
|
if (dlen == 0) {
|
||||||
/* Automatic match */
|
/* Automatic match */
|
||||||
iCurrent_Device_Idx = idx;
|
iCurrent_Device_Idx = idx;
|
||||||
result = true;
|
result = true;
|
||||||
} else if (mac_adress != NULL) {
|
} else if (dadr != NULL) {
|
||||||
for (i = 0; i < address_len; i++) {
|
for (i = 0; i < dlen; i++) {
|
||||||
if (pDev->bacDevAddr.mac[i] != mac_adress[i]) {
|
if (pDev->bacDevAddr.adr[i] != dadr[i]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == address_len) { /* Success! */
|
if (i == dlen) { /* Success! */
|
||||||
iCurrent_Device_Idx = idx;
|
iCurrent_Device_Idx = idx;
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
@@ -370,25 +370,51 @@ uint32_t Routed_Device_Index_To_Instance(unsigned index)
|
|||||||
return Devices[iCurrent_Device_Idx].bacObj.Object_Instance_Number;
|
return Devices[iCurrent_Device_Idx].bacObj.Object_Instance_Number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** See if the requested Object instance matches that for the currently
|
/**
|
||||||
* indexed Device Object.
|
* For a given object instance-number, determines a 1..N-1 index
|
||||||
* iCurrent_Device_Idx must have been set to point to this Device Object
|
* of Device objects where N is MAX_NUM_DEVICES
|
||||||
* before this function is called.
|
*
|
||||||
* @param object_id [in] Object ID of the desired Device object.
|
* @param object_instance - object-instance number of the object
|
||||||
* If the wildcard value (BACNET_MAX_INSTANCE), always
|
* @return index for the given instance-number, or 0 if not valid.
|
||||||
* matches.
|
*/
|
||||||
* @return True if Object ID matches the present Device, else False.
|
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 Routed_Device_Valid_Object_Instance_Number(uint32_t object_id)
|
||||||
{
|
{
|
||||||
bool bResult = false;
|
bool valid = false;
|
||||||
DEVICE_OBJECT_DATA *pDev = &Devices[iCurrent_Device_Idx];
|
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) {
|
if (pDev->bacObj.Object_Instance_Number == object_id) {
|
||||||
bResult = true;
|
valid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bResult;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Routed_Device_Name(
|
bool Routed_Device_Name(
|
||||||
|
|||||||
+1
-1
@@ -62,7 +62,7 @@
|
|||||||
/* Enable the Gateway (Routing) functionality here, if desired. */
|
/* Enable the Gateway (Routing) functionality here, if desired. */
|
||||||
#if !defined(MAX_NUM_DEVICES)
|
#if !defined(MAX_NUM_DEVICES)
|
||||||
#ifdef BAC_ROUTING
|
#ifdef BAC_ROUTING
|
||||||
#define MAX_NUM_DEVICES 3 /* Eg, Gateway + two remote devices */
|
#define MAX_NUM_DEVICES 32 /* Eg, Gateway + 31 remote devices */
|
||||||
#else
|
#else
|
||||||
#define MAX_NUM_DEVICES 1 /* Just the one normal BACnet Device Object */
|
#define MAX_NUM_DEVICES 1 /* Just the one normal BACnet Device Object */
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user