Fixed CreateObject service list-of-initial-values encoding and decoding. (#1199)

Fixes the CreateObject service list-of-initial-values encoding and decoding by refactoring the data structure to be similar to WriteProperty. The implementation changes from using a linked list of property values to using a flat buffer approach with delayed decoding.

Changes:

* Refactored BACNET_CREATE_OBJECT_DATA structure to use an application_data buffer instead of a linked list for initial values
* Added a new create_object_process() and create_object_initializer_list_process() functions to centralize object creation logic and error reporting
* Updated all device implementations to use the new centralized creation functions
* Enhanced the create-object example application to support command-line specification of initial property values
* Added comprehensive test coverage for the new encoding/decoding and processing functions
This commit is contained in:
Steve Karg
2026-01-15 14:50:59 -06:00
committed by GitHub
parent 21daea9eb4
commit 5802bd0ecc
18 changed files with 921 additions and 212 deletions
+5 -2
View File
@@ -721,9 +721,12 @@ static bool Channel_Write_Members(
"channel[%lu].Channel_Write_Member[%u] coerced\n",
(unsigned long)object_instance, m);
if (Write_Property_Internal_Callback) {
status = Write_Property_Internal_Callback(&wp_data);
status = write_property_bacnet_array_valid(&wp_data);
if (status) {
wp_data.error_code = ERROR_CODE_SUCCESS;
status = Write_Property_Internal_Callback(&wp_data);
if (status) {
wp_data.error_code = ERROR_CODE_SUCCESS;
}
}
debug_printf(
"channel[%lu].Channel_Write_Member[%u] "
+14 -39
View File
@@ -2339,51 +2339,26 @@ bool Device_Create_Object(BACNET_CREATE_OBJECT_DATA *data)
{
bool status = false;
struct object_functions *pObject = NULL;
uint32_t object_instance;
bool object_exists = false;
bool object_supported = false;
pObject = Device_Object_Functions_Find(data->object_type);
if (pObject != NULL) {
if (!pObject->Object_Create) {
/* The device supports the object type and may have
sufficient space, but does not support the creation of the
object for some other reason.*/
data->error_class = ERROR_CLASS_OBJECT;
data->error_code = ERROR_CODE_DYNAMIC_CREATION_NOT_SUPPORTED;
} else if (
pObject->Object_Valid_Instance &&
if (pObject->Object_Valid_Instance &&
pObject->Object_Valid_Instance(data->object_instance)) {
/* The object being created already exists */
data->error_class = ERROR_CLASS_OBJECT;
data->error_code = ERROR_CODE_OBJECT_IDENTIFIER_ALREADY_EXISTS;
} else {
if (data->list_of_initial_values) {
/* FIXME: add support for writing to list of initial values */
/* A property specified by the Property_Identifier in the
List of Initial Values does not support initialization
during the CreateObject service. */
data->first_failed_element_number = 1;
data->error_class = ERROR_CLASS_PROPERTY;
data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
/* and the object shall not be created */
} else {
object_instance = pObject->Object_Create(data->object_instance);
if (object_instance == BACNET_MAX_INSTANCE) {
/* The device cannot allocate the space needed
for the new object.*/
data->error_class = ERROR_CLASS_RESOURCES;
data->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
} else {
/* required by ACK */
data->object_instance = object_instance;
Device_Inc_Database_Revision();
status = true;
}
}
object_exists = true;
}
object_supported = true;
status = create_object_process(
data, object_supported, object_exists, pObject->Object_Create,
pObject->Object_Delete, pObject->Object_Write_Property);
} else {
/* The device does not support the specified object type. */
data->error_class = ERROR_CLASS_OBJECT;
data->error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE;
/* fill in the error values */
status = create_object_process(
data, object_supported, object_exists, NULL, NULL, NULL);
}
if (status) {
Device_Inc_Database_Revision();
}
return status;
+5 -2
View File
@@ -2051,9 +2051,12 @@ static bool Loop_Write_Manipulated_Variable(
wp_data.application_data_len =
encode_application_real(wp_data.application_data, value);
if (Write_Property_Internal_Callback) {
status = Write_Property_Internal_Callback(&wp_data);
status = write_property_bacnet_array_valid(&wp_data);
if (status) {
wp_data.error_code = ERROR_CODE_SUCCESS;
status = Write_Property_Internal_Callback(&wp_data);
if (status) {
wp_data.error_code = ERROR_CODE_SUCCESS;
}
}
}
}
+5 -2
View File
@@ -496,9 +496,12 @@ static bool Timer_Write_Members(
wp_data.application_data, sizeof(wp_data.application_data),
value);
if (Write_Property_Internal_Callback) {
status = Write_Property_Internal_Callback(&wp_data);
status = write_property_bacnet_array_valid(&wp_data);
if (status) {
wp_data.error_code = ERROR_CODE_SUCCESS;
status = Write_Property_Internal_Callback(&wp_data);
if (status) {
wp_data.error_code = ERROR_CODE_SUCCESS;
}
}
}
}
+14 -39
View File
@@ -2763,51 +2763,26 @@ bool Device_Create_Object(BACNET_CREATE_OBJECT_DATA *data)
{
bool status = false;
struct object_functions *pObject = NULL;
uint32_t object_instance;
bool object_exists = false;
bool object_supported = false;
pObject = Device_Object_Functions_Find(data->object_type);
if (pObject != NULL) {
if (!pObject->Object_Create) {
/* The device supports the object type and may have
sufficient space, but does not support the creation of the
object for some other reason.*/
data->error_class = ERROR_CLASS_OBJECT;
data->error_code = ERROR_CODE_DYNAMIC_CREATION_NOT_SUPPORTED;
} else if (
pObject->Object_Valid_Instance &&
if (pObject->Object_Valid_Instance &&
pObject->Object_Valid_Instance(data->object_instance)) {
/* The object being created already exists */
data->error_class = ERROR_CLASS_OBJECT;
data->error_code = ERROR_CODE_OBJECT_IDENTIFIER_ALREADY_EXISTS;
} else {
if (data->list_of_initial_values) {
/* FIXME: add support for writing to list of initial values */
/* A property specified by the Property_Identifier in the
List of Initial Values does not support initialization
during the CreateObject service. */
data->first_failed_element_number = 1;
data->error_class = ERROR_CLASS_PROPERTY;
data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
/* and the object shall not be created */
} else {
object_instance = pObject->Object_Create(data->object_instance);
if (object_instance == BACNET_MAX_INSTANCE) {
/* The device cannot allocate the space needed
for the new object.*/
data->error_class = ERROR_CLASS_RESOURCES;
data->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
} else {
/* required by ACK */
data->object_instance = object_instance;
Device_Inc_Database_Revision();
status = true;
}
}
object_exists = true;
}
object_supported = true;
status = create_object_process(
data, object_supported, object_exists, pObject->Object_Create,
pObject->Object_Delete, pObject->Object_Write_Property);
} else {
/* The device does not support the specified object type. */
data->error_class = ERROR_CLASS_OBJECT;
data->error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE;
/* fill in the error values */
status = create_object_process(
data, object_supported, object_exists, NULL, NULL, NULL);
}
if (status) {
Device_Inc_Database_Revision();
}
return status;
+1 -1
View File
@@ -34,7 +34,7 @@
* - an Abort if
* - the message is segmented
* - if decoding fails
* - a SimpleACK if Device_Create_Object() succeeds
* - a ComplexACK if Device_Create_Object() succeeds
* - an Error if Device_Create_Object() fails
*
* @param service_request [in] The contents of the service request.
+13 -1
View File
@@ -56,6 +56,8 @@ uint8_t Send_Create_Object_Request_Data(
BACNET_CREATE_OBJECT_DATA data = { 0 };
BACNET_NPDU_DATA npdu_data = { 0 };
uint8_t service = SERVICE_CONFIRMED_CREATE_OBJECT;
BACNET_PROPERTY_VALUE *value;
uint8_t *application_data = NULL;
if (!dcc_communication_enabled()) {
return 0;
@@ -81,7 +83,17 @@ uint8_t Send_Create_Object_Request_Data(
/* encode the APDU service */
data.object_type = object_type;
data.object_instance = object_instance;
data.list_of_initial_values = values;
data.application_data_len = 0;
value = values;
#if BACNET_CREATE_OBJECT_LIST_VALUES_ENABLED
application_data = data.application_data;
#endif
while (value) {
len = create_object_encode_initial_value(
application_data, data.application_data_len, value);
data.application_data_len += len;
value = value->next;
}
/* get the length of the APDU */
len = create_object_encode_service_request(NULL, &data);
pdu_len += len;
+332 -24
View File
@@ -15,6 +15,151 @@
#include "bacnet/bacerror.h"
#include "bacnet/create_object.h"
/**
* @brief Encode one value for CreateObject List-of-Initial-Values
* @param apdu Pointer to the buffer for encoded values
* @param offset Offset into the buffer to start encoding
* @param value Pointer to the property value used for encoding
* @return Bytes encoded or zero on error.
*/
int create_object_encode_initial_value(
uint8_t *apdu, int offset, const BACNET_PROPERTY_VALUE *value)
{
if (apdu) {
apdu += offset;
}
return bacapp_property_value_encode(apdu, value);
}
/**
* @brief Decode one BACnetPropertyValue value
*
* BACnetPropertyValue ::= SEQUENCE {
* property-identifier [0] BACnetPropertyIdentifier,
* property-array-index [1] Unsigned OPTIONAL,
* -- used only with array datatypes
* -- if omitted with an array the entire array is referenced
* property-value [2] ABSTRACT-SYNTAX.&Type,
* -- any datatype appropriate for the specified property
* priority [3] Unsigned (1..16) OPTIONAL
* -- used only when property is commandable
* }
*
* @param apdu Pointer to the buffer of encoded value
* @param apdu_size Size of the buffer holding the encode value
* @param value Pointer to the data used for decoding one value
* @return number of bytes decoded or BACNET_STATUS_ERROR on error.
*/
int create_object_decode_initial_value(
const uint8_t *apdu,
uint32_t apdu_size,
BACNET_CREATE_OBJECT_PROPERTY_VALUE *value)
{
int len = 0;
int apdu_len = 0;
uint32_t enumerated_value = 0;
uint32_t len_value_type = 0;
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
BACNET_PROPERTY_ID property_identifier = PROP_ALL;
int imax = 0;
if (!apdu) {
return BACNET_STATUS_ERROR;
}
/* property-identifier [0] BACnetPropertyIdentifier */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &enumerated_value);
if (len > 0) {
property_identifier = enumerated_value;
if (value) {
value->propertyIdentifier = property_identifier;
}
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* property-array-index [1] Unsigned OPTIONAL */
if (bacnet_is_context_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 1, &len, &len_value_type)) {
apdu_len += len;
len = bacnet_unsigned_decode(
&apdu[apdu_len], apdu_size - apdu_len, len_value_type,
&unsigned_value);
if (len > 0) {
if (unsigned_value > UINT32_MAX) {
return BACNET_STATUS_ERROR;
} else {
apdu_len += len;
if (value) {
value->propertyArrayIndex = unsigned_value;
}
}
} else {
return BACNET_STATUS_ERROR;
}
} else {
if (value) {
value->propertyArrayIndex = BACNET_ARRAY_ALL;
}
}
/* property-value [2] ABSTRACT-SYNTAX.&Type */
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 2, &len)) {
/* determine the length of the data within the tags */
imax =
bacnet_enclosed_data_length(&apdu[apdu_len], apdu_size - apdu_len);
if (imax == BACNET_STATUS_ERROR) {
return BACNET_STATUS_ERROR;
}
/* count the opening tag number length after finding enclosed length */
apdu_len += len;
if (imax > MAX_APDU) {
/* not enough size in application_data to store the data chunk */
return BACNET_STATUS_ERROR;
} else if (value) {
/* point to the data from the APDU */
value->application_data = &apdu[apdu_len];
value->application_data_len = imax;
}
/* add on the data length */
apdu_len += imax;
if (!bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 2, &len)) {
return BACNET_STATUS_ERROR;
}
/* count the closing tag number length */
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* priority [3] Unsigned (1..16) OPTIONAL */
if (bacnet_is_context_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 3, &len, &len_value_type)) {
apdu_len += len;
len = bacnet_unsigned_decode(
&apdu[apdu_len], apdu_size - apdu_len, len_value_type,
&unsigned_value);
if (len > 0) {
if (unsigned_value > UINT8_MAX) {
return BACNET_STATUS_ERROR;
} else {
apdu_len += len;
if (value) {
value->priority = unsigned_value;
}
}
} else {
return BACNET_STATUS_ERROR;
}
} else {
if (value) {
value->priority = BACNET_NO_PRIORITY;
}
}
return apdu_len;
}
/**
* @brief Encode the CreateObject service request
*
@@ -36,7 +181,6 @@ int create_object_encode_service_request(
{
int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */
BACNET_PROPERTY_VALUE *value = NULL; /* value in list */
if (data) {
/* object-specifier [0] */
@@ -66,29 +210,27 @@ int create_object_encode_service_request(
if (apdu) {
apdu += len;
}
if (data->list_of_initial_values) {
#if BACNET_CREATE_OBJECT_LIST_VALUES_ENABLED
if ((data->application_data_len > 0) &&
(data->application_data_len <= sizeof(data->application_data))) {
/* list-of-initial-values [1] OPTIONAL */
len = encode_opening_tag(apdu, 1);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* the first value includes a pointer to the next value, etc */
value = data->list_of_initial_values;
while (value != NULL) {
/* SEQUENCE OF BACnetPropertyValue */
len = bacapp_property_value_encode(apdu, value);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* is there another one to encode? */
/* FIXME: check to see if there is room in the APDU */
value = value->next;
len = data->application_data_len;
if (apdu) {
memmove(apdu, data->application_data, len);
}
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 1);
apdu_len += len;
}
#endif
}
return apdu_len;
@@ -141,7 +283,7 @@ int create_object_decode_service_request(
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t object_instance = 0;
uint32_t enumerated_value = 0;
BACNET_PROPERTY_VALUE *list_of_initial_values = NULL;
int imax = 0;
/* object-specifier [0] CHOICE */
if (!bacnet_is_opening_tag_number(
@@ -203,27 +345,41 @@ int create_object_decode_service_request(
apdu_len += len;
/* list-of-initial-values [1] SEQUENCE OF BACnetPropertyValue OPTIONAL */
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
apdu_len += len;
if (data) {
list_of_initial_values = data->list_of_initial_values;
}
len = bacapp_property_value_decode(
&apdu[apdu_len], apdu_size - apdu_len, list_of_initial_values);
if (len <= 0) {
&apdu[apdu_len], apdu_size - apdu_len, 1, &len)) {
/* determine the length of the data within the tags */
imax =
bacnet_enclosed_data_length(&apdu[apdu_len], apdu_size - apdu_len);
if (imax == BACNET_STATUS_ERROR) {
if (data) {
data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
/* count the opening tag number length after finding enclosed length */
apdu_len += len;
if (imax > MAX_APDU) {
/* not enough size in application_data to store the data chunk */
if (data) {
data->error_code = ERROR_CODE_REJECT_BUFFER_OVERFLOW;
}
return BACNET_STATUS_REJECT;
} else if (data) {
/* copy the data from the APDU */
#if BACNET_CREATE_OBJECT_LIST_VALUES_ENABLED
memmove(data->application_data, &apdu[apdu_len], (size_t)imax);
#endif
data->application_data_len = imax;
}
/* add on the data length */
apdu_len += imax;
if (!bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
&apdu[apdu_len], apdu_size - apdu_len, 1, &len)) {
if (data) {
data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
/* count the closing tag number length */
apdu_len += len;
}
@@ -441,3 +597,155 @@ int create_object_error_ack_service_decode(
return apdu_len;
}
/**
* @brief Initialize the created object with the provided initializers.
* @param data [in] The Create Object data containing the initial values.
* @param write_property [in] Function pointer to the Write Property handler.
* @return true if successful, false on error.
*/
bool create_object_initializer_list_process(
BACNET_CREATE_OBJECT_DATA *data, write_property_function write_property)
{
BACNET_WRITE_PROPERTY_DATA wp_data = { 0 };
BACNET_CREATE_OBJECT_PROPERTY_VALUE value = { 0 };
int len = 0, apdu_len = 0;
uint8_t *application_data = NULL;
if (!data) {
return false;
}
if (!write_property) {
return false;
}
data->first_failed_element_number = 1;
wp_data.object_type = data->object_type;
wp_data.object_instance = data->object_instance;
wp_data.error_class = ERROR_CLASS_PROPERTY;
wp_data.error_code = ERROR_CODE_SUCCESS;
while (data->application_data_len > apdu_len) {
#if BACNET_CREATE_OBJECT_LIST_VALUES_ENABLED
application_data = &data->application_data[apdu_len];
#endif
len = create_object_decode_initial_value(
application_data, data->application_data_len - apdu_len, &value);
if (len <= 0) {
return false;
}
wp_data.object_property = value.propertyIdentifier;
wp_data.array_index = value.propertyArrayIndex;
memmove(
&wp_data.application_data[0], value.application_data,
(size_t)value.application_data_len);
wp_data.application_data_len = value.application_data_len;
wp_data.priority = value.priority;
if (!write_property_bacnet_array_valid(&wp_data)) {
return false;
}
/* write the property - use the provided function */
if (!write_property(&wp_data)) {
/* report the error */
data->error_class = wp_data.error_class;
data->error_code = wp_data.error_code;
return false;
}
data->first_failed_element_number++;
apdu_len += len;
}
return true;
}
/**
* @brief Process the CreateObject request.
* @param data [in,out] The Create Object data containing the request details.
* @param object_supported [in] Flag indicating if the object type is supported.
* @param object_exists [in] Flag indicating if the object already exists.
* @param create_object [in] Function pointer to the Create Object handler.
* @param delete_object [in] Function pointer to the Delete Object handler.
* @param write_property [in] Function pointer to the Write Property handler.
* @return true if successful, false on error.
*/
bool create_object_process(
BACNET_CREATE_OBJECT_DATA *data,
bool object_supported,
bool object_exists,
create_object_function create_object,
delete_object_function delete_object,
write_property_function write_property)
{
bool status = false;
uint32_t object_instance;
if (!data) {
return false;
}
if (!object_supported) {
/* The device does not support the specified object type. */
data->error_class = ERROR_CLASS_OBJECT;
data->error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE;
} else if (!create_object) {
/* The device supports the object type and may have
sufficient space, but does not support the creation of the
object for some other reason.*/
data->error_class = ERROR_CLASS_OBJECT;
data->error_code = ERROR_CODE_DYNAMIC_CREATION_NOT_SUPPORTED;
} else if (object_exists) {
/* The object being created already exists */
data->error_class = ERROR_CLASS_OBJECT;
data->error_code = ERROR_CODE_OBJECT_IDENTIFIER_ALREADY_EXISTS;
} else {
if (data->application_data_len) {
/* The optional 'List of Initial Values' parameter is included */
object_instance = create_object(data->object_instance);
if (object_instance == BACNET_MAX_INSTANCE) {
/* The device cannot allocate the space needed
for the new object.*/
data->error_class = ERROR_CLASS_RESOURCES;
data->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
} else if (write_property) {
/* set the created object instance */
data->object_instance = object_instance;
/* If the optional 'List of Initial Values' parameter
is included, then all properties in the list shall
be initialized as indicated. */
data->error_class = ERROR_CLASS_PROPERTY;
data->error_code = ERROR_CODE_SUCCESS;
if (!create_object_initializer_list_process(
data, write_property)) {
/* initialization failed - remove the object */
if (delete_object) {
(void)delete_object(object_instance);
}
if (data->error_code == ERROR_CODE_SUCCESS) {
/* A property specified by the Property_Identifier
in the List of Initial Values does not support
initialization during the CreateObject service.*/
data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
}
} else {
data->first_failed_element_number = 0;
status = true;
}
} else {
/* cannot initialize without write property handler */
data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
}
} else {
object_instance = create_object(data->object_instance);
if (object_instance == BACNET_MAX_INSTANCE) {
/* The device cannot allocate the space needed
for the new object.*/
data->error_class = ERROR_CLASS_RESOURCES;
data->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
} else {
/* required by ACK */
data->object_instance = object_instance;
data->first_failed_element_number = 0;
status = true;
}
}
}
return status;
}
+53 -2
View File
@@ -15,6 +15,12 @@
/* BACnet Stack API */
#include "bacnet/bacdcode.h"
#include "bacnet/bacapp.h"
#include "bacnet/delete_object.h"
#include "bacnet/wp.h"
#ifndef BACNET_CREATE_OBJECT_LIST_VALUES_ENABLED
#define BACNET_CREATE_OBJECT_LIST_VALUES_ENABLED 1
#endif
/**
* CreateObject-Request ::= SEQUENCE {
@@ -29,13 +35,42 @@ typedef struct BACnet_Create_Object_Data {
/* note: use BACNET_MAX_INSTANCE to choose CHOICE=[0] object_type */
uint32_t object_instance;
BACNET_OBJECT_TYPE object_type;
/* simple linked list of values */
BACNET_PROPERTY_VALUE *list_of_initial_values;
BACNET_ERROR_CLASS error_class;
BACNET_ERROR_CODE error_code;
#if BACNET_CREATE_OBJECT_LIST_VALUES_ENABLED
/* list of values similar to WriteProperty - decoded later */
uint8_t application_data[MAX_APDU];
#endif
int application_data_len;
/* This parameter, of type Unsigned, shall convey the numerical
position, starting at 1, of the offending 'Initial Value' in the
'List of Initial Values' parameter received in the request.
If the request is considered invalid for reasons other than the 'List of
Initial Values' parameter, the 'First Failed Element Number' shall
be equal to zero. */
BACNET_UNSIGNED_INTEGER first_failed_element_number;
} BACNET_CREATE_OBJECT_DATA;
/**
* BACnetPropertyValue ::= SEQUENCE {
* property-identifier [0] BACnetPropertyIdentifier,
* property-array-index [1] Unsigned OPTIONAL,
* -- used only with array datatypes
* -- if omitted with an array the entire array is referenced
* property-value [2] ABSTRACT-SYNTAX.&Type,
* -- any datatype appropriate for the specified property
* priority [3] Unsigned (1..16) OPTIONAL
* -- used only when property is commandable
* }
*/
typedef struct BACnet_Create_Object_Property_Value {
BACNET_PROPERTY_ID propertyIdentifier;
BACNET_ARRAY_INDEX propertyArrayIndex;
const uint8_t *application_data;
int application_data_len;
uint8_t priority;
} BACNET_CREATE_OBJECT_PROPERTY_VALUE;
/**
* @brief CreateObject service handler for an object
* @ingroup ObjHelpers
@@ -49,6 +84,10 @@ typedef uint32_t (*create_object_function)(uint32_t object_instance);
extern "C" {
#endif /* __cplusplus */
BACNET_STACK_EXPORT
int create_object_encode_initial_value(
uint8_t *apdu, int offset, const BACNET_PROPERTY_VALUE *value);
BACNET_STACK_EXPORT
size_t create_object_service_request_encode(
uint8_t *apdu, size_t apdu_size, BACNET_CREATE_OBJECT_DATA *data);
@@ -82,6 +121,18 @@ BACNET_STACK_EXPORT
int create_object_error_ack_encode(
uint8_t *apdu, uint8_t invoke_id, const BACNET_CREATE_OBJECT_DATA *data);
BACNET_STACK_EXPORT
bool create_object_initializer_list_process(
BACNET_CREATE_OBJECT_DATA *data, write_property_function write_property);
BACNET_STACK_EXPORT
bool create_object_process(
BACNET_CREATE_OBJECT_DATA *data,
bool object_supported,
bool object_exists,
create_object_function create_object,
delete_object_function delete_object,
write_property_function write_property);
#ifdef __cplusplus
}
#endif /* __cplusplus */