diff --git a/CMakeLists.txt b/CMakeLists.txt index 831cf85f..438f9711 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,6 +213,8 @@ add_library(${PROJECT_NAME} src/bacnet/basic/object/bacfile.h src/bacnet/basic/object/bi.c src/bacnet/basic/object/bi.h + src/bacnet/basic/object/bitstring_value.c + src/bacnet/basic/object/bitstring_value.h src/bacnet/basic/object/blo.c src/bacnet/basic/object/blo.h src/bacnet/basic/object/bo.c diff --git a/apps/gateway/Makefile b/apps/gateway/Makefile index 6074189c..604309a1 100644 --- a/apps/gateway/Makefile +++ b/apps/gateway/Makefile @@ -15,6 +15,7 @@ BACNET_OBJECT_SRC := \ $(BACNET_OBJECT_DIR)/ao.c \ $(BACNET_OBJECT_DIR)/av.c \ $(BACNET_OBJECT_DIR)/bi.c \ + $(BACNET_OBJECT_DIR)/bitstring_value.c \ $(BACNET_OBJECT_DIR)/blo.c \ $(BACNET_OBJECT_DIR)/bo.c \ $(BACNET_OBJECT_DIR)/bv.c \ diff --git a/apps/server/Makefile b/apps/server/Makefile index 0961c7b0..86dd4834 100644 --- a/apps/server/Makefile +++ b/apps/server/Makefile @@ -10,6 +10,7 @@ SRC = main.c \ $(BACNET_OBJECT_DIR)/ao.c \ $(BACNET_OBJECT_DIR)/av.c \ $(BACNET_OBJECT_DIR)/bi.c \ + $(BACNET_OBJECT_DIR)/bitstring_value.c \ $(BACNET_OBJECT_DIR)/bo.c \ $(BACNET_OBJECT_DIR)/blo.c \ $(BACNET_OBJECT_DIR)/bv.c \ diff --git a/src/bacnet/basic/object/bitstring_value.c b/src/bacnet/basic/object/bitstring_value.c new file mode 100644 index 00000000..34daedce --- /dev/null +++ b/src/bacnet/basic/object/bitstring_value.c @@ -0,0 +1,831 @@ +/** + * @file + * @author Steve Karg + * @date June 2024 + * @brief The BitString Value object is an object with a present-value that + * uses a BACnetBitString data type. + * @copyright SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include +#include "bacnet/bacdef.h" +#include "bacnet/bacdcode.h" +#include "bacnet/bacenum.h" +#include "bacnet/bacapp.h" +#include "bacnet/config.h" +#include "bacnet/proplist.h" +#include "bacnet/property.h" +#include "bacnet/rp.h" +#include "bacnet/wp.h" +#include "bacnet/basic/services.h" +#include "bacnet/basic/sys/keylist.h" +/* me! */ +#include "bitstring_value.h" + +struct object_data { + bool Change_Of_Value : 1; + bool Write_Enabled : 1; + bool Out_Of_Service : 1; + BACNET_BIT_STRING Present_Value; + BACNET_RELIABILITY Reliability; + const char *Object_Name; + const char *Description; +}; +/* Key List for storing the object data sorted by instance number */ +static OS_Keylist Object_List; +/* callback for present value writes */ +static bitstring_value_write_present_value_callback + BitString_Value_Write_Present_Value_Callback; + +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Properties_Required[] = { PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, PROP_OBJECT_TYPE, PROP_PRESENT_VALUE, PROP_STATUS_FLAGS, + -1 }; + +static const int Properties_Optional[] = { PROP_RELIABILITY, + PROP_OUT_OF_SERVICE, PROP_DESCRIPTION, -1 }; + +static const int Properties_Proprietary[] = { -1 }; + +/** + * Initialize the pointers for the required, the optional and the properitary + * value properties. + * + * @param pRequired - Pointer to the pointer of required values. + * @param pOptional - Pointer to the pointer of optional values. + * @param pProprietary - Pointer to the pointer of properitary values. + */ +void BitString_Value_Property_Lists( + const int **pRequired, const int **pOptional, const int **pProprietary) +{ + if (pRequired) { + *pRequired = Properties_Required; + } + if (pOptional) { + *pOptional = Properties_Optional; + } + if (pProprietary) { + *pProprietary = Properties_Proprietary; + } + + return; +} + +/** + * @brief Gets an object from the list using an instance number as the key + * @param object_instance - object-instance number of the object + * @return object found in the list, or NULL if not found + */ +static struct object_data *BitString_Value_Object(uint32_t object_instance) +{ + 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. + * + * @param object_instance Object instance + * + * @return true/false + */ +bool BitString_Value_Valid_Instance(uint32_t object_instance) +{ + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + return true; + } + + return false; +} + +/** + * Return the count of character string values. + * + * @return Count of character string values. + */ +unsigned BitString_Value_Count(void) +{ + return Keylist_Count(Object_List); +} + +/** + * 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 + * + * @param index Object index + * + * @return Index in the object table. + */ +uint32_t BitString_Value_Index_To_Instance(unsigned index) +{ + return Keylist_Key(Object_List, index); +} + +/** + * 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. + * + * @param object_instance Object instance + * + * @return Object instance + */ +unsigned BitString_Value_Instance_To_Index(uint32_t object_instance) +{ + return Keylist_Index(Object_List, object_instance); +} + +/** + * @brief For a given object instance-number, read the present-value. + * @param object_instance - object-instance number of the object + * @param value - Pointer to the new value + * @return true if value is within range and copied + */ +bool BitString_Value_Present_Value( + uint32_t object_instance, BACNET_BIT_STRING *value) +{ + bool status = false; + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + status = bitstring_copy(value, &pObject->Present_Value); + } + + return status; +} + +/** + * @brief For a given object instance-number, sets the present-value, + * taken from another bitstring. + * @param object_instance - object-instance number of the object + * @param value - Pointer to the value. + * @return true if value is within range and copied + */ +bool BitString_Value_Present_Value_Set( + uint32_t object_instance, BACNET_BIT_STRING *value) +{ + bool status = false; + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + if (!bitstring_same(&pObject->Present_Value, value)) { + pObject->Change_Of_Value = true; + } + status = bitstring_copy(&pObject->Present_Value, value); + } + + return status; +} + +/** + * For a given object instance-number, sets the present-value + * from WriteProperty service + * + * @param object_instance - object-instance number of the object + * @param value - new present value + * @param priority - priority-array index value 1..16 + * @param error_class - the BACnet error class + * @param error_code - BACnet Error code + * + * @return true if values are within range and present-value is set. + */ +static bool BitString_Value_Present_Value_Write( + uint32_t object_instance, + BACNET_BIT_STRING *value, + uint8_t priority, + BACNET_ERROR_CLASS *error_class, + BACNET_ERROR_CODE *error_code) +{ + bool status = false; + struct object_data *pObject; + BACNET_BIT_STRING old_value; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + (void)priority; + if (pObject->Write_Enabled) { + bitstring_copy(&old_value, &pObject->Present_Value); + bitstring_copy(&pObject->Present_Value, value); + if (pObject->Out_Of_Service) { + /* The physical point that the object represents + is not in service. This means that changes to the + Present_Value property are decoupled from the + physical point when the value of Out_Of_Service + is true. */ + } else if (BitString_Value_Write_Present_Value_Callback) { + BitString_Value_Write_Present_Value_Callback( + object_instance, &old_value, value); + } + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } + } else { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + } + + return status; +} + +/** + * For a given object instance-number, read the out of service value. + * + * @param object_instance - object-instance number of the object + * + * @return true/false + */ +bool BitString_Value_Out_Of_Service(uint32_t object_instance) +{ + bool value = false; + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + value = pObject->Out_Of_Service; + } + + return value; +} + +/** + * @brief For a given object instance-number, set the out of service value. + * @param object_instance - object-instance number of the object + * @param true/false + */ +void BitString_Value_Out_Of_Service_Set( + uint32_t object_instance, bool value) +{ + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + if (pObject->Out_Of_Service != value) { + pObject->Change_Of_Value = true; + } + pObject->Out_Of_Service = value; + } + + return; +} + +/** + * @brief For a given object instance-number, read the reliability value. + * @param object_instance - object-instance number of the object + * @return BACNET_RELIABILITY value + */ +BACNET_RELIABILITY BitString_Value_Reliablity( + uint32_t object_instance) +{ + BACNET_RELIABILITY value = RELIABILITY_NO_FAULT_DETECTED; + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + value = pObject->Reliability; + } + + return value; + +} + +/** + * @brief For a given object, gets the Fault status flag + * @param object_instance - object-instance number of the object + * @return true the status flag is in Fault + */ +static bool BitString_Value_Object_Fault(struct object_data *pObject) +{ + bool fault = false; + + if (pObject) { + if (pObject->Reliability != RELIABILITY_NO_FAULT_DETECTED) { + fault = true; + } + } + + return fault; +} + +/** + * @brief For a given object instance-number, set the reliability value. + * @param object_instance - object-instance number of the object + * @param true/false + */ +bool BitString_Value_Reliablity_Set( + uint32_t object_instance, BACNET_RELIABILITY value) +{ + struct object_data *pObject; + bool status = false; + bool fault = false; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + if (value <= 255) { + fault = BitString_Value_Object_Fault(pObject); + pObject->Reliability = value; + if (fault != BitString_Value_Object_Fault(pObject)) { + pObject->Change_Of_Value = true; + } + status = true; + } + pObject->Reliability = value; + } + + return status; +} + +/** + * @brief For a given object instance-number, gets the Fault status flag + * @param object_instance - object-instance number of the object + * @return true the status flag is in Fault + */ +static bool BitString_Value_Fault(uint32_t object_instance) +{ + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + + return BitString_Value_Object_Fault(pObject); +} + +/** + * @brief Get the COV change flag status + * @param object_instance - object-instance number of the object + * @return the COV change flag status + */ +bool BitString_Value_Change_Of_Value(uint32_t object_instance) +{ + bool changed = false; + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + changed = pObject->Change_Of_Value; + } + + return changed; +} + +/** + * @brief Clear the COV change flag + * @param object_instance - object-instance number of the object + */ +void BitString_Value_Change_Of_Value_Clear(uint32_t object_instance) +{ + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + pObject->Change_Of_Value = false; + } +} + +/** + * @brief For a given object instance-number, + * loads the value_list with the COV data. + * @param object_instance - object-instance number of the object + * @param value_list - list of COV data + * @return true if the value list is encoded + */ +bool BitString_Value_Encode_Value_List( + uint32_t object_instance, BACNET_PROPERTY_VALUE *value_list) +{ + bool status = false; + const bool in_alarm = false; + const bool fault = false; + const bool overridden = false; + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + status = cov_value_list_encode_bit_string(value_list, + &pObject->Present_Value, in_alarm, fault, overridden, + pObject->Out_Of_Service); + } + + return status; +} + +/** + * For a given object instance-number, loads the object-name into + * a characterstring. Note that the object name must be unique + * within this device. + * + * @param object_instance - object-instance number of the object + * @param object_name - holds the object-name retrieved + * + * @return true if object-name was retrieved + */ +bool BitString_Value_Object_Name( + uint32_t object_instance, BACNET_CHARACTER_STRING *object_name) +{ + bool status = false; + struct object_data *pObject; + char name_text[32] = "BITSTRING_VALUE-4194303"; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + if (pObject->Object_Name) { + status = + characterstring_init_ansi(object_name, pObject->Object_Name); + } else { + snprintf(name_text, sizeof(name_text), "BITSTRING_VALUE-%u", + object_instance); + status = characterstring_init_ansi(object_name, name_text); + } + } + + return status; +} + +/** + * 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 BitString_Value_Name_Set(uint32_t object_instance, char *new_name) +{ + bool status = false; /* return value */ + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + if (new_name) { + status = true; + pObject->Object_Name = new_name; + } + } + + return status; +} + +/** + * @brief For a given object instance-number, return the description. + * @param object_instance - object-instance number of the object + * @return C-string pointer to the description, + * or NULL if object doesn't exist + */ +char *BitString_Value_Description(uint32_t object_instance) +{ + char *name = NULL; /* return value */ + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + if (pObject->Description) { + name = (char *)pObject->Description; + } else { + name = ""; + } + } + + return name; +} + +/** + * For a given object instance-number, set the description text. + * + * @param object_instance - object-instance number of the object + * @param new_descr - C-String pointer to the string, representing the + * description text + * + * @return True on success, false otherwise. + */ +bool BitString_Value_Description_Set( + uint32_t object_instance, char *value) +{ + bool status = false; /* return value */ + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + status = true; + pObject->Description = value; + } + + return status; +} + +/** + * Return the requested property of the character string value. + * + * @param rpdata Property requested, see for BACNET_READ_PROPERTY_DATA details. + * + * @return apdu len, or BACNET_STATUS_ERROR on error + */ +int BitString_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) +{ + int apdu_len = 0; /* return value */ + BACNET_BIT_STRING bit_string; + BACNET_CHARACTER_STRING char_string; + bool state = false; + bool is_array = false; + uint8_t *apdu = NULL; + + if ((rpdata == NULL) || (rpdata->application_data == NULL) || + (rpdata->application_data_len == 0)) { + return 0; + } + apdu = rpdata->application_data; + switch (rpdata->object_property) { + case PROP_OBJECT_IDENTIFIER: + apdu_len = encode_application_object_id(&apdu[0], + OBJECT_BITSTRING_VALUE, rpdata->object_instance); + break; + case PROP_OBJECT_NAME: + if (BitString_Value_Object_Name( + rpdata->object_instance, &char_string)) { + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + } + break; + case PROP_DESCRIPTION: + characterstring_init_ansi( + &char_string, BitString_Value_Description( + rpdata->object_instance)); + apdu_len = encode_application_character_string(apdu, &char_string); + break; + case PROP_OBJECT_TYPE: + apdu_len = encode_application_enumerated( + &apdu[0], OBJECT_BITSTRING_VALUE); + break; + case PROP_PRESENT_VALUE: + BitString_Value_Present_Value(rpdata->object_instance, &bit_string); + apdu_len = encode_application_bitstring(&apdu[0], &bit_string); + break; + case PROP_STATUS_FLAGS: + /* note: see the details in the standard on how to use these */ + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); + state = BitString_Value_Fault(rpdata->object_instance); + bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, state); + bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); + state = BitString_Value_Out_Of_Service(rpdata->object_instance); + bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state); + apdu_len = encode_application_bitstring(&apdu[0], &bit_string); + break; + case PROP_OUT_OF_SERVICE: + state = BitString_Value_Out_Of_Service(rpdata->object_instance); + apdu_len = encode_application_boolean(&apdu[0], state); + break; + case PROP_RELIABILITY: + apdu_len = + encode_application_enumerated(&apdu[0], + BitString_Value_Reliablity(rpdata->object_instance)); + break; + default: + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; + apdu_len = BACNET_STATUS_ERROR; + break; + } + /* only array properties can have array options */ + is_array = property_list_bacnet_array_member( + rpdata->object_type, rpdata->object_property); + if ((apdu_len >= 0) && (!is_array) && + (rpdata->array_index != BACNET_ARRAY_ALL)) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; + apdu_len = BACNET_STATUS_ERROR; + } + + return apdu_len; +} + +/** + * Set the requested property of the character string value. + * + * @param wp_data Property requested, see for BACNET_WRITE_PROPERTY_DATA + * details. + * + * @return true if successful + */ +bool BitString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) +{ + bool status = false; /* return value */ + int len = 0; + BACNET_APPLICATION_DATA_VALUE value; + + 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( + wp_data->application_data, wp_data->application_data_len, &value); + /* FIXME: len < application_data_len: more data? */ + if (len < 0) { + /* error while decoding - a value larger than we can handle */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + return false; + } + if ((wp_data->object_property != PROP_PRIORITY_ARRAY) && + (wp_data->object_property != PROP_EVENT_TIME_STAMPS) && + (wp_data->array_index != BACNET_ARRAY_ALL)) { + /* only array properties can have array options */ + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; + return false; + } + switch (wp_data->object_property) { + case PROP_PRESENT_VALUE: + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_BIT_STRING); + if (status) { + status = BitString_Value_Present_Value_Write( + wp_data->object_instance, &value.type.Bit_String, + wp_data->priority, &wp_data->error_class, + &wp_data->error_code); + } + break; + case PROP_OUT_OF_SERVICE: + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_BOOLEAN); + if (status) { + BitString_Value_Out_Of_Service_Set( + wp_data->object_instance, value.type.Boolean); + } + break; + default: + if (property_lists_member( + Properties_Required, Properties_Optional, + Properties_Proprietary, wp_data->object_property)) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; + } + break; + } + + return status; +} + +/** + * @brief Sets a callback used when present-value is written from BACnet + * @param cb - callback used to provide indications + */ +void BitString_Value_Write_Present_Value_Callback_Set( + bitstring_value_write_present_value_callback cb) +{ + BitString_Value_Write_Present_Value_Callback = cb; +} + +/** + * @brief Determines a object write-enabled flag state + * @param object_instance - object-instance number of the object + * @return write-enabled status flag + */ +bool BitString_Value_Write_Enabled(uint32_t object_instance) +{ + bool value = false; + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + value = pObject->Write_Enabled; + } + + return value; +} + +/** + * @brief For a given object instance-number, sets the write-enabled flag + * @param object_instance - object-instance number of the object + */ +void BitString_Value_Write_Enable(uint32_t object_instance) +{ + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + pObject->Write_Enabled = true; + } +} + +/** + * @brief For a given object instance-number, clears the write-enabled flag + * @param object_instance - object-instance number of the object + */ +void BitString_Value_Write_Disable(uint32_t object_instance) +{ + struct object_data *pObject; + + pObject = BitString_Value_Object(object_instance); + if (pObject) { + pObject->Write_Enabled = false; + } +} + +/** + * Creates a BitString Value object + * @param object_instance - object-instance number of the object + */ +uint32_t BitString_Value_Create(uint32_t object_instance) +{ + struct object_data *pObject = NULL; + int index = 0; + + if (object_instance > BACNET_MAX_INSTANCE) { + return BACNET_MAX_INSTANCE; + } else if (object_instance == BACNET_MAX_INSTANCE) { + /* wildcard instance */ + /* the Object_Identifier property of the newly created object + shall be initialized to a value that is unique within the + responding BACnet-user device. The method used to generate + the object identifier is a local matter.*/ + object_instance = Keylist_Next_Empty_Key(Object_List, 1); + } + + pObject = BitString_Value_Object(object_instance); + if (!pObject) { + pObject = calloc(1, sizeof(struct object_data)); + if (pObject) { + pObject->Object_Name = NULL; + pObject->Description = NULL; + bitstring_init(&pObject->Present_Value); + pObject->Reliability = RELIABILITY_NO_FAULT_DETECTED; + pObject->Out_Of_Service = false; + pObject->Change_Of_Value = false; + pObject->Write_Enabled = true; + /* add to list */ + index = Keylist_Data_Add(Object_List, object_instance, pObject); + if (index < 0) { + free(pObject); + return BACNET_MAX_INSTANCE; + } + } else { + return BACNET_MAX_INSTANCE; + } + } + + return object_instance; +} + +/** + * Deletes an BitString Value object + * @param object_instance - object-instance number of the object + * @return true if the object is deleted + */ +bool BitString_Value_Delete(uint32_t object_instance) +{ + bool status = false; + struct object_data *pObject = NULL; + + pObject = Keylist_Data_Delete(Object_List, object_instance); + if (pObject) { + free(pObject); + status = true; + } + + return status; +} + +/** + * Deletes all the BitString Value objects and their data + */ +void BitString_Value_Cleanup(void) +{ + struct object_data *pObject; + + if (Object_List) { + do { + pObject = Keylist_Data_Pop(Object_List); + if (pObject) { + free(pObject); + } + } while (pObject); + Keylist_Delete(Object_List); + Object_List = NULL; + } +} + +/** + * Initializes the object data + */ +void BitString_Value_Init(void) +{ + if (!Object_List) { + Object_List = Keylist_Create(); + } +} diff --git a/src/bacnet/basic/object/bitstring_value.h b/src/bacnet/basic/object/bitstring_value.h new file mode 100644 index 00000000..19fc280f --- /dev/null +++ b/src/bacnet/basic/object/bitstring_value.h @@ -0,0 +1,144 @@ +/** + * @file + * @author Steve Karg + * @date June 2024 + * @brief The BitString Value object is an object with a present-value that + * uses a BACnetBitString data type. + * @copyright SPDX-License-Identifier: MIT + */ +#ifndef BITSTRING_VALUE_H +#define BITSTRING_VALUE_H + +#include +#include +/* BACnet Stack defines - first */ +#include "bacnet/bacdef.h" +/* BACnet Stack API */ +#include "bacnet/bacerror.h" +#include "bacnet/cov.h" +#include "bacnet/rp.h" +#include "bacnet/wp.h" + +/** + * @brief Callback for gateway write present value request + * @param object_instance - object-instance number of the object + * @param old_value - BIT STRING value prior to write + * @param value - BIT STRING value of the write + */ +typedef void (*bitstring_value_write_present_value_callback)( + uint32_t object_instance, + BACNET_BIT_STRING *old_value, + BACNET_BIT_STRING *value); + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + BACNET_STACK_EXPORT + void BitString_Value_Write_Present_Value_Callback_Set( + bitstring_value_write_present_value_callback cb); + + BACNET_STACK_EXPORT + void BitString_Value_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary); + + BACNET_STACK_EXPORT + bool BitString_Value_Valid_Instance( + uint32_t object_instance); + BACNET_STACK_EXPORT + unsigned BitString_Value_Count( + void); + BACNET_STACK_EXPORT + uint32_t BitString_Value_Index_To_Instance( + unsigned index); + BACNET_STACK_EXPORT + unsigned BitString_Value_Instance_To_Index( + uint32_t instance); + + BACNET_STACK_EXPORT + int BitString_Value_Read_Property( + BACNET_READ_PROPERTY_DATA * rpdata); + + BACNET_STACK_EXPORT + bool BitString_Value_Write_Property( + BACNET_WRITE_PROPERTY_DATA * wp_data); + + /* optional API */ + BACNET_STACK_EXPORT + bool BitString_Value_Object_Instance_Add( + uint32_t instance); + + BACNET_STACK_EXPORT + bool BitString_Value_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING * object_name); + BACNET_STACK_EXPORT + bool BitString_Value_Name_Set( + uint32_t object_instance, + char *new_name); + + BACNET_STACK_EXPORT + bool BitString_Value_Present_Value( + uint32_t object_instance, + BACNET_BIT_STRING * value); + BACNET_STACK_EXPORT + bool BitString_Value_Present_Value_Set( + uint32_t object_instance, + BACNET_BIT_STRING * value); + + BACNET_STACK_EXPORT + char *BitString_Value_Description( + uint32_t instance); + BACNET_STACK_EXPORT + bool BitString_Value_Description_Set( + uint32_t object_instance, + char *text_string); + + BACNET_STACK_EXPORT + bool BitString_Value_Out_Of_Service( + uint32_t object_instance); + BACNET_STACK_EXPORT + void BitString_Value_Out_Of_Service_Set( + uint32_t object_instance, bool value); + + BACNET_STACK_EXPORT + BACNET_RELIABILITY BitString_Value_Reliablity( + uint32_t object_instance); + BACNET_STACK_EXPORT + bool BitString_Value_Reliablity_Set( + uint32_t object_instance, BACNET_RELIABILITY value); + + BACNET_STACK_EXPORT + bool BitString_Value_Change_Of_Value( + uint32_t instance); + BACNET_STACK_EXPORT + void BitString_Value_Change_Of_Value_Clear( + uint32_t instance); + BACNET_STACK_EXPORT + bool BitString_Value_Encode_Value_List( + uint32_t object_instance, + BACNET_PROPERTY_VALUE * value_list); + + BACNET_STACK_EXPORT + bool BitString_Value_Write_Enabled(uint32_t instance); + BACNET_STACK_EXPORT + void BitString_Value_Write_Enable(uint32_t instance); + BACNET_STACK_EXPORT + void BitString_Value_Write_Disable(uint32_t instance); + + BACNET_STACK_EXPORT + uint32_t BitString_Value_Create(uint32_t object_instance); + BACNET_STACK_EXPORT + bool BitString_Value_Delete(uint32_t object_instance); + BACNET_STACK_EXPORT + void BitString_Value_Cleanup(void); + + BACNET_STACK_EXPORT + void BitString_Value_Init( + void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/src/bacnet/basic/object/device.c b/src/bacnet/basic/object/device.c index 2cb3679e..760dfc5a 100644 --- a/src/bacnet/basic/object/device.c +++ b/src/bacnet/basic/object/device.c @@ -33,33 +33,18 @@ #include "bacnet/basic/object/ao.h" #include "bacnet/basic/object/av.h" #include "bacnet/basic/object/bi.h" -#if (BACNET_PROTOCOL_REVISION >= 16) -#include "bacnet/basic/object/blo.h" -#endif #include "bacnet/basic/object/bo.h" #include "bacnet/basic/object/bv.h" #include "bacnet/basic/object/calendar.h" #include "bacnet/basic/object/command.h" -#include "bacnet/basic/object/csv.h" -#include "bacnet/basic/object/iv.h" #include "bacnet/basic/object/lc.h" -#if (BACNET_PROTOCOL_REVISION >= 14) -#include "bacnet/basic/object/channel.h" -#include "bacnet/basic/object/lo.h" -#endif #include "bacnet/basic/object/lsp.h" #include "bacnet/basic/object/lsz.h" #include "bacnet/basic/object/ms-input.h" #include "bacnet/basic/object/mso.h" #include "bacnet/basic/object/msv.h" -#if (BACNET_PROTOCOL_REVISION >= 17) -#include "bacnet/basic/object/netport.h" -#endif -#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/time_value.h" #include "bacnet/basic/object/trendlog.h" #if defined(INTRINSIC_REPORTING) #include "bacnet/basic/object/nc.h" @@ -67,6 +52,24 @@ #if defined(BACFILE) #include "bacnet/basic/object/bacfile.h" #endif /* defined(BACFILE) */ +#if (BACNET_PROTOCOL_REVISION >= 10) +#include "bacnet/basic/object/bitstring_value.h" +#include "bacnet/basic/object/csv.h" +#include "bacnet/basic/object/iv.h" +#include "bacnet/basic/object/osv.h" +#include "bacnet/basic/object/piv.h" +#include "bacnet/basic/object/time_value.h" +#endif +#if (BACNET_PROTOCOL_REVISION >= 14) +#include "bacnet/basic/object/channel.h" +#include "bacnet/basic/object/lo.h" +#endif +#if (BACNET_PROTOCOL_REVISION >= 16) +#include "bacnet/basic/object/blo.h" +#endif +#if (BACNET_PROTOCOL_REVISION >= 17) +#include "bacnet/basic/object/netport.h" +#endif #if (BACNET_PROTOCOL_REVISION >= 24) #include "bacnet/basic/object/color_object.h" #include "bacnet/basic/object/color_temperature.h" @@ -163,6 +166,17 @@ static object_functions_t My_Object_Table[] = { NULL /* COV */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */, NULL /* Add_List_Element */, NULL /* Remove_List_Element */, NULL /* Create */, NULL /* Delete */, NULL /* Timer */ }, +#if (BACNET_PROTOCOL_REVISION >= 10) + { OBJECT_BITSTRING_VALUE, BitString_Value_Init, + BitString_Value_Count, BitString_Value_Index_To_Instance, + BitString_Value_Valid_Instance, BitString_Value_Object_Name, + BitString_Value_Read_Property, BitString_Value_Write_Property, + BitString_Value_Property_Lists, NULL /* ReadRangeInfo */, + NULL /* Iterator */, BitString_Value_Encode_Value_List, + BitString_Value_Change_Of_Value, BitString_Value_Change_Of_Value_Clear, + NULL /* Intrinsic Reporting */, NULL /* Add_List_Element */, + NULL /* Remove_List_Element */, NULL /* Create */, NULL /* Delete */, + NULL /* Timer */ }, { OBJECT_CHARACTERSTRING_VALUE, CharacterString_Value_Init, CharacterString_Value_Count, CharacterString_Value_Index_To_Instance, CharacterString_Value_Valid_Instance, CharacterString_Value_Object_Name, @@ -175,6 +189,33 @@ static object_functions_t My_Object_Table[] = { NULL /* Intrinsic Reporting */, NULL /* Add_List_Element */, NULL /* Remove_List_Element */, NULL /* Create */, NULL /* Delete */, NULL /* Timer */ }, + { 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 */, + NULL /* Create */, NULL /* Delete */, NULL /* Timer */ }, + { 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 */, + NULL /* Create */, NULL /* Delete */, NULL /* Timer */ }, + { 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 */, + NULL /* Create */, NULL /* Delete */, NULL /* Timer */ }, +#endif { OBJECT_COMMAND, Command_Init, Command_Count, Command_Index_To_Instance, Command_Valid_Instance, Command_Object_Name, Command_Read_Property, Command_Write_Property, Command_Property_Lists, @@ -320,24 +361,6 @@ static object_functions_t My_Object_Table[] = { NULL /* Add_List_Element */, NULL /* Remove_List_Element */, bacfile_create, bacfile_delete, NULL /* Timer */ }, #endif - { 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 */, - NULL /* Create */, NULL /* Delete */, NULL /* Timer */ }, - { 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 */, - NULL /* Create */, NULL /* Delete */, NULL /* Timer */ }, { OBJECT_SCHEDULE, Schedule_Init, Schedule_Count, Schedule_Index_To_Instance, Schedule_Valid_Instance, Schedule_Object_Name, Schedule_Read_Property, Schedule_Write_Property, @@ -354,14 +377,6 @@ static object_functions_t My_Object_Table[] = { NULL /* COV */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */, NULL /* Add_List_Element */, NULL /* Remove_List_Element */, Structured_View_Create, Structured_View_Delete, NULL /* Timer */ }, - { 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 */, - NULL /* Create */, NULL /* Delete */, NULL /* Timer */ }, { OBJECT_ACCUMULATOR, Accumulator_Init, Accumulator_Count, Accumulator_Index_To_Instance, Accumulator_Valid_Instance, Accumulator_Object_Name, Accumulator_Read_Property, diff --git a/src/bacnet/cov.c b/src/bacnet/cov.c index 72be827a..84056366 100644 --- a/src/bacnet/cov.c +++ b/src/bacnet/cov.c @@ -865,6 +865,31 @@ int cov_subscribe_property_decode_service_request( return len; } +/** + * @brief Link an array or buffer of BACNET_PROPERTY_VALUE elements + * @param value_list - One or more BACNET_PROPERTY_VALUE elements in + * a buffer or array. + * @param count - number of BACNET_PROPERTY_VALUE elements + */ +void cov_property_value_list_link( + BACNET_PROPERTY_VALUE *value_list, size_t count) +{ + BACNET_PROPERTY_VALUE *current_value_list = NULL; + + if (value_list) { + while (count) { + if (count > 1) { + current_value_list = value_list; + value_list++; + current_value_list->next = value_list; + } else { + value_list->next = NULL; + } + count--; + } + } +} + /** Link an array or buffer of BACNET_PROPERTY_VALUE elements and add them * to the BACNET_COV_DATA structure. It is used prior to encoding or * decoding the APDU data into the structure. @@ -878,20 +903,9 @@ int cov_subscribe_property_decode_service_request( void cov_data_value_list_link( BACNET_COV_DATA *data, BACNET_PROPERTY_VALUE *value_list, size_t count) { - BACNET_PROPERTY_VALUE *current_value_list = NULL; - if (data && value_list) { data->listOfValues = value_list; - while (count) { - if (count > 1) { - current_value_list = value_list; - value_list++; - current_value_list->next = value_list; - } else { - value_list->next = NULL; - } - count--; - } + cov_property_value_list_link(value_list, count); } } @@ -1109,3 +1123,59 @@ bool cov_value_list_encode_character_string(BACNET_PROPERTY_VALUE *value_list, return status; } #endif + +#if defined(BACAPP_BIT_STRING) +/** + * @brief Encode the Value List for CHARACTER_STRING Present-Value and + * Status-Flags + * @param value_list - #BACNET_PROPERTY_VALUE with at least 2 entries + * @param value - CHARACTER_STRING present-value + * @param in_alarm - value of in-alarm status-flags + * @param fault - value of in-alarm status-flags + * @param overridden - value of overridden status-flags + * @param out_of_service - value of out-of-service status-flags + * + * @return true if values were encoded + */ +bool cov_value_list_encode_bit_string(BACNET_PROPERTY_VALUE *value_list, + BACNET_BIT_STRING *value, + bool in_alarm, + bool fault, + bool overridden, + bool out_of_service) +{ + bool status = false; + + if (value_list) { + value_list->propertyIdentifier = PROP_PRESENT_VALUE; + value_list->propertyArrayIndex = BACNET_ARRAY_ALL; + value_list->value.context_specific = false; + value_list->value.tag = BACNET_APPLICATION_TAG_BIT_STRING; + bitstring_copy(&value_list->value.type.Bit_String, value); + value_list->value.next = NULL; + value_list->priority = BACNET_NO_PRIORITY; + value_list = value_list->next; + } + if (value_list) { + value_list->propertyIdentifier = PROP_STATUS_FLAGS; + value_list->propertyArrayIndex = BACNET_ARRAY_ALL; + value_list->value.context_specific = false; + value_list->value.tag = BACNET_APPLICATION_TAG_BIT_STRING; + bitstring_init(&value_list->value.type.Bit_String); + bitstring_set_bit( + &value_list->value.type.Bit_String, STATUS_FLAG_IN_ALARM, in_alarm); + bitstring_set_bit( + &value_list->value.type.Bit_String, STATUS_FLAG_FAULT, fault); + bitstring_set_bit(&value_list->value.type.Bit_String, + STATUS_FLAG_OVERRIDDEN, overridden); + bitstring_set_bit(&value_list->value.type.Bit_String, + STATUS_FLAG_OUT_OF_SERVICE, out_of_service); + value_list->value.next = NULL; + value_list->priority = BACNET_NO_PRIORITY; + value_list->next = NULL; + status = true; + } + + return status; +} +#endif diff --git a/src/bacnet/cov.h b/src/bacnet/cov.h index 517ccdc6..270cecbb 100644 --- a/src/bacnet/cov.h +++ b/src/bacnet/cov.h @@ -145,8 +145,14 @@ int cov_subscribe_encode_apdu(uint8_t *apdu, BACNET_SUBSCRIBE_COV_DATA *data); BACNET_STACK_EXPORT +void cov_property_value_list_link( + BACNET_PROPERTY_VALUE *value_list, + size_t count); +BACNET_STACK_EXPORT void cov_data_value_list_link( - BACNET_COV_DATA *data, BACNET_PROPERTY_VALUE *value_list, size_t count); + BACNET_COV_DATA *data, + BACNET_PROPERTY_VALUE *value_list, + size_t count); BACNET_STACK_EXPORT bool cov_value_list_encode_real(BACNET_PROPERTY_VALUE *value_list, @@ -176,6 +182,13 @@ bool cov_value_list_encode_character_string(BACNET_PROPERTY_VALUE *value_list, bool fault, bool overridden, bool out_of_service); + BACNET_STACK_EXPORT + bool cov_value_list_encode_bit_string(BACNET_PROPERTY_VALUE *value_list, + BACNET_BIT_STRING *value, + bool in_alarm, + bool fault, + bool overridden, + bool out_of_service); #ifdef __cplusplus } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 727160aa..5c3ee1cb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -122,6 +122,7 @@ list(APPEND testdirs bacnet/basic/object/av bacnet/basic/object/bacfile bacnet/basic/object/bi + bacnet/basic/object/bitstring_value bacnet/basic/object/blo bacnet/basic/object/bo bacnet/basic/object/bv diff --git a/test/bacnet/basic/object/bitstring_value/CMakeLists.txt b/test/bacnet/basic/object/bitstring_value/CMakeLists.txt new file mode 100644 index 00000000..4740ee3f --- /dev/null +++ b/test/bacnet/basic/object/bitstring_value/CMakeLists.txt @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.10 FATAL_ERROR) + +get_filename_component(basename ${CMAKE_CURRENT_SOURCE_DIR} NAME) +project(test_${basename} + VERSION 1.0.0 + LANGUAGES C) + +string(REGEX REPLACE + "/test/bacnet/[a-zA-Z_/-]*$" + "/src" + SRC_DIR + ${CMAKE_CURRENT_SOURCE_DIR}) +string(REGEX REPLACE + "/test/bacnet/[a-zA-Z_/-]*$" + "/test" + TST_DIR + ${CMAKE_CURRENT_SOURCE_DIR}) +set(ZTST_DIR "${TST_DIR}/ztest/src") + +add_compile_definitions( + BIG_ENDIAN=0 + CONFIG_ZTEST=1 + BACNET_PROPERTY_ARRAY_LISTS=1 + ) + +include_directories( + ${SRC_DIR} + ${TST_DIR}/bacnet/basic/object + ${TST_DIR}/ztest/include + ) + +add_executable(${PROJECT_NAME} + # File(s) under test + ${SRC_DIR}/bacnet/basic/object/bitstring_value.c + # Support files and stubs (pathname alphabetical) + ${SRC_DIR}/bacnet/bacaddr.c + ${SRC_DIR}/bacnet/bacapp.c + ${SRC_DIR}/bacnet/bacdcode.c + ${SRC_DIR}/bacnet/bacdest.c + ${SRC_DIR}/bacnet/bacdevobjpropref.c + ${SRC_DIR}/bacnet/bacint.c + ${SRC_DIR}/bacnet/bacreal.c + ${SRC_DIR}/bacnet/bacstr.c + ${SRC_DIR}/bacnet/bactext.c + ${SRC_DIR}/bacnet/bactimevalue.c + ${SRC_DIR}/bacnet/basic/sys/bigend.c + ${SRC_DIR}/bacnet/basic/sys/keylist.c + ${SRC_DIR}/bacnet/basic/sys/days.c + ${SRC_DIR}/bacnet/cov.c + ${SRC_DIR}/bacnet/datetime.c + ${SRC_DIR}/bacnet/indtext.c + ${SRC_DIR}/bacnet/hostnport.c + ${SRC_DIR}/bacnet/lighting.c + ${SRC_DIR}/bacnet/proplist.c + ${SRC_DIR}/bacnet/property.c + ${SRC_DIR}/bacnet/timestamp.c + ${SRC_DIR}/bacnet/wp.c + ${SRC_DIR}/bacnet/weeklyschedule.c + ${SRC_DIR}/bacnet/dailyschedule.c + ${SRC_DIR}/bacnet/calendar_entry.c + ${SRC_DIR}/bacnet/special_event.c + # Test and test library files + ./src/main.c + ${TST_DIR}/bacnet/basic/object/property_test.c + ${ZTST_DIR}/ztest_mock.c + ${ZTST_DIR}/ztest.c + ) diff --git a/test/bacnet/basic/object/bitstring_value/src/main.c b/test/bacnet/basic/object/bitstring_value/src/main.c new file mode 100644 index 00000000..7a4f394c --- /dev/null +++ b/test/bacnet/basic/object/bitstring_value/src/main.c @@ -0,0 +1,160 @@ +/** + * @file + * @brief Unit test for object + * @author Steve Karg + * @date June 2024 + * @copyright SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include + +/** + * @addtogroup bacnet_tests + * @{ + */ + +/** + * @brief Test + */ +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST(bitstring_value_object_tests, test_BitString_Value_Object) +#else +static void test_BitString_Value_Object(void) +#endif +{ + uint8_t apdu[MAX_APDU] = { 0 }; + int len = 0; + int test_len = 0; + const int skip_fail_property_list[] = { -1 }; + const uint32_t instance = 123; + uint32_t test_instance = 0; + unsigned test_count = 0; + unsigned test_index = 0; + bool status = false; + BACNET_WRITE_PROPERTY_DATA wpdata = { 0 }; + BACNET_APPLICATION_DATA_VALUE value = { 0 }; + BACNET_PROPERTY_VALUE value_list[2] = { 0 }; + const int *required_property = NULL; + const int *optional_property = NULL; + const int *proprietary_property = NULL; + + BitString_Value_Init(); + status = BitString_Value_Create(instance); + zassert_true(status, NULL); + status = BitString_Value_Valid_Instance(instance); + zassert_true(status, NULL); + status = BitString_Value_Valid_Instance(instance+1); + zassert_false(status, NULL); + test_count = BitString_Value_Count(); + zassert_equal(test_count, 1, NULL); + test_instance = BitString_Value_Index_To_Instance(0); + zassert_equal(test_instance, instance, NULL); + test_index = BitString_Value_Instance_To_Index(instance); + zassert_equal(test_index, 0, NULL); + bacnet_object_properties_read_write_test( + OBJECT_BINARY_INPUT, instance, BitString_Value_Property_Lists, + BitString_Value_Read_Property, BitString_Value_Write_Property, + skip_fail_property_list); + /* test specific WriteProperty values */ + BitString_Value_Write_Disable(instance); + status = BitString_Value_Write_Enabled(instance); + zassert_false(status, NULL); + BitString_Value_Write_Enable(instance); + status = BitString_Value_Write_Enabled(instance); + zassert_true(status, NULL); + wpdata.object_instance = instance; + wpdata.object_type = OBJECT_BITSTRING_VALUE; + wpdata.array_index = BACNET_ARRAY_ALL; + wpdata.priority = BACNET_NO_PRIORITY; + wpdata.error_class = ERROR_CLASS_OBJECT; + wpdata.error_code = ERROR_CODE_UNKNOWN_OBJECT; + /* WP to present-value */ + wpdata.object_property = PROP_PRESENT_VALUE; + value.tag = BACNET_APPLICATION_TAG_BIT_STRING; + bitstring_init(&value.type.Bit_String); + wpdata.application_data_len = bacapp_encode_application_data( + wpdata.application_data, &value); + status = BitString_Value_Write_Property(&wpdata); + zassert_true(status, NULL); + /* WP to out-of-service */ + wpdata.object_property = PROP_OUT_OF_SERVICE; + value.tag = BACNET_APPLICATION_TAG_BOOLEAN; + value.type.Boolean = false; + wpdata.application_data_len = bacapp_encode_application_data( + wpdata.application_data, &value); + status = BitString_Value_Write_Property(&wpdata); + zassert_true(status, NULL); + /* WP to status-flags - read-only */ + wpdata.object_property = PROP_STATUS_FLAGS; + value.tag = BACNET_APPLICATION_TAG_BIT_STRING; + bitstring_init(&value.type.Bit_String); + wpdata.application_data_len = bacapp_encode_application_data( + wpdata.application_data, &value); + status = BitString_Value_Write_Property(&wpdata); + zassert_false(status, NULL); + zassert_equal(wpdata.error_class, ERROR_CLASS_PROPERTY, NULL); + zassert_equal(wpdata.error_code, ERROR_CODE_WRITE_ACCESS_DENIED, NULL); + /* WP to property using priority array */ + wpdata.object_property = PROP_PRESENT_VALUE; + value.tag = BACNET_APPLICATION_TAG_BIT_STRING; + wpdata.array_index = 0; + wpdata.application_data_len = bacapp_encode_application_data( + wpdata.application_data, &value); + status = BitString_Value_Write_Property(&wpdata); + zassert_false(status, NULL); + zassert_equal(wpdata.error_class, ERROR_CLASS_PROPERTY, NULL); + zassert_equal(wpdata.error_code, ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY, NULL); + /* no application data */ + wpdata.application_data_len = 0; + status = BitString_Value_Write_Property(&wpdata); + zassert_false(status, NULL); + /* NULL pointer */ + status = BitString_Value_Write_Property(NULL); + zassert_false(status, NULL); + /* set same value */ + BitString_Value_Change_Of_Value_Clear(instance); + status = BitString_Value_Present_Value_Set(instance, + &value.type.Bit_String); + zassert_true(status, NULL); + status = BitString_Value_Change_Of_Value(instance); + zassert_false(status, NULL); + /* set different value */ + bitstring_set_bit(&value.type.Bit_String, 1, true); + status = BitString_Value_Present_Value_Set(instance, + &value.type.Bit_String); + zassert_true(status, NULL); + status = BitString_Value_Change_Of_Value(instance); + zassert_true(status, NULL); + /* COV */ + cov_property_value_list_link(value_list, + sizeof(value_list)/sizeof(value_list[0])); + status = BitString_Value_Encode_Value_List(instance, value_list); + zassert_true(status, NULL); + /* delete */ + status = BitString_Value_Delete(instance); + zassert_true(status, NULL); + /* create - test that cleanup works */ + status = BitString_Value_Create(instance); + zassert_true(status, NULL); + + return; +} +/** + * @} + */ + +#if defined(CONFIG_ZTEST_NEW_API) +ZTEST_SUITE(bitstring_value_object_tests, NULL, NULL, NULL, NULL, NULL); +#else +void test_main(void) +{ + ztest_test_suite(bitstring_value_object_tests, + ztest_unit_test(test_BitString_Value_Object) + ); + + ztest_run_test_suite(bitstring_value_object_tests); +} +#endif diff --git a/test/bacnet/basic/object/device/CMakeLists.txt b/test/bacnet/basic/object/device/CMakeLists.txt index 0cdbc537..71c85c0a 100644 --- a/test/bacnet/basic/object/device/CMakeLists.txt +++ b/test/bacnet/basic/object/device/CMakeLists.txt @@ -53,6 +53,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/basic/object/ao.c ${SRC_DIR}/bacnet/basic/object/av.c ${SRC_DIR}/bacnet/basic/object/bi.c + ${SRC_DIR}/bacnet/basic/object/bitstring_value.c ${SRC_DIR}/bacnet/basic/object/blo.c ${SRC_DIR}/bacnet/basic/object/bo.c ${SRC_DIR}/bacnet/basic/object/bv.c