Added optional MAC, DNET, and DADR command line options for the TimeSync demo application.
This commit is contained in:
@@ -28,6 +28,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <time.h> /* for time */
|
#include <time.h> /* for time */
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "bactext.h"
|
#include "bactext.h"
|
||||||
@@ -39,6 +40,7 @@
|
|||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "datalink.h"
|
#include "datalink.h"
|
||||||
#include "timesync.h"
|
#include "timesync.h"
|
||||||
|
#include "version.h"
|
||||||
/* some demo stuff needed */
|
/* some demo stuff needed */
|
||||||
#include "filename.h"
|
#include "filename.h"
|
||||||
#include "handlers.h"
|
#include "handlers.h"
|
||||||
@@ -48,13 +50,7 @@
|
|||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
/* error flag */
|
||||||
/* 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
|
|
||||||
|
|
||||||
static bool Error_Detected = false;
|
static bool Error_Detected = false;
|
||||||
|
|
||||||
void MyAbortHandler(
|
void MyAbortHandler(
|
||||||
@@ -67,7 +63,7 @@ void MyAbortHandler(
|
|||||||
(void) src;
|
(void) src;
|
||||||
(void) invoke_id;
|
(void) invoke_id;
|
||||||
(void) server;
|
(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;
|
Error_Detected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +75,7 @@ void MyRejectHandler(
|
|||||||
/* FIXME: verify src and invoke id */
|
/* FIXME: verify src and invoke id */
|
||||||
(void) src;
|
(void) src;
|
||||||
(void) invoke_id;
|
(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;
|
Error_Detected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,6 +103,99 @@ static void Init_Service_Handlers(
|
|||||||
apdu_set_reject_handler(MyRejectHandler);
|
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 main(
|
||||||
int argc,
|
int argc,
|
||||||
char *argv[])
|
char *argv[])
|
||||||
@@ -124,26 +213,88 @@ int main(
|
|||||||
struct tm *my_time;
|
struct tm *my_time;
|
||||||
BACNET_DATE bdate;
|
BACNET_DATE bdate;
|
||||||
BACNET_TIME btime;
|
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? */
|
/* decode any command line parameters */
|
||||||
#if 0
|
for (argi = 1; argi < argc; argi++) {
|
||||||
if (argc < 2) {
|
if (strcmp(argv[argi], "--help") == 0) {
|
||||||
printf("Usage: %s date time [device-instance]\r\n"
|
print_usage(filename_remove_path(argv[0]));
|
||||||
"Send BACnet TimeSynchronization request to all devices.\r\n"
|
print_help(filename_remove_path(argv[0]));
|
||||||
"date format: year/month/day:dayofweek (e.g. 2006/4/1:6)\r\n"
|
return 0;
|
||||||
"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"
|
if (strcmp(argv[argi], "--version") == 0) {
|
||||||
"time format: hour:minute:second.hundredths (e.g. 23:59:59.12)\r\n"
|
printf("%s %s\n",
|
||||||
"hour: 0-23\r\n" "minute: 0-59\r\n" "second: 0-59\r\n"
|
filename_remove_path(argv[0]),
|
||||||
"hundredths: 0-99\r\n" "\r\n"
|
BACNET_VERSION_TEXT);
|
||||||
"Optional device-instance sends a unicast time sync.\r\n",
|
printf("Copyright (C) 2014 by Steve Karg\n"
|
||||||
filename_remove_path(argv[0]));
|
"This is free software; see the source for copying conditions.\n"
|
||||||
return 0;
|
"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 */
|
/* setup my info */
|
||||||
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
|
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
|
||||||
Init_Service_Handlers();
|
Init_Service_Handlers();
|
||||||
@@ -163,7 +314,7 @@ int main(
|
|||||||
btime.min = my_time->tm_min;
|
btime.min = my_time->tm_min;
|
||||||
btime.sec = my_time->tm_sec;
|
btime.sec = my_time->tm_sec;
|
||||||
btime.hundredths = 0;
|
btime.hundredths = 0;
|
||||||
Send_TimeSync(&bdate, &btime);
|
Send_TimeSync_Remote(&dest, &bdate, &btime);
|
||||||
/* loop forever - not necessary for time sync, but we can watch */
|
/* loop forever - not necessary for time sync, but we can watch */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* increment timer - exit if timed out */
|
/* increment timer - exit if timed out */
|
||||||
|
|||||||
Reference in New Issue
Block a user