diff --git a/CHANGELOG.md b/CHANGELOG.md index 106e1df1..c60fbb26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -122,6 +122,9 @@ The git repositories are hosted at the following sites: ### Fixed +* Fixed Event parsing and help text for the example uevent and event apps. + Fixed initialization of event data by adding static CharacterString for + message text. Fixed the event parsing to start at argument zero. (#1221) * Fixed You-Are-Request encoding and decoding to use object-id instead of unsigned. (#1220) * Fixed handling for abort and reject errors in Write Property service. (#1216) diff --git a/apps/event/main.c b/apps/event/main.c index db106f39..baf86821 100644 --- a/apps/event/main.c +++ b/apps/event/main.c @@ -226,12 +226,14 @@ static void print_help(const char *filename) "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"); printf("\n"); - (void)filename; + printf("Example:\n"); + printf("%s 123 1 2 binary-value 4 5 6 7 message event\n", filename); } int main(int argc, char *argv[]) { BACNET_EVENT_NOTIFICATION_DATA event_data = { 0 }; + BACNET_CHARACTER_STRING event_data_message_text = { 0 }; unsigned long long_value = 0; BACNET_ADDRESS src = { 0 }; /* address where message came from */ unsigned timeout = 100; /* milliseconds */ @@ -251,6 +253,7 @@ int main(int argc, char *argv[]) unsigned int target_args = 0; const char *filename = NULL; + event_data.messageText = &event_data_message_text; filename = filename_remove_path(argv[0]); for (argi = 1; argi < argc; argi++) { if (strcmp(argv[argi], "--help") == 0) { @@ -305,11 +308,12 @@ int main(int argc, char *argv[]) Target_Device_Object_Instance = (uint32_t)long_value; target_args++; } else if (target_args == 1) { - if (!event_notify_parse( - &event_data, argc - argi, &argv[argi])) { - fprintf(stderr, "event=%s invalid\n", argv[argi]); - } else { + if (event_notify_parse(&event_data, argc - argi, &argv[argi])) { target_args++; + break; + } else { + fprintf(stderr, "event parsing invalid\n"); + return 1; } } else { print_usage(filename); @@ -317,7 +321,7 @@ int main(int argc, char *argv[]) } } } - if (target_args < 14) { + if (target_args < 2) { print_usage(filename); return 0; } diff --git a/apps/uevent/main.c b/apps/uevent/main.c index 92dd8469..7fc8aef8 100644 --- a/apps/uevent/main.c +++ b/apps/uevent/main.c @@ -26,12 +26,18 @@ #include "bacnet/basic/binding/address.h" #include "bacnet/basic/object/device.h" #include "bacnet/basic/sys/filename.h" +#include "bacnet/basic/sys/mstimer.h" #include "bacnet/basic/services.h" #include "bacnet/basic/tsm/tsm.h" #include "bacnet/datalink/datalink.h" #include "bacnet/datalink/dlenv.h" #include "bacport.h" +static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE; +static BACNET_ADDRESS Target_Address; +static bool Error_Detected = false; +static uint8_t Handler_Receive_Buffer[MAX_MPDU] = { 0 }; + static void Init_Service_Handlers(void) { Device_Init(NULL); @@ -59,13 +65,55 @@ static void print_usage(const char *filename) " [new-state status-flags message notify-type\n" " ack-required from-state to-state]\n", filename); - printf(" [--dnet][--dadr][--mac]\n"); + printf(" [--dnet][--dadr][--mac][--device]\n"); printf(" [--version][--help]\n"); } static void print_help(const char *filename) { printf("Send BACnet UnconfirmedEventNotification message for a device.\n"); + printf("process-id:\n" + "Process Identifier in the receiving device for which the\n" + "notification is intended.\n"); + printf("\n"); + printf("initiating-device-id: the BACnet Device Object Instance number\n" + "that initiated the UnconfirmedEventNotification request.\n"); + printf("\n"); + printf( + "event-object-type:\n" + "The object type is defined either as the object-type name string\n" + "as defined in the BACnet specification, or as the integer value.\n"); + printf("\n"); + printf("event-object-instance:\n" + "The object instance number of the event object.\n"); + printf("\n"); + printf("sequence-number:\n" + "The sequence number of the event.\n"); + printf("\n"); + printf("notification-class:\n" + "The notification-class of the event.\n"); + printf("\n"); + printf("priority:\n" + "The priority of the event.\n"); + printf("\n"); + printf("message-text:\n" + "The message text of the event.\n"); + printf("\n"); + printf("notify-type:\n" + "The notify type of the event.\n"); + printf("\n"); + printf("ack-required:\n" + "The ack-required of the event (0=FALSE,1=TRUE).\n"); + printf("\n"); + printf("from-state:\n" + "The from-state of the event.\n"); + printf("\n"); + printf("to-state:\n" + "The to-state of the event.\n"); + printf("\n"); + printf("event-type:\n" + "The event-type of the event.\n"); + printf("\n"); printf("--mac A\n" "Optional BACnet mac address." "Valid ranges are from 00 to FF (hex) for MS/TP or ARCNET,\n" @@ -83,12 +131,25 @@ static void print_help(const char *filename) "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"); printf("\n"); - (void)filename; + printf("--device D:\n" + "BACnet Device Object Instance number of the target device.\n" + "This application will try and bind with this device using\n" + "Who-Is and I-Am services.\n"); + printf("Example:\n"); + printf("%s 1 2 binary-value 4 5 6 7 message event\n", filename); } int main(int argc, char *argv[]) { BACNET_EVENT_NOTIFICATION_DATA event_data = { 0 }; + BACNET_CHARACTER_STRING event_data_message_text = { 0 }; + BACNET_ADDRESS src = { 0 }; /* address where message came from */ + uint16_t pdu_len = 0; + unsigned timeout = 100; /* milliseconds */ + unsigned max_apdu = 0; + bool found = false; + int apdu_len = 0; + struct mstimer apdu_timer = { 0 }; long dnet = -1; BACNET_MAC_ADDRESS mac = { 0 }; BACNET_MAC_ADDRESS adr = { 0 }; @@ -98,6 +159,7 @@ int main(int argc, char *argv[]) unsigned int target_args = 0; const char *filename = NULL; + event_data.messageText = &event_data_message_text; filename = filename_remove_path(argv[0]); for (argi = 1; argi < argc; argi++) { if (strcmp(argv[argi], "--help") == 0) { @@ -136,29 +198,100 @@ int main(int argc, char *argv[]) specific_address = true; } } + } else if (strcmp(argv[argi], "--device") == 0) { + if (++argi < argc) { + Target_Device_Object_Instance = strtol(argv[argi], NULL, 0); + if (Target_Device_Object_Instance > BACNET_MAX_INSTANCE) { + fprintf( + stderr, "device=%u exceeds maximum %u\n", + Target_Device_Object_Instance, BACNET_MAX_INSTANCE); + return 1; + } + } } else { if (target_args == 0) { - if (!event_notify_parse( - &event_data, argc - argi, &argv[argi])) { - fprintf(stderr, "event=%s invalid\n", argv[argi]); - } else { + if (event_notify_parse(&event_data, argc - argi, &argv[argi])) { target_args++; + break; + } else { + fprintf(stderr, "event parsing invalid\n"); + return 1; } - } else { - print_usage(filename); - return 1; } } } + if (target_args < 1) { + print_usage(filename); + return 0; + } + address_init(); if (specific_address) { bacnet_address_init(&dest, &mac, dnet, &adr); + address_add(Target_Device_Object_Instance, MAX_APDU, &dest); + printf( + "Added Device %u to address cache\n", + Target_Device_Object_Instance); + } else if (Target_Device_Object_Instance == BACNET_MAX_INSTANCE) { + printf("Using broadcast to notify device\n"); + bacnet_address_init(&dest, NULL, BACNET_BROADCAST_NETWORK, NULL); + address_add(Target_Device_Object_Instance, MAX_APDU, &dest); } /* setup my info */ Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); Init_Service_Handlers(); dlenv_init(); atexit(datalink_cleanup); - Send_UEvent_Notify(&Handler_Transmit_Buffer[0], &event_data, &dest); + mstimer_init(); + mstimer_set(&apdu_timer, apdu_timeout()); + /* try to bind with the device */ + found = address_bind_request( + Target_Device_Object_Instance, &max_apdu, &Target_Address); + if (!found) { + Send_WhoIs( + Target_Device_Object_Instance, Target_Device_Object_Instance); + } + /* main loop: run until the event notification is sent or + an error/timeout occurs */ + for (;;) { + if (found) { + if (Target_Device_Object_Instance == BACNET_MAX_INSTANCE) { + /* use BACNET_ADDRESS API */ + apdu_len = Send_UEvent_Notify( + Handler_Transmit_Buffer, &event_data, &Target_Address); + } else { + /* use device API */ + apdu_len = Send_UEvent_Notify_Device( + Handler_Transmit_Buffer, &event_data, + Target_Device_Object_Instance); + } + if (apdu_len <= 0) { + printf("Error: Failed to send UEvent Notification!\n"); + Error_Detected = true; + } else { + printf( + "Sent UEvent Notification (%u bytes) to device %u\n", + apdu_len, Target_Device_Object_Instance); + break; + } + } else { + found = address_bind_request( + Target_Device_Object_Instance, &max_apdu, &Target_Address); + } + /* returns 0 bytes on timeout */ + pdu_len = datalink_receive( + &src, &Handler_Receive_Buffer[0], MAX_MPDU, timeout); + /* process */ + if (pdu_len) { + npdu_handler(&src, &Handler_Receive_Buffer[0], pdu_len); + } + if (Error_Detected) { + break; + } + if (mstimer_expired(&apdu_timer)) { + printf("\rError: APDU Timeout!\n"); + Error_Detected = true; + } + } return 0; } diff --git a/src/bacnet/basic/service/s_uevent.c b/src/bacnet/basic/service/s_uevent.c index 5c7305f0..73e1ebd2 100644 --- a/src/bacnet/basic/service/s_uevent.c +++ b/src/bacnet/basic/service/s_uevent.c @@ -47,3 +47,33 @@ int Send_UEvent_Notify( return bytes_sent; } + +/** + * @brief Sends an Unconfirmed Alarm/Event Notification. + * @ingroup BIBB-AE-N-A + * @param buffer [in,out] The buffer to build the message in for sending. + * @param data [in] The information about the Event to be sent. + * @param device_id [in] ID of the destination device + * @return Size of the message sent (bytes), or a negative value on error. + */ +int Send_UEvent_Notify_Device( + uint8_t *buffer, + const BACNET_EVENT_NOTIFICATION_DATA *data, + uint32_t device_id) +{ + int bytes_sent = 0; + BACNET_ADDRESS dest = { 0 }; + unsigned max_apdu = 0; + bool status = false; + uint8_t segmentation = 0; + uint16_t maxsegments = 0; + + /* is the device bound? */ + status = address_segment_get_by_device( + device_id, &max_apdu, &dest, &segmentation, &maxsegments); + if (status) { + bytes_sent = Send_UEvent_Notify(buffer, data, &dest); + } + + return bytes_sent; +} diff --git a/src/bacnet/basic/service/s_uevent.h b/src/bacnet/basic/service/s_uevent.h index 4958b9aa..04c32b4e 100644 --- a/src/bacnet/basic/service/s_uevent.h +++ b/src/bacnet/basic/service/s_uevent.h @@ -31,6 +31,12 @@ int Send_UEvent_Notify( const BACNET_EVENT_NOTIFICATION_DATA *data, BACNET_ADDRESS *dest); +BACNET_STACK_EXPORT +int Send_UEvent_Notify_Device( + uint8_t *buffer, + const BACNET_EVENT_NOTIFICATION_DATA *data, + uint32_t device_id); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/bacnet/event.c b/src/bacnet/event.c index 25d18cd6..17cf53ba 100644 --- a/src/bacnet/event.c +++ b/src/bacnet/event.c @@ -3139,7 +3139,7 @@ bool event_notify_parse( BACNET_PROPERTY_STATES tag = PROP_STATE_BOOLEAN_VALUE; BACNET_BIT_STRING *pBitString = NULL; - for (argi = 1; argi < argc; argi++) { + for (argi = 0; argi < argc; argi++) { if (target_args == 1) { /* process-id */ if (!bacnet_string_to_uint32(