diff --git a/src/bacnet/basic/service/h_ccov.c b/src/bacnet/basic/service/h_ccov.c index ce46e2c9..7de34a68 100644 --- a/src/bacnet/basic/service/h_ccov.c +++ b/src/bacnet/basic/service/h_ccov.c @@ -40,11 +40,62 @@ #include "bacnet/basic/tsm/tsm.h" #include "bacnet/datalink/datalink.h" +/** @file h_ccov.c Handles Confirmed COV Notifications. */ +#if PRINT_ENABLED +#include +#define PRINTF(...) fprintf(stderr,__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +/* max number of COV properties decoded in a COV notification */ #ifndef MAX_COV_PROPERTIES #define MAX_COV_PROPERTIES 2 #endif -/** @file h_ccov.c Handles Confirmed COV Notifications. */ +/* COV notification callbacks list */ +static BACNET_COV_NOTIFICATION Confirmed_COV_Notification_Head; + +/** + * @brief call the COV notification callbacks + * @param cov_data - data decoded from the COV notification + */ +static void handler_ccov_notification_callback( + BACNET_COV_DATA *cov_data) +{ + BACNET_COV_NOTIFICATION *head; + + head = &Confirmed_COV_Notification_Head; + do { + if (head->callback) { + head->callback(cov_data); + } + head = head->next; + } while (head); +} + +/** + * @brief Add a Confirmed COV notification callback + * @param cb - COV notification callback to be added + */ +void handler_ccov_notification_add( + BACNET_COV_NOTIFICATION *cb) +{ + BACNET_COV_NOTIFICATION *head; + + head = &Confirmed_COV_Notification_Head; + do { + if (head->next == cb) { + /* already here! */ + break; + } else if (!head->next) { + /* first available free node */ + head->next = cb; + break; + } + head = head->next; + } while (head); +} /* */ /** Handler for an Confirmed COV Notification. @@ -68,9 +119,7 @@ void handler_ccov_notification(uint8_t *service_request, BACNET_NPDU_DATA npdu_data; BACNET_COV_DATA cov_data; BACNET_PROPERTY_VALUE property_value[MAX_COV_PROPERTIES]; -#if PRINT_ENABLED BACNET_PROPERTY_VALUE *pProperty_value = NULL; -#endif int len = 0; int pdu_len = 0; int bytes_sent = 0; @@ -85,74 +134,62 @@ void handler_ccov_notification(uint8_t *service_request, npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu( &Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); -#if PRINT_ENABLED - fprintf(stderr, "CCOV: Received Notification!\n"); -#endif + PRINTF("CCOV: Received Notification!\n"); if (service_data->segmented_message) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); -#if PRINT_ENABLED - fprintf(stderr, "CCOV: Segmented message. Sending Abort!\n"); -#endif + PRINTF("CCOV: Segmented message. Sending Abort!\n"); goto CCOV_ABORT; } /* decode the service request only */ len = cov_notify_decode_service_request( service_request, service_len, &cov_data); -#if PRINT_ENABLED if (len > 0) { - fprintf(stderr, "CCOV: PID=%u ", cov_data.subscriberProcessIdentifier); - fprintf(stderr, "instance=%u ", cov_data.initiatingDeviceIdentifier); - fprintf(stderr, "%s %u ", + handler_ccov_notification_callback(&cov_data); + PRINTF("CCOV: PID=%u ", cov_data.subscriberProcessIdentifier); + PRINTF("instance=%u ", cov_data.initiatingDeviceIdentifier); + PRINTF("%s %u ", bactext_object_type_name(cov_data.monitoredObjectIdentifier.type), cov_data.monitoredObjectIdentifier.instance); - fprintf(stderr, "time remaining=%u seconds ", cov_data.timeRemaining); - fprintf(stderr, "\n"); + PRINTF("time remaining=%u seconds ", cov_data.timeRemaining); + PRINTF("\n"); pProperty_value = &property_value[0]; while (pProperty_value) { - fprintf(stderr, "CCOV: "); + PRINTF("CCOV: "); if (pProperty_value->propertyIdentifier < 512) { - fprintf(stderr, "%s ", + PRINTF("%s ", bactext_property_name(pProperty_value->propertyIdentifier)); } else { - fprintf(stderr, "proprietary %u ", + PRINTF("proprietary %u ", pProperty_value->propertyIdentifier); } if (pProperty_value->propertyArrayIndex != BACNET_ARRAY_ALL) { - fprintf(stderr, "%u ", pProperty_value->propertyArrayIndex); + PRINTF("%u ", pProperty_value->propertyArrayIndex); } - fprintf(stderr, "\n"); + PRINTF("\n"); pProperty_value = pProperty_value->next; } } -#endif /* bad decoding or something we didn't understand - send an abort */ if (len <= 0) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER, true); -#if PRINT_ENABLED - fprintf(stderr, "CCOV: Bad Encoding. Sending Abort!\n"); -#endif + PRINTF("CCOV: Bad Encoding. Sending Abort!\n"); goto CCOV_ABORT; } else { len = encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_COV_NOTIFICATION); -#if PRINT_ENABLED - fprintf(stderr, "CCOV: Sending Simple Ack!\n"); -#endif + PRINTF("CCOV: Sending Simple Ack!\n"); } CCOV_ABORT: pdu_len += len; bytes_sent = datalink_send_pdu( src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); -#if PRINT_ENABLED if (bytes_sent <= 0) { - fprintf(stderr, "CCOV: Failed to send PDU (%s)!\n", strerror(errno)); + PRINTF("CCOV: Failed to send PDU (%s)!\n", strerror(errno)); } -#else bytes_sent = bytes_sent; -#endif return; } diff --git a/src/bacnet/basic/service/h_ccov.h b/src/bacnet/basic/service/h_ccov.h index ddd7fa63..684f366b 100644 --- a/src/bacnet/basic/service/h_ccov.h +++ b/src/bacnet/basic/service/h_ccov.h @@ -36,10 +36,14 @@ #include "bacnet/bacdef.h" #include "bacnet/bacenum.h" #include "bacnet/apdu.h" +#include "bacnet/cov.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ + BACNET_STACK_EXPORT + void handler_ccov_notification_add( + BACNET_COV_NOTIFICATION *callback); BACNET_STACK_EXPORT void handler_ccov_notification( diff --git a/src/bacnet/basic/service/h_ucov.c b/src/bacnet/basic/service/h_ucov.c index 0650676d..1a8ea2d5 100644 --- a/src/bacnet/basic/service/h_ucov.c +++ b/src/bacnet/basic/service/h_ucov.c @@ -38,11 +38,61 @@ #include "bacnet/basic/services.h" #include "bacnet/basic/tsm/tsm.h" +/** @file h_ucov.c Handles Unconfirmed COV Notifications. */ +#if PRINT_ENABLED +#include +#define PRINTF(...) fprintf(stderr,__VA_ARGS__) +#else +#define PRINTF(...) +#endif + #ifndef MAX_COV_PROPERTIES #define MAX_COV_PROPERTIES 2 #endif -/** @file h_ucov.c Handles Unconfirmed COV Notifications. */ +/* COV notification callbacks list */ +static BACNET_COV_NOTIFICATION Unconfirmed_COV_Notification_Head; + +/** + * @brief call the COV notification callbacks + * @param cov_data - data decoded from the COV notification + */ +static void handler_ucov_notification_callback( + BACNET_COV_DATA *cov_data) +{ + BACNET_COV_NOTIFICATION *head; + + head = &Unconfirmed_COV_Notification_Head; + do { + if (head->callback) { + head->callback(cov_data); + } + head = head->next; + } while (head); +} + +/** + * @brief Add a Confirmed COV notification callback + * @param cb - COV notification callback to be added + */ +void handler_ucov_notification_add( + BACNET_COV_NOTIFICATION *cb) +{ + BACNET_COV_NOTIFICATION *head; + + head = &Unconfirmed_COV_Notification_Head; + do { + if (head->next == cb) { + /* already here! */ + break; + } else if (!head->next) { + /* first available free node */ + head->next = cb; + break; + } + head = head->next; + } while (head); +} /* */ /** Handler for an Unconfirmed COV Notification. @@ -61,10 +111,8 @@ void handler_ucov_notification( { BACNET_COV_DATA cov_data; BACNET_PROPERTY_VALUE property_value[MAX_COV_PROPERTIES]; -#if PRINT_ENABLED BACNET_PROPERTY_VALUE *pProperty_value = NULL; int len = 0; -#endif /* src not needed for this application */ (void)src; @@ -72,42 +120,37 @@ void handler_ucov_notification( than one property value is expected */ bacapp_property_value_list_init(&property_value[0], MAX_COV_PROPERTIES); cov_data.listOfValues = &property_value[0]; -#if PRINT_ENABLED - fprintf(stderr, "UCOV: Received Notification!\n"); -#endif + PRINTF("UCOV: Received Notification!\n"); /* decode the service request only */ -#if PRINT_ENABLED len = -#endif cov_notify_decode_service_request( service_request, service_len, &cov_data); -#if PRINT_ENABLED if (len > 0) { - fprintf(stderr, "UCOV: PID=%u ", cov_data.subscriberProcessIdentifier); - fprintf(stderr, "instance=%u ", cov_data.initiatingDeviceIdentifier); - fprintf(stderr, "%s %u ", + handler_ucov_notification_callback(&cov_data); + PRINTF("UCOV: PID=%u ", cov_data.subscriberProcessIdentifier); + PRINTF("instance=%u ", cov_data.initiatingDeviceIdentifier); + PRINTF("%s %u ", bactext_object_type_name(cov_data.monitoredObjectIdentifier.type), cov_data.monitoredObjectIdentifier.instance); - fprintf(stderr, "time remaining=%u seconds ", cov_data.timeRemaining); - fprintf(stderr, "\n"); + PRINTF("time remaining=%u seconds ", cov_data.timeRemaining); + PRINTF("\n"); pProperty_value = &property_value[0]; while (pProperty_value) { - fprintf(stderr, "UCOV: "); + PRINTF("UCOV: "); if (pProperty_value->propertyIdentifier < 512) { - fprintf(stderr, "%s ", + PRINTF("%s ", bactext_property_name(pProperty_value->propertyIdentifier)); } else { - fprintf(stderr, "proprietary %u ", + PRINTF("proprietary %u ", pProperty_value->propertyIdentifier); } if (pProperty_value->propertyArrayIndex != BACNET_ARRAY_ALL) { - fprintf(stderr, "%u ", pProperty_value->propertyArrayIndex); + PRINTF("%u ", pProperty_value->propertyArrayIndex); } - fprintf(stderr, "\n"); + PRINTF("\n"); pProperty_value = pProperty_value->next; } } else { - fprintf(stderr, "UCOV: Unable to decode service request!\n"); + PRINTF("UCOV: Unable to decode service request!\n"); } -#endif } diff --git a/src/bacnet/basic/service/h_ucov.h b/src/bacnet/basic/service/h_ucov.h index 2eca8776..86d6fba6 100644 --- a/src/bacnet/basic/service/h_ucov.h +++ b/src/bacnet/basic/service/h_ucov.h @@ -36,10 +36,14 @@ #include "bacnet/bacdef.h" #include "bacnet/bacenum.h" #include "bacnet/apdu.h" +#include "bacnet/cov.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ + BACNET_STACK_EXPORT + void handler_ucov_notification_add( + BACNET_COV_NOTIFICATION *callback); BACNET_STACK_EXPORT void handler_ucov_notification( diff --git a/src/bacnet/cov.h b/src/bacnet/cov.h index 01d38b66..502d1941 100644 --- a/src/bacnet/cov.h +++ b/src/bacnet/cov.h @@ -53,11 +53,19 @@ typedef struct BACnet_Subscribe_COV_Data { struct BACnet_Subscribe_COV_Data *next; } BACNET_SUBSCRIBE_COV_DATA; +/* generic callback for COV notifications */ +typedef void (*BACnet_COV_Notification_Callback) + (BACNET_COV_DATA *cov_data); +struct BACnet_COV_Notification; +typedef struct BACnet_COV_Notification { + struct BACnet_COV_Notification *next; + BACnet_COV_Notification_Callback callback; +} BACNET_COV_NOTIFICATION; + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ - BACNET_STACK_EXPORT int ucov_notify_encode_apdu( uint8_t * apdu, unsigned max_apdu_len,