diff --git a/src/bacnet/bacdcode.c b/src/bacnet/bacdcode.c index a784a4d2..25af2946 100644 --- a/src/bacnet/bacdcode.c +++ b/src/bacnet/bacdcode.c @@ -4703,3 +4703,86 @@ int bacnet_array_encode( return apdu_len; } + +/** + * @brief Decode a BACnetARRAY property value and call a function for each + * element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index to be decoded + * 0 for the array size + * 1 to n for individual array members + * BACNET_ARRAY_ALL for the full array to be read. + * @param decode_function [in] function to decode one property array element and + * determine the length + * @param write_function [in] function to write one property array element with + * the encoded value + * @param array_size [in] number of elements in the array + * @param apdu [out] Buffer in which the APDU contents are built. + * @param max_apdu [in] Max length of the APDU buffer. + * @return BACNET_ERROR_CODE value + */ +BACNET_ERROR_CODE bacnet_array_write( + uint32_t object_instance, + BACNET_ARRAY_INDEX array_index, + bacnet_array_property_element_decode_function decode_function, + bacnet_array_property_element_write_function write_function, + BACNET_UNSIGNED_INTEGER array_size, + uint8_t *apdu, + size_t apdu_size) +{ + int len = 0; + BACNET_ERROR_CODE error_code = ERROR_CODE_SUCCESS; + size_t apdu_len; + BACNET_ARRAY_INDEX index; + BACNET_UNSIGNED_INTEGER unsigned_value; + + if (array_index == 0) { + /* Array element zero is the number of objects in the list */ + len = bacnet_unsigned_application_decode( + apdu, apdu_size, &unsigned_value); + if (len > 0) { + error_code = + write_function(object_instance, array_index, apdu, apdu_size); + } else if (len == 0) { + error_code = ERROR_CODE_INVALID_DATA_TYPE; + } else { + error_code = ERROR_CODE_ABORT_OTHER; + } + } else if (array_index == BACNET_ARRAY_ALL) { + /* verify decoding of all elements */ + apdu_len = 0; + for (index = 1; index <= array_size; index++) { + len = decode_function( + object_instance, &apdu[apdu_len], apdu_size - apdu_len); + if (len > 0) { + apdu_len += len; + } else { + error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + break; + } + } + if (error_code == ERROR_CODE_SUCCESS) { + /* write each element */ + apdu_len = 0; + for (index = 1; index <= array_size; index++) { + len = decode_function( + object_instance, &apdu[apdu_len], apdu_size - apdu_len); + error_code = write_function( + object_instance, index, &apdu[apdu_len], len); + if (error_code != ERROR_CODE_SUCCESS) { + break; + } + apdu_len += len; + } + } + } else if (array_index <= array_size) { + /* index was specified; write a single array element */ + error_code = + write_function(object_instance, array_index, apdu, apdu_size); + } else { + /* array_index was specified out of range */ + error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + } + + return error_code; +} diff --git a/src/bacnet/bacdcode.h b/src/bacnet/bacdcode.h index 9fb49543..87077405 100644 --- a/src/bacnet/bacdcode.h +++ b/src/bacnet/bacdcode.h @@ -32,6 +32,31 @@ typedef int (*bacnet_array_property_element_encode_function)( uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu); +/** + * @brief Decode a BACnetARRAY property element to determine the length + * @param object_instance [in] BACnet network port object instance number + * @param apdu [in] Buffer in which the APDU contents are extracted + * @param apdu_size [in] The size of the APDU buffer + * @return The length of the decoded apdu or BACNET_STATUS_ERROR + */ +typedef int (*bacnet_array_property_element_decode_function)( + uint32_t object_instance, uint8_t *apdu, size_t apdu_size); + +/** + * @brief Write a value to a BACnetARRAY property element value + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index to write: + * 0=array size, 1 to N for individual array members + * @param application_data [in] encoded element value + * @param application_data_len [in] The size of the encoded element value + * @return BACNET_ERROR_CODE value + */ +typedef BACNET_ERROR_CODE (*bacnet_array_property_element_write_function)( + uint32_t object_instance, + BACNET_ARRAY_INDEX array_index, + uint8_t *application_data, + size_t application_data_len); + typedef struct BACnetTag { uint8_t number; bool application : 1; @@ -605,6 +630,16 @@ int bacnet_array_encode( uint8_t *apdu, int max_apdu); +BACNET_STACK_EXPORT +BACNET_ERROR_CODE bacnet_array_write( + uint32_t object_instance, + BACNET_ARRAY_INDEX array_index, + bacnet_array_property_element_decode_function decode_function, + bacnet_array_property_element_write_function write_function, + BACNET_UNSIGNED_INTEGER array_size, + uint8_t *apdu, + size_t apdu_size); + /* from clause 20.2.1.2 Tag Number */ /* true if extended tag numbering is used */ #define IS_EXTENDED_TAG_NUMBER(x) (((x) & 0xF0) == 0xF0)