From 862d6622d7fdd21c0d054e567c0b3b363af2e345 Mon Sep 17 00:00:00 2001 From: skarg Date: Sat, 2 Aug 2014 00:03:51 +0000 Subject: [PATCH] Added optional MAC, DNET, and DADR command line options for the TimeSync demo application. --- bacnet-stack/demo/timesync/main.c | 207 ++++++++++++++++++++++++++---- 1 file changed, 179 insertions(+), 28 deletions(-) diff --git a/bacnet-stack/demo/timesync/main.c b/bacnet-stack/demo/timesync/main.c index 7d58db03..4d33f67e 100644 --- a/bacnet-stack/demo/timesync/main.c +++ b/bacnet-stack/demo/timesync/main.c @@ -28,6 +28,7 @@ #include #include #include +#include #include /* for time */ #include #include "bactext.h" @@ -39,6 +40,7 @@ #include "net.h" #include "datalink.h" #include "timesync.h" +#include "version.h" /* some demo stuff needed */ #include "filename.h" #include "handlers.h" @@ -48,13 +50,7 @@ /* buffer used for receive */ static uint8_t Rx_Buf[MAX_MPDU] = { 0 }; - -/* global variables used in this file */ -#if 0 -static int32_t Target_Object_Instance_Min = 0; -static int32_t Target_Object_Instance_Max = BACNET_MAX_INSTANCE; -#endif - +/* error flag */ static bool Error_Detected = false; void MyAbortHandler( @@ -67,7 +63,7 @@ void MyAbortHandler( (void) src; (void) invoke_id; (void) server; - printf("BACnet Abort: %s\r\n", bactext_abort_reason_name(abort_reason)); + printf("BACnet Abort: %s\n", bactext_abort_reason_name(abort_reason)); Error_Detected = true; } @@ -79,7 +75,7 @@ void MyRejectHandler( /* FIXME: verify src and invoke id */ (void) src; (void) invoke_id; - printf("BACnet Reject: %s\r\n", bactext_reject_reason_name(reject_reason)); + printf("BACnet Reject: %s\n", bactext_reject_reason_name(reject_reason)); Error_Detected = true; } @@ -107,6 +103,99 @@ 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); +} + +static void print_help(char *filename) +{ + printf("Send BACnet TimeSynchronization request.\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" + "\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" + "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); +#if 0 + "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" + "time format: hour:minute:second.hundredths (e.g. 23:59:59.12)\n" + "hour: 0-23\n" "minute: 0-59\n" "second: 0-59\n" + "hundredths: 0-99\n" "\n" + "Optional device-instance sends a unicast time sync.\n", + filename); +#endif +} + int main( int argc, char *argv[]) @@ -124,26 +213,88 @@ 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; + bool global_broadcast = true; - /* FIXME: we could send directed time sync, and how do we send UTC? */ -#if 0 - if (argc < 2) { - printf("Usage: %s date time [device-instance]\r\n" - "Send BACnet TimeSynchronization request to all devices.\r\n" - "date format: year/month/day:dayofweek (e.g. 2006/4/1:6)\r\n" - "year: AD, such as 2006\r\n" "month: 1=January, 12=December\r\n" - "day: 1-31\r\n" "dayofweek: 1=Monday, 7=Sunday\r\n" "\r\n" - "time format: hour:minute:second.hundredths (e.g. 23:59:59.12)\r\n" - "hour: 0-23\r\n" "minute: 0-59\r\n" "second: 0-59\r\n" - "hundredths: 0-99\r\n" "\r\n" - "Optional device-instance sends a unicast time sync.\r\n", - filename_remove_path(argv[0])); - return 0; + /* decode any command line parameters */ + 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])); + 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" + "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"); + return 0; + } + if (strcmp(argv[argi], "--mac") == 0) { + if (++argi < argc) { + mac_len = address_from_ascii(&mac[0], argv[argi]); + if (mac_len) { + global_broadcast = false; + } + } + } + if (strcmp(argv[argi], "--dnet") == 0) { + if (++argi < argc) { + dnet = strtol(argv[argi], NULL, 0); + if ((dnet >= 0) && (dnet <= BACNET_BROADCAST_NETWORK)) { + global_broadcast = false; + } + } + } + if (strcmp(argv[argi], "--dadr") == 0) { + if (++argi < argc) { + len = address_from_ascii(&adr[0], argv[argi]); + if (len) { + global_broadcast = false; + } + } + } + } + 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 ((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; + dest.len = 0; + if ((dnet >= 0) && (dnet <= BACNET_BROADCAST_NETWORK)) { + dest.net = dnet; + } else { + dest.net = 0; + } + } else { + if ((dnet >= 0) && (dnet <= BACNET_BROADCAST_NETWORK)) { + dest.net = dnet; + } else { + dest.net = BACNET_BROADCAST_NETWORK; + } + dest.mac_len = 0; + dest.len = 0; + } } -#else - (void) argc; - (void) argv; -#endif /* setup my info */ Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); Init_Service_Handlers(); @@ -163,7 +314,7 @@ int main( btime.min = my_time->tm_min; btime.sec = my_time->tm_sec; btime.hundredths = 0; - Send_TimeSync(&bdate, &btime); + Send_TimeSync_Remote(&dest, &bdate, &btime); /* loop forever - not necessary for time sync, but we can watch */ for (;;) { /* increment timer - exit if timed out */