From 1437a68ce1290d5b0d36bf32c5f97ce89e6a4ecb Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Thu, 26 Feb 2026 16:25:03 -0600 Subject: [PATCH] Add CreateObject and DeleteObject for Octet String and Positive Integer Values (#1246) * Added CreateObject and DeleteObject for basic Octet String Value and Positive Integer Value objects. * Changed PositiveInteger present-value datatype to BACNET_UNSIGNED_INTEGER. --- CHANGELOG.md | 4 + apps/blinkt/Makefile | 1 + apps/server-basic/Makefile | 1 + src/bacnet/basic/object/device.c | 5 +- src/bacnet/basic/object/osv.c | 284 ++++++++++++++----- src/bacnet/basic/object/osv.h | 12 +- src/bacnet/basic/object/piv.c | 290 ++++++++++++++------ src/bacnet/basic/object/piv.h | 20 +- src/bacnet/basic/server/bacnet_device.c | 52 ++++ test/bacnet/basic/object/osv/CMakeLists.txt | 5 +- test/bacnet/basic/object/osv/src/main.c | 78 +++--- test/bacnet/basic/object/piv/CMakeLists.txt | 5 +- test/bacnet/basic/object/piv/src/main.c | 76 ++--- 13 files changed, 599 insertions(+), 234 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4b10183..8fc6d8b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,8 @@ The git repositories are hosted at the following sites: ### Added +* Added CreateObject and DeleteObject for Octet StringValue and + PositiveInteger Value objects. (#1246) * Added PROP_TIMER_RUNNING to writable properties and implement Timer_Running_Set functionality. (#1245) * Added BACNET_STACK_DEPRECATED_DISABLE guards around all of the deprecated @@ -150,6 +152,8 @@ The git repositories are hosted at the following sites: ### Changed +* Changed PositiveInteger present-value datatype to + BACNET_UNSIGNED_INTEGER. (#1246) * Changed BACFILE define dependencies to reflect bacfile-posix.c dependence since bacfile.c is now independent of any back end file system. (#1227) * Changed the default BACnet protocol revision to 28 to enable usage of diff --git a/apps/blinkt/Makefile b/apps/blinkt/Makefile index 7adc6cad..0b08bf7e 100644 --- a/apps/blinkt/Makefile +++ b/apps/blinkt/Makefile @@ -46,6 +46,7 @@ SRC = main.c blinkt.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)/structured_view.c \ $(BACNET_OBJECT_DIR)/timer.c \ diff --git a/apps/server-basic/Makefile b/apps/server-basic/Makefile index 584dab2b..0badcfd7 100644 --- a/apps/server-basic/Makefile +++ b/apps/server-basic/Makefile @@ -40,6 +40,7 @@ SRC = main.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)/structured_view.c \ $(BACNET_OBJECT_DIR)/timer.c \ diff --git a/src/bacnet/basic/object/device.c b/src/bacnet/basic/object/device.c index e5eab3e3..916ffc2f 100644 --- a/src/bacnet/basic/object/device.c +++ b/src/bacnet/basic/object/device.c @@ -218,7 +218,7 @@ static object_functions_t My_Object_Table[] = { NULL /* ReadRangeInfo */, NULL /* Iterator */, NULL /* Value_Lists */, NULL /* COV */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */, NULL /* Add_List_Element */, NULL /* Remove_List_Element */, - NULL /* Create */, NULL /* Delete */, NULL /* Timer */, + OctetString_Value_Create, OctetString_Value_Delete, NULL /* Timer */, OctetString_Value_Writable_Property_List }, { OBJECT_POSITIVE_INTEGER_VALUE, PositiveInteger_Value_Init, PositiveInteger_Value_Count, PositiveInteger_Value_Index_To_Instance, @@ -229,7 +229,8 @@ static object_functions_t My_Object_Table[] = { NULL /* Iterator */, NULL /* Value_Lists */, NULL /* COV */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */, NULL /* Add_List_Element */, NULL /* Remove_List_Element */, - NULL /* Create */, NULL /* Delete */, NULL /* Timer */, + PositiveInteger_Value_Create, PositiveInteger_Value_Delete, + NULL /* Timer */, PositiveInteger_Value_Writable_Property_List }, { OBJECT_TIME_VALUE, Time_Value_Init, Time_Value_Count, Time_Value_Index_To_Instance, Time_Value_Valid_Instance, diff --git a/src/bacnet/basic/object/osv.c b/src/bacnet/basic/object/osv.c index 4680f4ef..c6649c74 100644 --- a/src/bacnet/basic/object/osv.c +++ b/src/bacnet/basic/object/osv.c @@ -9,6 +9,7 @@ #include #include #include +#include /* BACnet Stack defines - first */ #include "bacnet/bacdef.h" /* BACnet Stack API */ @@ -17,13 +18,11 @@ #include "bacnet/bactext.h" #include "bacnet/basic/object/device.h" #include "bacnet/basic/services.h" +#include "bacnet/basic/sys/keylist.h" #include "bacnet/basic/object/osv.h" -#ifndef MAX_OCTETSTRING_VALUES -#define MAX_OCTETSTRING_VALUES 4 -#endif - -static OCTETSTRING_VALUE_DESCR OSV_Descr[MAX_OCTETSTRING_VALUES]; +/* Key List for storing object data sorted by instance number */ +static OS_Keylist Object_List = NULL; /* These three arrays are used by the ReadPropertyMultiple handler */ static const int32_t Properties_Required[] = { @@ -48,6 +47,12 @@ static const int32_t Writable_Properties[] = { PROP_PRESENT_VALUE, PROP_OUT_OF_SERVICE, -1 }; +/** + * @brief Retrieves property identifier lists for Octet String Value objects. + * @param pRequired Optional pointer to receive required property list. + * @param pOptional Optional pointer to receive optional property list. + * @param pProprietary Optional pointer to receive proprietary property list. + */ void OctetString_Value_Property_Lists( const int32_t **pRequired, const int32_t **pOptional, @@ -80,55 +85,128 @@ void OctetString_Value_Writable_Property_List( } } -void OctetString_Value_Init(void) +/** + * @brief Finds an Octet String Value object descriptor by instance number. + * @param object_instance Object instance number. + * @return Pointer to object descriptor, or NULL if not found. + */ +static OCTETSTRING_VALUE_DESCR * +OctetString_Value_Object(uint32_t object_instance) { - unsigned i; - - for (i = 0; i < MAX_OCTETSTRING_VALUES; i++) { - memset(&OSV_Descr[i], 0x00, sizeof(OCTETSTRING_VALUE_DESCR)); - octetstring_init(&OSV_Descr[i].Present_Value, NULL, 0); - } + return Keylist_Data(Object_List, object_instance); } -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need validate that the */ -/* given instance exists */ -bool OctetString_Value_Valid_Instance(uint32_t object_instance) +/** + * @brief Creates an Octet String Value object instance. + * @param object_instance Requested object instance number, or + * BACNET_MAX_INSTANCE for auto-allocation. + * @return Created instance number, or BACNET_MAX_INSTANCE on failure. + */ +uint32_t OctetString_Value_Create(uint32_t object_instance) { - if (object_instance < MAX_OCTETSTRING_VALUES) { + OCTETSTRING_VALUE_DESCR *pObject = NULL; + int index = 0; + + if (!Object_List) { + Object_List = Keylist_Create(); + } + if (object_instance > BACNET_MAX_INSTANCE) { + return BACNET_MAX_INSTANCE; + } else if (object_instance == BACNET_MAX_INSTANCE) { + object_instance = Keylist_Next_Empty_Key(Object_List, 1); + } + pObject = OctetString_Value_Object(object_instance); + if (!pObject) { + pObject = calloc(1, sizeof(OCTETSTRING_VALUE_DESCR)); + if (!pObject) { + return BACNET_MAX_INSTANCE; + } + index = Keylist_Data_Add(Object_List, object_instance, pObject); + if (index < 0) { + free(pObject); + return BACNET_MAX_INSTANCE; + } + octetstring_init(&pObject->Present_Value, NULL, 0); + pObject->Out_Of_Service = false; + pObject->Event_State = EVENT_STATE_NORMAL; + } + + return object_instance; +} + +/** + * @brief Deletes an Octet String Value object instance. + * @param object_instance Object instance number. + * @return true if object existed and was deleted. + */ +bool OctetString_Value_Delete(uint32_t object_instance) +{ + OCTETSTRING_VALUE_DESCR *pObject = NULL; + + pObject = Keylist_Data_Delete(Object_List, object_instance); + if (pObject) { + free(pObject); return true; } return false; } -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then count how many you have */ +/** + * @brief Initializes Octet String Value object instances. + */ +void OctetString_Value_Init(void) +{ +#ifdef MAX_OCTETSTRING_VALUES + unsigned i = 0; + + for (i = 0; i < MAX_OCTETSTRING_VALUES; i++) { + OctetString_Value_Create(i); + } +#endif +} + +/** + * @brief Checks whether an Octet String Value instance exists. + * @param object_instance Object instance number. + * @return true if the instance exists. + */ +bool OctetString_Value_Valid_Instance(uint32_t object_instance) +{ + return (OctetString_Value_Object(object_instance) != NULL); +} + +/** + * @brief Gets the number of Octet String Value instances. + * @return Number of object instances. + */ unsigned OctetString_Value_Count(void) { - return MAX_OCTETSTRING_VALUES; + return Keylist_Count(Object_List); } -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need to return the instance */ -/* that correlates to the correct index */ +/** + * @brief Maps an object list index to an instance number. + * @param index Zero-based object index. + * @return Object instance number, or UINT32_MAX if index is invalid. + */ uint32_t OctetString_Value_Index_To_Instance(unsigned index) { - return index; + KEY key = UINT32_MAX; + + Keylist_Index_Key(Object_List, index, &key); + + return key; } -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need to return the index */ -/* that correlates to the correct instance number */ +/** + * @brief Maps an instance number to object list index. + * @param object_instance Object instance number. + * @return Zero-based object index. + */ unsigned OctetString_Value_Instance_To_Index(uint32_t object_instance) { - unsigned index = MAX_OCTETSTRING_VALUES; - - if (object_instance < MAX_OCTETSTRING_VALUES) { - index = object_instance; - } - - return index; + return Keylist_Index(Object_List, object_instance); } /** @@ -146,59 +224,119 @@ bool OctetString_Value_Present_Value_Set( const BACNET_OCTET_STRING *value, uint8_t priority) { - unsigned index = 0; + OCTETSTRING_VALUE_DESCR *pObject = NULL; bool status = false; (void)priority; - index = OctetString_Value_Instance_To_Index(object_instance); - if (index < MAX_OCTETSTRING_VALUES) { - octetstring_copy(&OSV_Descr[index].Present_Value, value); + pObject = OctetString_Value_Object(object_instance); + if (pObject) { + octetstring_copy(&pObject->Present_Value, value); status = true; } + return status; } +/** + * @brief Gets the present value for an Octet String Value object. + * @param object_instance Object instance number. + * @return Pointer to present value, or NULL if object does not exist. + */ BACNET_OCTET_STRING *OctetString_Value_Present_Value(uint32_t object_instance) { BACNET_OCTET_STRING *value = NULL; - unsigned index = 0; + OCTETSTRING_VALUE_DESCR *pObject = NULL; - index = OctetString_Value_Instance_To_Index(object_instance); - if (index < MAX_OCTETSTRING_VALUES) { - value = &OSV_Descr[index].Present_Value; + pObject = OctetString_Value_Object(object_instance); + if (pObject) { + value = &pObject->Present_Value; } return value; } -/* note: the object name must be unique within this device */ +/** + * @brief Gets the object name for an Octet String Value object. + * @param object_instance Object instance number. + * @param object_name Pointer to string storage for resulting object name. + * @return true if object name is generated successfully. + */ bool OctetString_Value_Object_Name( uint32_t object_instance, BACNET_CHARACTER_STRING *object_name) { char text[32] = ""; bool status = false; + OCTETSTRING_VALUE_DESCR *pObject = NULL; - if (object_instance < MAX_OCTETSTRING_VALUES) { - snprintf( - text, sizeof(text), "OCTETSTRING VALUE %lu", - (unsigned long)object_instance); - status = characterstring_init_ansi(object_name, text); + pObject = OctetString_Value_Object(object_instance); + if (pObject) { + if (pObject->Object_Name) { + status = + characterstring_init_ansi(object_name, pObject->Object_Name); + } else { + snprintf( + text, sizeof(text), "OCTETSTRING VALUE %lu", + (unsigned long)object_instance); + status = characterstring_init_ansi(object_name, text); + } } return status; } -/* return apdu len, or BACNET_STATUS_ERROR on error */ +/** + * @brief For a given object instance-number, sets the object-name + * Note that the object name must be unique within this device. + * @param object_instance - object-instance number of the object + * @param new_name - holds the object-name to be set + * @return true if object-name was set + */ +bool OctetString_Value_Name_Set(uint32_t object_instance, const char *new_name) +{ + bool status = false; /* return value */ + OCTETSTRING_VALUE_DESCR *pObject; + + pObject = OctetString_Value_Object(object_instance); + if (pObject) { + status = true; + pObject->Object_Name = new_name; + } + + return status; +} + +/** + * @brief Return the object name C string + * @param object_instance [in] BACnet object instance number + * @return object name or NULL if not found + */ +const char *OctetString_Value_Name_ASCII(uint32_t object_instance) +{ + const char *name = NULL; + OCTETSTRING_VALUE_DESCR *pObject; + + pObject = OctetString_Value_Object(object_instance); + if (pObject) { + name = pObject->Object_Name; + } + + return name; +} + +/** + * @brief Encodes a read-property response for an Octet String Value object. + * @param rpdata Read property request/response context. + * @return Encoded APDU length, or BACNET_STATUS_ERROR on error. + */ int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) { int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; BACNET_OCTET_STRING *real_value = NULL; - unsigned object_index = 0; bool state = false; uint8_t *apdu = NULL; - OCTETSTRING_VALUE_DESCR *CurrentAV; + OCTETSTRING_VALUE_DESCR *pObject = NULL; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { @@ -207,10 +345,10 @@ int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) apdu = rpdata->application_data; - object_index = OctetString_Value_Instance_To_Index(rpdata->object_instance); - if (object_index < MAX_OCTETSTRING_VALUES) { - CurrentAV = &OSV_Descr[object_index]; - } else { + pObject = OctetString_Value_Object(rpdata->object_instance); + if (!pObject) { + rpdata->error_class = ERROR_CLASS_OBJECT; + rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT; return BACNET_STATUS_ERROR; } @@ -246,7 +384,7 @@ int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit( &bit_string, STATUS_FLAG_OUT_OF_SERVICE, - CurrentAV->Out_Of_Service); + pObject->Out_Of_Service); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; @@ -257,7 +395,7 @@ int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OUT_OF_SERVICE: - state = CurrentAV->Out_Of_Service; + state = pObject->Out_Of_Service; apdu_len = encode_application_boolean(&apdu[0], state); break; default: @@ -270,14 +408,24 @@ int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) return apdu_len; } -/* returns true if successful */ +/** + * @brief Processes a write-property request for an Octet String Value object. + * @param wp_data Write property request/response context. + * @return true if property write is successful. + */ bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) { bool status = false; /* return value */ - unsigned int object_index = 0; int len = 0; BACNET_APPLICATION_DATA_VALUE value = { 0 }; - OCTETSTRING_VALUE_DESCR *CurrentAV; + OCTETSTRING_VALUE_DESCR *pObject = NULL; + + if (wp_data == NULL) { + return false; + } + if (wp_data->application_data_len == 0) { + return false; + } /* decode the some of the request */ len = bacapp_decode_application_data( @@ -289,11 +437,10 @@ bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; return false; } - object_index = - OctetString_Value_Instance_To_Index(wp_data->object_instance); - if (object_index < MAX_OCTETSTRING_VALUES) { - CurrentAV = &OSV_Descr[object_index]; - } else { + pObject = OctetString_Value_Object(wp_data->object_instance); + if (!pObject) { + wp_data->error_class = ERROR_CLASS_OBJECT; + wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT; return false; } @@ -326,7 +473,7 @@ bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) status = write_property_type_valid( wp_data, &value, BACNET_APPLICATION_TAG_BOOLEAN); if (status) { - CurrentAV->Out_Of_Service = value.type.Boolean; + pObject->Out_Of_Service = value.type.Boolean; } break; default: @@ -344,8 +491,3 @@ bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) return status; } - -void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance) -{ - (void)object_instance; -} diff --git a/src/bacnet/basic/object/osv.h b/src/bacnet/basic/object/osv.h index 1e0abcb7..752baaeb 100644 --- a/src/bacnet/basic/object/osv.h +++ b/src/bacnet/basic/object/osv.h @@ -24,6 +24,7 @@ typedef struct octetstring_value_descr { unsigned Event_State : 3; bool Out_Of_Service; BACNET_OCTET_STRING Present_Value; + const char *Object_Name; } OCTETSTRING_VALUE_DESCR; BACNET_STACK_EXPORT @@ -47,6 +48,10 @@ unsigned OctetString_Value_Instance_To_Index(uint32_t object_instance); BACNET_STACK_EXPORT bool OctetString_Value_Object_Name( uint32_t object_instance, BACNET_CHARACTER_STRING *object_name); +BACNET_STACK_EXPORT +bool OctetString_Value_Name_Set(uint32_t object_instance, const char *new_name); +BACNET_STACK_EXPORT +const char *OctetString_Value_Name_ASCII(uint32_t object_instance); BACNET_STACK_EXPORT int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata); @@ -80,8 +85,11 @@ bool OctetString_Value_Out_Of_Service(uint32_t instance); BACNET_STACK_EXPORT void OctetString_Value_Out_Of_Service_Set(uint32_t instance, bool oos_flag); -/* note: header of Intrinsic_Reporting function is required - even when INTRINSIC_REPORTING is not defined */ +BACNET_STACK_EXPORT +uint32_t OctetString_Value_Create(uint32_t object_instance); +BACNET_STACK_EXPORT +bool OctetString_Value_Delete(uint32_t object_instance); + BACNET_STACK_EXPORT void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance); diff --git a/src/bacnet/basic/object/piv.c b/src/bacnet/basic/object/piv.c index d34d5071..3f728ff1 100644 --- a/src/bacnet/basic/object/piv.c +++ b/src/bacnet/basic/object/piv.c @@ -9,6 +9,7 @@ #include #include #include +#include /* BACnet Stack defines - first */ #include "bacnet/bacdef.h" /* BACnet Stack API */ @@ -17,13 +18,13 @@ #include "bacnet/bactext.h" #include "bacnet/basic/object/device.h" #include "bacnet/basic/services.h" +#include "bacnet/basic/sys/keylist.h" #include "bacnet/basic/object/piv.h" -#ifndef MAX_POSITIVEINTEGER_VALUES -#define MAX_POSITIVEINTEGER_VALUES 4 -#endif - -static POSITIVEINTEGER_VALUE_DESCR PIV_Descr[MAX_POSITIVEINTEGER_VALUES]; +/* Key List for storing object data sorted by instance number */ +static OS_Keylist Object_List = NULL; +/* common object type */ +static const BACNET_OBJECT_TYPE Object_Type = OBJECT_POSITIVE_INTEGER_VALUE; /* These three arrays are used by the ReadPropertyMultiple handler */ static const int32_t Properties_Required[] = { @@ -97,56 +98,131 @@ void PositiveInteger_Value_Writable_Property_List( } /** - * @brief Initializes the Positive Integer Value objects + * @brief Finds a Positive Integer Value object descriptor by instance number. + * @param object_instance Object instance number. + * @return Pointer to object descriptor, or NULL if not found. */ -void PositiveInteger_Value_Init(void) +static POSITIVEINTEGER_VALUE_DESCR * +PositiveInteger_Value_Object(uint32_t object_instance) { - unsigned i; - - for (i = 0; i < MAX_POSITIVEINTEGER_VALUES; i++) { - memset(&PIV_Descr[i], 0x00, sizeof(POSITIVEINTEGER_VALUE_DESCR)); - } + return Keylist_Data(Object_List, object_instance); } -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need validate that the */ -/* given instance exists */ -bool PositiveInteger_Value_Valid_Instance(uint32_t object_instance) +/** + * @brief Creates a Positive Integer Value object instance. + * @param object_instance Requested object instance number, or + * BACNET_MAX_INSTANCE for auto-allocation. + * @return Created instance number, or BACNET_MAX_INSTANCE on failure. + */ +uint32_t PositiveInteger_Value_Create(uint32_t object_instance) { - if (object_instance < MAX_POSITIVEINTEGER_VALUES) { + POSITIVEINTEGER_VALUE_DESCR *pObject = NULL; + int index = 0; + + if (!Object_List) { + Object_List = Keylist_Create(); + } + if (object_instance > BACNET_MAX_INSTANCE) { + return BACNET_MAX_INSTANCE; + } else if (object_instance == BACNET_MAX_INSTANCE) { + object_instance = Keylist_Next_Empty_Key(Object_List, 1); + } + pObject = PositiveInteger_Value_Object(object_instance); + if (!pObject) { + pObject = calloc(1, sizeof(POSITIVEINTEGER_VALUE_DESCR)); + if (!pObject) { + return BACNET_MAX_INSTANCE; + } + index = Keylist_Data_Add(Object_List, object_instance, pObject); + if (index < 0) { + free(pObject); + return BACNET_MAX_INSTANCE; + } + pObject->Out_Of_Service = false; + pObject->Present_Value = 0; + pObject->Units = UNITS_NO_UNITS; + pObject->Object_Name = NULL; + } + + return object_instance; +} + +/** + * @brief Deletes a Positive Integer Value object instance. + * @param object_instance Object instance number. + * @return true if object existed and was deleted. + */ +bool PositiveInteger_Value_Delete(uint32_t object_instance) +{ + POSITIVEINTEGER_VALUE_DESCR *pObject = NULL; + + pObject = Keylist_Data_Delete(Object_List, object_instance); + if (pObject) { + free(pObject); return true; } return false; } -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then count how many you have */ +/** + * @brief Initializes the Positive Integer Value objects + */ +void PositiveInteger_Value_Init(void) +{ +#ifdef MAX_POSITIVEINTEGER_VALUES + unsigned i = 0; + + if (!Object_List) { + Object_List = Keylist_Create(); + } + for (i = 0; i < MAX_POSITIVEINTEGER_VALUES; i++) { + PositiveInteger_Value_Create(i); + } +#endif +} + +/** + * @brief Checks whether a Positive Integer Value instance exists. + * @param object_instance Object instance number. + * @return true if the instance exists. + */ +bool PositiveInteger_Value_Valid_Instance(uint32_t object_instance) +{ + return (PositiveInteger_Value_Object(object_instance) != NULL); +} + +/** + * @brief Gets the number of Positive Integer Value instances. + * @return Number of object instances. + */ unsigned PositiveInteger_Value_Count(void) { - return MAX_POSITIVEINTEGER_VALUES; + return Keylist_Count(Object_List); } -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need to return the instance */ -/* that correlates to the correct index */ +/** + * @brief Maps an object list index to an instance number. + * @param index Zero-based object index. + * @return Object instance number, or UINT32_MAX if index is invalid. + */ uint32_t PositiveInteger_Value_Index_To_Instance(unsigned index) { - return index; + KEY key = UINT32_MAX; + + Keylist_Index_Key(Object_List, index, &key); + + return key; } -/* we simply have 0-n object instances. Yours might be */ -/* more complex, and then you need to return the index */ -/* that correlates to the correct instance number */ +/** + * @brief Maps an instance number to object list index. + * @param object_instance Object instance number. + * @return Zero-based object index. + */ unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance) { - unsigned index = MAX_POSITIVEINTEGER_VALUES; - - if (object_instance < MAX_POSITIVEINTEGER_VALUES) { - index = object_instance; - } - - return index; + return Keylist_Index(Object_List, object_instance); } /** @@ -160,51 +236,109 @@ unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance) * @return true if values are within range and present-value is set. */ bool PositiveInteger_Value_Present_Value_Set( - uint32_t object_instance, uint32_t value, uint8_t priority) + uint32_t object_instance, BACNET_UNSIGNED_INTEGER value, uint8_t priority) { - unsigned index = 0; + POSITIVEINTEGER_VALUE_DESCR *pObject = NULL; bool status = false; (void)priority; - index = PositiveInteger_Value_Instance_To_Index(object_instance); - if (index < MAX_POSITIVEINTEGER_VALUES) { - PIV_Descr[index].Present_Value = value; + pObject = PositiveInteger_Value_Object(object_instance); + if (pObject) { + pObject->Present_Value = value; status = true; } return status; } -uint32_t PositiveInteger_Value_Present_Value(uint32_t object_instance) +/** + * @brief Gets the present value for a Positive Integer Value object. + * @param object_instance Object instance number. + * @return Present value, or 0 if object does not exist. + */ +BACNET_UNSIGNED_INTEGER +PositiveInteger_Value_Present_Value(uint32_t object_instance) { - uint32_t value = 0; - unsigned index = 0; + BACNET_UNSIGNED_INTEGER value = 0; + POSITIVEINTEGER_VALUE_DESCR *pObject = NULL; - index = PositiveInteger_Value_Instance_To_Index(object_instance); - if (index < MAX_POSITIVEINTEGER_VALUES) { - value = PIV_Descr[index].Present_Value; + pObject = PositiveInteger_Value_Object(object_instance); + if (pObject) { + value = pObject->Present_Value; } return value; } -/* note: the object name must be unique within this device */ +/** + * @brief Gets the object name for a Positive Integer Value object. + * @param object_instance Object instance number. + * @param object_name Pointer to string storage for resulting object name. + * @return true if object name is generated successfully. + */ bool PositiveInteger_Value_Object_Name( uint32_t object_instance, BACNET_CHARACTER_STRING *object_name) { - char text[32] = ""; + char text[48] = ""; bool status = false; + POSITIVEINTEGER_VALUE_DESCR *pObject = NULL; - if (object_instance < MAX_POSITIVEINTEGER_VALUES) { - snprintf( - text, sizeof(text), "POSITIVEINTEGER VALUE %lu", - (unsigned long)object_instance); - status = characterstring_init_ansi(object_name, text); + pObject = PositiveInteger_Value_Object(object_instance); + if (pObject) { + if (pObject->Object_Name) { + status = + characterstring_init_ansi(object_name, pObject->Object_Name); + } else { + snprintf( + text, sizeof(text), "POSITIVEINTEGER VALUE %lu", + (unsigned long)object_instance); + status = characterstring_init_ansi(object_name, text); + } } return status; } +/** + * @brief For a given object instance-number, sets the object-name + * Note that the object name must be unique within this device. + * @param object_instance - object-instance number of the object + * @param new_name - holds the object-name to be set + * @return true if object-name was set + */ +bool PositiveInteger_Value_Name_Set( + uint32_t object_instance, const char *new_name) +{ + bool status = false; /* return value */ + POSITIVEINTEGER_VALUE_DESCR *pObject; + + pObject = PositiveInteger_Value_Object(object_instance); + if (pObject) { + status = true; + pObject->Object_Name = new_name; + } + + return status; +} + +/** + * @brief Return the object name C string + * @param object_instance [in] BACnet object instance number + * @return object name or NULL if not found + */ +const char *PositiveInteger_Value_Name_ASCII(uint32_t object_instance) +{ + const char *name = NULL; + POSITIVEINTEGER_VALUE_DESCR *pObject; + + pObject = PositiveInteger_Value_Object(object_instance); + if (pObject) { + name = pObject->Object_Name; + } + + return name; +} + /** * ReadProperty handler for this object. For the given ReadProperty * data, the application_data is loaded or the error flags are set. @@ -220,10 +354,9 @@ int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; - unsigned object_index = 0; bool state = false; uint8_t *apdu = NULL; - POSITIVEINTEGER_VALUE_DESCR *CurrentAV; + POSITIVEINTEGER_VALUE_DESCR *pObject = NULL; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { @@ -232,19 +365,17 @@ int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) apdu = rpdata->application_data; - object_index = - PositiveInteger_Value_Instance_To_Index(rpdata->object_instance); - if (object_index < MAX_POSITIVEINTEGER_VALUES) { - CurrentAV = &PIV_Descr[object_index]; - } else { + pObject = PositiveInteger_Value_Object(rpdata->object_instance); + if (!pObject) { + rpdata->error_class = ERROR_CLASS_OBJECT; + rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT; return BACNET_STATUS_ERROR; } switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id( - &apdu[0], OBJECT_POSITIVE_INTEGER_VALUE, - rpdata->object_instance); + &apdu[0], Object_Type, rpdata->object_instance); break; case PROP_OBJECT_NAME: @@ -255,8 +386,7 @@ int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_TYPE: - apdu_len = encode_application_enumerated( - &apdu[0], OBJECT_POSITIVE_INTEGER_VALUE); + apdu_len = encode_application_enumerated(&apdu[0], Object_Type); break; case PROP_PRESENT_VALUE: @@ -272,14 +402,14 @@ int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit( &bit_string, STATUS_FLAG_OUT_OF_SERVICE, - CurrentAV->Out_Of_Service); + pObject->Out_Of_Service); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_UNITS: apdu_len = encode_application_enumerated( - &apdu[0], (uint32_t)CurrentAV->Units); + &apdu[0], (uint32_t)pObject->Units); break; /* BACnet Testing Observed Incident oi00109 Positive Integer Value / Units returned wrong datatype - @@ -291,7 +421,7 @@ int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) parties. Say 6 months -> September 2016 */ case PROP_OUT_OF_SERVICE: - state = CurrentAV->Out_Of_Service; + state = pObject->Out_Of_Service; apdu_len = encode_application_boolean(&apdu[0], state); break; default: @@ -316,10 +446,16 @@ int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) { bool status = false; /* return value */ - unsigned int object_index = 0; int len = 0; BACNET_APPLICATION_DATA_VALUE value = { 0 }; - POSITIVEINTEGER_VALUE_DESCR *CurrentAV; + POSITIVEINTEGER_VALUE_DESCR *pObject = NULL; + + if (wp_data == NULL) { + return false; + } + if (wp_data->application_data_len == 0) { + return false; + } /* decode the some of the request */ len = bacapp_decode_application_data( @@ -331,11 +467,10 @@ bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; return false; } - object_index = - PositiveInteger_Value_Instance_To_Index(wp_data->object_instance); - if (object_index < MAX_POSITIVEINTEGER_VALUES) { - CurrentAV = &PIV_Descr[object_index]; - } else { + pObject = PositiveInteger_Value_Object(wp_data->object_instance); + if (!pObject) { + wp_data->error_class = ERROR_CLASS_OBJECT; + wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT; return false; } switch (wp_data->object_property) { @@ -366,7 +501,7 @@ bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) status = write_property_type_valid( wp_data, &value, BACNET_APPLICATION_TAG_BOOLEAN); if (status) { - CurrentAV->Out_Of_Service = value.type.Boolean; + pObject->Out_Of_Service = value.type.Boolean; } break; case PROP_UNITS: @@ -374,7 +509,7 @@ bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) wp_data, &value, BACNET_APPLICATION_TAG_ENUMERATED); if (status) { if (value.type.Enumerated <= UINT16_MAX) { - CurrentAV->Units = (uint16_t)value.type.Enumerated; + pObject->Units = (uint16_t)value.type.Enumerated; } else { status = false; wp_data->error_class = ERROR_CLASS_PROPERTY; @@ -397,8 +532,3 @@ bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) return status; } - -void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance) -{ - (void)object_instance; -} diff --git a/src/bacnet/basic/object/piv.h b/src/bacnet/basic/object/piv.h index 52f72c5b..457291a7 100644 --- a/src/bacnet/basic/object/piv.h +++ b/src/bacnet/basic/object/piv.h @@ -22,8 +22,9 @@ extern "C" { typedef struct positiveinteger_value_descr { bool Out_Of_Service : 1; - uint32_t Present_Value; + BACNET_UNSIGNED_INTEGER Present_Value; BACNET_ENGINEERING_UNITS Units; + const char *Object_Name; } POSITIVEINTEGER_VALUE_DESCR; BACNET_STACK_EXPORT @@ -46,6 +47,11 @@ unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance); BACNET_STACK_EXPORT bool PositiveInteger_Value_Object_Name( uint32_t object_instance, BACNET_CHARACTER_STRING *object_name); +BACNET_STACK_EXPORT +bool PositiveInteger_Value_Name_Set( + uint32_t object_instance, const char *new_name); +BACNET_STACK_EXPORT +const char *PositiveInteger_Value_Name_ASCII(uint32_t object_instance); BACNET_STACK_EXPORT int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata); @@ -55,9 +61,10 @@ bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data); BACNET_STACK_EXPORT bool PositiveInteger_Value_Present_Value_Set( - uint32_t object_instance, uint32_t value, uint8_t priority); + uint32_t object_instance, BACNET_UNSIGNED_INTEGER value, uint8_t priority); BACNET_STACK_EXPORT -uint32_t PositiveInteger_Value_Present_Value(uint32_t object_instance); +BACNET_UNSIGNED_INTEGER +PositiveInteger_Value_Present_Value(uint32_t object_instance); BACNET_STACK_EXPORT bool PositiveInteger_Value_Change_Of_Value(uint32_t instance); @@ -78,8 +85,11 @@ bool PositiveInteger_Value_Out_Of_Service(uint32_t instance); BACNET_STACK_EXPORT void PositiveInteger_Value_Out_Of_Service_Set(uint32_t instance, bool oos_flag); -/* note: header of Intrinsic_Reporting function is required - even when INTRINSIC_REPORTING is not defined */ +BACNET_STACK_EXPORT +uint32_t PositiveInteger_Value_Create(uint32_t object_instance); +BACNET_STACK_EXPORT +bool PositiveInteger_Value_Delete(uint32_t object_instance); + BACNET_STACK_EXPORT void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance); diff --git a/src/bacnet/basic/server/bacnet_device.c b/src/bacnet/basic/server/bacnet_device.c index ce031501..c682b358 100644 --- a/src/bacnet/basic/server/bacnet_device.c +++ b/src/bacnet/basic/server/bacnet_device.c @@ -45,6 +45,8 @@ #include "bacnet/basic/object/ms-input.h" #include "bacnet/basic/object/mso.h" #include "bacnet/basic/object/msv.h" +#include "bacnet/basic/object/osv.h" +#include "bacnet/basic/object/piv.h" #include "bacnet/basic/object/schedule.h" #include "bacnet/basic/object/structured_view.h" #include "bacnet/basic/object/trendlog.h" @@ -122,6 +124,7 @@ defined(CONFIG_BACNET_BASIC_OBJECT_NETWORK_PORT) || \ defined(CONFIG_BACNET_BASIC_OBJECT_CALENDAR) || \ defined(CONFIG_BACNET_BASIC_OBJECT_INTEGER_VALUE) || \ + defined(CONFIG_BACNET_BASIC_OBJECT_POSITIVE_INTEGER_VALUE) || \ defined(CONFIG_BACNET_BASIC_OBJECT_LIFE_SAFETY_POINT) || \ defined(CONFIG_BACNET_BASIC_OBJECT_LIFE_SAFETY_ZONE) || \ defined(CONFIG_BACNET_BASIC_OBJECT_LIGHTING_OUTPUT) || \ @@ -133,6 +136,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_OCTETSTRING_VALUE) || \ defined(CONFIG_BACNET_BASIC_OBJECT_TIME_VALUE) || \ defined(CONFIG_BACNET_BASIC_OBJECT_TIMER) || \ defined(CONFIG_BACNET_BASIC_OBJECT_LOOP) || \ @@ -155,6 +159,7 @@ #define CONFIG_BACNET_BASIC_OBJECT_NETWORK_PORT #define CONFIG_BACNET_BASIC_OBJECT_CALENDAR #define CONFIG_BACNET_BASIC_OBJECT_INTEGER_VALUE +#define CONFIG_BACNET_BASIC_OBJECT_POSITIVE_INTEGER_VALUE #define CONFIG_BACNET_BASIC_OBJECT_LIFE_SAFETY_POINT #define CONFIG_BACNET_BASIC_OBJECT_LIFE_SAFETY_ZONE #define CONFIG_BACNET_BASIC_OBJECT_LIGHTING_OUTPUT @@ -166,6 +171,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_OCTETSTRING_VALUE #define CONFIG_BACNET_BASIC_OBJECT_TIME_VALUE #define CONFIG_BACNET_BASIC_OBJECT_TIMER #define CONFIG_BACNET_BASIC_OBJECT_LOOP @@ -813,6 +819,52 @@ static object_functions_t My_Object_Table[] = { NULL /* Timer */, CharacterString_Value_Writable_Property_List }, #endif +#if defined(CONFIG_BACNET_BASIC_OBJECT_OCTETSTRING_VALUE) + { OBJECT_OCTETSTRING_VALUE, + OctetString_Value_Init, + OctetString_Value_Count, + OctetString_Value_Index_To_Instance, + OctetString_Value_Valid_Instance, + OctetString_Value_Object_Name, + OctetString_Value_Read_Property, + OctetString_Value_Write_Property, + OctetString_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 */, + OctetString_Value_Create, + OctetString_Value_Delete, + NULL /* Timer */, + OctetString_Value_Writable_Property_List }, +#endif +#if defined(CONFIG_BACNET_BASIC_OBJECT_POSITIVE_INTEGER_VALUE) + { OBJECT_POSITIVE_INTEGER_VALUE, + PositiveInteger_Value_Init, + PositiveInteger_Value_Count, + PositiveInteger_Value_Index_To_Instance, + PositiveInteger_Value_Valid_Instance, + PositiveInteger_Value_Object_Name, + PositiveInteger_Value_Read_Property, + PositiveInteger_Value_Write_Property, + PositiveInteger_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 */, + PositiveInteger_Value_Create, + PositiveInteger_Value_Delete, + NULL /* Timer */, + PositiveInteger_Value_Writable_Property_List }, +#endif #if defined(CONFIG_BACNET_BASIC_OBJECT_TIME_VALUE) { OBJECT_TIME_VALUE, Time_Value_Init, diff --git a/test/bacnet/basic/object/osv/CMakeLists.txt b/test/bacnet/basic/object/osv/CMakeLists.txt index 46dba899..140a3cfb 100644 --- a/test/bacnet/basic/object/osv/CMakeLists.txt +++ b/test/bacnet/basic/object/osv/CMakeLists.txt @@ -27,6 +27,7 @@ add_compile_definitions( include_directories( ${SRC_DIR} + ${TST_DIR}/bacnet/basic/object/test ${TST_DIR}/ztest/include ) @@ -46,9 +47,10 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/bacreal.c ${SRC_DIR}/bacnet/bacstr.c ${SRC_DIR}/bacnet/bactext.c - ${SRC_DIR}/bacnet/basic/sys/bigend.c ${SRC_DIR}/bacnet/datetime.c + ${SRC_DIR}/bacnet/basic/sys/bigend.c ${SRC_DIR}/bacnet/basic/sys/days.c + ${SRC_DIR}/bacnet/basic/sys/keylist.c ${SRC_DIR}/bacnet/indtext.c ${SRC_DIR}/bacnet/hostnport.c ${SRC_DIR}/bacnet/lighting.c @@ -66,6 +68,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/secure_connect.c # Test and test library files ./src/main.c + ${TST_DIR}/bacnet/basic/object/test/property_test.c ${ZTST_DIR}/ztest_mock.c ${ZTST_DIR}/ztest.c ) diff --git a/test/bacnet/basic/object/osv/src/main.c b/test/bacnet/basic/object/osv/src/main.c index 7c2f0f50..9ff49c66 100644 --- a/test/bacnet/basic/object/osv/src/main.c +++ b/test/bacnet/basic/object/osv/src/main.c @@ -9,6 +9,7 @@ #include #include #include +#include /** * @addtogroup bacnet_tests @@ -24,46 +25,47 @@ ZTEST(osv_tests, testOctetString_Value) static void testOctetString_Value(void) #endif { - uint8_t apdu[MAX_APDU] = { 0 }; - int len = 0, test_len = 0; - BACNET_READ_PROPERTY_DATA rpdata = { 0 }; - BACNET_APPLICATION_DATA_VALUE value = { 0 }; - const int32_t *required_property = NULL; - const uint32_t instance = 1; + bool status = false; + unsigned count = 0, index = 0; + uint32_t object_instance = 0, test_object_instance = 0; + const int32_t *writable_properties = NULL; + const int32_t skip_fail_property_list[] = { -1 }; OctetString_Value_Init(); - rpdata.application_data = &apdu[0]; - rpdata.application_data_len = sizeof(apdu); - rpdata.object_type = OBJECT_OCTETSTRING_VALUE; - rpdata.object_instance = instance; - rpdata.array_index = BACNET_ARRAY_ALL; - - OctetString_Value_Property_Lists(&required_property, NULL, NULL); - while ((*required_property) >= 0) { - rpdata.object_property = *required_property; - len = OctetString_Value_Read_Property(&rpdata); - zassert_true(len >= 0, NULL); - if (len >= 0) { - test_len = bacapp_decode_known_property( - rpdata.application_data, len, &value, rpdata.object_type, - rpdata.object_property); - if (len != test_len) { - printf( - "property '%s': failed to decode!\n", - bactext_property_name(rpdata.object_property)); - } - if (rpdata.object_property == PROP_PRIORITY_ARRAY) { - /* FIXME: known fail to decode */ - len = test_len; - } - zassert_equal(len, test_len, NULL); - } else { - printf( - "property '%s': failed to read!\n", - bactext_property_name(rpdata.object_property)); - } - required_property++; - } + test_object_instance = OctetString_Value_Create(BACNET_MAX_INSTANCE + 1); + zassert_equal(test_object_instance, BACNET_MAX_INSTANCE, NULL); + test_object_instance = OctetString_Value_Create(BACNET_MAX_INSTANCE); + zassert_not_equal(test_object_instance, BACNET_MAX_INSTANCE, NULL); + status = OctetString_Value_Delete(test_object_instance); + zassert_true(status, NULL); + count = OctetString_Value_Count(); + zassert_true(count == 0, NULL); + test_object_instance = OctetString_Value_Create(object_instance); + zassert_equal(test_object_instance, object_instance, NULL); + status = OctetString_Value_Valid_Instance(object_instance); + zassert_true(status, NULL); + status = OctetString_Value_Valid_Instance(object_instance - 1); + zassert_false(status, NULL); + index = OctetString_Value_Instance_To_Index(object_instance); + zassert_equal(index, 0, NULL); + test_object_instance = OctetString_Value_Index_To_Instance(index); + zassert_equal(object_instance, test_object_instance, NULL); + count = OctetString_Value_Count(); + zassert_true(count == 1, NULL); + test_object_instance = OctetString_Value_Index_To_Instance(0); + zassert_equal(object_instance, test_object_instance, NULL); + bacnet_object_properties_read_write_test( + OBJECT_OCTETSTRING_VALUE, object_instance, + OctetString_Value_Property_Lists, OctetString_Value_Read_Property, + OctetString_Value_Write_Property, skip_fail_property_list); + bacnet_object_name_ascii_test( + object_instance, OctetString_Value_Name_Set, + OctetString_Value_Name_ASCII); + OctetString_Value_Writable_Property_List( + object_instance, &writable_properties); + zassert_not_null(writable_properties, NULL); + status = OctetString_Value_Delete(object_instance); + zassert_true(status, NULL); } /** * @} diff --git a/test/bacnet/basic/object/piv/CMakeLists.txt b/test/bacnet/basic/object/piv/CMakeLists.txt index c07ef266..ae1c581f 100644 --- a/test/bacnet/basic/object/piv/CMakeLists.txt +++ b/test/bacnet/basic/object/piv/CMakeLists.txt @@ -27,6 +27,7 @@ add_compile_definitions( include_directories( ${SRC_DIR} + ${TST_DIR}/bacnet/basic/object/test ${TST_DIR}/ztest/include ) @@ -46,9 +47,10 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/bacreal.c ${SRC_DIR}/bacnet/bacstr.c ${SRC_DIR}/bacnet/bactext.c - ${SRC_DIR}/bacnet/basic/sys/bigend.c ${SRC_DIR}/bacnet/datetime.c + ${SRC_DIR}/bacnet/basic/sys/bigend.c ${SRC_DIR}/bacnet/basic/sys/days.c + ${SRC_DIR}/bacnet/basic/sys/keylist.c ${SRC_DIR}/bacnet/indtext.c ${SRC_DIR}/bacnet/hostnport.c ${SRC_DIR}/bacnet/lighting.c @@ -66,6 +68,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/secure_connect.c # Test and test library files ./src/main.c + ${TST_DIR}/bacnet/basic/object/test/property_test.c ${ZTST_DIR}/ztest_mock.c ${ZTST_DIR}/ztest.c ) diff --git a/test/bacnet/basic/object/piv/src/main.c b/test/bacnet/basic/object/piv/src/main.c index d23cf42c..f5382094 100644 --- a/test/bacnet/basic/object/piv/src/main.c +++ b/test/bacnet/basic/object/piv/src/main.c @@ -10,6 +10,7 @@ #include #include #include +#include /** * @addtogroup bacnet_tests @@ -25,42 +26,49 @@ ZTEST(piv_tests, testPositiveInteger_Value) static void testPositiveInteger_Value(void) #endif { - uint8_t apdu[MAX_APDU] = { 0 }; - int len = 0, test_len = 0; - BACNET_READ_PROPERTY_DATA rpdata = { 0 }; - BACNET_APPLICATION_DATA_VALUE value = { 0 }; - const int32_t *required_property = NULL; - const uint32_t instance = 1; + bool status = false; + unsigned count = 0, index = 0; + uint32_t object_instance = 0, test_object_instance = 0; + const int32_t *writable_properties = NULL; + const int32_t skip_fail_property_list[] = { -1 }; PositiveInteger_Value_Init(); - rpdata.application_data = &apdu[0]; - rpdata.application_data_len = sizeof(apdu); - rpdata.object_type = OBJECT_POSITIVE_INTEGER_VALUE; - rpdata.object_instance = instance; - rpdata.array_index = BACNET_ARRAY_ALL; - - PositiveInteger_Value_Property_Lists(&required_property, NULL, NULL); - while ((*required_property) >= 0) { - rpdata.object_property = *required_property; - len = PositiveInteger_Value_Read_Property(&rpdata); - zassert_true(len >= 0, NULL); - if (len >= 0) { - test_len = bacapp_decode_known_property( - rpdata.application_data, len, &value, rpdata.object_type, - rpdata.object_property); - if (len != test_len) { - printf( - "property '%s': failed to decode!\n", - bactext_property_name(rpdata.object_property)); - } - if (rpdata.object_property == PROP_PRIORITY_ARRAY) { - /* FIXME: known fail to decode */ - len = test_len; - } - zassert_equal(len, test_len, NULL); - } - required_property++; - } + test_object_instance = + PositiveInteger_Value_Create(BACNET_MAX_INSTANCE + 1); + zassert_equal(test_object_instance, BACNET_MAX_INSTANCE, NULL); + test_object_instance = PositiveInteger_Value_Create(BACNET_MAX_INSTANCE); + zassert_not_equal(test_object_instance, BACNET_MAX_INSTANCE, NULL); + status = PositiveInteger_Value_Delete(test_object_instance); + zassert_true(status, NULL); + count = PositiveInteger_Value_Count(); + zassert_true(count == 0, NULL); + test_object_instance = PositiveInteger_Value_Create(object_instance); + zassert_equal(test_object_instance, object_instance, NULL); + status = PositiveInteger_Value_Valid_Instance(object_instance); + zassert_true(status, NULL); + status = PositiveInteger_Value_Valid_Instance(object_instance - 1); + zassert_false(status, NULL); + index = PositiveInteger_Value_Instance_To_Index(object_instance); + zassert_equal(index, 0, NULL); + test_object_instance = PositiveInteger_Value_Index_To_Instance(index); + zassert_equal(object_instance, test_object_instance, NULL); + count = PositiveInteger_Value_Count(); + zassert_true(count == 1, NULL); + test_object_instance = PositiveInteger_Value_Index_To_Instance(0); + zassert_equal(object_instance, test_object_instance, NULL); + bacnet_object_properties_read_write_test( + OBJECT_POSITIVE_INTEGER_VALUE, object_instance, + PositiveInteger_Value_Property_Lists, + PositiveInteger_Value_Read_Property, + PositiveInteger_Value_Write_Property, skip_fail_property_list); + bacnet_object_name_ascii_test( + object_instance, PositiveInteger_Value_Name_Set, + PositiveInteger_Value_Name_ASCII); + PositiveInteger_Value_Writable_Property_List( + object_instance, &writable_properties); + zassert_not_null(writable_properties, NULL); + status = PositiveInteger_Value_Delete(object_instance); + zassert_true(status, NULL); } /** * @}