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.
This commit is contained in:
Steve Karg
2026-02-26 16:25:03 -06:00
committed by GitHub
parent 24587dfc27
commit 1437a68ce1
13 changed files with 599 additions and 234 deletions
+4
View File
@@ -52,6 +52,8 @@ The git repositories are hosted at the following sites:
### Added ### Added
* Added CreateObject and DeleteObject for Octet StringValue and
PositiveInteger Value objects. (#1246)
* Added PROP_TIMER_RUNNING to writable properties and implement * Added PROP_TIMER_RUNNING to writable properties and implement
Timer_Running_Set functionality. (#1245) Timer_Running_Set functionality. (#1245)
* Added BACNET_STACK_DEPRECATED_DISABLE guards around all of the deprecated * 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
* Changed PositiveInteger present-value datatype to
BACNET_UNSIGNED_INTEGER. (#1246)
* Changed BACFILE define dependencies to reflect bacfile-posix.c dependence * Changed BACFILE define dependencies to reflect bacfile-posix.c dependence
since bacfile.c is now independent of any back end file system. (#1227) 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 * Changed the default BACnet protocol revision to 28 to enable usage of
+1
View File
@@ -46,6 +46,7 @@ SRC = main.c blinkt.c \
$(BACNET_OBJECT_DIR)/nc.c \ $(BACNET_OBJECT_DIR)/nc.c \
$(BACNET_OBJECT_DIR)/netport.c \ $(BACNET_OBJECT_DIR)/netport.c \
$(BACNET_OBJECT_DIR)/osv.c \ $(BACNET_OBJECT_DIR)/osv.c \
$(BACNET_OBJECT_DIR)/piv.c \
$(BACNET_OBJECT_DIR)/program.c \ $(BACNET_OBJECT_DIR)/program.c \
$(BACNET_OBJECT_DIR)/structured_view.c \ $(BACNET_OBJECT_DIR)/structured_view.c \
$(BACNET_OBJECT_DIR)/timer.c \ $(BACNET_OBJECT_DIR)/timer.c \
+1
View File
@@ -40,6 +40,7 @@ SRC = main.c \
$(BACNET_OBJECT_DIR)/nc.c \ $(BACNET_OBJECT_DIR)/nc.c \
$(BACNET_OBJECT_DIR)/netport.c \ $(BACNET_OBJECT_DIR)/netport.c \
$(BACNET_OBJECT_DIR)/osv.c \ $(BACNET_OBJECT_DIR)/osv.c \
$(BACNET_OBJECT_DIR)/piv.c \
$(BACNET_OBJECT_DIR)/program.c \ $(BACNET_OBJECT_DIR)/program.c \
$(BACNET_OBJECT_DIR)/structured_view.c \ $(BACNET_OBJECT_DIR)/structured_view.c \
$(BACNET_OBJECT_DIR)/timer.c \ $(BACNET_OBJECT_DIR)/timer.c \
+3 -2
View File
@@ -218,7 +218,7 @@ static object_functions_t My_Object_Table[] = {
NULL /* ReadRangeInfo */, NULL /* Iterator */, NULL /* Value_Lists */, NULL /* ReadRangeInfo */, NULL /* Iterator */, NULL /* Value_Lists */,
NULL /* COV */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */, NULL /* COV */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */, NULL /* Remove_List_Element */, 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 }, OctetString_Value_Writable_Property_List },
{ OBJECT_POSITIVE_INTEGER_VALUE, PositiveInteger_Value_Init, { OBJECT_POSITIVE_INTEGER_VALUE, PositiveInteger_Value_Init,
PositiveInteger_Value_Count, PositiveInteger_Value_Index_To_Instance, 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 /* Iterator */, NULL /* Value_Lists */, NULL /* COV */,
NULL /* COV Clear */, NULL /* Intrinsic Reporting */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */, NULL /* Remove_List_Element */, 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 }, PositiveInteger_Value_Writable_Property_List },
{ OBJECT_TIME_VALUE, Time_Value_Init, Time_Value_Count, { OBJECT_TIME_VALUE, Time_Value_Init, Time_Value_Count,
Time_Value_Index_To_Instance, Time_Value_Valid_Instance, Time_Value_Index_To_Instance, Time_Value_Valid_Instance,
+213 -71
View File
@@ -9,6 +9,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
/* BACnet Stack defines - first */ /* BACnet Stack defines - first */
#include "bacnet/bacdef.h" #include "bacnet/bacdef.h"
/* BACnet Stack API */ /* BACnet Stack API */
@@ -17,13 +18,11 @@
#include "bacnet/bactext.h" #include "bacnet/bactext.h"
#include "bacnet/basic/object/device.h" #include "bacnet/basic/object/device.h"
#include "bacnet/basic/services.h" #include "bacnet/basic/services.h"
#include "bacnet/basic/sys/keylist.h"
#include "bacnet/basic/object/osv.h" #include "bacnet/basic/object/osv.h"
#ifndef MAX_OCTETSTRING_VALUES /* Key List for storing object data sorted by instance number */
#define MAX_OCTETSTRING_VALUES 4 static OS_Keylist Object_List = NULL;
#endif
static OCTETSTRING_VALUE_DESCR OSV_Descr[MAX_OCTETSTRING_VALUES];
/* These three arrays are used by the ReadPropertyMultiple handler */ /* These three arrays are used by the ReadPropertyMultiple handler */
static const int32_t Properties_Required[] = { static const int32_t Properties_Required[] = {
@@ -48,6 +47,12 @@ static const int32_t Writable_Properties[] = {
PROP_PRESENT_VALUE, PROP_OUT_OF_SERVICE, -1 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( void OctetString_Value_Property_Lists(
const int32_t **pRequired, const int32_t **pRequired,
const int32_t **pOptional, 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; return Keylist_Data(Object_List, object_instance);
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);
}
} }
/* we simply have 0-n object instances. Yours might be */ /**
/* more complex, and then you need validate that the */ * @brief Creates an Octet String Value object instance.
/* given instance exists */ * @param object_instance Requested object instance number, or
bool OctetString_Value_Valid_Instance(uint32_t object_instance) * 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 true;
} }
return false; 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) 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 */ * @brief Maps an object list index to an instance number.
/* that correlates to the correct index */ * @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) 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 */ * @brief Maps an instance number to object list index.
/* that correlates to the correct instance number */ * @param object_instance Object instance number.
* @return Zero-based object index.
*/
unsigned OctetString_Value_Instance_To_Index(uint32_t object_instance) unsigned OctetString_Value_Instance_To_Index(uint32_t object_instance)
{ {
unsigned index = MAX_OCTETSTRING_VALUES; return Keylist_Index(Object_List, object_instance);
if (object_instance < MAX_OCTETSTRING_VALUES) {
index = object_instance;
}
return index;
} }
/** /**
@@ -146,59 +224,119 @@ bool OctetString_Value_Present_Value_Set(
const BACNET_OCTET_STRING *value, const BACNET_OCTET_STRING *value,
uint8_t priority) uint8_t priority)
{ {
unsigned index = 0; OCTETSTRING_VALUE_DESCR *pObject = NULL;
bool status = false; bool status = false;
(void)priority; (void)priority;
index = OctetString_Value_Instance_To_Index(object_instance); pObject = OctetString_Value_Object(object_instance);
if (index < MAX_OCTETSTRING_VALUES) { if (pObject) {
octetstring_copy(&OSV_Descr[index].Present_Value, value); octetstring_copy(&pObject->Present_Value, value);
status = true; status = true;
} }
return status; 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 *OctetString_Value_Present_Value(uint32_t object_instance)
{ {
BACNET_OCTET_STRING *value = NULL; BACNET_OCTET_STRING *value = NULL;
unsigned index = 0; OCTETSTRING_VALUE_DESCR *pObject = NULL;
index = OctetString_Value_Instance_To_Index(object_instance); pObject = OctetString_Value_Object(object_instance);
if (index < MAX_OCTETSTRING_VALUES) { if (pObject) {
value = &OSV_Descr[index].Present_Value; value = &pObject->Present_Value;
} }
return 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( bool OctetString_Value_Object_Name(
uint32_t object_instance, BACNET_CHARACTER_STRING *object_name) uint32_t object_instance, BACNET_CHARACTER_STRING *object_name)
{ {
char text[32] = ""; char text[32] = "";
bool status = false; bool status = false;
OCTETSTRING_VALUE_DESCR *pObject = NULL;
if (object_instance < MAX_OCTETSTRING_VALUES) { pObject = OctetString_Value_Object(object_instance);
snprintf( if (pObject) {
text, sizeof(text), "OCTETSTRING VALUE %lu", if (pObject->Object_Name) {
(unsigned long)object_instance); status =
status = characterstring_init_ansi(object_name, text); 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 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 OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
{ {
int apdu_len = 0; /* return value */ int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string; BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string; BACNET_CHARACTER_STRING char_string;
BACNET_OCTET_STRING *real_value = NULL; BACNET_OCTET_STRING *real_value = NULL;
unsigned object_index = 0;
bool state = false; bool state = false;
uint8_t *apdu = NULL; uint8_t *apdu = NULL;
OCTETSTRING_VALUE_DESCR *CurrentAV; OCTETSTRING_VALUE_DESCR *pObject = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) || if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) { (rpdata->application_data_len == 0)) {
@@ -207,10 +345,10 @@ int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
apdu = rpdata->application_data; apdu = rpdata->application_data;
object_index = OctetString_Value_Instance_To_Index(rpdata->object_instance); pObject = OctetString_Value_Object(rpdata->object_instance);
if (object_index < MAX_OCTETSTRING_VALUES) { if (!pObject) {
CurrentAV = &OSV_Descr[object_index]; rpdata->error_class = ERROR_CLASS_OBJECT;
} else { rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
return BACNET_STATUS_ERROR; 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_OVERRIDDEN, false);
bitstring_set_bit( bitstring_set_bit(
&bit_string, STATUS_FLAG_OUT_OF_SERVICE, &bit_string, STATUS_FLAG_OUT_OF_SERVICE,
CurrentAV->Out_Of_Service); pObject->Out_Of_Service);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string); apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break; break;
@@ -257,7 +395,7 @@ int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
break; break;
case PROP_OUT_OF_SERVICE: case PROP_OUT_OF_SERVICE:
state = CurrentAV->Out_Of_Service; state = pObject->Out_Of_Service;
apdu_len = encode_application_boolean(&apdu[0], state); apdu_len = encode_application_boolean(&apdu[0], state);
break; break;
default: default:
@@ -270,14 +408,24 @@ int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
return apdu_len; 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 OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
{ {
bool status = false; /* return value */ bool status = false; /* return value */
unsigned int object_index = 0;
int len = 0; int len = 0;
BACNET_APPLICATION_DATA_VALUE value = { 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 */ /* decode the some of the request */
len = bacapp_decode_application_data( 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; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false; return false;
} }
object_index = pObject = OctetString_Value_Object(wp_data->object_instance);
OctetString_Value_Instance_To_Index(wp_data->object_instance); if (!pObject) {
if (object_index < MAX_OCTETSTRING_VALUES) { wp_data->error_class = ERROR_CLASS_OBJECT;
CurrentAV = &OSV_Descr[object_index]; wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
} else {
return false; return false;
} }
@@ -326,7 +473,7 @@ bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
status = write_property_type_valid( status = write_property_type_valid(
wp_data, &value, BACNET_APPLICATION_TAG_BOOLEAN); wp_data, &value, BACNET_APPLICATION_TAG_BOOLEAN);
if (status) { if (status) {
CurrentAV->Out_Of_Service = value.type.Boolean; pObject->Out_Of_Service = value.type.Boolean;
} }
break; break;
default: default:
@@ -344,8 +491,3 @@ bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
return status; return status;
} }
void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance)
{
(void)object_instance;
}
+10 -2
View File
@@ -24,6 +24,7 @@ typedef struct octetstring_value_descr {
unsigned Event_State : 3; unsigned Event_State : 3;
bool Out_Of_Service; bool Out_Of_Service;
BACNET_OCTET_STRING Present_Value; BACNET_OCTET_STRING Present_Value;
const char *Object_Name;
} OCTETSTRING_VALUE_DESCR; } OCTETSTRING_VALUE_DESCR;
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
@@ -47,6 +48,10 @@ unsigned OctetString_Value_Instance_To_Index(uint32_t object_instance);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
bool OctetString_Value_Object_Name( bool OctetString_Value_Object_Name(
uint32_t object_instance, BACNET_CHARACTER_STRING *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 BACNET_STACK_EXPORT
int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata); 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 BACNET_STACK_EXPORT
void OctetString_Value_Out_Of_Service_Set(uint32_t instance, bool oos_flag); void OctetString_Value_Out_Of_Service_Set(uint32_t instance, bool oos_flag);
/* note: header of Intrinsic_Reporting function is required BACNET_STACK_EXPORT
even when INTRINSIC_REPORTING is not defined */ uint32_t OctetString_Value_Create(uint32_t object_instance);
BACNET_STACK_EXPORT
bool OctetString_Value_Delete(uint32_t object_instance);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance); void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance);
+210 -80
View File
@@ -9,6 +9,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
/* BACnet Stack defines - first */ /* BACnet Stack defines - first */
#include "bacnet/bacdef.h" #include "bacnet/bacdef.h"
/* BACnet Stack API */ /* BACnet Stack API */
@@ -17,13 +18,13 @@
#include "bacnet/bactext.h" #include "bacnet/bactext.h"
#include "bacnet/basic/object/device.h" #include "bacnet/basic/object/device.h"
#include "bacnet/basic/services.h" #include "bacnet/basic/services.h"
#include "bacnet/basic/sys/keylist.h"
#include "bacnet/basic/object/piv.h" #include "bacnet/basic/object/piv.h"
#ifndef MAX_POSITIVEINTEGER_VALUES /* Key List for storing object data sorted by instance number */
#define MAX_POSITIVEINTEGER_VALUES 4 static OS_Keylist Object_List = NULL;
#endif /* common object type */
static const BACNET_OBJECT_TYPE Object_Type = OBJECT_POSITIVE_INTEGER_VALUE;
static POSITIVEINTEGER_VALUE_DESCR PIV_Descr[MAX_POSITIVEINTEGER_VALUES];
/* These three arrays are used by the ReadPropertyMultiple handler */ /* These three arrays are used by the ReadPropertyMultiple handler */
static const int32_t Properties_Required[] = { 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; return Keylist_Data(Object_List, object_instance);
for (i = 0; i < MAX_POSITIVEINTEGER_VALUES; i++) {
memset(&PIV_Descr[i], 0x00, sizeof(POSITIVEINTEGER_VALUE_DESCR));
}
} }
/* we simply have 0-n object instances. Yours might be */ /**
/* more complex, and then you need validate that the */ * @brief Creates a Positive Integer Value object instance.
/* given instance exists */ * @param object_instance Requested object instance number, or
bool PositiveInteger_Value_Valid_Instance(uint32_t object_instance) * 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 true;
} }
return false; 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) 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 */ * @brief Maps an object list index to an instance number.
/* that correlates to the correct index */ * @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) 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 */ * @brief Maps an instance number to object list index.
/* that correlates to the correct instance number */ * @param object_instance Object instance number.
* @return Zero-based object index.
*/
unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance) unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance)
{ {
unsigned index = MAX_POSITIVEINTEGER_VALUES; return Keylist_Index(Object_List, object_instance);
if (object_instance < MAX_POSITIVEINTEGER_VALUES) {
index = object_instance;
}
return index;
} }
/** /**
@@ -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. * @return true if values are within range and present-value is set.
*/ */
bool PositiveInteger_Value_Present_Value_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; bool status = false;
(void)priority; (void)priority;
index = PositiveInteger_Value_Instance_To_Index(object_instance); pObject = PositiveInteger_Value_Object(object_instance);
if (index < MAX_POSITIVEINTEGER_VALUES) { if (pObject) {
PIV_Descr[index].Present_Value = value; pObject->Present_Value = value;
status = true; status = true;
} }
return status; 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; BACNET_UNSIGNED_INTEGER value = 0;
unsigned index = 0; POSITIVEINTEGER_VALUE_DESCR *pObject = NULL;
index = PositiveInteger_Value_Instance_To_Index(object_instance); pObject = PositiveInteger_Value_Object(object_instance);
if (index < MAX_POSITIVEINTEGER_VALUES) { if (pObject) {
value = PIV_Descr[index].Present_Value; value = pObject->Present_Value;
} }
return 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( bool PositiveInteger_Value_Object_Name(
uint32_t object_instance, BACNET_CHARACTER_STRING *object_name) uint32_t object_instance, BACNET_CHARACTER_STRING *object_name)
{ {
char text[32] = ""; char text[48] = "";
bool status = false; bool status = false;
POSITIVEINTEGER_VALUE_DESCR *pObject = NULL;
if (object_instance < MAX_POSITIVEINTEGER_VALUES) { pObject = PositiveInteger_Value_Object(object_instance);
snprintf( if (pObject) {
text, sizeof(text), "POSITIVEINTEGER VALUE %lu", if (pObject->Object_Name) {
(unsigned long)object_instance); status =
status = characterstring_init_ansi(object_name, text); 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; 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 * ReadProperty handler for this object. For the given ReadProperty
* data, the application_data is loaded or the error flags are set. * 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 */ int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string; BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string; BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
bool state = false; bool state = false;
uint8_t *apdu = NULL; uint8_t *apdu = NULL;
POSITIVEINTEGER_VALUE_DESCR *CurrentAV; POSITIVEINTEGER_VALUE_DESCR *pObject = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) || if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) { (rpdata->application_data_len == 0)) {
@@ -232,19 +365,17 @@ int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
apdu = rpdata->application_data; apdu = rpdata->application_data;
object_index = pObject = PositiveInteger_Value_Object(rpdata->object_instance);
PositiveInteger_Value_Instance_To_Index(rpdata->object_instance); if (!pObject) {
if (object_index < MAX_POSITIVEINTEGER_VALUES) { rpdata->error_class = ERROR_CLASS_OBJECT;
CurrentAV = &PIV_Descr[object_index]; rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
} else {
return BACNET_STATUS_ERROR; return BACNET_STATUS_ERROR;
} }
switch (rpdata->object_property) { switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER: case PROP_OBJECT_IDENTIFIER:
apdu_len = encode_application_object_id( apdu_len = encode_application_object_id(
&apdu[0], OBJECT_POSITIVE_INTEGER_VALUE, &apdu[0], Object_Type, rpdata->object_instance);
rpdata->object_instance);
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
@@ -255,8 +386,7 @@ int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
break; break;
case PROP_OBJECT_TYPE: case PROP_OBJECT_TYPE:
apdu_len = encode_application_enumerated( apdu_len = encode_application_enumerated(&apdu[0], Object_Type);
&apdu[0], OBJECT_POSITIVE_INTEGER_VALUE);
break; break;
case PROP_PRESENT_VALUE: 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_OVERRIDDEN, false);
bitstring_set_bit( bitstring_set_bit(
&bit_string, STATUS_FLAG_OUT_OF_SERVICE, &bit_string, STATUS_FLAG_OUT_OF_SERVICE,
CurrentAV->Out_Of_Service); pObject->Out_Of_Service);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string); apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break; break;
case PROP_UNITS: case PROP_UNITS:
apdu_len = encode_application_enumerated( apdu_len = encode_application_enumerated(
&apdu[0], (uint32_t)CurrentAV->Units); &apdu[0], (uint32_t)pObject->Units);
break; break;
/* BACnet Testing Observed Incident oi00109 /* BACnet Testing Observed Incident oi00109
Positive Integer Value / Units returned wrong datatype - 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 */ parties. Say 6 months -> September 2016 */
case PROP_OUT_OF_SERVICE: case PROP_OUT_OF_SERVICE:
state = CurrentAV->Out_Of_Service; state = pObject->Out_Of_Service;
apdu_len = encode_application_boolean(&apdu[0], state); apdu_len = encode_application_boolean(&apdu[0], state);
break; break;
default: 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 PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
{ {
bool status = false; /* return value */ bool status = false; /* return value */
unsigned int object_index = 0;
int len = 0; int len = 0;
BACNET_APPLICATION_DATA_VALUE value = { 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 */ /* decode the some of the request */
len = bacapp_decode_application_data( 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; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false; return false;
} }
object_index = pObject = PositiveInteger_Value_Object(wp_data->object_instance);
PositiveInteger_Value_Instance_To_Index(wp_data->object_instance); if (!pObject) {
if (object_index < MAX_POSITIVEINTEGER_VALUES) { wp_data->error_class = ERROR_CLASS_OBJECT;
CurrentAV = &PIV_Descr[object_index]; wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
} else {
return false; return false;
} }
switch (wp_data->object_property) { 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( status = write_property_type_valid(
wp_data, &value, BACNET_APPLICATION_TAG_BOOLEAN); wp_data, &value, BACNET_APPLICATION_TAG_BOOLEAN);
if (status) { if (status) {
CurrentAV->Out_Of_Service = value.type.Boolean; pObject->Out_Of_Service = value.type.Boolean;
} }
break; break;
case PROP_UNITS: 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); wp_data, &value, BACNET_APPLICATION_TAG_ENUMERATED);
if (status) { if (status) {
if (value.type.Enumerated <= UINT16_MAX) { if (value.type.Enumerated <= UINT16_MAX) {
CurrentAV->Units = (uint16_t)value.type.Enumerated; pObject->Units = (uint16_t)value.type.Enumerated;
} else { } else {
status = false; status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_class = ERROR_CLASS_PROPERTY;
@@ -397,8 +532,3 @@ bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
return status; return status;
} }
void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance)
{
(void)object_instance;
}
+15 -5
View File
@@ -22,8 +22,9 @@ extern "C" {
typedef struct positiveinteger_value_descr { typedef struct positiveinteger_value_descr {
bool Out_Of_Service : 1; bool Out_Of_Service : 1;
uint32_t Present_Value; BACNET_UNSIGNED_INTEGER Present_Value;
BACNET_ENGINEERING_UNITS Units; BACNET_ENGINEERING_UNITS Units;
const char *Object_Name;
} POSITIVEINTEGER_VALUE_DESCR; } POSITIVEINTEGER_VALUE_DESCR;
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
@@ -46,6 +47,11 @@ unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
bool PositiveInteger_Value_Object_Name( bool PositiveInteger_Value_Object_Name(
uint32_t object_instance, BACNET_CHARACTER_STRING *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 BACNET_STACK_EXPORT
int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata); 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 BACNET_STACK_EXPORT
bool PositiveInteger_Value_Present_Value_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);
BACNET_STACK_EXPORT 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 BACNET_STACK_EXPORT
bool PositiveInteger_Value_Change_Of_Value(uint32_t instance); 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 BACNET_STACK_EXPORT
void PositiveInteger_Value_Out_Of_Service_Set(uint32_t instance, bool oos_flag); void PositiveInteger_Value_Out_Of_Service_Set(uint32_t instance, bool oos_flag);
/* note: header of Intrinsic_Reporting function is required BACNET_STACK_EXPORT
even when INTRINSIC_REPORTING is not defined */ uint32_t PositiveInteger_Value_Create(uint32_t object_instance);
BACNET_STACK_EXPORT
bool PositiveInteger_Value_Delete(uint32_t object_instance);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance); void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance);
+52
View File
@@ -45,6 +45,8 @@
#include "bacnet/basic/object/ms-input.h" #include "bacnet/basic/object/ms-input.h"
#include "bacnet/basic/object/mso.h" #include "bacnet/basic/object/mso.h"
#include "bacnet/basic/object/msv.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/schedule.h"
#include "bacnet/basic/object/structured_view.h" #include "bacnet/basic/object/structured_view.h"
#include "bacnet/basic/object/trendlog.h" #include "bacnet/basic/object/trendlog.h"
@@ -122,6 +124,7 @@
defined(CONFIG_BACNET_BASIC_OBJECT_NETWORK_PORT) || \ defined(CONFIG_BACNET_BASIC_OBJECT_NETWORK_PORT) || \
defined(CONFIG_BACNET_BASIC_OBJECT_CALENDAR) || \ defined(CONFIG_BACNET_BASIC_OBJECT_CALENDAR) || \
defined(CONFIG_BACNET_BASIC_OBJECT_INTEGER_VALUE) || \ 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_POINT) || \
defined(CONFIG_BACNET_BASIC_OBJECT_LIFE_SAFETY_ZONE) || \ defined(CONFIG_BACNET_BASIC_OBJECT_LIFE_SAFETY_ZONE) || \
defined(CONFIG_BACNET_BASIC_OBJECT_LIGHTING_OUTPUT) || \ defined(CONFIG_BACNET_BASIC_OBJECT_LIGHTING_OUTPUT) || \
@@ -133,6 +136,7 @@
defined(CONFIG_BACNET_BASIC_OBJECT_FILE) || \ defined(CONFIG_BACNET_BASIC_OBJECT_FILE) || \
defined(CONFIG_BACNET_BASIC_OBJECT_STRUCTURED_VIEW) || \ defined(CONFIG_BACNET_BASIC_OBJECT_STRUCTURED_VIEW) || \
defined(CONFIG_BACNET_BASIC_OBJECT_BITSTRING_VALUE) || \ 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_TIME_VALUE) || \
defined(CONFIG_BACNET_BASIC_OBJECT_TIMER) || \ defined(CONFIG_BACNET_BASIC_OBJECT_TIMER) || \
defined(CONFIG_BACNET_BASIC_OBJECT_LOOP) || \ defined(CONFIG_BACNET_BASIC_OBJECT_LOOP) || \
@@ -155,6 +159,7 @@
#define CONFIG_BACNET_BASIC_OBJECT_NETWORK_PORT #define CONFIG_BACNET_BASIC_OBJECT_NETWORK_PORT
#define CONFIG_BACNET_BASIC_OBJECT_CALENDAR #define CONFIG_BACNET_BASIC_OBJECT_CALENDAR
#define CONFIG_BACNET_BASIC_OBJECT_INTEGER_VALUE #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_POINT
#define CONFIG_BACNET_BASIC_OBJECT_LIFE_SAFETY_ZONE #define CONFIG_BACNET_BASIC_OBJECT_LIFE_SAFETY_ZONE
#define CONFIG_BACNET_BASIC_OBJECT_LIGHTING_OUTPUT #define CONFIG_BACNET_BASIC_OBJECT_LIGHTING_OUTPUT
@@ -166,6 +171,7 @@
#define CONFIG_BACNET_BASIC_OBJECT_FILE #define CONFIG_BACNET_BASIC_OBJECT_FILE
#define CONFIG_BACNET_BASIC_OBJECT_STRUCTURED_VIEW #define CONFIG_BACNET_BASIC_OBJECT_STRUCTURED_VIEW
#define CONFIG_BACNET_BASIC_OBJECT_BITSTRING_VALUE #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_TIME_VALUE
#define CONFIG_BACNET_BASIC_OBJECT_TIMER #define CONFIG_BACNET_BASIC_OBJECT_TIMER
#define CONFIG_BACNET_BASIC_OBJECT_LOOP #define CONFIG_BACNET_BASIC_OBJECT_LOOP
@@ -813,6 +819,52 @@ static object_functions_t My_Object_Table[] = {
NULL /* Timer */, NULL /* Timer */,
CharacterString_Value_Writable_Property_List }, CharacterString_Value_Writable_Property_List },
#endif #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) #if defined(CONFIG_BACNET_BASIC_OBJECT_TIME_VALUE)
{ OBJECT_TIME_VALUE, { OBJECT_TIME_VALUE,
Time_Value_Init, Time_Value_Init,
+4 -1
View File
@@ -27,6 +27,7 @@ add_compile_definitions(
include_directories( include_directories(
${SRC_DIR} ${SRC_DIR}
${TST_DIR}/bacnet/basic/object/test
${TST_DIR}/ztest/include ${TST_DIR}/ztest/include
) )
@@ -46,9 +47,10 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/bacreal.c ${SRC_DIR}/bacnet/bacreal.c
${SRC_DIR}/bacnet/bacstr.c ${SRC_DIR}/bacnet/bacstr.c
${SRC_DIR}/bacnet/bactext.c ${SRC_DIR}/bacnet/bactext.c
${SRC_DIR}/bacnet/basic/sys/bigend.c
${SRC_DIR}/bacnet/datetime.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/days.c
${SRC_DIR}/bacnet/basic/sys/keylist.c
${SRC_DIR}/bacnet/indtext.c ${SRC_DIR}/bacnet/indtext.c
${SRC_DIR}/bacnet/hostnport.c ${SRC_DIR}/bacnet/hostnport.c
${SRC_DIR}/bacnet/lighting.c ${SRC_DIR}/bacnet/lighting.c
@@ -66,6 +68,7 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/secure_connect.c ${SRC_DIR}/bacnet/secure_connect.c
# Test and test library files # Test and test library files
./src/main.c ./src/main.c
${TST_DIR}/bacnet/basic/object/test/property_test.c
${ZTST_DIR}/ztest_mock.c ${ZTST_DIR}/ztest_mock.c
${ZTST_DIR}/ztest.c ${ZTST_DIR}/ztest.c
) )
+40 -38
View File
@@ -9,6 +9,7 @@
#include <zephyr/ztest.h> #include <zephyr/ztest.h>
#include <bacnet/basic/object/osv.h> #include <bacnet/basic/object/osv.h>
#include <bacnet/bactext.h> #include <bacnet/bactext.h>
#include <property_test.h>
/** /**
* @addtogroup bacnet_tests * @addtogroup bacnet_tests
@@ -24,46 +25,47 @@ ZTEST(osv_tests, testOctetString_Value)
static void testOctetString_Value(void) static void testOctetString_Value(void)
#endif #endif
{ {
uint8_t apdu[MAX_APDU] = { 0 }; bool status = false;
int len = 0, test_len = 0; unsigned count = 0, index = 0;
BACNET_READ_PROPERTY_DATA rpdata = { 0 }; uint32_t object_instance = 0, test_object_instance = 0;
BACNET_APPLICATION_DATA_VALUE value = { 0 }; const int32_t *writable_properties = NULL;
const int32_t *required_property = NULL; const int32_t skip_fail_property_list[] = { -1 };
const uint32_t instance = 1;
OctetString_Value_Init(); OctetString_Value_Init();
rpdata.application_data = &apdu[0]; test_object_instance = OctetString_Value_Create(BACNET_MAX_INSTANCE + 1);
rpdata.application_data_len = sizeof(apdu); zassert_equal(test_object_instance, BACNET_MAX_INSTANCE, NULL);
rpdata.object_type = OBJECT_OCTETSTRING_VALUE; test_object_instance = OctetString_Value_Create(BACNET_MAX_INSTANCE);
rpdata.object_instance = instance; zassert_not_equal(test_object_instance, BACNET_MAX_INSTANCE, NULL);
rpdata.array_index = BACNET_ARRAY_ALL; status = OctetString_Value_Delete(test_object_instance);
zassert_true(status, NULL);
OctetString_Value_Property_Lists(&required_property, NULL, NULL); count = OctetString_Value_Count();
while ((*required_property) >= 0) { zassert_true(count == 0, NULL);
rpdata.object_property = *required_property; test_object_instance = OctetString_Value_Create(object_instance);
len = OctetString_Value_Read_Property(&rpdata); zassert_equal(test_object_instance, object_instance, NULL);
zassert_true(len >= 0, NULL); status = OctetString_Value_Valid_Instance(object_instance);
if (len >= 0) { zassert_true(status, NULL);
test_len = bacapp_decode_known_property( status = OctetString_Value_Valid_Instance(object_instance - 1);
rpdata.application_data, len, &value, rpdata.object_type, zassert_false(status, NULL);
rpdata.object_property); index = OctetString_Value_Instance_To_Index(object_instance);
if (len != test_len) { zassert_equal(index, 0, NULL);
printf( test_object_instance = OctetString_Value_Index_To_Instance(index);
"property '%s': failed to decode!\n", zassert_equal(object_instance, test_object_instance, NULL);
bactext_property_name(rpdata.object_property)); count = OctetString_Value_Count();
} zassert_true(count == 1, NULL);
if (rpdata.object_property == PROP_PRIORITY_ARRAY) { test_object_instance = OctetString_Value_Index_To_Instance(0);
/* FIXME: known fail to decode */ zassert_equal(object_instance, test_object_instance, NULL);
len = test_len; bacnet_object_properties_read_write_test(
} OBJECT_OCTETSTRING_VALUE, object_instance,
zassert_equal(len, test_len, NULL); OctetString_Value_Property_Lists, OctetString_Value_Read_Property,
} else { OctetString_Value_Write_Property, skip_fail_property_list);
printf( bacnet_object_name_ascii_test(
"property '%s': failed to read!\n", object_instance, OctetString_Value_Name_Set,
bactext_property_name(rpdata.object_property)); OctetString_Value_Name_ASCII);
} OctetString_Value_Writable_Property_List(
required_property++; object_instance, &writable_properties);
} zassert_not_null(writable_properties, NULL);
status = OctetString_Value_Delete(object_instance);
zassert_true(status, NULL);
} }
/** /**
* @} * @}
+4 -1
View File
@@ -27,6 +27,7 @@ add_compile_definitions(
include_directories( include_directories(
${SRC_DIR} ${SRC_DIR}
${TST_DIR}/bacnet/basic/object/test
${TST_DIR}/ztest/include ${TST_DIR}/ztest/include
) )
@@ -46,9 +47,10 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/bacreal.c ${SRC_DIR}/bacnet/bacreal.c
${SRC_DIR}/bacnet/bacstr.c ${SRC_DIR}/bacnet/bacstr.c
${SRC_DIR}/bacnet/bactext.c ${SRC_DIR}/bacnet/bactext.c
${SRC_DIR}/bacnet/basic/sys/bigend.c
${SRC_DIR}/bacnet/datetime.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/days.c
${SRC_DIR}/bacnet/basic/sys/keylist.c
${SRC_DIR}/bacnet/indtext.c ${SRC_DIR}/bacnet/indtext.c
${SRC_DIR}/bacnet/hostnport.c ${SRC_DIR}/bacnet/hostnport.c
${SRC_DIR}/bacnet/lighting.c ${SRC_DIR}/bacnet/lighting.c
@@ -66,6 +68,7 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/secure_connect.c ${SRC_DIR}/bacnet/secure_connect.c
# Test and test library files # Test and test library files
./src/main.c ./src/main.c
${TST_DIR}/bacnet/basic/object/test/property_test.c
${ZTST_DIR}/ztest_mock.c ${ZTST_DIR}/ztest_mock.c
${ZTST_DIR}/ztest.c ${ZTST_DIR}/ztest.c
) )
+42 -34
View File
@@ -10,6 +10,7 @@
#include <zephyr/ztest.h> #include <zephyr/ztest.h>
#include <bacnet/basic/object/piv.h> #include <bacnet/basic/object/piv.h>
#include <bacnet/bactext.h> #include <bacnet/bactext.h>
#include <property_test.h>
/** /**
* @addtogroup bacnet_tests * @addtogroup bacnet_tests
@@ -25,42 +26,49 @@ ZTEST(piv_tests, testPositiveInteger_Value)
static void testPositiveInteger_Value(void) static void testPositiveInteger_Value(void)
#endif #endif
{ {
uint8_t apdu[MAX_APDU] = { 0 }; bool status = false;
int len = 0, test_len = 0; unsigned count = 0, index = 0;
BACNET_READ_PROPERTY_DATA rpdata = { 0 }; uint32_t object_instance = 0, test_object_instance = 0;
BACNET_APPLICATION_DATA_VALUE value = { 0 }; const int32_t *writable_properties = NULL;
const int32_t *required_property = NULL; const int32_t skip_fail_property_list[] = { -1 };
const uint32_t instance = 1;
PositiveInteger_Value_Init(); PositiveInteger_Value_Init();
rpdata.application_data = &apdu[0]; test_object_instance =
rpdata.application_data_len = sizeof(apdu); PositiveInteger_Value_Create(BACNET_MAX_INSTANCE + 1);
rpdata.object_type = OBJECT_POSITIVE_INTEGER_VALUE; zassert_equal(test_object_instance, BACNET_MAX_INSTANCE, NULL);
rpdata.object_instance = instance; test_object_instance = PositiveInteger_Value_Create(BACNET_MAX_INSTANCE);
rpdata.array_index = BACNET_ARRAY_ALL; zassert_not_equal(test_object_instance, BACNET_MAX_INSTANCE, NULL);
status = PositiveInteger_Value_Delete(test_object_instance);
PositiveInteger_Value_Property_Lists(&required_property, NULL, NULL); zassert_true(status, NULL);
while ((*required_property) >= 0) { count = PositiveInteger_Value_Count();
rpdata.object_property = *required_property; zassert_true(count == 0, NULL);
len = PositiveInteger_Value_Read_Property(&rpdata); test_object_instance = PositiveInteger_Value_Create(object_instance);
zassert_true(len >= 0, NULL); zassert_equal(test_object_instance, object_instance, NULL);
if (len >= 0) { status = PositiveInteger_Value_Valid_Instance(object_instance);
test_len = bacapp_decode_known_property( zassert_true(status, NULL);
rpdata.application_data, len, &value, rpdata.object_type, status = PositiveInteger_Value_Valid_Instance(object_instance - 1);
rpdata.object_property); zassert_false(status, NULL);
if (len != test_len) { index = PositiveInteger_Value_Instance_To_Index(object_instance);
printf( zassert_equal(index, 0, NULL);
"property '%s': failed to decode!\n", test_object_instance = PositiveInteger_Value_Index_To_Instance(index);
bactext_property_name(rpdata.object_property)); zassert_equal(object_instance, test_object_instance, NULL);
} count = PositiveInteger_Value_Count();
if (rpdata.object_property == PROP_PRIORITY_ARRAY) { zassert_true(count == 1, NULL);
/* FIXME: known fail to decode */ test_object_instance = PositiveInteger_Value_Index_To_Instance(0);
len = test_len; zassert_equal(object_instance, test_object_instance, NULL);
} bacnet_object_properties_read_write_test(
zassert_equal(len, test_len, NULL); OBJECT_POSITIVE_INTEGER_VALUE, object_instance,
} PositiveInteger_Value_Property_Lists,
required_property++; 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);
} }
/** /**
* @} * @}