diff --git a/bacnet-stack/demo/timesync/main.c b/bacnet-stack/demo/timesync/main.c index 4d33f67e..1f7d5209 100644 --- a/bacnet-stack/demo/timesync/main.c +++ b/bacnet-stack/demo/timesync/main.c @@ -31,6 +31,7 @@ #include #include /* for time */ #include +#include "address.h" #include "bactext.h" #include "config.h" #include "bacdef.h" @@ -103,88 +104,42 @@ static void Init_Service_Handlers( apdu_set_reject_handler(MyRejectHandler); } -/** Parse a string for a bacnet-address - * - * @param mac [out] BACNET Address MAC at least 6 octets - * @param arg [in] nul terminated string to parse - * @return length of address parsed in bytes - */ -int address_from_ascii( - uint8_t *mac, - char *arg) -{ - unsigned a[6] = {0}, p = 0; - uint16_t port = 0; - int c, len = 0; - - c = sscanf(arg, "%3u.%3u.%3u.%3u:%5u", &a[0],&a[1],&a[2],&a[3],&p); - if ((c == 4) || (c == 5)) { - mac[0] = a[0]; - mac[1] = a[1]; - mac[2] = a[2]; - mac[3] = a[3]; - if (c == 4) { - port = htons((uint16_t) 0xBAC0); - } else { - port = htons((uint16_t) p); - } - memcpy(&mac[4], &port, 2); - len = 6; - } else { - c = sscanf(arg, "%2x:%2x:%2x:%2x:%2x:%2x", - &a[0],&a[1],&a[2],&a[3],&a[4],&a[5]); - if (c == 6) { - mac[0] = a[0]; - mac[1] = a[1]; - mac[2] = a[2]; - mac[3] = a[3]; - mac[4] = a[4]; - mac[5] = a[5]; - len = 6; - } else if (c == 1) { - a[0] = (unsigned)strtol(arg, NULL, 0); - if (a[0] <= 255) { - mac[0] = a[0]; - len = 1; - } - } - } - - return len; -} - static void print_usage(char *filename) { - printf("Usage: %s [--dnet][--dadr][--mac][--version][--help]\n", filename); + printf("Usage: %s [--dnet][--dadr][--mac]\n", filename); + printf(" [--version][--help]\n"); } static void print_help(char *filename) { printf("Send BACnet TimeSynchronization request.\n" + "\n" + "--mac A\n" + "BACnet mac address." + "Valid ranges are from 0 to 255\n" + "or an IP string with optional port number like 10.1.2.3:47808\n" + "or an Ethernet MAC in hex like 00:21:70:7e:32:bb\n" "\n" "--dnet N\n" - " BACnet network number N for directed requests." - " Valid range is from 0 to 65535\n" - " where 0 is the local connection\n" - " and 65535 is network broadcast.\n" + "BACnet network number N for directed requests.\n" + "Valid range is from 0 to 65535 where 0 is the local connection\n" + "and 65535 is network broadcast.\n" "\n" "--dadr A\n" - " BACnet mac address." - " Valid ranges are from 0 to 255\n" - " or an IP string with optional port number like 10.1.2.3:47808\n" - " or an Ethernet MAC in hex like 00:21:70:7e:32:bb\n" - "\n" - "Examples:\n" + "BACnet mac address on the destination BACnet network number.\n" + "Valid ranges are from 0 to 255\n" + "or an IP string with optional port number like 10.1.2.3:47808\n" + "or an Ethernet MAC in hex like 00:21:70:7e:32:bb\n" + "\n"); + printf("Examples:\n" "Send a TimeSynchronization request to DNET 123:\n" - "%s --dnet 123\n" - "Send a TimeSynchronization request to MAC 10.0.0.1 DNET 123 DADR 5:\n" - "%s --mac 10.0.0.1 --dnet 123 --dadr 5\n" - "Send a TimeSynchronization request to MAC 10.1.2.3:47808:\n" - "%s --mac 10.1.2.3:47808\n", - filename, - filename, - filename); + "%s --dnet 123\n", filename); + printf("Send a TimeSynchronization request to MAC 10.0.0.1 DNET 123 DADR 5:\n" + "%s --mac 10.0.0.1 --dnet 123 --dadr 5\n", filename); + printf("Send a TimeSynchronization request to MAC 10.1.2.3:47808:\n" + "%s --mac 10.1.2.3:47808\n", filename); #if 0 + /* FIXME: it would be nice to be able to send arbitrary time values */ "date format: year/month/day:dayofweek (e.g. 2006/4/1:6)\n" "year: AD, such as 2006\n" "month: 1=January, 12=December\n" "day: 1-31\n" "dayofweek: 1=Monday, 7=Sunday\n" "\n" @@ -213,26 +168,25 @@ int main( struct tm *my_time; BACNET_DATE bdate; BACNET_TIME btime; - BACNET_ADDRESS dest; long dnet = -1; - uint8_t mac[MAX_MAC_LEN]; - uint8_t adr[MAX_MAC_LEN]; - int argi = 0; - int len = 0, mac_len = 0; + BACNET_MAC_ADDRESS mac = { 0 }; + BACNET_MAC_ADDRESS adr = { 0 }; + BACNET_ADDRESS dest = { 0 }; bool global_broadcast = true; + int argi = 0; + char *filename = NULL; /* decode any command line parameters */ + filename = filename_remove_path(argv[0]); for (argi = 1; argi < argc; argi++) { if (strcmp(argv[argi], "--help") == 0) { - print_usage(filename_remove_path(argv[0])); - print_help(filename_remove_path(argv[0])); + print_usage(filename); + print_help(filename); return 0; } if (strcmp(argv[argi], "--version") == 0) { - printf("%s %s\n", - filename_remove_path(argv[0]), - BACNET_VERSION_TEXT); - printf("Copyright (C) 2014 by Steve Karg\n" + printf("%s %s\n", filename, BACNET_VERSION_TEXT); + printf("Copyright (C) 2014 by Steve Karg and others.\n" "This is free software; see the source for copying conditions.\n" "There is NO warranty; not even for MERCHANTABILITY or\n" "FITNESS FOR A PARTICULAR PURPOSE.\n"); @@ -240,8 +194,7 @@ int main( } if (strcmp(argv[argi], "--mac") == 0) { if (++argi < argc) { - mac_len = address_from_ascii(&mac[0], argv[argi]); - if (mac_len) { + if (address_mac_from_ascii(&mac, argv[argi])) { global_broadcast = false; } } @@ -256,8 +209,7 @@ int main( } if (strcmp(argv[argi], "--dadr") == 0) { if (++argi < argc) { - len = address_from_ascii(&adr[0], argv[argi]); - if (len) { + if (address_mac_from_ascii(&adr, argv[argi])) { global_broadcast = false; } } @@ -266,19 +218,19 @@ int main( if (global_broadcast) { datalink_get_broadcast_address(&dest); } else { - if (len && mac_len) { - memcpy(&dest.mac[0], &mac[0], mac_len); - dest.mac_len = mac_len; - memcpy(&dest.adr[0], &adr[0], len); - dest.len = len; + if (adr.len && mac.len) { + memcpy(&dest.mac[0], &mac.adr[0], mac.len); + dest.mac_len = mac.len; + memcpy(&dest.adr[0], &adr.adr[0], adr.len); + dest.len = adr.len; if ((dnet >= 0) && (dnet <= BACNET_BROADCAST_NETWORK)) { dest.net = dnet; } else { dest.net = BACNET_BROADCAST_NETWORK; } - } else if (mac_len) { - memcpy(&dest.mac[0], &mac[0], mac_len); - dest.mac_len = mac_len; + } else if (mac.len) { + memcpy(&dest.mac[0], &mac.adr[0], mac.len); + dest.mac_len = mac.len; dest.len = 0; if ((dnet >= 0) && (dnet <= BACNET_BROADCAST_NETWORK)) { dest.net = dnet; diff --git a/bacnet-stack/include/address.h b/bacnet-stack/include/address.h index 1f19c34d..af97fe3b 100644 --- a/bacnet-stack/include/address.h +++ b/bacnet-stack/include/address.h @@ -96,6 +96,15 @@ extern "C" { void address_cache_timer( uint16_t uSeconds); + void address_mac_init( + BACNET_MAC_ADDRESS *mac, + uint8_t *adr, + uint8_t len); + + bool address_mac_from_ascii( + BACNET_MAC_ADDRESS *mac, + char *arg); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bacnet-stack/include/bacdef.h b/bacnet-stack/include/bacdef.h index 6574d957..408c9b6a 100644 --- a/bacnet-stack/include/bacdef.h +++ b/bacnet-stack/include/bacdef.h @@ -134,6 +134,12 @@ struct BACnet_Device_Address { uint8_t adr[MAX_MAC_LEN]; /* hwaddr (MAC) address */ }; typedef struct BACnet_Device_Address BACNET_ADDRESS; +/* define a MAC address for manipulation */ +struct BACnet_MAC_Address { + uint8_t len; /* length of MAC address */ + uint8_t adr[MAX_MAC_LEN]; +}; +typedef struct BACnet_MAC_Address BACNET_MAC_ADDRESS; /* note: with microprocessors having lots more code space than memory, it might be better to have a packed encoding with a library to diff --git a/bacnet-stack/src/address.c b/bacnet-stack/src/address.c index dfca1222..f564e6ba 100644 --- a/bacnet-stack/src/address.c +++ b/bacnet-stack/src/address.c @@ -189,6 +189,86 @@ static struct Address_Cache_Entry *address_remove_oldest( return (pCandidate); } +/** Initialize a BACNET_MAC_ADDRESS + * + * @param mac [out] BACNET_MAC_ADDRESS structure + * @param adr [in] address to initialize, null if empty + * @param len [in] length of address in bytes + */ +void address_mac_init( + BACNET_MAC_ADDRESS *mac, + uint8_t *adr, + uint8_t len) +{ + uint8_t i = 0; + + if (mac && adr && (len <= sizeof(mac->adr))) { + for (i = 0; i < len; i++) { + mac->adr[i] = adr[i]; + } + mac->len = len; + } else { + mac->len = 0; + } +} + +/** Parse an ASCII string for a bacnet-address + * + * @param mac [out] BACNET_MAC_ADDRESS structure to store the results + * @param arg [in] nul terminated ASCII string to parse + * + * @return true if the address was parsed + */ +bool address_mac_from_ascii( + BACNET_MAC_ADDRESS *mac, + char *arg) +{ + unsigned a[6] = {0}, p = 0; + uint16_t port = 0; + int c; + bool status = false; + + if (!(mac && arg)) { + return false; + } + c = sscanf(arg, "%3u.%3u.%3u.%3u:%5u", &a[0],&a[1],&a[2],&a[3],&p); + if ((c == 4) || (c == 5)) { + mac->adr[0] = a[0]; + mac->adr[1] = a[1]; + mac->adr[2] = a[2]; + mac->adr[3] = a[3]; + if (c == 4) { + port = 0xBAC0; + } else { + port = (uint16_t)p; + } + encode_unsigned16(&mac->adr[4], port); + mac->len = 6; + status = true; + } else { + c = sscanf(arg, "%2x:%2x:%2x:%2x:%2x:%2x", + &a[0],&a[1],&a[2],&a[3],&a[4],&a[5]); + if (c == 6) { + mac->adr[0] = a[0]; + mac->adr[1] = a[1]; + mac->adr[2] = a[2]; + mac->adr[3] = a[3]; + mac->adr[4] = a[4]; + mac->adr[5] = a[5]; + mac->len = 6; + status = true; + } else if (c == 1) { + a[0] = (unsigned)strtol(arg, NULL, 0); + if (a[0] <= 255) { + mac->adr[0] = a[0]; + mac->len = 1; + status = true; + } + } + } + + return status; +} /* File format: DeviceID MAC SNET SADR MAX-APDU @@ -206,11 +286,10 @@ static void address_file_init( long device_id = 0; unsigned snet = 0; unsigned max_apdu = 0; - unsigned mac[MAX_MAC_LEN] = { 0 }; - int count = 0; char mac_string[80] = { "" }, sadr_string[80] = { ""}; BACNET_ADDRESS src = { 0 }; + BACNET_MAC_ADDRESS mac = { 0 }; int index = 0; pFile = fopen(pFilename, "r"); @@ -221,22 +300,19 @@ static void address_file_init( if (sscanf(line, "%7ld %79s %5u %79s %4u", &device_id, &mac_string[0], &snet, &sadr_string[0], &max_apdu) == 5) { - count = - sscanf(mac_string, "%2x:%2x:%2x:%2x:%2x:%2x", &mac[0], - &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); - src.mac_len = (uint8_t) count; - for (index = 0; index < MAX_MAC_LEN; index++) { - src.mac[index] = (uint8_t) mac[index]; + if (address_mac_from_ascii(&mac, mac_string)) { + src.mac_len = mac.len; + for (index = 0; index < MAX_MAC_LEN; index++) { + src.mac[index] = mac.adr[index]; + } } src.net = (uint16_t) snet; if (snet) { - count = - sscanf(sadr_string, "%2x:%2x:%2x:%2x:%2x:%2x", - &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], - &mac[5]); - src.len = (uint8_t) count; - for (index = 0; index < MAX_MAC_LEN; index++) { - src.adr[index] = (uint8_t) mac[index]; + if (address_mac_from_ascii(&mac, sadr_string)) { + src.len = mac.len; + for (index = 0; index < MAX_MAC_LEN; index++) { + src.adr[index] = mac.adr[index]; + } } } else { src.len = 0;