Bugfix/example-app-uevent-event-parsing (#1221)

* Added Send_UEvent_Notify_Device function for device-specific unconfirmed event notifications.

* Fixed event_notify_parse() loop index to start from zero.

* Added device ID binding support in the UEvent command-line application.

* Fixed the UEvent command-line application help output.

* Fixed initialization of event data in the UEvent command-line application by adding static CharacterString for message text and handling the failure case.
This commit is contained in:
Steve Karg
2026-02-05 13:41:56 -06:00
committed by GitHub
parent edff06a9c0
commit 94e79efead
6 changed files with 193 additions and 17 deletions
+3
View File
@@ -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)
+10 -6
View File
@@ -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;
}
+143 -10
View File
@@ -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;
}
+30
View File
@@ -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;
}
+6
View File
@@ -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 */
+1 -1
View File
@@ -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(