From e517df0d472822386239a578250717d1ec97f657 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Thu, 13 Apr 2023 20:43:54 -0500 Subject: [PATCH] Bugfix/bacnet array encoding overflows (#414) * Add common BACnetARRAY encode function to fix Device object list buffer overflow. Refactor device, analog-output, access-door and binary-output objects to use common BACnetARRAY encoder. * Fix non-POSIX builds (win32). * Cleanup some ports/stm32 build warnings --------- Co-authored-by: Steve Karg --- apps/piface/device.c | 93 +++++------ ports/at91sam7s/device.c | 89 +++++----- ports/atmega168/device.c | 81 +++++---- ports/bdk-atxx4-mstp/device.c | 89 +++++----- ports/pic18f6720/device.c | 87 +++++----- ports/pic18f97j60/device.c | 88 +++++----- ports/rx62n/device.c | 91 +++++----- ports/stm32f10x/Makefile | 16 +- ports/stm32f10x/device.c | 116 +++++++------ ports/stm32f10x/dlmstp.c | 60 ++++++- ports/stm32f10x/netport.c | 4 +- ports/stm32f4xx/device.c | 103 ++++++------ ports/xplained/device.c | 89 +++++----- src/bacnet/bacdcode.c | 70 ++++++++ src/bacnet/bacdcode.h | 22 +++ src/bacnet/basic/object/access_door.c | 82 +++++---- src/bacnet/basic/object/ao.c | 152 ++++++----------- src/bacnet/basic/object/bacfile.c | 20 ++- src/bacnet/basic/object/bo.c | 156 ++++++------------ .../basic/object/client/device-client.c | 95 +++++------ src/bacnet/basic/object/device.c | 93 +++++------ src/bacnet/basic/object/device.h | 6 + src/bacnet/basic/sys/platform.h | 4 +- 23 files changed, 872 insertions(+), 834 deletions(-) diff --git a/apps/piface/device.c b/apps/piface/device.c index fad1ef71..07b3fd93 100644 --- a/apps/piface/device.c +++ b/apps/piface/device.c @@ -694,6 +694,39 @@ bool Device_Object_List_Identifier( return status; } +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +int Device_Object_List_Element_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + BACNET_OBJECT_TYPE object_type; + uint32_t instance; + bool found; + + if (object_instance == Device_Object_Instance_Number()) { + /* single element is zero based, add 1 for BACnetARRAY which is one + * based */ + array_index++; + found = + Device_Object_List_Identifier(array_index, &object_type, &instance); + if (found) { + apdu_len = + encode_application_object_id(apdu, object_type, instance); + } + } + + return apdu_len; +} + /** Determine if we have an object with the given object_name. * If the object_type and object_instance pointers are not null, * and the lookup succeeds, they will be given the resulting values. @@ -858,16 +891,12 @@ bool Device_Daylight_Savings_Status(void) int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) { int apdu_len = 0; /* return value */ - int len = 0; /* apdu len intermediate value */ BACNET_BIT_STRING bit_string = { 0 }; BACNET_CHARACTER_STRING char_string = { 0 }; uint32_t i = 0; - BACNET_OBJECT_TYPE object_type = OBJECT_NONE; - uint32_t instance = 0; uint32_t count = 0; uint8_t *apdu = NULL; struct object_functions *pObject = NULL; - bool found = false; uint16_t apdu_max = 0; if ((rpdata == NULL) || (rpdata->application_data == NULL) || @@ -981,52 +1010,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_LIST: count = Device_Object_List_Count(); - /* Array element zero is the number of objects in the list */ - if (rpdata->array_index == 0) { - apdu_len = encode_application_unsigned(&apdu[0], count); - /* if no index was specified, then try to encode the entire list - */ - /* into one packet. Note that more than likely you will have */ - /* to return an error if the number of encoded objects exceeds - */ - /* your maximum APDU size. */ - } else if (rpdata->array_index == BACNET_ARRAY_ALL) { - for (i = 1; i <= count; i++) { - found = Device_Object_List_Identifier( - i, &object_type, &instance); - if (found) { - len = encode_application_object_id( - &apdu[apdu_len], object_type, instance); - apdu_len += len; - /* assume next one is the same size as this one */ - /* can we all fit into the APDU? Don't check for last - * entry */ - if ((i != count) && (apdu_len + len) >= apdu_max) { - /* Abort response */ - rpdata->error_code = - ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; - apdu_len = BACNET_STATUS_ABORT; - break; - } - } else { - /* error: internal error? */ - rpdata->error_class = ERROR_CLASS_SERVICES; - rpdata->error_code = ERROR_CODE_OTHER; - apdu_len = BACNET_STATUS_ERROR; - break; - } - } - } else { - found = Device_Object_List_Identifier( - rpdata->array_index, &object_type, &instance); - if (found) { - apdu_len = encode_application_object_id( - &apdu[0], object_type, instance); - } else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Device_Object_List_Element_Encode, + count, apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_MAX_APDU_LENGTH_ACCEPTED: diff --git a/ports/at91sam7s/device.c b/ports/at91sam7s/device.c index 6746beb2..4020b021 100644 --- a/ports/at91sam7s/device.c +++ b/ports/at91sam7s/device.c @@ -512,6 +512,39 @@ bool Device_Object_List_Identifier( return status; } +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +int Device_Object_List_Element_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + BACNET_OBJECT_TYPE object_type; + uint32_t instance; + bool found; + + if (object_instance == Device_Object_Instance_Number()) { + /* single element is zero based, add 1 for BACnetARRAY which is one + * based */ + array_index++; + found = + Device_Object_List_Identifier(array_index, &object_type, &instance); + if (found) { + apdu_len = + encode_application_object_id(apdu, object_type, instance); + } + } + + return apdu_len; +} + bool Device_Valid_Object_Name(BACNET_CHARACTER_STRING *object_name1, BACNET_OBJECT_TYPE *object_type, uint32_t *object_instance) @@ -580,14 +613,12 @@ bool Device_Object_Name_Copy(BACNET_OBJECT_TYPE object_type, int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) { int apdu_len = 0; /* return value */ - int len = 0; /* apdu len intermediate value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; uint32_t i = 0; - BACNET_OBJECT_TYPE object_type = OBJECT_NONE; - uint32_t instance = 0; uint32_t count = 0; uint8_t *apdu = NULL; + int apdu_max = 0; struct my_object_functions *pObject = NULL; if ((rpdata->application_data == NULL) || @@ -595,6 +626,7 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) return 0; } apdu = rpdata->application_data; + apdu_max = rpdata->application_data_len; switch ((int)rpdata->object_property) { case PROP_DESCRIPTION: characterstring_init_ansi(&char_string, "BACnet Demo"); @@ -672,47 +704,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_LIST: count = Device_Object_List_Count(); - /* Array element zero is the number of objects in the list */ - if (rpdata->array_index == 0) - apdu_len = encode_application_unsigned(&apdu[0], count); - /* if no index was specified, then try to encode the entire list */ - /* into one packet. Note that more than likely you will have */ - /* to return an error if the number of encoded objects exceeds */ - /* your maximum APDU size. */ - else if (rpdata->array_index == BACNET_ARRAY_ALL) { - for (i = 1; i <= count; i++) { - if (Device_Object_List_Identifier( - i, &object_type, &instance)) { - len = encode_application_object_id( - &apdu[apdu_len], object_type, instance); - apdu_len += len; - /* assume next one is the same size as this one */ - /* can we all fit into the APDU? */ - if ((apdu_len + len) >= MAX_APDU) { - /* Abort response */ - rpdata->error_code = - ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; - apdu_len = BACNET_STATUS_ABORT; - break; - } - } else { - /* error: internal error? */ - rpdata->error_class = ERROR_CLASS_SERVICES; - rpdata->error_code = ERROR_CODE_OTHER; - apdu_len = BACNET_STATUS_ERROR; - break; - } - } - } else { - if (Device_Object_List_Identifier( - rpdata->array_index, &object_type, &instance)) - apdu_len = encode_application_object_id( - &apdu[0], object_type, instance); - else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Device_Object_List_Element_Encode, + count, apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_MAX_APDU_LENGTH_ACCEPTED: diff --git a/ports/atmega168/device.c b/ports/atmega168/device.c index 38f080b4..fc123241 100644 --- a/ports/atmega168/device.c +++ b/ports/atmega168/device.c @@ -154,20 +154,52 @@ bool Device_Object_List_Identifier( return status; } +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +int Device_Object_List_Element_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + BACNET_OBJECT_TYPE object_type; + uint32_t instance; + bool found; + + if (object_instance == Device_Object_Instance_Number()) { + /* single element is zero based, add 1 for BACnetARRAY which is one + * based */ + array_index++; + found = + Device_Object_List_Identifier(array_index, &object_type, &instance); + if (found) { + apdu_len = + encode_application_object_id(apdu, object_type, instance); + } + } + + return apdu_len; +} + /* return the length of the apdu encoded or -1 for error */ int Device_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) { uint8_t *apdu; int apdu_len = 0; /* return value */ - int len = 0; /* apdu len intermediate value */ + int apdu_max = 0; BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; uint32_t i = 0; - BACNET_OBJECT_TYPE object_type = OBJECT_NONE; - uint32_t instance = 0; uint32_t count = 0; apdu = rpdata->application_data; + apdu_max = rpdata->application_data_len; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id( @@ -243,39 +275,16 @@ int Device_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_LIST: count = Device_Object_List_Count(); - /* Array element zero is the number of objects in the list */ - if (rpdata->array_index == 0) - apdu_len = encode_application_unsigned(&apdu[0], count); - /* if no index was specified, then try to encode the entire list */ - /* into one packet. Note that more than likely you will have */ - /* to return an error if the number of encoded objects exceeds */ - /* your maximum APDU size. */ - else if (rpdata->array_index == BACNET_ARRAY_ALL) { - for (i = 1; i <= count; i++) { - Device_Object_List_Identifier(i, &object_type, &instance); - len = encode_application_object_id( - &apdu[apdu_len], object_type, instance); - apdu_len += len; - /* assume next one is the same size as this one */ - /* can we all fit into the APDU? */ - if ((apdu_len + len) >= MAX_APDU) { - /* Abort response */ - rpdata->error_code = - ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; - apdu_len = BACNET_STATUS_ABORT; - break; - } - } - } else { - if (Device_Object_List_Identifier( - rpdata->array_index, &object_type, &instance)) - apdu_len = encode_application_object_id( - &apdu[0], object_type, instance); - else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Device_Object_List_Element_Encode, + count, apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_MAX_APDU_LENGTH_ACCEPTED: diff --git a/ports/bdk-atxx4-mstp/device.c b/ports/bdk-atxx4-mstp/device.c index e54bc290..22933dba 100644 --- a/ports/bdk-atxx4-mstp/device.c +++ b/ports/bdk-atxx4-mstp/device.c @@ -487,6 +487,39 @@ bool Device_Object_List_Identifier( return status; } +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +int Device_Object_List_Element_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + BACNET_OBJECT_TYPE object_type; + uint32_t instance; + bool found; + + if (object_instance == Device_Object_Instance_Number()) { + /* single element is zero based, add 1 for BACnetARRAY which is one + * based */ + array_index++; + found = + Device_Object_List_Identifier(array_index, &object_type, &instance); + if (found) { + apdu_len = + encode_application_object_id(apdu, object_type, instance); + } + } + + return apdu_len; +} + bool Device_Valid_Object_Name(BACNET_CHARACTER_STRING *object_name1, BACNET_OBJECT_TYPE *object_type, uint32_t *object_instance) @@ -555,14 +588,12 @@ bool Device_Object_Name_Copy(BACNET_OBJECT_TYPE object_type, int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) { int apdu_len = 0; /* return value */ - int len = 0; /* apdu len intermediate value */ BACNET_BIT_STRING bit_string = { 0 }; BACNET_CHARACTER_STRING char_string = { 0 }; uint32_t i = 0; - BACNET_OBJECT_TYPE object_type = OBJECT_NONE; - uint32_t instance = 0; uint32_t count = 0; uint8_t *apdu = NULL; + int apdu_max = 0; struct my_object_functions *pObject = NULL; if ((rpdata->application_data == NULL) || @@ -570,6 +601,7 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) return 0; } apdu = rpdata->application_data; + apdu_max = rpdata->application_data_len; switch ((int)rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id( @@ -662,47 +694,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_LIST: count = Device_Object_List_Count(); - /* Array element zero is the number of objects in the list */ - if (rpdata->array_index == 0) - apdu_len = encode_application_unsigned(&apdu[0], count); - /* if no index was specified, then try to encode the entire list */ - /* into one packet. Note that more than likely you will have */ - /* to return an error if the number of encoded objects exceeds */ - /* your maximum APDU size. */ - else if (rpdata->array_index == BACNET_ARRAY_ALL) { - for (i = 1; i <= count; i++) { - if (Device_Object_List_Identifier( - i, &object_type, &instance)) { - len = encode_application_object_id( - &apdu[apdu_len], object_type, instance); - apdu_len += len; - /* assume next one is the same size as this one */ - /* can we all fit into the APDU? */ - if ((apdu_len + len) >= MAX_APDU) { - /* Abort response */ - rpdata->error_code = - ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; - apdu_len = BACNET_STATUS_ABORT; - break; - } - } else { - /* error: internal error? */ - rpdata->error_class = ERROR_CLASS_SERVICES; - rpdata->error_code = ERROR_CODE_OTHER; - apdu_len = BACNET_STATUS_ERROR; - break; - } - } - } else { - if (Device_Object_List_Identifier( - rpdata->array_index, &object_type, &instance)) - apdu_len = encode_application_object_id( - &apdu[0], object_type, instance); - else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Device_Object_List_Element_Encode, + count, apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_MAX_APDU_LENGTH_ACCEPTED: diff --git a/ports/pic18f6720/device.c b/ports/pic18f6720/device.c index ecbaac20..263b19af 100644 --- a/ports/pic18f6720/device.c +++ b/ports/pic18f6720/device.c @@ -269,23 +269,54 @@ bool Device_Object_List_Identifier( return status; } +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +int Device_Object_List_Element_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + BACNET_OBJECT_TYPE object_type; + uint32_t instance; + bool found; + + if (object_instance == Device_Object_Instance_Number()) { + /* single element is zero based, add 1 for BACnetARRAY which is one + * based */ + array_index++; + found = + Device_Object_List_Identifier(array_index, &object_type, &instance); + if (found) { + apdu_len = + encode_application_object_id(apdu, object_type, instance); + } + } + + return apdu_len; +} + /* returns true if successful */ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) { static char string_buffer[28]; static BACNET_CHARACTER_STRING char_string; int apdu_len = 0; /* return value */ - int len = 0; /* apdu len intermediate value */ BACNET_BIT_STRING bit_string; uint32_t i = 0; - BACNET_OBJECT_TYPE object_type = OBJECT_NONE; - uint32_t instance = 0; uint32_t count = 0; BACNET_TIME local_time; BACNET_DATE local_date; uint8_t year = 0; int16_t TimeZone = 0; uint8_t *apdu = NULL; + int apdu_max = 0; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { @@ -387,46 +418,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_LIST: count = Device_Object_List_Count(); - /* Array element zero is the number of objects in the list */ - if (rpdata->array_index == 0) - apdu_len = encode_application_unsigned(&apdu[0], count); - /* if no index was specified, then try to encode the entire list */ - /* into one packet. Note that more than likely you will have */ - /* to return an error if the number of encoded objects exceeds */ - /* your maximum APDU size. */ - else if (rpdata->array_index == BACNET_ARRAY_ALL) { - for (i = 1; i <= count; i++) { - if (Device_Object_List_Identifier( - i, &object_type, &instance)) { - len = encode_application_object_id( - &apdu[apdu_len], object_type, instance); - apdu_len += len; - /* assume next one is the same size as this one */ - /* can we all fit into the APDU? */ - if ((apdu_len + len) >= MAX_APDU) { - rpdata->error_code = - ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; - apdu_len = BACNET_STATUS_ABORT; - break; - } - } else { - /* error: internal error? */ - rpdata->error_class = ERROR_CLASS_SERVICES; - rpdata->error_code = ERROR_CODE_OTHER; - apdu_len = BACNET_STATUS_ERROR; - break; - } - } - } else { - if (Device_Object_List_Identifier( - rpdata->array_index, &object_type, &instance)) - apdu_len = encode_application_object_id( - &apdu[0], object_type, instance); - else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Device_Object_List_Element_Encode, + count, apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_MAX_APDU_LENGTH_ACCEPTED: diff --git a/ports/pic18f97j60/device.c b/ports/pic18f97j60/device.c index 58d239f3..bd980329 100644 --- a/ports/pic18f97j60/device.c +++ b/ports/pic18f97j60/device.c @@ -247,16 +247,46 @@ bool Device_Object_List_Identifier( return status; } +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +int Device_Object_List_Element_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + BACNET_OBJECT_TYPE object_type; + uint32_t instance; + bool found; + + if (object_instance == Device_Object_Instance_Number()) { + /* single element is zero based, add 1 for BACnetARRAY which is one + * based */ + array_index++; + found = + Device_Object_List_Identifier(array_index, &object_type, &instance); + if (found) { + apdu_len = + encode_application_object_id(apdu, object_type, instance); + } + } + + return apdu_len; +} + /* returns true if successful */ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) { int apdu_len = 0; /* return value */ - int len = 0; /* apdu len intermediate value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; uint32_t i = 0; - BACNET_OBJECT_TYPE object_type = OBJECT_NONE; - uint32_t instance = 0; uint32_t count = 0; BACNET_TIME local_time; BACNET_DATE local_date; @@ -264,12 +294,14 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) char string_buffer[28]; int16_t TimeZone = 0; uint8_t *apdu = NULL; + int apdu_max = 0; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; + apdu_max = rpdata->application_data_len; /* FIXME: change the hardcoded names to suit your application */ switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: @@ -365,46 +397,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_LIST: count = Device_Object_List_Count(); - /* Array element zero is the number of objects in the list */ - if (rpdata->array_index == 0) - apdu_len = encode_application_unsigned(&apdu[0], count); - /* if no index was specified, then try to encode the entire list */ - /* into one packet. Note that more than likely you will have */ - /* to return an error if the number of encoded objects exceeds */ - /* your maximum APDU size. */ - else if (rpdata->array_index == BACNET_ARRAY_ALL) { - for (i = 1; i <= count; i++) { - if (Device_Object_List_Identifier( - i, &object_type, &instance)) { - len = encode_application_object_id( - &apdu[apdu_len], object_type, instance); - apdu_len += len; - /* assume next one is the same size as this one */ - /* can we all fit into the APDU? */ - if ((apdu_len + len) >= MAX_APDU) { - rpdata->error_code = - ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; - apdu_len = BACNET_STATUS_ABORT; - break; - } - } else { - /* error: internal error? */ - rpdata->error_class = ERROR_CLASS_SERVICES; - rpdata->error_code = ERROR_CODE_OTHER; - apdu_len = BACNET_STATUS_ERROR; - break; - } - } - } else { - if (Device_Object_List_Identifier( - rpdata->array_index, &object_type, &instance)) - apdu_len = encode_application_object_id( - &apdu[0], object_type, instance); - else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Device_Object_List_Element_Encode, + count, apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_MAX_APDU_LENGTH_ACCEPTED: diff --git a/ports/rx62n/device.c b/ports/rx62n/device.c index 80633372..d1a1511c 100644 --- a/ports/rx62n/device.c +++ b/ports/rx62n/device.c @@ -509,6 +509,39 @@ bool Device_Object_List_Identifier( return status; } +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +int Device_Object_List_Element_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + BACNET_OBJECT_TYPE object_type; + uint32_t instance; + bool found; + + if (object_instance == Device_Object_Instance_Number()) { + /* single element is zero based, add 1 for BACnetARRAY which is one + * based */ + array_index++; + found = + Device_Object_List_Identifier(array_index, &object_type, &instance); + if (found) { + apdu_len = + encode_application_object_id(apdu, object_type, instance); + } + } + + return apdu_len; +} + /** Determine if we have an object with the given object_name. * If the object_type and object_instance pointers are not null, * and the lookup succeeds, they will be given the resulting values. @@ -569,22 +602,20 @@ char *Device_Valid_Object_Id( int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) { int apdu_len = 0; /* return value */ - int len = 0; /* apdu len intermediate value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; uint32_t i = 0; - BACNET_OBJECT_TYPE object_type = OBJECT_NONE; - uint32_t instance = 0; uint32_t count = 0; uint8_t *apdu = NULL; + int apdu_max = 0; struct my_object_functions *pObject = NULL; - bool found = false; if ((rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; + apdu_max = rpdata->application_data_len; switch (rpdata->object_property) { case PROP_DESCRIPTION: characterstring_init_ansi(&char_string, Description); @@ -664,48 +695,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_LIST: count = Device_Object_List_Count(); - /* Array element zero is the number of objects in the list */ - if (rpdata->array_index == 0) - apdu_len = encode_application_unsigned(&apdu[0], count); - /* if no index was specified, then try to encode the entire list */ - /* into one packet. Note that more than likely you will have */ - /* to return an error if the number of encoded objects exceeds */ - /* your maximum APDU size. */ - else if (rpdata->array_index == BACNET_ARRAY_ALL) { - for (i = 1; i <= count; i++) { - if (Device_Object_List_Identifier( - i, &object_type, &instance)) { - len = encode_application_object_id( - &apdu[apdu_len], object_type, instance); - apdu_len += len; - /* assume next one is the same size as this one */ - /* can we all fit into the APDU? */ - if ((apdu_len + len) >= MAX_APDU) { - /* Abort response */ - rpdata->error_code = - ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; - apdu_len = BACNET_STATUS_ABORT; - break; - } - } else { - /* error: internal error? */ - rpdata->error_class = ERROR_CLASS_SERVICES; - rpdata->error_code = ERROR_CODE_OTHER; - apdu_len = BACNET_STATUS_ERROR; - break; - } - } - } else { - found = Device_Object_List_Identifier( - rpdata->array_index, &object_type, &instance); - if (found) { - apdu_len = encode_application_object_id( - &apdu[0], object_type, instance); - } else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Device_Object_List_Element_Encode, + count, apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_MAX_APDU_LENGTH_ACCEPTED: diff --git a/ports/stm32f10x/Makefile b/ports/stm32f10x/Makefile index 479042cb..e0739582 100644 --- a/ports/stm32f10x/Makefile +++ b/ports/stm32f10x/Makefile @@ -158,13 +158,14 @@ CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing CFLAGS += -fno-builtin # place uninitialized global variables in the data section of the object file. CFLAGS += -fno-common +WARNING_ALL := -Wall # enable all relevant warnings that find bugs -WARNING_ALL := -Wall -Wextra -Wall -Wfloat-equal -Wconversion -Wparentheses -WARNING_ALL += -pedantic -Wunused-parameter -Wunused-variable -Wreturn-type -WARNING_ALL += -Wunused-function -Wreturn-type -Wunused-value -WARNING_ALL += -Wswitch-default -Wuninitialized -Winit-self -WARNING_ALL += -Wno-sign-conversion -Wno-conversion -Wno-sign-compare -WARNING_ALL += -Wno-long-long +#WARNING_ALL += -pedantic -Wextra -Wfloat-equal -Wconversion -Wparentheses +#WARNING_ALL += -Wunused-parameter -Wunused-variable -Wreturn-type +#WARNING_ALL += -Wunused-function -Wreturn-type -Wunused-value +#WARNING_ALL += -Wswitch-default -Wuninitialized -Winit-self +#WARNING_ALL += -Wno-sign-conversion -Wno-conversion -Wno-sign-compare +#WARNING_ALL += -Wno-long-long #WARNING_ALL += -Wredundant-decls #WARNING_ALL += -Werror CFLAGS += $(WARNING_ALL) @@ -174,7 +175,8 @@ CFLAGS += -Wno-missing-braces CFLAGS += -Wno-missing-prototypes # don't warn about array subscript being char CFLAGS += -Wno-char-subscripts - +# FIXME later +CFLAGS += -Wno-unused-parameter # -Wa, Pass comma-separated on to the assembler AFLAGS = -Wa,-ahls,-mapcs-32,-adhlns=$(<:.s=.lst) diff --git a/ports/stm32f10x/device.c b/ports/stm32f10x/device.c index 266222ed..30cb8a39 100644 --- a/ports/stm32f10x/device.c +++ b/ports/stm32f10x/device.c @@ -59,12 +59,11 @@ static struct my_object_functions { read_property_function Object_Read_Property; write_property_function Object_Write_Property; rpm_property_lists_function Object_RPM_List; -} Object_Table[] = { - { OBJECT_DEVICE, NULL, /* don't init - recursive! */ - Device_Count, Device_Index_To_Instance, - Device_Valid_Object_Instance_Number, - Device_Object_Name, Device_Read_Property_Local, - Device_Write_Property_Local, Device_Property_Lists }, +} Object_Table[] = { { OBJECT_DEVICE, NULL, /* don't init - recursive! */ + Device_Count, Device_Index_To_Instance, + Device_Valid_Object_Instance_Number, + Device_Object_Name, Device_Read_Property_Local, + Device_Write_Property_Local, Device_Property_Lists }, { OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count, Binary_Output_Index_To_Instance, Binary_Output_Valid_Instance, Binary_Output_Object_Name, Binary_Output_Read_Property, @@ -75,7 +74,8 @@ static struct my_object_functions { Network_Port_Object_Name, Network_Port_Read_Property, Network_Port_Write_Property, Network_Port_Property_Lists }, #endif - { MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; + { MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL } }; /* note: you really only need to define variables for properties that are writable or that may change. @@ -185,13 +185,9 @@ static int Read_Property_Common( #if (BACNET_PROTOCOL_REVISION >= 14) case PROP_PROPERTY_LIST: Device_Objects_Property_List( - rpdata->object_type, - rpdata->object_instance, - &property_list); - apdu_len = property_list_encode( - rpdata, - property_list.Required.pList, - property_list.Optional.pList, + rpdata->object_type, rpdata->object_instance, &property_list); + apdu_len = property_list_encode(rpdata, + property_list.Required.pList, property_list.Optional.pList, property_list.Proprietary.pList); break; #endif @@ -346,8 +342,7 @@ bool Device_Set_Object_Name(BACNET_CHARACTER_STRING *object_name) return status; } -bool Device_Reinitialize( - BACNET_REINITIALIZE_DEVICE_DATA * rd_data) +bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data) { bool status = false; @@ -453,6 +448,7 @@ int Device_Set_System_Status(BACNET_DEVICE_STATUS status, bool local) /*return value - 0 = ok, -1 = bad value, -2 = not allowed */ int result = -1; + (void)local; if (status < MAX_DEVICE_STATUS) { System_Status = status; result = 0; @@ -532,6 +528,39 @@ bool Device_Object_List_Identifier( return status; } +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +int Device_Object_List_Element_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + BACNET_OBJECT_TYPE object_type; + uint32_t instance; + bool found; + + if (object_instance == Device_Object_Instance_Number()) { + /* single element is zero based, add 1 for BACnetARRAY which is one + * based */ + array_index++; + found = + Device_Object_List_Identifier(array_index, &object_type, &instance); + if (found) { + apdu_len = + encode_application_object_id(apdu, object_type, instance); + } + } + + return apdu_len; +} + bool Device_Valid_Object_Name(BACNET_CHARACTER_STRING *object_name1, BACNET_OBJECT_TYPE *object_type, uint32_t *object_instance) @@ -600,14 +629,12 @@ bool Device_Object_Name_Copy(BACNET_OBJECT_TYPE object_type, int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) { int apdu_len = 0; /* return value */ - int len = 0; /* apdu len intermediate value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; uint32_t i = 0; - BACNET_OBJECT_TYPE object_type = OBJECT_NONE; - uint32_t instance = 0; uint32_t count = 0; uint8_t *apdu = NULL; + int apdu_max = 0; struct my_object_functions *pObject = NULL; if ((rpdata->application_data == NULL) || @@ -615,6 +642,7 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) return 0; } apdu = rpdata->application_data; + apdu_max = rpdata->application_data_len; switch ((int)rpdata->object_property) { case PROP_DESCRIPTION: characterstring_init_ansi(&char_string, "BACnet Development Kit"); @@ -692,47 +720,15 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_LIST: count = Device_Object_List_Count(); - /* Array element zero is the number of objects in the list */ - if (rpdata->array_index == 0) - apdu_len = encode_application_unsigned(&apdu[0], count); - /* if no index was specified, then try to encode the entire list */ - /* into one packet. Note that more than likely you will have */ - /* to return an error if the number of encoded objects exceeds */ - /* your maximum APDU size. */ - else if (rpdata->array_index == BACNET_ARRAY_ALL) { - for (i = 1; i <= count; i++) { - if (Device_Object_List_Identifier( - i, &object_type, &instance)) { - len = encode_application_object_id( - &apdu[apdu_len], object_type, instance); - apdu_len += len; - /* assume next one is the same size as this one */ - /* can we all fit into the APDU? */ - if ((apdu_len + len) >= MAX_APDU) { - /* Abort response */ - rpdata->error_code = - ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; - apdu_len = BACNET_STATUS_ABORT; - break; - } - } else { - /* error: internal error? */ - rpdata->error_class = ERROR_CLASS_SERVICES; - rpdata->error_code = ERROR_CODE_OTHER; - apdu_len = BACNET_STATUS_ERROR; - break; - } - } - } else { - if (Device_Object_List_Identifier( - rpdata->array_index, &object_type, &instance)) - apdu_len = encode_application_object_id( - &apdu[0], object_type, instance); - else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, Device_Object_List_Element_Encode, count, + apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_MAX_APDU_LENGTH_ACCEPTED: diff --git a/ports/stm32f10x/dlmstp.c b/ports/stm32f10x/dlmstp.c index 5ecc2a6b..d31b7958 100644 --- a/ports/stm32f10x/dlmstp.c +++ b/ports/stm32f10x/dlmstp.c @@ -254,54 +254,96 @@ static bool dlmstp_compare_data_expecting_reply(uint8_t *request_pdu, }; struct DER_compare_t request; struct DER_compare_t reply; + bool request_segmented = false; + bool reply_segmented = false; /* decode the request data */ request.address.mac[0] = src_address; request.address.mac_len = 1; - offset = npdu_decode( - &request_pdu[0], NULL, &request.address, &request.npdu_data); + offset = bacnet_npdu_decode(request_pdu, request_pdu_len, NULL, + &request.address, &request.npdu_data); if (request.npdu_data.network_layer_message) { return false; } + if (offset >= request_pdu_len) { + return false; + } request.pdu_type = request_pdu[offset] & 0xF0; if (request.pdu_type != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) { return false; } + if (request_pdu[offset] & BIT(3)) { + request_segmented = true; + } + if ((offset + 2) >= request_pdu_len) { + return false; + } request.invoke_id = request_pdu[offset + 2]; /* segmented message? */ - if (request_pdu[offset] & BIT(3)) + if (request_segmented) { + if ((offset + 5) >= request_pdu_len) { + return false; + } request.service_choice = request_pdu[offset + 5]; - else + } else { + if ((offset + 3) >= request_pdu_len) { + return false; + } request.service_choice = request_pdu[offset + 3]; + } /* decode the reply data */ reply.address.mac[0] = dest_address; reply.address.mac_len = 1; - offset = npdu_decode(&reply_pdu[0], &reply.address, NULL, &reply.npdu_data); + offset = bacnet_npdu_decode( + reply_pdu, reply_pdu_len, &reply.address, NULL, &reply.npdu_data); if (reply.npdu_data.network_layer_message) { return false; } + if (offset >= request_pdu_len) { + return false; + } + reply.pdu_type = reply_pdu[offset] & 0xF0; + if (reply_pdu[offset] & BIT(3)) { + reply_segmented = true; + } /* reply could be a lot of things: confirmed, simple ack, abort, reject, error */ - reply.pdu_type = reply_pdu[offset] & 0xF0; switch (reply.pdu_type) { case PDU_TYPE_SIMPLE_ACK: + if ((offset + 2) >= request_pdu_len) { + return false; + } reply.invoke_id = reply_pdu[offset + 1]; reply.service_choice = reply_pdu[offset + 2]; break; case PDU_TYPE_COMPLEX_ACK: - reply.invoke_id = reply_pdu[offset + 1]; /* segmented message? */ - if (reply_pdu[offset] & BIT(3)) + if (reply_segmented) { + if ((offset + 4) >= request_pdu_len) { + return false; + } + reply.invoke_id = reply_pdu[offset + 1]; reply.service_choice = reply_pdu[offset + 4]; - else + } else { + if ((offset + 2) >= request_pdu_len) { + return false; + } + reply.invoke_id = reply_pdu[offset + 1]; reply.service_choice = reply_pdu[offset + 2]; + } break; case PDU_TYPE_ERROR: + if ((offset + 2) >= request_pdu_len) { + return false; + } reply.invoke_id = reply_pdu[offset + 1]; reply.service_choice = reply_pdu[offset + 2]; break; case PDU_TYPE_REJECT: case PDU_TYPE_ABORT: + if ((offset + 1) >= request_pdu_len) { + return false; + } reply.invoke_id = reply_pdu[offset + 1]; break; default: diff --git a/ports/stm32f10x/netport.c b/ports/stm32f10x/netport.c index 3a2899a6..47896e0b 100644 --- a/ports/stm32f10x/netport.c +++ b/ports/stm32f10x/netport.c @@ -47,7 +47,7 @@ /* MS/TP specific */ #include "bacnet/datalink/dlmstp.h" #include "rs485.h" -//#include "nvdata.h" +// #include "nvdata.h" /* me */ #include "bacnet/basic/object/netport.h" @@ -370,6 +370,8 @@ bool Network_Port_Link_Speed_Set(uint32_t object_instance, float value) Object_List[0].Changes_Pending = true; status = true; break; + default: + break; } return status; diff --git a/ports/stm32f4xx/device.c b/ports/stm32f4xx/device.c index 8cfd22f9..3276a98d 100644 --- a/ports/stm32f4xx/device.c +++ b/ports/stm32f4xx/device.c @@ -56,19 +56,19 @@ static struct my_object_functions { read_property_function Object_Read_Property; write_property_function Object_Write_Property; rpm_property_lists_function Object_RPM_List; -} Object_Table[] = { - { OBJECT_DEVICE, NULL, /* don't init - recursive! */ - Device_Count, Device_Index_To_Instance, - Device_Valid_Object_Instance_Number, - Device_Object_Name, Device_Read_Property_Local, - Device_Write_Property_Local, Device_Property_Lists }, +} Object_Table[] = { { OBJECT_DEVICE, NULL, /* don't init - recursive! */ + Device_Count, Device_Index_To_Instance, + Device_Valid_Object_Instance_Number, + Device_Object_Name, Device_Read_Property_Local, + Device_Write_Property_Local, Device_Property_Lists }, #if (BACNET_PROTOCOL_REVISION >= 17) { OBJECT_NETWORK_PORT, Network_Port_Init, Network_Port_Count, Network_Port_Index_To_Instance, Network_Port_Valid_Instance, Network_Port_Object_Name, Network_Port_Read_Property, Network_Port_Write_Property, Network_Port_Property_Lists }, #endif - { MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; + { MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL } }; /* note: you really only need to define variables for properties that are writable or that may change. @@ -442,6 +442,7 @@ int Device_Set_System_Status(BACNET_DEVICE_STATUS status, bool local) /*return value - 0 = ok, -1 = bad value, -2 = not allowed */ int result = -1; + (void)local; if (status < MAX_DEVICE_STATUS) { System_Status = status; result = 0; @@ -521,6 +522,39 @@ bool Device_Object_List_Identifier( return status; } +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +int Device_Object_List_Element_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + BACNET_OBJECT_TYPE object_type; + uint32_t instance; + bool found; + + if (object_instance == Device_Object_Instance_Number()) { + /* single element is zero based, add 1 for BACnetARRAY which is one + * based */ + array_index++; + found = + Device_Object_List_Identifier(array_index, &object_type, &instance); + if (found) { + apdu_len = + encode_application_object_id(apdu, object_type, instance); + } + } + + return apdu_len; +} + bool Device_Valid_Object_Name(BACNET_CHARACTER_STRING *object_name1, BACNET_OBJECT_TYPE *object_type, uint32_t *object_instance) @@ -589,14 +623,12 @@ bool Device_Object_Name_Copy(BACNET_OBJECT_TYPE object_type, int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) { int apdu_len = 0; /* return value */ - int len = 0; /* apdu len intermediate value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; uint32_t i = 0; - BACNET_OBJECT_TYPE object_type = OBJECT_NONE; - uint32_t instance = 0; uint32_t count = 0; uint8_t *apdu = NULL; + int apdu_max = 0; struct my_object_functions *pObject = NULL; if ((rpdata->application_data == NULL) || @@ -604,6 +636,7 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) return 0; } apdu = rpdata->application_data; + apdu_max = rpdata->application_data_len; switch ((int)rpdata->object_property) { case PROP_DESCRIPTION: characterstring_init_ansi(&char_string, "BACnet Development Kit"); @@ -681,47 +714,15 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_LIST: count = Device_Object_List_Count(); - /* Array element zero is the number of objects in the list */ - if (rpdata->array_index == 0) - apdu_len = encode_application_unsigned(&apdu[0], count); - /* if no index was specified, then try to encode the entire list */ - /* into one packet. Note that more than likely you will have */ - /* to return an error if the number of encoded objects exceeds */ - /* your maximum APDU size. */ - else if (rpdata->array_index == BACNET_ARRAY_ALL) { - for (i = 1; i <= count; i++) { - if (Device_Object_List_Identifier( - i, &object_type, &instance)) { - len = encode_application_object_id( - &apdu[apdu_len], object_type, instance); - apdu_len += len; - /* assume next one is the same size as this one */ - /* can we all fit into the APDU? */ - if ((apdu_len + len) >= MAX_APDU) { - /* Abort response */ - rpdata->error_code = - ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; - apdu_len = BACNET_STATUS_ABORT; - break; - } - } else { - /* error: internal error? */ - rpdata->error_class = ERROR_CLASS_SERVICES; - rpdata->error_code = ERROR_CODE_OTHER; - apdu_len = BACNET_STATUS_ERROR; - break; - } - } - } else { - if (Device_Object_List_Identifier( - rpdata->array_index, &object_type, &instance)) - apdu_len = encode_application_object_id( - &apdu[0], object_type, instance); - else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, Device_Object_List_Element_Encode, count, + apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_MAX_APDU_LENGTH_ACCEPTED: diff --git a/ports/xplained/device.c b/ports/xplained/device.c index 6a948e68..319127ea 100644 --- a/ports/xplained/device.c +++ b/ports/xplained/device.c @@ -509,6 +509,39 @@ bool Device_Object_List_Identifier( return status; } +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +int Device_Object_List_Element_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + BACNET_OBJECT_TYPE object_type; + uint32_t instance; + bool found; + + if (object_instance == Device_Object_Instance_Number()) { + /* single element is zero based, add 1 for BACnetARRAY which is one + * based */ + array_index++; + found = + Device_Object_List_Identifier(array_index, &object_type, &instance); + if (found) { + apdu_len = + encode_application_object_id(apdu, object_type, instance); + } + } + + return apdu_len; +} + bool Device_Valid_Object_Name(BACNET_CHARACTER_STRING *object_name1, BACNET_OBJECT_TYPE *object_type, uint32_t *object_instance) @@ -577,14 +610,12 @@ bool Device_Object_Name_Copy(BACNET_OBJECT_TYPE object_type, int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) { int apdu_len = 0; /* return value */ - int len = 0; /* apdu len intermediate value */ BACNET_BIT_STRING bit_string = { 0 }; BACNET_CHARACTER_STRING char_string = { 0 }; uint32_t i = 0; - BACNET_OBJECT_TYPE object_type = OBJECT_NONE; - uint32_t instance = 0; uint32_t count = 0; uint8_t *apdu = NULL; + int apdu_len = 0; struct my_object_functions *pObject = NULL; if ((rpdata->application_data == NULL) || @@ -592,6 +623,7 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) return 0; } apdu = rpdata->application_data; + apdu_max = rpdata->application_data_len; switch ((int)rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id( @@ -684,47 +716,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_LIST: count = Device_Object_List_Count(); - /* Array element zero is the number of objects in the list */ - if (rpdata->array_index == 0) - apdu_len = encode_application_unsigned(&apdu[0], count); - /* if no index was specified, then try to encode the entire list */ - /* into one packet. Note that more than likely you will have */ - /* to return an error if the number of encoded objects exceeds */ - /* your maximum APDU size. */ - else if (rpdata->array_index == BACNET_ARRAY_ALL) { - for (i = 1; i <= count; i++) { - if (Device_Object_List_Identifier( - i, &object_type, &instance)) { - len = encode_application_object_id( - &apdu[apdu_len], object_type, instance); - apdu_len += len; - /* assume next one is the same size as this one */ - /* can we all fit into the APDU? */ - if ((apdu_len + len) >= MAX_APDU) { - /* Abort response */ - rpdata->error_code = - ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; - apdu_len = BACNET_STATUS_ABORT; - break; - } - } else { - /* error: internal error? */ - rpdata->error_class = ERROR_CLASS_SERVICES; - rpdata->error_code = ERROR_CODE_OTHER; - apdu_len = BACNET_STATUS_ERROR; - break; - } - } - } else { - if (Device_Object_List_Identifier( - rpdata->array_index, &object_type, &instance)) - apdu_len = encode_application_object_id( - &apdu[0], object_type, instance); - else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Device_Object_List_Element_Encode, + count, apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_MAX_APDU_LENGTH_ACCEPTED: diff --git a/src/bacnet/bacdcode.c b/src/bacnet/bacdcode.c index 3b659e1d..1f10aeed 100644 --- a/src/bacnet/bacdcode.c +++ b/src/bacnet/bacdcode.c @@ -3084,3 +3084,73 @@ int decode_context_bacnet_address( } return len; } + +/** + * @brief Encode a BACnetARRAY property value + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 for the array size + * 1 to n for individual array members + * BACNET_ARRAY_ALL for the full array to be read. + * @param encoder [in] function to encode one property array element + * @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 The length of the apdu encoded or + * BACNET_STATUS_ERROR for an invalid array index + * BACNET_STATUS_ABORT for abort message. + */ +int bacnet_array_encode(uint32_t object_instance, + BACNET_ARRAY_INDEX array_index, + bacnet_array_property_element_encode_function encoder, + BACNET_UNSIGNED_INTEGER array_size, + uint8_t *apdu, + int max_apdu) +{ + int apdu_len = 0, len = 0; + BACNET_ARRAY_INDEX index; + + if (array_index == 0) { + /* Array element zero is the number of objects in the list */ + len = encode_application_unsigned(NULL, array_size); + if (len > max_apdu) { + apdu_len = BACNET_STATUS_ABORT; + } else { + len = encode_application_unsigned(NULL, array_size); + apdu_len = len; + } + } else if (array_index == BACNET_ARRAY_ALL) { + /* if no index was specified, then try to encode the entire list */ + /* into one packet. */ + for (index = 0; index < array_size; index++) { + len += encoder(object_instance, index, NULL); + } + if (len > max_apdu) { + /* encoded size is larger than APDU size */ + apdu_len = BACNET_STATUS_ABORT; + } else { + for (index = 1; index < array_size; index++) { + len = encoder(object_instance, index, apdu); + if (apdu) { + apdu += len; + } + apdu_len += len; + } + } + } else if (array_index <= array_size) { + /* index was specified; encode a single array element */ + index = array_index - 1; + len = encoder(object_instance, index, NULL); + if (len > max_apdu) { + apdu_len = BACNET_STATUS_ABORT; + } else { + len = encoder(object_instance, index, apdu); + apdu_len = len; + } + } else { + /* array_index was specified out of range */ + apdu_len = BACNET_STATUS_ERROR; + } + + return apdu_len; +} diff --git a/src/bacnet/bacdcode.h b/src/bacnet/bacdcode.h index a80addc1..61707b37 100644 --- a/src/bacnet/bacdcode.h +++ b/src/bacnet/bacdcode.h @@ -35,6 +35,19 @@ #include "bacnet/bacreal.h" #include "bacnet/bits.h" +/** + * @brief Encode a BACnetARRAY property element; a function template + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +typedef int (*bacnet_array_property_element_encode_function)( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu); + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -615,6 +628,15 @@ extern "C" { uint8_t tag_number, BACNET_ADDRESS * destination); + BACNET_STACK_EXPORT + int bacnet_array_encode( + uint32_t object_instance, + BACNET_ARRAY_INDEX array_index, + bacnet_array_property_element_encode_function encoder, + BACNET_UNSIGNED_INTEGER array_size, + uint8_t *apdu, + int max_apdu); + /* from clause 20.2.1.2 Tag Number */ /* true if extended tag numbering is used */ #define IS_EXTENDED_TAG_NUMBER(x) (((x) & 0xF0) == 0xF0) diff --git a/src/bacnet/basic/object/access_door.c b/src/bacnet/basic/object/access_door.c index 6f82755e..8a325d5e 100644 --- a/src/bacnet/basic/object/access_door.c +++ b/src/bacnet/basic/object/access_door.c @@ -243,6 +243,35 @@ BACNET_DOOR_VALUE Access_Door_Relinquish_Default(uint32_t object_instance) return status; } +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +static int Access_Door_Priority_Array_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + unsigned object_index = 0; + + object_index = Access_Door_Instance_To_Index(object_instance); + if (object_index < MAX_ACCESS_DOORS) { + if (ad_descr[object_index].value_active[array_index]) { + apdu_len = encode_application_null(apdu); + } else { + apdu_len = encode_application_enumerated( + apdu, ad_descr[object_index].priority_array[array_index]); + } + } + + return apdu_len; +} + /* note: the object name must be unique within this device */ bool Access_Door_Object_Name( uint32_t object_instance, BACNET_CHARACTER_STRING *object_name) @@ -284,20 +313,20 @@ void Access_Door_Out_Of_Service_Set(uint32_t instance, bool oos_flag) /* return apdu len, or BACNET_STATUS_ERROR on error */ int Access_Door_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) { - int len = 0; int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; unsigned object_index = 0; - unsigned i = 0; bool state = false; uint8_t *apdu = NULL; + int apdu_size = 0; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; + apdu_size = rpdata->application_data_len; object_index = Access_Door_Instance_To_Index(rpdata->object_instance); switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: @@ -339,46 +368,15 @@ int Access_Door_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) apdu_len = encode_application_boolean(&apdu[0], state); break; case PROP_PRIORITY_ARRAY: - /* Array element zero is the number of elements in the array */ - if (rpdata->array_index == 0) { - apdu_len = - encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY); - /* if no index was specified, then try to encode the entire list - */ - /* into one packet. */ - } else if (rpdata->array_index == BACNET_ARRAY_ALL) { - for (i = 0; i < BACNET_MAX_PRIORITY; i++) { - /* FIXME: check if we have room before adding it to APDU */ - if (ad_descr[object_index].value_active[i]) { - len = encode_application_null(&apdu[apdu_len]); - } else { - len = encode_application_enumerated(&apdu[apdu_len], - ad_descr[object_index].priority_array[i]); - } - /* add it if we have room */ - if ((apdu_len + len) < MAX_APDU) { - apdu_len += len; - } else { - rpdata->error_code = - ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; - apdu_len = BACNET_STATUS_ABORT; - break; - } - } - } else { - if (rpdata->array_index <= BACNET_MAX_PRIORITY) { - if (ad_descr[object_index].value_active[i]) { - apdu_len = encode_application_null(&apdu[0]); - } else { - apdu_len = - encode_application_enumerated(&apdu[apdu_len], - ad_descr[object_index].priority_array[i]); - } - } else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, Access_Door_Priority_Array_Encode, + BACNET_MAX_PRIORITY, apdu, apdu_size); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_RELINQUISH_DEFAULT: diff --git a/src/bacnet/basic/object/ao.c b/src/bacnet/basic/object/ao.c index 11f4a555..49e10ff8 100644 --- a/src/bacnet/basic/object/ao.c +++ b/src/bacnet/basic/object/ao.c @@ -202,8 +202,7 @@ float Analog_Output_Present_Value(uint32_t object_instance) * @param object_instance - object-instance number of the object * @return active priority 1..16, or 0 if no priority is active */ -unsigned Analog_Output_Present_Value_Priority( - uint32_t object_instance) +unsigned Analog_Output_Present_Value_Priority(uint32_t object_instance) { unsigned p = 0; /* loop counter */ unsigned priority = 0; /* return value */ @@ -223,55 +222,33 @@ unsigned Analog_Output_Present_Value_Priority( } /** - * @brief For a given object instance-number and priority 1..16, determines the - * priority-array value - * @param object_instance - object-instance number of the object - * @param priority - priority-array index value 1..16 - * - * @return priority-array value of the object + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX */ -static float Analog_Output_Priority_Array( - uint32_t object_instance, unsigned priority) +static int Analog_Output_Priority_Array_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX index, uint8_t *apdu) { - float value = 0.0; + int apdu_len = BACNET_STATUS_ERROR; struct object_data *pObject; + float real_value; pObject = Keylist_Data(Object_List, object_instance); - if (pObject) { - if ((priority >= BACNET_MIN_PRIORITY) && - (priority <= BACNET_MAX_PRIORITY)) { - value = pObject->Priority_Array[priority - 1]; + if (pObject && (index < BACNET_MAX_PRIORITY)) { + if (pObject->Relinquished[index]) { + apdu_len = encode_application_null(apdu); + } else { + real_value = pObject->Priority_Array[index]; + apdu_len = encode_application_real(apdu, real_value); } } - return value; -} - -/** - * @brief For a given object instance-number and priority 1..16, determines - * if the priority-array slot is NULL - * @param object_instance - object-instance number of the object - * @param priority - priority-array index value 1..16 - * @return true if the priority array slot is NULL - */ -static bool Analog_Output_Priority_Array_Null( - uint32_t object_instance, unsigned priority) -{ - bool null_value = false; - - struct object_data *pObject; - - pObject = Keylist_Data(Object_List, object_instance); - if (pObject) { - if ((priority >= BACNET_MIN_PRIORITY) && - (priority <= BACNET_MAX_PRIORITY)) { - if (pObject->Relinquished[priority - 1]) { - null_value = true; - } - } - } - - return null_value; + return apdu_len; } /** @@ -408,8 +385,9 @@ bool Analog_Output_Present_Value_Relinquish( * @param error_code - BACnet Error code * @return true if values are within range and present-value is set. */ -static bool Analog_Output_Present_Value_Write( - uint32_t object_instance, float value, uint8_t priority, +static bool Analog_Output_Present_Value_Write(uint32_t object_instance, + float value, + uint8_t priority, BACNET_ERROR_CLASS *error_class, BACNET_ERROR_CODE *error_code) { @@ -424,7 +402,8 @@ static bool Analog_Output_Present_Value_Write( (value >= 0.0) && (value <= 100.0)) { if (priority != 6) { old_value = Analog_Output_Present_Value(object_instance); - Analog_Output_Present_Value_Set(object_instance, value, priority); + Analog_Output_Present_Value_Set( + object_instance, value, priority); if (pObject->Out_Of_Service) { /* The physical point that the object represents is not in service. This means that changes to the @@ -463,7 +442,8 @@ static bool Analog_Output_Present_Value_Write( * @return true if values are within range and write is requested */ static bool Analog_Output_Present_Value_Relinquish_Write( - uint32_t object_instance, uint8_t priority, + uint32_t object_instance, + uint8_t priority, BACNET_ERROR_CLASS *error_class, BACNET_ERROR_CODE *error_code) { @@ -477,7 +457,8 @@ static bool Analog_Output_Present_Value_Relinquish_Write( if ((priority >= 1) && (priority <= BACNET_MAX_PRIORITY)) { if (priority != 6) { old_value = Analog_Output_Present_Value(object_instance); - Analog_Output_Present_Value_Relinquish(object_instance, priority); + Analog_Output_Present_Value_Relinquish( + object_instance, priority); if (pObject->Out_Of_Service) { /* The physical point that the object represents is not in service. This means that changes to the @@ -526,8 +507,8 @@ bool Analog_Output_Object_Name( pObject = Keylist_Data(Object_List, object_instance); if (pObject) { if (pObject->Object_Name) { - status = characterstring_init_ansi(object_name, - pObject->Object_Name); + status = + characterstring_init_ansi(object_name, pObject->Object_Name); } else { snprintf(name_text, sizeof(name_text), "ANALOG OUTPUT %u", object_instance); @@ -992,8 +973,8 @@ void Analog_Output_COV_Increment_Set(uint32_t object_instance, float value) */ int Analog_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) { - int len = 0; int apdu_len = 0; /* return value */ + int apdu_size = 0; BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; uint8_t *apdu = NULL; @@ -1008,6 +989,7 @@ int Analog_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) } apdu = rpdata->application_data; + apdu_size = rpdata->application_data_len; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id( @@ -1019,8 +1001,7 @@ int Analog_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: - apdu_len = - encode_application_enumerated(&apdu[0], Object_Type); + apdu_len = encode_application_enumerated(&apdu[0], Object_Type); break; case PROP_PRESENT_VALUE: real_value = Analog_Output_Present_Value(rpdata->object_instance); @@ -1062,49 +1043,15 @@ int Analog_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) apdu_len = encode_application_enumerated(&apdu[0], units); break; case PROP_PRIORITY_ARRAY: - if (rpdata->array_index == 0) { - /* Array element zero = the number of elements in the array */ - apdu_len = - encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY); - } else if (rpdata->array_index == BACNET_ARRAY_ALL) { - /* no index was specified; try to encode the entire list */ - for (i = 1; i <= BACNET_MAX_PRIORITY; i++) { - if (Analog_Output_Priority_Array_Null( - rpdata->object_instance, i)) { - len = encode_application_null(&apdu[apdu_len]); - } else { - real_value = Analog_Output_Priority_Array( - rpdata->object_instance, i); - len = encode_application_real( - &apdu[apdu_len], real_value); - } - /* add it if we have room */ - if ((apdu_len + len) < MAX_APDU) { - apdu_len += len; - } else { - /* Abort response */ - rpdata->error_code = - ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; - apdu_len = BACNET_STATUS_ABORT; - break; - } - } - } else { - if (rpdata->array_index <= BACNET_MAX_PRIORITY) { - if (Analog_Output_Priority_Array_Null( - rpdata->object_instance, rpdata->array_index)) { - apdu_len = encode_application_null(&apdu[apdu_len]); - } else { - real_value = Analog_Output_Priority_Array( - rpdata->object_instance, rpdata->array_index); - apdu_len = encode_application_real( - &apdu[apdu_len], real_value); - } - } else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, Analog_Output_Priority_Array_Encode, + BACNET_MAX_PRIORITY, apdu, apdu_size); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_RELINQUISH_DEFAULT: @@ -1183,16 +1130,16 @@ bool Analog_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) } switch (wp_data->object_property) { case PROP_PRESENT_VALUE: - status = write_property_type_valid(wp_data, &value, - BACNET_APPLICATION_TAG_REAL); + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_REAL); if (status) { status = Analog_Output_Present_Value_Write(wp_data->object_instance, value.type.Real, wp_data->priority, &wp_data->error_class, &wp_data->error_code); } else { - status = write_property_type_valid(wp_data, &value, - BACNET_APPLICATION_TAG_NULL); + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_NULL); if (status) { status = Analog_Output_Present_Value_Relinquish_Write( wp_data->object_instance, wp_data->priority, @@ -1201,8 +1148,8 @@ bool Analog_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) } break; case PROP_OUT_OF_SERVICE: - status = write_property_type_valid(wp_data, &value, - BACNET_APPLICATION_TAG_BOOLEAN); + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_BOOLEAN); if (status) { Analog_Output_Out_Of_Service_Set( wp_data->object_instance, value.type.Boolean); @@ -1236,7 +1183,6 @@ bool Analog_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) return status; } - /** * @brief Sets a callback used when present-value is written from BACnet * @param cb - callback used to provide indications diff --git a/src/bacnet/basic/object/bacfile.c b/src/bacnet/basic/object/bacfile.c index 67b17721..cd942a02 100644 --- a/src/bacnet/basic/object/bacfile.c +++ b/src/bacnet/basic/object/bacfile.c @@ -98,6 +98,20 @@ void BACfile_Property_Lists( return; } +/** + * @brief duplicate a string (replacement for POSIX strdup) + * @param s - string to duplicate + * @return a pointer to a new string on success, or a null pointer + */ +static char *bacfile_strdup(const char *s) { + size_t size = strlen(s) + 1; + char *p = malloc(size); + if (p != NULL) { + memcpy(p, s, size); + } + return p; +} + /** * @brief For a given object instance-number, returns the pathname * @param object_instance - object-instance number of the object @@ -130,7 +144,7 @@ void bacfile_pathname_set(uint32_t object_instance, const char *pathname) if (pObject->Pathname) { free(pObject->Pathname); } - pObject->Pathname = strdup(pathname); + pObject->Pathname = bacfile_strdup(pathname); } } @@ -409,10 +423,10 @@ void bacfile_file_type_set( if (pObject->File_Type) { if (strcmp(pObject->File_Type, mime_type) != 0) { free(pObject->File_Type); - pObject->File_Type = strdup(mime_type); + pObject->File_Type = bacfile_strdup(mime_type); } } else { - pObject->File_Type = strdup(mime_type); + pObject->File_Type = bacfile_strdup(mime_type); } } } diff --git a/src/bacnet/basic/object/bo.c b/src/bacnet/basic/object/bo.c index 15a48630..15325ecc 100644 --- a/src/bacnet/basic/object/bo.c +++ b/src/bacnet/basic/object/bo.c @@ -211,61 +211,35 @@ BACNET_BINARY_PV Binary_Output_Present_Value(uint32_t object_instance) } /** - * For a given object instance-number, determines the value at a - * given priority. - * - * @param object_instance - object-instance number of the object - * @param priority - priority 1..16 - * - * @return priority-array element of the object + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX */ -static BACNET_BINARY_PV Binary_Output_Priority_Array_Value( - uint32_t object_instance, unsigned priority) +static int Binary_Output_Priority_Array_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX index, uint8_t *apdu) { + int apdu_len = BACNET_STATUS_ERROR; + struct object_data *pObject; BACNET_BINARY_PV value = BINARY_INACTIVE; - struct object_data *pObject; pObject = Keylist_Data(Object_List, object_instance); - if (pObject) { - if (priority && (priority <= BACNET_MAX_PRIORITY)) { - priority--; - if (BIT_CHECK(pObject->Priority_Array, priority)) { + if (pObject && (index < BACNET_MAX_PRIORITY)) { + if (BIT_CHECK(pObject->Priority_Active_Bits, index)) { + if (BIT_CHECK(pObject->Priority_Array, index)) { value = BINARY_ACTIVE; - } else { - value = BINARY_INACTIVE; } + apdu_len = encode_application_enumerated(apdu, value); + } else { + apdu_len = encode_application_null(apdu); } } - return value; -} - -/** - * For a given object instance-number, determines if the given priority - * is active or NULL. - * - * @param object_instance - object-instance number of the object - * @param priority - priority 1..16 - * - * @return true if the priority slot is active - */ -static bool Binary_Output_Priority_Active( - uint32_t object_instance, unsigned priority) -{ - bool status = false; - struct object_data *pObject; - - pObject = Keylist_Data(Object_List, object_instance); - if (pObject) { - if (priority && (priority <= BACNET_MAX_PRIORITY)) { - priority--; - if (BIT_CHECK(pObject->Priority_Active_Bits, priority)) { - status = true; - } - } - } - - return status; + return apdu_len; } /** @@ -369,8 +343,9 @@ bool Binary_Output_Present_Value_Relinquish( * @param error_code - BACnet Error code * @return true if values are within range and present-value is set. */ -static bool Binary_Output_Present_Value_Write( - uint32_t object_instance, BACNET_BINARY_PV value, uint8_t priority, +static bool Binary_Output_Present_Value_Write(uint32_t object_instance, + BACNET_BINARY_PV value, + uint8_t priority, BACNET_ERROR_CLASS *error_class, BACNET_ERROR_CODE *error_code) { @@ -382,11 +357,11 @@ static bool Binary_Output_Present_Value_Write( pObject = Keylist_Data(Object_List, object_instance); if (pObject) { if ((priority >= 1) && (priority <= BACNET_MAX_PRIORITY) && - (value >= 0.0) && (value <= 100.0)) { + (value <= MAX_BINARY_PV)) { if (priority != 6) { old_value = Binary_Output_Present_Value(object_instance); - Binary_Output_Present_Value_Set(object_instance, value, - priority); + Binary_Output_Present_Value_Set( + object_instance, value, priority); if (pObject->Out_Of_Service) { /* The physical point that the object represents is not in service. This means that changes to the @@ -425,7 +400,8 @@ static bool Binary_Output_Present_Value_Write( * @return true if values are within range and write is requested */ static bool Binary_Output_Present_Value_Relinquish_Write( - uint32_t object_instance, uint8_t priority, + uint32_t object_instance, + uint8_t priority, BACNET_ERROR_CLASS *error_class, BACNET_ERROR_CODE *error_code) { @@ -439,7 +415,8 @@ static bool Binary_Output_Present_Value_Relinquish_Write( if ((priority >= 1) && (priority <= BACNET_MAX_PRIORITY)) { if (priority != 6) { old_value = Binary_Output_Present_Value(object_instance); - Binary_Output_Present_Value_Relinquish(object_instance, priority); + Binary_Output_Present_Value_Relinquish( + object_instance, priority); if (pObject->Out_Of_Service) { /* The physical point that the object represents is not in service. This means that changes to the @@ -530,8 +507,8 @@ bool Binary_Output_Object_Name( pObject = Keylist_Data(Object_List, object_instance); if (pObject) { if (pObject->Object_Name) { - status = characterstring_init_ansi(object_name, - pObject->Object_Name); + status = + characterstring_init_ansi(object_name, pObject->Object_Name); } else { snprintf(name_text, sizeof(name_text), "BINARY OUTPUT %u", object_instance); @@ -973,7 +950,6 @@ bool Binary_Output_Encode_Value_List( */ int Binary_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) { - int len = 0; int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; @@ -982,12 +958,14 @@ int Binary_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) unsigned i = 0; bool state = false; uint8_t *apdu = NULL; + int apdu_size = 0; if ((rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; + apdu_size = rpdata->application_data_len; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id( @@ -999,8 +977,7 @@ int Binary_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: - apdu_len = - encode_application_enumerated(&apdu[0], Object_Type); + apdu_len = encode_application_enumerated(&apdu[0], Object_Type); break; case PROP_PRESENT_VALUE: present_value = @@ -1035,50 +1012,15 @@ int Binary_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) apdu_len = encode_application_enumerated(&apdu[0], polarity); break; case PROP_PRIORITY_ARRAY: - /* Array element zero is the number of elements in the array */ - if (rpdata->array_index == 0) { - apdu_len = - encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY); - /* if no index was specified, then try to encode the entire list - */ - /* into one packet. */ - } else if (rpdata->array_index == BACNET_ARRAY_ALL) { - for (i = 1; i <= BACNET_MAX_PRIORITY; i++) { - if (Binary_Output_Priority_Active( - rpdata->object_instance, i)) { - present_value = Binary_Output_Priority_Array_Value( - rpdata->object_instance, i); - len = encode_application_enumerated( - &apdu[apdu_len], present_value); - } else { - len = encode_application_null(&apdu[apdu_len]); - } - /* add it if we have room */ - if ((apdu_len + len) < MAX_APDU) { - apdu_len += len; - } else { - rpdata->error_class = ERROR_CLASS_SERVICES; - rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; - apdu_len = BACNET_STATUS_ERROR; - break; - } - } - } else { - if (rpdata->array_index <= BACNET_MAX_PRIORITY) { - if (Binary_Output_Priority_Active( - rpdata->object_instance, rpdata->array_index)) { - present_value = Binary_Output_Priority_Array_Value( - rpdata->object_instance, rpdata->array_index); - apdu_len = encode_application_enumerated( - &apdu[0], present_value); - } else { - apdu_len = encode_application_null(&apdu[0]); - } - } else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, Binary_Output_Priority_Array_Encode, + BACNET_MAX_PRIORITY, apdu, apdu_size); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_RELINQUISH_DEFAULT: @@ -1165,16 +1107,16 @@ bool Binary_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) } switch (wp_data->object_property) { case PROP_PRESENT_VALUE: - status = write_property_type_valid(wp_data, &value, - BACNET_APPLICATION_TAG_ENUMERATED); + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_ENUMERATED); if (status) { status = Binary_Output_Present_Value_Write(wp_data->object_instance, value.type.Enumerated, wp_data->priority, &wp_data->error_class, &wp_data->error_code); } else { - status = write_property_type_valid(wp_data, &value, - BACNET_APPLICATION_TAG_NULL); + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_NULL); if (status) { status = Binary_Output_Present_Value_Relinquish_Write( wp_data->object_instance, wp_data->priority, @@ -1183,8 +1125,8 @@ bool Binary_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) } break; case PROP_OUT_OF_SERVICE: - status = write_property_type_valid(wp_data, &value, - BACNET_APPLICATION_TAG_BOOLEAN); + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_BOOLEAN); if (status) { Binary_Output_Out_Of_Service_Set( wp_data->object_instance, value.type.Boolean); diff --git a/src/bacnet/basic/object/client/device-client.c b/src/bacnet/basic/object/client/device-client.c index a76170ce..fa14b0b9 100644 --- a/src/bacnet/basic/object/client/device-client.c +++ b/src/bacnet/basic/object/client/device-client.c @@ -599,6 +599,39 @@ bool Device_Object_List_Identifier( return status; } +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +int Device_Object_List_Element_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + BACNET_OBJECT_TYPE object_type; + uint32_t instance; + bool found; + + if (object_instance == Device_Object_Instance_Number()) { + /* single element is zero based, add 1 for BACnetARRAY which is one + * based */ + array_index++; + found = + Device_Object_List_Identifier(array_index, &object_type, &instance); + if (found) { + apdu_len = + encode_application_object_id(apdu, object_type, instance); + } + } + + return apdu_len; +} + /** Determine if we have an object with the given object_name. * If the object_type and object_instance pointers are not null, * and the lookup succeeds, they will be given the resulting values. @@ -788,22 +821,20 @@ uint32_t Device_Interval_Offset(void) int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) { int apdu_len = 0; /* return value */ - int len = 0; /* apdu len intermediate value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; uint32_t i = 0; - BACNET_OBJECT_TYPE object_type = OBJECT_NONE; - uint32_t instance = 0; uint32_t count = 0; uint8_t *apdu = NULL; + int apdu_size = 0; struct object_functions *pObject = NULL; - bool found = false; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; + apdu_size = rpdata->application_data_len; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id( @@ -892,52 +923,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_LIST: count = Device_Object_List_Count(); - /* Array element zero is the number of objects in the list */ - if (rpdata->array_index == 0) { - apdu_len = encode_application_unsigned(&apdu[0], count); - /* if no index was specified, then try to encode the entire list - */ - /* into one packet. Note that more than likely you will have */ - /* to return an error if the number of encoded objects exceeds - */ - /* your maximum APDU size. */ - } else if (rpdata->array_index == BACNET_ARRAY_ALL) { - for (i = 1; i <= count; i++) { - found = Device_Object_List_Identifier( - i, &object_type, &instance); - if (found) { - len = encode_application_object_id( - &apdu[apdu_len], object_type, instance); - apdu_len += len; - /* assume next one is the same size as this one */ - /* can we all fit into the APDU? Don't check for last - * entry */ - if ((i != count) && (apdu_len + len) >= MAX_APDU) { - /* Abort response */ - rpdata->error_code = - ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; - apdu_len = BACNET_STATUS_ABORT; - break; - } - } else { - /* error: internal error? */ - rpdata->error_class = ERROR_CLASS_SERVICES; - rpdata->error_code = ERROR_CODE_OTHER; - apdu_len = BACNET_STATUS_ERROR; - break; - } - } - } else { - found = Device_Object_List_Identifier( - rpdata->array_index, &object_type, &instance); - if (found) { - apdu_len = encode_application_object_id( - &apdu[0], object_type, instance); - } else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Device_Object_List_Element_Encode, + count, apdu, apdu_size); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_MAX_APDU_LENGTH_ACCEPTED: diff --git a/src/bacnet/basic/object/device.c b/src/bacnet/basic/object/device.c index 0c0bc078..592d5a4d 100644 --- a/src/bacnet/basic/object/device.c +++ b/src/bacnet/basic/object/device.c @@ -892,6 +892,39 @@ bool Device_Object_List_Identifier( return status; } +/** + * @brief Encode a BACnetARRAY property element + * @param object_instance [in] BACnet network port object instance number + * @param array_index [in] array index requested: + * 0 to N for individual array members + * @param apdu [out] Buffer in which the APDU contents are built, or NULL to + * return the length of buffer if it had been built + * @return The length of the apdu encoded or + * BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX + */ +int Device_Object_List_Element_Encode( + uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu) +{ + int apdu_len = BACNET_STATUS_ERROR; + BACNET_OBJECT_TYPE object_type; + uint32_t instance; + bool found; + + if (object_instance == Device_Object_Instance_Number()) { + /* single element is zero based, add 1 for BACnetARRAY which is one + * based */ + array_index++; + found = + Device_Object_List_Identifier(array_index, &object_type, &instance); + if (found) { + apdu_len = + encode_application_object_id(apdu, object_type, instance); + } + } + + return apdu_len; +} + /** Determine if we have an object with the given object_name. * If the object_type and object_instance pointers are not null, * and the lookup succeeds, they will be given the resulting values. @@ -1086,16 +1119,12 @@ uint32_t Device_Interval_Offset(void) int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) { int apdu_len = 0; /* return value */ - int len = 0; /* apdu len intermediate value */ BACNET_BIT_STRING bit_string = { 0 }; BACNET_CHARACTER_STRING char_string = { 0 }; uint32_t i = 0; - BACNET_OBJECT_TYPE object_type = OBJECT_NONE; - uint32_t instance = 0; uint32_t count = 0; uint8_t *apdu = NULL; struct object_functions *pObject = NULL; - bool found = false; uint16_t apdu_max = 0; if ((rpdata == NULL) || (rpdata->application_data == NULL) || @@ -1210,52 +1239,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_LIST: count = Device_Object_List_Count(); - /* Array element zero is the number of objects in the list */ - if (rpdata->array_index == 0) { - apdu_len = encode_application_unsigned(&apdu[0], count); - /* if no index was specified, then try to encode the entire list - */ - /* into one packet. Note that more than likely you will have */ - /* to return an error if the number of encoded objects exceeds - */ - /* your maximum APDU size. */ - } else if (rpdata->array_index == BACNET_ARRAY_ALL) { - for (i = 1; i <= count; i++) { - found = Device_Object_List_Identifier( - i, &object_type, &instance); - if (found) { - len = encode_application_object_id( - &apdu[apdu_len], object_type, instance); - apdu_len += len; - /* assume next one is the same size as this one */ - /* can we all fit into the APDU? Don't check for last - * entry */ - if ((i != count) && (apdu_len + len) >= apdu_max) { - /* Abort response */ - rpdata->error_code = - ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; - apdu_len = BACNET_STATUS_ABORT; - break; - } - } else { - /* error: internal error? */ - rpdata->error_class = ERROR_CLASS_SERVICES; - rpdata->error_code = ERROR_CODE_OTHER; - apdu_len = BACNET_STATUS_ERROR; - break; - } - } - } else { - found = Device_Object_List_Identifier( - rpdata->array_index, &object_type, &instance); - if (found) { - apdu_len = encode_application_object_id( - &apdu[0], object_type, instance); - } else { - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - } + apdu_len = bacnet_array_encode(rpdata->object_instance, + rpdata->array_index, + Device_Object_List_Element_Encode, + count, apdu, apdu_max); + if (apdu_len == BACNET_STATUS_ABORT) { + rpdata->error_code = + ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; + } else if (apdu_len == BACNET_STATUS_ERROR) { + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; } break; case PROP_MAX_APDU_LENGTH_ACCEPTED: diff --git a/src/bacnet/basic/object/device.h b/src/bacnet/basic/object/device.h index 2a716697..6ad4b596 100644 --- a/src/bacnet/basic/object/device.h +++ b/src/bacnet/basic/object/device.h @@ -298,6 +298,7 @@ extern "C" { BACNET_STACK_EXPORT bool Device_Valid_Object_Instance_Number( uint32_t object_id); + BACNET_STACK_EXPORT unsigned Device_Object_List_Count( void); @@ -306,6 +307,11 @@ extern "C" { uint32_t array_index, BACNET_OBJECT_TYPE *object_type, uint32_t * instance); + BACNET_STACK_EXPORT + int Device_Object_List_Element_Encode( + uint32_t object_instance, + BACNET_ARRAY_INDEX array_index, + uint8_t *apdu); BACNET_STACK_EXPORT unsigned Device_Count( diff --git a/src/bacnet/basic/sys/platform.h b/src/bacnet/basic/sys/platform.h index 3328eaa1..9a6c23f6 100644 --- a/src/bacnet/basic/sys/platform.h +++ b/src/bacnet/basic/sys/platform.h @@ -39,7 +39,9 @@ # include # endif -#if defined(__GNUC__) +#if defined(__MINGW32__) +#define BACNET_STACK_FALLTHROUGH() /* fall through */ +#elif defined(__GNUC__) #define BACNET_STACK_FALLTHROUGH() __attribute__ ((fallthrough)) #else #define BACNET_STACK_FALLTHROUGH() /* fall through */