From 4e52f268234d4eed532f93cc3bfd542ef9a553b8 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Thu, 6 Nov 2025 14:10:07 -0600 Subject: [PATCH] Added Audit Log and Time Value objects to basic device. (#1128) * Added ListElement service callback for storing data. * Added Audit Log and Time Value objects to basic device. * Added Audit Log object to Makefile and CMake builds. --- CHANGELOG.md | 2 + CMakeLists.txt | 5 ++ apps/server-basic/Makefile | 1 + apps/server/Makefile | 29 +++---- src/bacnet/basic/object/auditlog.c | 2 - src/bacnet/basic/object/device.c | 26 +++++++ src/bacnet/basic/object/device.h | 5 +- src/bacnet/basic/server/bacnet_device.c | 77 +++++++++++++++++++ .../basic/server/bacnet_device/CMakeLists.txt | 2 + 9 files changed, 132 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 626a9c02..5b153a8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ The git repositories are hosted at the following sites: ### Added +* Added Audit Log and Time Value objects to basic device and builds. (#1128) +* Added ListElement service callback for storing data. (#1128) * Added a basic timer object type example. (#1123) * Added BACnetLIST utility for handling WriteProperty to a list. (#1123) * Added Device_Object_Functions() API to return basic object API table diff --git a/CMakeLists.txt b/CMakeLists.txt index 489bb107..93b7339c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -259,6 +259,8 @@ add_library(${PROJECT_NAME} src/bacnet/bacaction.h src/bacnet/bacapp.c src/bacnet/bacapp.h + src/bacnet/bacaudit.c + src/bacnet/bacaudit.h src/bacnet/bacdcode.c src/bacnet/bacdcode.h src/bacnet/bacdef.h @@ -340,6 +342,9 @@ add_library(${PROJECT_NAME} src/bacnet/basic/object/access_zone.c src/bacnet/basic/object/access_zone.h src/bacnet/basic/object/acc.c + src/bacnet/basic/object/acc.h + src/bacnet/basic/object/auditlog.c + src/bacnet/basic/object/auditlog.h src/bacnet/basic/object/ai.c src/bacnet/basic/object/ai.h src/bacnet/basic/object/ao.c diff --git a/apps/server-basic/Makefile b/apps/server-basic/Makefile index 76b6c8d3..6956bd64 100644 --- a/apps/server-basic/Makefile +++ b/apps/server-basic/Makefile @@ -15,6 +15,7 @@ SRC = main.c \ $(BACNET_OBJECT_DIR)/ai.c \ $(BACNET_OBJECT_DIR)/ao.c \ $(BACNET_OBJECT_DIR)/av.c \ + $(BACNET_OBJECT_DIR)/auditlog.c \ $(BACNET_OBJECT_DIR)/bacfile.c \ $(BACNET_OBJECT_DIR)/bi.c \ $(BACNET_OBJECT_DIR)/bitstring_value.c \ diff --git a/apps/server/Makefile b/apps/server/Makefile index 63c47b34..f6e1ce91 100644 --- a/apps/server/Makefile +++ b/apps/server/Makefile @@ -6,9 +6,18 @@ TARGET = bacserv BACNET_OBJECT_DIR = $(BACNET_SRC_DIR)/bacnet/basic/object SRC = main.c \ $(BACNET_OBJECT_DIR)/device.c \ + $(BACNET_OBJECT_DIR)/access_credential.c \ + $(BACNET_OBJECT_DIR)/access_door.c \ + $(BACNET_OBJECT_DIR)/access_point.c \ + $(BACNET_OBJECT_DIR)/access_rights.c \ + $(BACNET_OBJECT_DIR)/access_user.c \ + $(BACNET_OBJECT_DIR)/access_zone.c \ $(BACNET_OBJECT_DIR)/ai.c \ $(BACNET_OBJECT_DIR)/ao.c \ $(BACNET_OBJECT_DIR)/av.c \ + $(BACNET_OBJECT_DIR)/acc.c \ + $(BACNET_OBJECT_DIR)/auditlog.c \ + $(BACNET_OBJECT_DIR)/bacfile.c \ $(BACNET_OBJECT_DIR)/bi.c \ $(BACNET_OBJECT_DIR)/bitstring_value.c \ $(BACNET_OBJECT_DIR)/bo.c \ @@ -19,6 +28,7 @@ SRC = main.c \ $(BACNET_OBJECT_DIR)/color_object.c \ $(BACNET_OBJECT_DIR)/color_temperature.c \ $(BACNET_OBJECT_DIR)/command.c \ + $(BACNET_OBJECT_DIR)/credential_data_input.c \ $(BACNET_OBJECT_DIR)/csv.c \ $(BACNET_OBJECT_DIR)/iv.c \ $(BACNET_OBJECT_DIR)/lc.c \ @@ -28,25 +38,16 @@ SRC = main.c \ $(BACNET_OBJECT_DIR)/ms-input.c \ $(BACNET_OBJECT_DIR)/mso.c \ $(BACNET_OBJECT_DIR)/msv.c \ + $(BACNET_OBJECT_DIR)/nc.c \ + $(BACNET_OBJECT_DIR)/netport.c \ $(BACNET_OBJECT_DIR)/osv.c \ $(BACNET_OBJECT_DIR)/piv.c \ $(BACNET_OBJECT_DIR)/program.c \ - $(BACNET_OBJECT_DIR)/nc.c \ - $(BACNET_OBJECT_DIR)/netport.c \ - $(BACNET_OBJECT_DIR)/time_value.c \ - $(BACNET_OBJECT_DIR)/timer.c \ - $(BACNET_OBJECT_DIR)/trendlog.c \ $(BACNET_OBJECT_DIR)/schedule.c \ $(BACNET_OBJECT_DIR)/structured_view.c \ - $(BACNET_OBJECT_DIR)/access_credential.c \ - $(BACNET_OBJECT_DIR)/access_door.c \ - $(BACNET_OBJECT_DIR)/access_point.c \ - $(BACNET_OBJECT_DIR)/access_rights.c \ - $(BACNET_OBJECT_DIR)/access_user.c \ - $(BACNET_OBJECT_DIR)/access_zone.c \ - $(BACNET_OBJECT_DIR)/credential_data_input.c \ - $(BACNET_OBJECT_DIR)/acc.c \ - $(BACNET_OBJECT_DIR)/bacfile.c + $(BACNET_OBJECT_DIR)/time_value.c \ + $(BACNET_OBJECT_DIR)/timer.c \ + $(BACNET_OBJECT_DIR)/trendlog.c # TARGET_EXT is defined in apps/Makefile as .exe or nothing TARGET_BIN = ${TARGET}$(TARGET_EXT) diff --git a/src/bacnet/basic/object/auditlog.c b/src/bacnet/basic/object/auditlog.c index 9d1158a1..ad870dfc 100644 --- a/src/bacnet/basic/object/auditlog.c +++ b/src/bacnet/basic/object/auditlog.c @@ -653,14 +653,12 @@ int Audit_Log_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) BACNET_CHARACTER_STRING char_string = { 0 }; BACNET_BIT_STRING bit_string = { 0 }; uint8_t *apdu = NULL; - int apdu_max = 0; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; - apdu_max = rpdata->application_data_len; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id( diff --git a/src/bacnet/basic/object/device.c b/src/bacnet/basic/object/device.c index cfb66495..5628ae04 100644 --- a/src/bacnet/basic/object/device.c +++ b/src/bacnet/basic/object/device.c @@ -666,6 +666,8 @@ static uint32_t Database_Revision = 0; static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE; static const char *Reinit_Password = "filister"; static write_property_function Device_Write_Property_Store_Callback; +static list_element_function Device_Add_List_Element_Callback; +static list_element_function Device_Remove_List_Element_Callback; #ifdef BAC_ROUTING static bool Device_Router_Mode = false; @@ -2150,6 +2152,15 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) return (status); } +/** + * @brief Set the callback for a Add_List_Element successful operation + * @param cb [in] The function to be called, or NULL to disable + */ +void Device_Add_List_Element_Callback_Set(list_element_function cb) +{ + Device_Add_List_Element_Callback = cb; +} + /** * @brief AddListElement from an object list property * @param list_element [in] Pointer to the BACnet_List_Element_Data structure, @@ -2168,6 +2179,9 @@ int Device_Add_List_Element(BACNET_LIST_ELEMENT_DATA *list_element) pObject->Object_Valid_Instance(list_element->object_instance)) { if (pObject->Object_Add_List_Element) { status = pObject->Object_Add_List_Element(list_element); + if (status) { + Device_Add_List_Element_Callback(list_element); + } } else { list_element->error_class = ERROR_CLASS_PROPERTY; list_element->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; @@ -2184,6 +2198,15 @@ int Device_Add_List_Element(BACNET_LIST_ELEMENT_DATA *list_element) return status; } +/** + * @brief Set the callback for a Remove_List_Element successful operation + * @param cb [in] The function to be called, or NULL to disable + */ +void Device_Remove_List_Element_Callback_Set(list_element_function cb) +{ + Device_Remove_List_Element_Callback = cb; +} + /** * @brief RemoveListElement from an object list property * @param list_element [in] Pointer to the BACnet_List_Element_Data structure, @@ -2202,6 +2225,9 @@ int Device_Remove_List_Element(BACNET_LIST_ELEMENT_DATA *list_element) pObject->Object_Valid_Instance(list_element->object_instance)) { if (pObject->Object_Remove_List_Element) { status = pObject->Object_Remove_List_Element(list_element); + if (status) { + Device_Remove_List_Element_Callback(list_element); + } } else { list_element->error_class = ERROR_CLASS_PROPERTY; list_element->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; diff --git a/src/bacnet/basic/object/device.h b/src/bacnet/basic/object/device.h index 7fb3e846..47664dc4 100644 --- a/src/bacnet/basic/object/device.h +++ b/src/bacnet/basic/object/device.h @@ -394,9 +394,12 @@ int Device_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata); BACNET_STACK_EXPORT bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data); +BACNET_STACK_EXPORT +void Device_Add_List_Element_Callback_Set(list_element_function cb); BACNET_STACK_EXPORT int Device_Add_List_Element(BACNET_LIST_ELEMENT_DATA *list_element); - +BACNET_STACK_EXPORT +void Device_Remove_List_Element_Callback_Set(list_element_function cb); BACNET_STACK_EXPORT int Device_Remove_List_Element(BACNET_LIST_ELEMENT_DATA *list_element); diff --git a/src/bacnet/basic/server/bacnet_device.c b/src/bacnet/basic/server/bacnet_device.c index 1c3f8049..149d8def 100644 --- a/src/bacnet/basic/server/bacnet_device.c +++ b/src/bacnet/basic/server/bacnet_device.c @@ -32,6 +32,7 @@ #include "bacnet/basic/object/ai.h" #include "bacnet/basic/object/ao.h" #include "bacnet/basic/object/av.h" +#include "bacnet/basic/object/auditlog.h" #include "bacnet/basic/object/bi.h" #include "bacnet/basic/object/bo.h" #include "bacnet/basic/object/bv.h" @@ -110,6 +111,7 @@ defined(CONFIG_BACNET_BASIC_OBJECT_ANALOG_INPUT) || \ defined(CONFIG_BACNET_BASIC_OBJECT_ANALOG_OUTPUT) || \ defined(CONFIG_BACNET_BASIC_OBJECT_ANALOG_VALUE) || \ + defined(CONFIG_BACNET_BASIC_OBJECT_AUDIT_LOG) || \ defined(CONFIG_BACNET_BASIC_OBJECT_BINARY_INPUT) || \ defined(CONFIG_BACNET_BASIC_OBJECT_BINARY_OUTPUT) || \ defined(CONFIG_BACNET_BASIC_OBJECT_BINARY_VALUE) || \ @@ -130,6 +132,7 @@ defined(CONFIG_BACNET_BASIC_OBJECT_FILE) || \ defined(CONFIG_BACNET_BASIC_OBJECT_STRUCTURED_VIEW) || \ defined(CONFIG_BACNET_BASIC_OBJECT_BITSTRING_VALUE) || \ + defined(CONFIG_BACNET_BASIC_OBJECT_TIME_VALUE) || \ defined(CONFIG_BACNET_BASIC_OBJECT_TIMER) || \ defined(CONFIG_BACNET_BASIC_OBJECT_PROGRAM) || \ defined(CONFIG_BACNET_BASIC_OBJECT_CHARACTERSTRING_VALUE)) @@ -140,6 +143,7 @@ #define CONFIG_BACNET_BASIC_OBJECT_ANALOG_INPUT #define CONFIG_BACNET_BASIC_OBJECT_ANALOG_OUTPUT #define CONFIG_BACNET_BASIC_OBJECT_ANALOG_VALUE +#define CONFIG_BACNET_BASIC_OBJECT_AUDIT_LOG #define CONFIG_BACNET_BASIC_OBJECT_BINARY_INPUT #define CONFIG_BACNET_BASIC_OBJECT_BINARY_OUTPUT #define CONFIG_BACNET_BASIC_OBJECT_BINARY_VALUE @@ -160,6 +164,7 @@ #define CONFIG_BACNET_BASIC_OBJECT_FILE #define CONFIG_BACNET_BASIC_OBJECT_STRUCTURED_VIEW #define CONFIG_BACNET_BASIC_OBJECT_BITSTRING_VALUE +#define CONFIG_BACNET_BASIC_OBJECT_TIME_VALUE #define CONFIG_BACNET_BASIC_OBJECT_TIMER #define CONFIG_BACNET_BASIC_OBJECT_PROGRAM #define CONFIG_BACNET_BASIC_OBJECT_CHARACTERSTRING_VALUE @@ -294,6 +299,28 @@ static object_functions_t My_Object_Table[] = { Analog_Value_Delete, NULL /* Timer */ }, #endif +#if defined(CONFIG_BACNET_BASIC_OBJECT_AUDIT_LOG) + { OBJECT_AUDIT_LOG, + Audit_Log_Init, + Audit_Log_Count, + Audit_Log_Index_To_Instance, + Audit_Log_Valid_Instance, + Audit_Log_Object_Name, + Audit_Log_Read_Property, + Audit_Log_Write_Property, + Audit_Log_Property_Lists, + NULL /* ReadRangeInfo */, + NULL /* Iterator */, + NULL /* Value_Lists */, + NULL /* COV */, + NULL /* COV Clear */, + NULL /* Intrinsic Reporting */, + NULL /* Add_List_Element */, + NULL /* Remove_List_Element */, + Audit_Log_Create, + Audit_Log_Delete, + NULL /* Timer */ }, +#endif #if defined(CONFIG_BACNET_BASIC_OBJECT_BINARY_INPUT) { OBJECT_BINARY_INPUT, Binary_Input_Init, @@ -757,6 +784,28 @@ static object_functions_t My_Object_Table[] = { CharacterString_Value_Delete, NULL /* Timer */ }, #endif +#if defined(CONFIG_BACNET_BASIC_OBJECT_TIME_VALUE) + { OBJECT_TIME_VALUE, + Time_Value_Init, + Time_Value_Count, + Time_Value_Index_To_Instance, + Time_Value_Valid_Instance, + Time_Value_Object_Name, + Time_Value_Read_Property, + Time_Value_Write_Property, + Time_Value_Property_Lists, + NULL /* ReadRangeInfo */, + NULL /* Iterator */, + NULL /* Value_Lists */, + NULL /* COV */, + NULL /* COV Clear */, + NULL /* Intrinsic Reporting */, + NULL /* Add_List_Element */, + NULL /* Remove_List_Element */, + Time_Value_Create, + Time_Value_Delete, + NULL /* Timer */ }, +#endif #if defined(CONFIG_BACNET_BASIC_OBJECT_TIMER) { OBJECT_TIMER, Timer_Init, @@ -1054,6 +1103,8 @@ static uint32_t Database_Revision; static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE; static BACNET_CHARACTER_STRING Reinit_Password; static write_property_function Device_Write_Property_Store_Callback; +static list_element_function Device_Add_List_Element_Callback; +static list_element_function Device_Remove_List_Element_Callback; static uint8_t Device_UUID[16]; static const char *Serial_Number = BACNET_DEVICE_SERIAL_NUMBER; static BACNET_TIMESTAMP Time_Of_Device_Restart; @@ -2506,6 +2557,15 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) return (status); } +/** + * @brief Set the callback for a Add_List_Element successful operation + * @param cb [in] The function to be called, or NULL to disable + */ +void Device_Add_List_Element_Callback_Set(list_element_function cb) +{ + Device_Add_List_Element_Callback = cb; +} + /** * @brief AddListElement from an object list property * @param list_element [in] Pointer to the BACnet_List_Element_Data structure, @@ -2524,6 +2584,11 @@ int Device_Add_List_Element(BACNET_LIST_ELEMENT_DATA *list_element) pObject->Object_Valid_Instance(list_element->object_instance)) { if (pObject->Object_Add_List_Element) { status = pObject->Object_Add_List_Element(list_element); + if (status) { + if (Device_Add_List_Element_Callback) { + (void)Device_Add_List_Element_Callback(list_element); + } + } } else { list_element->error_class = ERROR_CLASS_PROPERTY; list_element->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; @@ -2540,6 +2605,15 @@ int Device_Add_List_Element(BACNET_LIST_ELEMENT_DATA *list_element) return status; } +/** + * @brief Set the callback for a Remove_List_Element successful operation + * @param cb [in] The function to be called, or NULL to disable + */ +void Device_Remove_List_Element_Callback_Set(list_element_function cb) +{ + Device_Remove_List_Element_Callback = cb; +} + /** * @brief RemoveListElement from an object list property * @param list_element [in] Pointer to the BACnet_List_Element_Data structure, @@ -2558,6 +2632,9 @@ int Device_Remove_List_Element(BACNET_LIST_ELEMENT_DATA *list_element) pObject->Object_Valid_Instance(list_element->object_instance)) { if (pObject->Object_Remove_List_Element) { status = pObject->Object_Remove_List_Element(list_element); + if (status) { + Device_Remove_List_Element_Callback(list_element); + } } else { list_element->error_class = ERROR_CLASS_PROPERTY; list_element->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; diff --git a/test/bacnet/basic/server/bacnet_device/CMakeLists.txt b/test/bacnet/basic/server/bacnet_device/CMakeLists.txt index 75cc76d6..09462e36 100644 --- a/test/bacnet/basic/server/bacnet_device/CMakeLists.txt +++ b/test/bacnet/basic/server/bacnet_device/CMakeLists.txt @@ -41,6 +41,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/bacaction.c ${SRC_DIR}/bacnet/bacaddr.c ${SRC_DIR}/bacnet/bacapp.c + ${SRC_DIR}/bacnet/bacaudit.c ${SRC_DIR}/bacnet/bacdcode.c ${SRC_DIR}/bacnet/bacdest.c ${SRC_DIR}/bacnet/bacdevobjpropref.c @@ -56,6 +57,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/basic/object/ai.c ${SRC_DIR}/bacnet/basic/object/ao.c ${SRC_DIR}/bacnet/basic/object/av.c + ${SRC_DIR}/bacnet/basic/object/auditlog.c ${SRC_DIR}/bacnet/basic/object/bi.c ${SRC_DIR}/bacnet/basic/object/bitstring_value.c ${SRC_DIR}/bacnet/basic/object/blo.c