diff --git a/src/bacnet/bacapp.c b/src/bacnet/bacapp.c index 41ff0d59..d12bc84b 100644 --- a/src/bacnet/bacapp.c +++ b/src/bacnet/bacapp.c @@ -251,14 +251,19 @@ int bacapp_encode_application_data( /** * @brief Decode the data and store it into value. * @param apdu Receive buffer + * @param apdu_size Size of the receive buffer * @param tag_data_type Data type of the given tag * @param len_value_type Count of bytes of given tag * @param value Pointer to the application value structure, * used to store the decoded value to. * - * @return Number of octets consumed. + * @return Number of octets consumed (could be zero). + * Parameter value->tag set to MAX_BACNET_APPLICATION_TAG when + * the number of octets consumed is zero and there is an error + * in the decoding, or BACNET_STATUS_ERROR/ABORT/REJECT if malformed. */ -int bacapp_decode_data(uint8_t *apdu, +int bacapp_data_decode(uint8_t *apdu, + uint32_t apdu_size, uint8_t tag_data_type, uint32_t len_value_type, BACNET_APPLICATION_DATA_VALUE *value) @@ -279,162 +284,158 @@ int bacapp_decode_data(uint8_t *apdu, #endif #if defined(BACAPP_UNSIGNED) case BACNET_APPLICATION_TAG_UNSIGNED_INT: - len = decode_unsigned( - apdu, len_value_type, &value->type.Unsigned_Int); + len = bacnet_unsigned_decode( + apdu, apdu_size, len_value_type, &value->type.Unsigned_Int); break; #endif #if defined(BACAPP_SIGNED) case BACNET_APPLICATION_TAG_SIGNED_INT: - len = decode_signed( - apdu, len_value_type, &value->type.Signed_Int); + len = bacnet_signed_decode( + apdu, apdu_size, len_value_type, &value->type.Signed_Int); break; #endif #if defined(BACAPP_REAL) case BACNET_APPLICATION_TAG_REAL: - len = - decode_real_safe(apdu, len_value_type, &(value->type.Real)); + len = bacnet_real_decode( + apdu, apdu_size, len_value_type, &(value->type.Real)); break; #endif #if defined(BACAPP_DOUBLE) case BACNET_APPLICATION_TAG_DOUBLE: - len = decode_double_safe( - apdu, len_value_type, &(value->type.Double)); + len = bacnet_double_decode( + apdu, apdu_size, len_value_type, &(value->type.Double)); break; #endif #if defined(BACAPP_OCTET_STRING) case BACNET_APPLICATION_TAG_OCTET_STRING: - len = decode_octet_string( - apdu, len_value_type, &value->type.Octet_String); + len = bacnet_octet_string_decode( + apdu, apdu_size, len_value_type, &value->type.Octet_String); break; #endif #if defined(BACAPP_CHARACTER_STRING) case BACNET_APPLICATION_TAG_CHARACTER_STRING: - len = decode_character_string( - apdu, len_value_type, &value->type.Character_String); + len = bacnet_character_string_decode(apdu, apdu_size, + len_value_type, &value->type.Character_String); break; #endif #if defined(BACAPP_BIT_STRING) case BACNET_APPLICATION_TAG_BIT_STRING: - len = decode_bitstring( - apdu, len_value_type, &value->type.Bit_String); + len = bacnet_bitstring_decode( + apdu, apdu_size, len_value_type, &value->type.Bit_String); break; #endif #if defined(BACAPP_ENUMERATED) case BACNET_APPLICATION_TAG_ENUMERATED: - len = decode_enumerated( - apdu, len_value_type, &value->type.Enumerated); + len = bacnet_enumerated_decode( + apdu, apdu_size, len_value_type, &value->type.Enumerated); break; #endif #if defined(BACAPP_DATE) case BACNET_APPLICATION_TAG_DATE: - len = decode_date_safe(apdu, len_value_type, &value->type.Date); + len = bacnet_date_decode( + apdu, apdu_size, len_value_type, &value->type.Date); break; #endif #if defined(BACAPP_TIME) case BACNET_APPLICATION_TAG_TIME: - len = decode_bacnet_time_safe( - apdu, len_value_type, &value->type.Time); + len = bacnet_time_decode( + apdu, apdu_size, len_value_type, &value->type.Time); break; #endif #if defined(BACAPP_OBJECT_ID) case BACNET_APPLICATION_TAG_OBJECT_ID: { - BACNET_OBJECT_TYPE object_type = OBJECT_NONE; - uint32_t instance = 0; - len = decode_object_id_safe( - apdu, len_value_type, &object_type, &instance); - value->type.Object_Id.type = object_type; - value->type.Object_Id.instance = instance; + len = bacnet_object_id_decode(apdu, apdu_size, len_value_type, + &value->type.Object_Id.type, + &value->type.Object_Id.instance); } break; #endif #if defined(BACAPP_TIMESTAMP) case BACNET_APPLICATION_TAG_TIMESTAMP: len = bacnet_timestamp_decode( - apdu, len_value_type, &value->type.Time_Stamp); + apdu, apdu_size, &value->type.Time_Stamp); break; #endif #if defined(BACAPP_DATETIME) case BACNET_APPLICATION_TAG_DATETIME: len = bacnet_datetime_decode( - apdu, len_value_type, &value->type.Date_Time); + apdu, apdu_size, &value->type.Date_Time); break; #endif #if defined(BACAPP_DATERANGE) case BACNET_APPLICATION_TAG_DATERANGE: len = bacnet_daterange_decode( - apdu, len_value_type, &value->type.Date_Range); + apdu, apdu_size, &value->type.Date_Range); break; #endif #if defined(BACAPP_LIGHTING_COMMAND) case BACNET_APPLICATION_TAG_LIGHTING_COMMAND: len = lighting_command_decode( - apdu, len_value_type, &value->type.Lighting_Command); + apdu, apdu_size, &value->type.Lighting_Command); break; #endif #if defined(BACAPP_XY_COLOR) case BACNET_APPLICATION_TAG_XY_COLOR: /* BACnetxyColor */ - len = xy_color_decode( - apdu, len_value_type, &value->type.XY_Color); + len = xy_color_decode(apdu, apdu_size, &value->type.XY_Color); break; #endif #if defined(BACAPP_COLOR_COMMAND) case BACNET_APPLICATION_TAG_COLOR_COMMAND: /* BACnetColorCommand */ len = color_command_decode( - apdu, len_value_type, NULL, &value->type.Color_Command); + apdu, apdu_size, NULL, &value->type.Color_Command); break; #endif #if defined(BACAPP_WEEKLY_SCHEDULE) case BACNET_APPLICATION_TAG_WEEKLY_SCHEDULE: len = bacnet_weeklyschedule_decode( - apdu, (int)len_value_type, &value->type.Weekly_Schedule); + apdu, apdu_size, &value->type.Weekly_Schedule); break; #endif #if defined(BACAPP_CALENDAR_ENTRY) case BACNET_APPLICATION_TAG_CALENDAR_ENTRY: len = bacnet_calendar_entry_decode( - apdu, len_value_type, &value->type.Calendar_Entry); + apdu, apdu_size, &value->type.Calendar_Entry); break; #endif #if defined(BACAPP_SPECIAL_EVENT) case BACNET_APPLICATION_TAG_SPECIAL_EVENT: len = bacnet_special_event_decode( - apdu, (int)len_value_type, &value->type.Special_Event); + apdu, apdu_size, &value->type.Special_Event); break; #endif #if defined(BACAPP_HOST_N_PORT) case BACNET_APPLICATION_TAG_HOST_N_PORT: len = host_n_port_decode( - apdu, len_value_type, NULL, &value->type.Host_Address); + apdu, apdu_size, NULL, &value->type.Host_Address); break; #endif #if defined(BACAPP_DEVICE_OBJECT_PROPERTY_REFERENCE) case BACNET_APPLICATION_TAG_DEVICE_OBJECT_PROPERTY_REFERENCE: /* BACnetDeviceObjectPropertyReference */ len = bacnet_device_object_property_reference_decode(apdu, - len_value_type, - &value->type.Device_Object_Property_Reference); + apdu_size, &value->type.Device_Object_Property_Reference); break; #endif #if defined(BACAPP_DEVICE_OBJECT_REFERENCE) case BACNET_APPLICATION_TAG_DEVICE_OBJECT_REFERENCE: /* BACnetDeviceObjectReference */ - len = bacapp_decode_device_obj_ref( - apdu, &value->type.Device_Object_Reference); + len = bacnet_device_object_reference_decode( + apdu, apdu_size, &value->type.Device_Object_Reference); break; #endif #if defined(BACAPP_OBJECT_PROPERTY_REFERENCE) case BACNET_APPLICATION_TAG_OBJECT_PROPERTY_REFERENCE: /* BACnetObjectPropertyReference */ - len = bacapp_decode_obj_property_ref(apdu, len_value_type, - &value->type.Object_Property_Reference); + len = bacapp_decode_obj_property_ref( + apdu, apdu_size, &value->type.Object_Property_Reference); break; #endif #if defined(BACAPP_DESTINATION) case BACNET_APPLICATION_TAG_DESTINATION: /* BACnetDestination */ len = bacnet_destination_decode( - apdu, len_value_type, &value->type.Destination); + apdu, apdu_size, &value->type.Destination); break; #endif default: @@ -450,9 +451,30 @@ int bacapp_decode_data(uint8_t *apdu, value->tag = MAX_BACNET_APPLICATION_TAG; } } + return len; } +/** + * @brief Decode the data and store it into value. + * @param apdu Receive buffer + * @param tag_data_type Data type of the given tag + * @param len_value_type Count of bytes of given tag + * @param value Pointer to the application value structure, + * used to store the decoded value to. + * + * @return Number of octets consumed + * @deprecated Use bacapp_data_decode() instead. + */ +int bacapp_decode_data(uint8_t *apdu, + uint8_t tag_data_type, + uint32_t len_value_type, + BACNET_APPLICATION_DATA_VALUE *value) +{ + return bacapp_data_decode( + apdu, MAX_APDU, tag_data_type, len_value_type, value); +} + /** * @brief Decode the BACnet Application Data * @@ -460,46 +482,37 @@ int bacapp_decode_data(uint8_t *apdu, * @param apdu_len_max - number of bytes in the buffer * @param value - decoded value, if decoded * - * @return the number of apdu bytes consumed, or #BACNET_STATUS_ERROR + * @return the number of apdu bytes consumed, 0 on bad args, or + * BACNET_STATUS_ERROR */ int bacapp_decode_application_data( uint8_t *apdu, uint32_t apdu_size, BACNET_APPLICATION_DATA_VALUE *value) { int len = 0; - int tag_len = 0; - int decode_len = 0; - uint8_t tag_number = 0; - uint32_t len_value_type = 0; + int apdu_len = 0; + BACNET_TAG tag = { 0 }; - if (apdu && value && apdu_size && !IS_CONTEXT_SPECIFIC(*apdu)) { + if (!value) { + return 0; + } + len = bacnet_tag_decode(apdu, apdu_size, &tag); + if ((len > 0) && tag.application) { value->context_specific = false; - tag_len = bacnet_tag_number_and_value_decode( - &apdu[0], apdu_size, &tag_number, &len_value_type); - if (tag_len > 0) { - len += tag_len; - value->tag = tag_number; - if ((unsigned)len <= apdu_size) { - decode_len = - bacapp_decode_data_len(NULL, tag_number, len_value_type); - if ((unsigned)decode_len <= (apdu_size - len)) { - decode_len = bacapp_decode_data( - &apdu[len], tag_number, len_value_type, value); - if (value->tag != MAX_BACNET_APPLICATION_TAG) { - len += decode_len; - } else { - len = BACNET_STATUS_ERROR; - } - } else { - len = BACNET_STATUS_ERROR; - } - } else { - len = BACNET_STATUS_ERROR; - } + value->tag = tag.number; + apdu_len += len; + len = bacapp_data_decode(&apdu[apdu_len], apdu_size - apdu_len, + tag.number, tag.len_value_type, value); + if ((len >= 0) && (value->tag != MAX_BACNET_APPLICATION_TAG)) { + apdu_len += len; + } else { + apdu_len = BACNET_STATUS_ERROR; } value->next = NULL; + } else if (apdu && (apdu_size > 0)) { + apdu_len = BACNET_STATUS_ERROR; } - return len; + return apdu_len; } /* @@ -527,8 +540,7 @@ bool bacapp_decode_application_data_safe(uint8_t *new_apdu, static uint32_t apdu_len = 0; int len = 0; int tag_len = 0; - uint8_t tag_number = 0; - uint32_t len_value_type = 0; + BACNET_TAG tag = { 0 }; bool ret = false; @@ -537,27 +549,28 @@ bool bacapp_decode_application_data_safe(uint8_t *new_apdu, apdu_len_remaining = new_apdu_len; apdu_len = 0; } - - if (value && apdu_len_remaining > 0 && - !IS_CONTEXT_SPECIFIC(apdu[apdu_len])) { - value->context_specific = false; - tag_len = bacnet_tag_number_and_value_decode( - &apdu[apdu_len], apdu_len_remaining, &tag_number, &len_value_type); + if (!value) { + return ret; + } + tag_len = bacnet_tag_decode(&apdu[apdu_len], apdu_len_remaining, &tag); + if ((tag_len > 0) && tag.application) { /* If tag_len is zero, then the tag information is truncated */ - if (tag_len) { - apdu_len += tag_len; - apdu_len_remaining -= tag_len; - /* The tag is boolean then len_value_type is interpreted as value, - not length, so don't bother checking with apdu_len_remaining */ - if (tag_number == BACNET_APPLICATION_TAG_BOOLEAN || - len_value_type <= apdu_len_remaining) { - value->tag = tag_number; - len = bacapp_decode_data( - &apdu[apdu_len], tag_number, len_value_type, value); + value->context_specific = false; + apdu_len += tag_len; + apdu_len_remaining -= tag_len; + /* The tag is boolean then len_value_type is interpreted as value, + not length, so don't bother checking with apdu_len_remaining */ + if (tag.number == BACNET_APPLICATION_TAG_BOOLEAN || + (tag.len_value_type <= apdu_len_remaining)) { + value->tag = tag.number; + len = bacapp_data_decode(&apdu[apdu_len], apdu_len_remaining, + tag.number, tag.len_value_type, value); + if (value->tag != MAX_BACNET_APPLICATION_TAG) { apdu_len += len; apdu_len_remaining -= len; - ret = true; + } else { + ret = false; } } value->next = NULL; @@ -610,29 +623,23 @@ int bacapp_decode_data_len( /** * @brief Determine the BACnet Application Data number of APDU bytes consumed * @param apdu - buffer of data to be decoded - * @param apdu_len_max - number of bytes in the buffer + * @param apdu_size - number of bytes in the buffer * @return number of bytes decoded, or zero if errors occur */ -int bacapp_decode_application_data_len(uint8_t *apdu, unsigned apdu_len_max) +int bacapp_decode_application_data_len(uint8_t *apdu, unsigned apdu_size) { + int apdu_len = 0; int len = 0; - int tag_len = 0; - int decode_len = 0; - uint8_t tag_number = 0; - uint32_t len_value_type = 0; + BACNET_TAG tag = { 0 }; - if (apdu && !IS_CONTEXT_SPECIFIC(*apdu)) { - tag_len = bacnet_tag_number_and_value_decode( - &apdu[0], apdu_len_max, &tag_number, &len_value_type); - if (tag_len > 0) { - len += tag_len; - decode_len = - bacapp_decode_data_len(NULL, tag_number, len_value_type); - len += decode_len; - } + len = bacnet_tag_decode(apdu, apdu_size, &tag); + if ((len > 0) && (tag.application)) { + apdu_len += len; + len = bacapp_decode_data_len(NULL, tag.number, tag.len_value_type); + apdu_len += len; } - return len; + return apdu_len; } int bacapp_encode_context_data_value(uint8_t *apdu, @@ -834,7 +841,7 @@ BACNET_APPLICATION_TAG bacapp_context_tag_type( date [0] Date, date-range [1] BACnetDateRange, weekNDay [2] BACnetWeekNDay - } + } */ switch (tag_number) { case 0: /* single calendar date */ @@ -857,7 +864,7 @@ BACNET_APPLICATION_TAG bacapp_context_tag_type( percent [0] Unsigned, level [1] Unsigned, amount [2] REAL - } + } */ switch (tag_number) { case 0: @@ -909,9 +916,9 @@ BACNET_APPLICATION_TAG bacapp_context_tag_type( case PROP_LIST_OF_GROUP_MEMBERS: /* ReadAccessSpecification ::= SEQUENCE { object-identifier [0] BACnetObjectIdentifier, - list-of-property-references [1] SEQUENCE OF + list-of-property-references [1] SEQUENCE OF BACnetPropertyReference - } + } */ switch (tag_number) { case 0: @@ -986,17 +993,17 @@ BACNET_APPLICATION_TAG bacapp_context_tag_type( monitored-property-reference [1] BACnetObjectPropertyReference, issue-confirmed-notifications [2] BOOLEAN, time-remaining [3] Unsigned, - cov-increment [4] REAL OPTIONAL + cov-increment [4] REAL OPTIONAL -- used only with monitored -- properties with a numeric datatype } */ switch (tag_number) { - case 0: + case 0: /* BACnetRecipientProcess ::= SEQUENCE { recipient [0] BACnetRecipient, process-identifier [1] Unsigned32 - } + } */ break; case 1: /* BACnetObjectPropertyReference */ @@ -1147,43 +1154,54 @@ int bacapp_encode_context_data(uint8_t *apdu, return apdu_len; } +/** + * @brief Decode context encoded data + * + * @param apdu - buffer of data to be decoded + * @param apdu_size - number of bytes in the buffer + * @param value - stores the decoded property value + * @param property - context property identifier + * @return number of bytes decoded, or #BACNET_STATUS_ERROR + */ int bacapp_decode_context_data(uint8_t *apdu, - unsigned max_apdu_len, + unsigned apdu_size, BACNET_APPLICATION_DATA_VALUE *value, BACNET_PROPERTY_ID property) { int apdu_len = 0, len = 0; - int tag_len = 0; - uint8_t tag_number = 0; - uint32_t len_value_type = 0; + BACNET_TAG tag = { 0 }; - if (apdu && value && IS_CONTEXT_SPECIFIC(*apdu)) { - value->context_specific = true; - value->next = NULL; - tag_len = - decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type); - apdu_len = tag_len; - /* Empty construct : (closing tag) => returns NULL value */ - if (tag_len && ((unsigned)tag_len <= max_apdu_len) && - !decode_is_closing_tag_number(&apdu[0], tag_number)) { - value->context_tag = tag_number; - value->tag = bacapp_context_tag_type(property, tag_number); + if (!value) { + return apdu_len; + } + len = bacnet_tag_decode(&apdu[0], apdu_size, &tag); + if (len > 0) { + if (tag.closing) { + /* Empty construct : (closing tag) */ + /* Don't advance over that closing tag. */ + apdu_len = 0; + } else if (tag.context) { + apdu_len += len; + value->context_specific = true; + value->next = NULL; + value->context_tag = tag.number; + value->tag = bacapp_context_tag_type(property, tag.number); if (value->tag != MAX_BACNET_APPLICATION_TAG) { - len = bacapp_decode_data( - &apdu[apdu_len], value->tag, len_value_type, value); - apdu_len += len; - } else if (len_value_type) { + len = bacapp_data_decode(&apdu[apdu_len], apdu_size - apdu_len, + value->tag, tag.len_value_type, value); + if ((len >= 0) && (value->tag != MAX_BACNET_APPLICATION_TAG)) { + apdu_len += len; + } else { + apdu_len = BACNET_STATUS_ERROR; + } + } else if (tag.len_value_type) { /* Unknown value : non null size (elementary type) */ - apdu_len += len_value_type; + apdu_len += tag.len_value_type; /* SHOULD NOT HAPPEN, EXCEPTED WHEN READING UNKNOWN CONTEXTUAL * PROPERTY */ } else { apdu_len = BACNET_STATUS_ERROR; } - } else if (tag_len == 1) { - /* and is a Closing tag */ - /* Don't advance over that closing tag. */ - apdu_len = 0; } } @@ -1195,62 +1213,68 @@ int bacapp_decode_context_data(uint8_t *apdu, * @brief Context or Application tagged property value decoding * * @param apdu - buffer of data to be decoded - * @param max_apdu_len - number of bytes in the buffer + * @param apdu_size - number of bytes in the buffer * @param value - stores the decoded property value * @param property - context property identifier - * @return number of bytes decoded, or ERROR if errors occur + * @return number of bytes decoded, or #BACNET_STATUS_ERROR */ int bacapp_decode_generic_property(uint8_t *apdu, - int max_apdu_len, + int apdu_size, BACNET_APPLICATION_DATA_VALUE *value, BACNET_PROPERTY_ID prop) { - int len = 0; - if (IS_CONTEXT_SPECIFIC(*apdu)) { - len = bacapp_decode_context_data(apdu, max_apdu_len, value, prop); - } else { - len = bacapp_decode_application_data(apdu, max_apdu_len, value); + int apdu_len = BACNET_STATUS_ERROR; + + if (apdu && (apdu_size > 0)) { + if (IS_CONTEXT_SPECIFIC(*apdu)) { + apdu_len = bacapp_decode_context_data(apdu, apdu_size, value, prop); + } else { + apdu_len = bacapp_decode_application_data(apdu, apdu_size, value); + } } - return len; + + return apdu_len; } #endif #if defined(BACAPP_COMPLEX_TYPES) -/* decode one value of a priority array */ +/** + * @brief Decode BACnetPriorityValue complex data + * + * @param apdu - buffer of data to be decoded + * @param apdu_size - number of bytes in the buffer + * @param value - stores the decoded property value + * @param property - context property identifier + * @return number of bytes decoded, or #BACNET_STATUS_ERROR + */ static int decode_priority_value(uint8_t *apdu, - unsigned max_apdu_len, + unsigned apdu_size, BACNET_APPLICATION_DATA_VALUE *value, - BACNET_PROPERTY_ID prop) + BACNET_PROPERTY_ID property) { - int val_len = 0; - uint32_t len_value_type = 0; + int apdu_len = 0; int len = 0; - bool is_opening_tag; - uint8_t tag_number; - if (decode_is_context_tag(apdu, 0) && !decode_is_closing_tag(apdu)) { + if (bacnet_is_opening_tag_number(apdu, apdu_size, 0, &len)) { /* Contextual Abstract-syntax & type */ - val_len = - decode_tag_number_and_value(apdu, &tag_number, &len_value_type); - is_opening_tag = decode_is_opening_tag(apdu); - len += val_len; - val_len = bacapp_decode_generic_property( - &apdu[len], max_apdu_len - len, value, prop); - if (val_len < 0) { + apdu_len += len; + len = bacapp_decode_generic_property( + &apdu[apdu_len], apdu_size - apdu_len, value, property); + if (len < 0) { return BACNET_STATUS_ERROR; } - len += val_len; - if (is_opening_tag) { - if (!decode_is_closing_tag_number(apdu, 0)) { - return BACNET_STATUS_ERROR; - } - len++; + apdu_len += len; + if (!bacnet_is_closing_tag_number( + &apdu[apdu_len], apdu_size - apdu_len, 0, &len)) { + return BACNET_STATUS_ERROR; } + apdu_len += len; } else { - len = bacapp_decode_generic_property(apdu, max_apdu_len, value, prop); + apdu_len = + bacapp_decode_generic_property(apdu, apdu_size, value, property); } - return len; + return apdu_len; } #endif @@ -1492,7 +1516,8 @@ int bacapp_decode_known_property(uint8_t *apdu, case PROP_ACCESS_EVENT_TIME: #ifdef BACAPP_TIMESTAMP /* Properties using BACnetTimeStamp */ - len = bacapp_decode_timestamp(apdu, &value->type.Time_Stamp); + len = bacnet_timestamp_decode( + apdu, max_apdu_len, &value->type.Time_Stamp); #endif break; @@ -1619,23 +1644,19 @@ int bacapp_decode_context_data_len( uint8_t *apdu, unsigned apdu_len_max, BACNET_PROPERTY_ID property) { int apdu_len = 0, len = 0; - int tag_len = 0; - uint8_t tag_number = 0; - uint32_t len_value_type = 0; - uint8_t tag = 0; + BACNET_TAG tag = { 0 }; + uint8_t application_tag = 0; - if (apdu && IS_CONTEXT_SPECIFIC(*apdu)) { - tag_len = bacnet_tag_number_and_value_decode( - &apdu[0], apdu_len_max, &tag_number, &len_value_type); - if (tag_len) { - apdu_len = tag_len; - tag = bacapp_context_tag_type(property, tag_number); - if (tag != MAX_BACNET_APPLICATION_TAG) { - len = bacapp_decode_data_len(NULL, tag, len_value_type); - apdu_len += len; - } else { - apdu_len += len_value_type; - } + len = bacnet_tag_decode(&apdu[0], apdu_len_max, &tag); + if ((len > 0) && tag.context) { + apdu_len = len; + application_tag = bacapp_context_tag_type(property, tag.number); + if (application_tag != MAX_BACNET_APPLICATION_TAG) { + len = bacapp_decode_data_len( + NULL, application_tag, tag.len_value_type); + apdu_len += len; + } else { + apdu_len += tag.len_value_type; } } @@ -1758,69 +1779,68 @@ bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE *dest_value, * Include a value property identifier for context specific data * such as the value received in a WriteProperty request. * - * @param Pointer to the APDU buffer - * @param apdu_len_max Bytes valid in the buffer + * @param apdu Pointer to the APDU buffer + * @param apdu_size Bytes valid in the buffer * @param property ID of the property to get the length for. * * @return Length in bytes 0..N, or BACNET_STATUS_ERROR. */ int bacapp_data_len( - uint8_t *apdu, unsigned apdu_len_max, BACNET_PROPERTY_ID property) + uint8_t *apdu, unsigned apdu_size, BACNET_PROPERTY_ID property) { int len = 0; int total_len = 0; int apdu_len = 0; - uint8_t tag_number = 0; + BACNET_TAG tag = { 0 }; uint8_t opening_tag_number = 0; uint8_t opening_tag_number_counter = 0; - uint32_t value = 0; bool total_len_enable = false; if (!apdu) { return BACNET_STATUS_ERROR; } - if (apdu_len_max <= apdu_len) { + if (apdu_size <= apdu_len) { /* error: exceeding our buffer limit */ return BACNET_STATUS_ERROR; } - if (!bacnet_is_opening_tag(apdu, apdu_len_max)) { + if (!bacnet_is_opening_tag(apdu, apdu_size)) { /* error: opening tag is missing */ return BACNET_STATUS_ERROR; } do { - if (bacnet_is_opening_tag(apdu, apdu_len_max)) { - len = bacnet_tag_number_and_value_decode( - apdu, apdu_len_max - apdu_len, &tag_number, &value); + len = bacnet_tag_decode(apdu, apdu_size - apdu_len, &tag); + if (len == 0) { + return BACNET_STATUS_ERROR; + } + if (tag.opening) { if (opening_tag_number_counter == 0) { - opening_tag_number = tag_number; + opening_tag_number = tag.number; opening_tag_number_counter = 1; total_len_enable = false; - } else if (tag_number == opening_tag_number) { + } else if (tag.number == opening_tag_number) { total_len_enable = true; opening_tag_number_counter++; } else { total_len_enable = true; } - } else if (bacnet_is_closing_tag(apdu, apdu_len_max)) { - len = bacnet_tag_number_and_value_decode( - apdu, apdu_len_max - apdu_len, &tag_number, &value); - if (tag_number == opening_tag_number) { + } else if (tag.closing) { + if (tag.number == opening_tag_number) { if (opening_tag_number_counter > 0) { opening_tag_number_counter--; } } total_len_enable = true; - } else if (bacnet_is_context_specific(apdu, apdu_len_max)) { + } else if (tag.context) { #if defined(BACAPP_COMPLEX_TYPES) /* context-specific tagged data */ len = bacapp_decode_context_data_len( - apdu, apdu_len_max - apdu_len, property); + apdu, apdu_size - apdu_len, property); total_len_enable = true; #endif } else { /* application tagged data */ - len = bacapp_decode_application_data_len( - apdu, apdu_len_max - apdu_len); + len = + bacapp_decode_application_data_len(apdu, apdu_size - apdu_len); total_len_enable = true; } if (opening_tag_number_counter > 0) { @@ -1833,7 +1853,7 @@ int bacapp_data_len( return BACNET_STATUS_ERROR; } apdu_len += len; - if (apdu_len_max <= apdu_len) { + if (apdu_size <= apdu_len) { /* error: exceeding our buffer limit */ return BACNET_STATUS_ERROR; } diff --git a/src/bacnet/bacapp.h b/src/bacnet/bacapp.h index a09cbc50..57381740 100644 --- a/src/bacnet/bacapp.h +++ b/src/bacnet/bacapp.h @@ -206,10 +206,18 @@ extern "C" { uint8_t * apdu, BACNET_APPLICATION_DATA_VALUE * value); BACNET_STACK_EXPORT + int bacapp_data_decode( + uint8_t * apdu, + uint32_t apdu_size, + uint8_t tag_data_type, + uint32_t len_value_type, + BACNET_APPLICATION_DATA_VALUE * value); + BACNET_STACK_DEPRECATED("Use bacapp_data_decode() instead") + BACNET_STACK_EXPORT int bacapp_decode_data( uint8_t * apdu, uint8_t tag_data_type, - uint32_t apdu_size, + uint32_t len_value_type, BACNET_APPLICATION_DATA_VALUE * value); BACNET_STACK_EXPORT diff --git a/src/bacnet/basic/object/command.c b/src/bacnet/basic/object/command.c index 5554412c..7595f71d 100644 --- a/src/bacnet/basic/object/command.c +++ b/src/bacnet/basic/object/command.c @@ -379,6 +379,34 @@ void Command_Property_Lists( return; } +/** + * @brief Determine if the object property is a member of this object instance + * @param object_instance - object-instance number of the object + * @param object_property - object-property to be checked + * @return true if the property is a member of this object instance + */ +static bool Property_List_Member( + uint32_t object_instance, int object_property) +{ + bool found = false; + const int *pRequired = NULL; + const int *pOptional = NULL; + const int *pProprietary = NULL; + + (void)object_instance; + Command_Property_Lists( + &pRequired, &pOptional, &pProprietary); + found = property_list_member(pRequired, object_property); + if (!found) { + found = property_list_member(pOptional, object_property); + } + if (!found) { + found = property_list_member(pProprietary, object_property); + } + + return found; +} + /** * Initializes the Command object data */ @@ -797,21 +825,16 @@ bool Command_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; status = false; } - - break; - - case PROP_OBJECT_IDENTIFIER: - case PROP_OBJECT_NAME: - case PROP_OBJECT_TYPE: - case PROP_IN_PROCESS: - case PROP_ALL_WRITES_SUCCESSFUL: - case PROP_ACTION: - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; break; default: - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; + if (Property_List_Member( + wp_data->object_instance, wp_data->object_property)) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; + } break; } diff --git a/src/bacnet/basic/object/netport.c b/src/bacnet/basic/object/netport.c index 45fe8079..2d1b45cd 100644 --- a/src/bacnet/basic/object/netport.c +++ b/src/bacnet/basic/object/netport.c @@ -223,6 +223,33 @@ void Network_Port_Property_Lists( Object_List[0].Instance_Number, pRequired, pOptional, pProprietary); } +/** + * @brief Determine if the object property is a member of this object instance + * @param object_instance - object-instance number of the object + * @param object_property - object-property to be checked + * @return true if the property is a member of this object instance + */ +static bool Property_List_Member( + uint32_t object_instance, int object_property) +{ + bool found = false; + const int *pRequired = NULL; + const int *pOptional = NULL; + const int *pProprietary = NULL; + + Network_Port_Property_List(object_instance, + &pRequired, &pOptional, &pProprietary); + found = property_list_member(pRequired, object_property); + if (!found) { + found = property_list_member(pOptional, object_property); + } + if (!found) { + found = property_list_member(pProprietary, object_property); + } + + return found; +} + /** * For a given object instance-number, loads the object-name into * a characterstring. Note that the object name must be unique @@ -2523,26 +2550,15 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) } } break; - case PROP_OBJECT_IDENTIFIER: - case PROP_OBJECT_NAME: - case PROP_OBJECT_TYPE: - case PROP_STATUS_FLAGS: - case PROP_RELIABILITY: - case PROP_OUT_OF_SERVICE: - case PROP_NETWORK_TYPE: - case PROP_PROTOCOL_LEVEL: - case PROP_NETWORK_NUMBER: - case PROP_NETWORK_NUMBER_QUALITY: - case PROP_MAC_ADDRESS: - case PROP_LINK_SPEED: - case PROP_CHANGES_PENDING: - case PROP_APDU_LENGTH: - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - break; default: - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; + if (Property_List_Member( + wp_data->object_instance, wp_data->object_property)) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY; + } break; } diff --git a/test/bacnet/bacapp/src/main.c b/test/bacnet/bacapp/src/main.c index cf1d82a8..0c3c7706 100644 --- a/test/bacnet/bacapp/src/main.c +++ b/test/bacnet/bacapp/src/main.c @@ -829,16 +829,32 @@ static bool verifyBACnetApplicationDataValue( uint8_t apdu[480] = { 0 }; int apdu_len = 0; int null_len = 0; + int test_len = 0; + bool status = false; BACNET_APPLICATION_DATA_VALUE test_value = { 0 }; apdu_len = bacapp_encode_application_data(&apdu[0], value); zassert_true(apdu_len > 0, NULL); null_len = bacapp_encode_application_data(NULL, value); zassert_equal(apdu_len, null_len, NULL); - apdu_len = bacapp_decode_application_data(&apdu[0], apdu_len, &test_value); - zassert_true(apdu_len != BACNET_STATUS_ERROR, NULL); + test_len = bacapp_decode_application_data(&apdu[0], apdu_len, &test_value); + zassert_true(test_len != BACNET_STATUS_ERROR, NULL); + status = bacapp_same_value(value, &test_value); + while (apdu_len) { + apdu_len--; + test_len = + bacapp_decode_application_data(&apdu[0], apdu_len, &test_value); + if (apdu_len == 0) { + zassert_equal(test_len, 0, "tag=%u apdu_len=%d test_len=%d\n", + value->tag, apdu_len, test_len); + } else { + zassert_equal(test_len, BACNET_STATUS_ERROR, + "tag=%u apdu_len=%d test_len=%d null_len=%d\n", value->tag, + apdu_len, test_len, null_len); + } + } - return bacapp_same_value(value, &test_value); + return status; } /** diff --git a/test/bacnet/basic/object/command/CMakeLists.txt b/test/bacnet/basic/object/command/CMakeLists.txt index b26080b8..82cd6c31 100644 --- a/test/bacnet/basic/object/command/CMakeLists.txt +++ b/test/bacnet/basic/object/command/CMakeLists.txt @@ -27,6 +27,7 @@ add_compile_definitions( include_directories( ${SRC_DIR} + ${TST_DIR}/bacnet/basic/object ${TST_DIR}/ztest/include ) @@ -49,6 +50,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/indtext.c ${SRC_DIR}/bacnet/hostnport.c ${SRC_DIR}/bacnet/lighting.c + ${SRC_DIR}/bacnet/proplist.c ${SRC_DIR}/bacnet/timestamp.c ${SRC_DIR}/bacnet/wp.c ${SRC_DIR}/bacnet/weeklyschedule.c @@ -58,6 +60,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/special_event.c # Test and test library files ./src/main.c + ${TST_DIR}/bacnet/basic/object/property_test.c ${ZTST_DIR}/ztest_mock.c ${ZTST_DIR}/ztest.c ) diff --git a/test/bacnet/basic/object/command/src/main.c b/test/bacnet/basic/object/command/src/main.c index f793c9e1..7aff9576 100644 --- a/test/bacnet/basic/object/command/src/main.c +++ b/test/bacnet/basic/object/command/src/main.c @@ -8,7 +8,7 @@ */ #include #include -#include +#include /** * @addtogroup bacnet_tests @@ -24,83 +24,34 @@ ZTEST(tests_object_command, test_object_command) static void test_object_command(void) #endif { - uint8_t apdu[MAX_APDU] = { 0 }; - int len = 0; - int test_len = 0; - BACNET_READ_PROPERTY_DATA rpdata; - /* for decode value data */ - BACNET_APPLICATION_DATA_VALUE value; - const int *pRequired = NULL; - const int *pOptional = NULL; - const int *pProprietary = NULL; + bool status = false; unsigned count = 0; uint32_t object_instance = 0; + const int skip_fail_property_list[] = { PROP_ACTION, -1 }; Command_Init(); count = Command_Count(); zassert_true(count > 0, NULL); object_instance = Command_Index_To_Instance(0); - rpdata.application_data = &apdu[0]; - rpdata.application_data_len = sizeof(apdu); - rpdata.object_type = OBJECT_COMMAND; - rpdata.object_instance = object_instance; - Command_Property_Lists(&pRequired, &pOptional, &pProprietary); - while ((*pRequired) != -1) { - rpdata.object_property = *pRequired; - rpdata.array_index = BACNET_ARRAY_ALL; - len = Command_Read_Property(&rpdata); - zassert_not_equal(len, BACNET_STATUS_ERROR, NULL); - if (len > 0) { - test_len = bacapp_decode_application_data(rpdata.application_data, - (uint8_t)rpdata.application_data_len, &value); - if (len != test_len) { - printf("property '%s': failed to decode!\n", - bactext_property_name(rpdata.object_property)); - } - if (rpdata.object_property == PROP_PRIORITY_ARRAY) { - /* FIXME: known fail to decode */ - len = test_len; - } - zassert_true(test_len >= 0, NULL); - } - pRequired++; - } - while ((*pOptional) != -1) { - rpdata.object_property = *pOptional; - rpdata.array_index = BACNET_ARRAY_ALL; - len = Command_Read_Property(&rpdata); - zassert_not_equal(len, BACNET_STATUS_ERROR, NULL); - if (len > 0) { - test_len = bacapp_decode_application_data(rpdata.application_data, - (uint8_t)rpdata.application_data_len, &value); - if (len != test_len) { - printf("property '%s': failed to decode!\n", - bactext_property_name(rpdata.object_property)); - } - if (rpdata.object_property == PROP_PRIORITY_ARRAY) { - /* FIXME: known fail to decode */ - len = test_len; - } - zassert_true(test_len >= 0, NULL); - } - pOptional++; - } - - return; + bacnet_object_properties_read_write_test( + OBJECT_COMMAND, + object_instance, + Command_Property_Lists, + Command_Read_Property, + Command_Write_Property, + skip_fail_property_list); } /** * @} */ - #if defined(CONFIG_ZTEST_NEW_API) ZTEST_SUITE(tests_object_command, NULL, NULL, NULL, NULL, NULL); #else void test_main(void) { - ztest_test_suite(tests_object_command, - ztest_unit_test(test_object_command) - ); + ztest_test_suite( + tests_object_command, ztest_unit_test(test_object_command)); ztest_run_test_suite(tests_object_command); } diff --git a/test/bacnet/basic/object/credential_data_input/CMakeLists.txt b/test/bacnet/basic/object/credential_data_input/CMakeLists.txt index 214b15ae..460004ce 100644 --- a/test/bacnet/basic/object/credential_data_input/CMakeLists.txt +++ b/test/bacnet/basic/object/credential_data_input/CMakeLists.txt @@ -27,6 +27,7 @@ add_compile_definitions( include_directories( ${SRC_DIR} + ${TST_DIR}/bacnet/basic/object ${TST_DIR}/ztest/include ) @@ -52,6 +53,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/indtext.c ${SRC_DIR}/bacnet/hostnport.c ${SRC_DIR}/bacnet/lighting.c + ${SRC_DIR}/bacnet/proplist.c ${SRC_DIR}/bacnet/timestamp.c ${SRC_DIR}/bacnet/wp.c ${SRC_DIR}/bacnet/weeklyschedule.c @@ -61,6 +63,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/special_event.c # Test and test library files ./src/main.c + ${TST_DIR}/bacnet/basic/object/property_test.c ${ZTST_DIR}/ztest_mock.c ${ZTST_DIR}/ztest.c ) diff --git a/test/bacnet/basic/object/credential_data_input/src/main.c b/test/bacnet/basic/object/credential_data_input/src/main.c index 4d7d803f..22b54997 100644 --- a/test/bacnet/basic/object/credential_data_input/src/main.c +++ b/test/bacnet/basic/object/credential_data_input/src/main.c @@ -1,16 +1,15 @@ -/* - * Copyright (c) 2020 Legrand North America, LLC. +/** + * @file + * @brief Unit test for object + * @author Steve Karg + * @date February 2024 * * SPDX-License-Identifier: MIT */ - -/* @file - * @brief test BACnet integer encode/decode APIs - */ - #include #include #include +#include /** * @addtogroup bacnet_tests @@ -26,65 +25,25 @@ ZTEST(credential_data_input_tests, testCredentialDataInput) static void testCredentialDataInput(void) #endif { - uint8_t apdu[MAX_APDU] = { 0 }; - int len = 0; - int test_len = 0; - BACNET_READ_PROPERTY_DATA rpdata; - /* for decode value data */ - BACNET_APPLICATION_DATA_VALUE value; - const int *pRequired = NULL; - const int *pOptional = NULL; - const int *pProprietary = NULL; unsigned count = 0; uint32_t object_instance = 0; + const int skip_fail_property_list[] = { + PROP_PRESENT_VALUE, + PROP_UPDATE_TIME, + PROP_SUPPORTED_FORMATS, + -1 }; Credential_Data_Input_Init(); count = Credential_Data_Input_Count(); zassert_true(count > 0, NULL); object_instance = Credential_Data_Input_Index_To_Instance(0); - rpdata.application_data = &apdu[0]; - rpdata.application_data_len = sizeof(apdu); - rpdata.object_type = OBJECT_CREDENTIAL_DATA_INPUT; - rpdata.object_instance = object_instance; - Credential_Data_Input_Property_Lists(&pRequired, &pOptional, &pProprietary); - while ((*pRequired) != -1) { - rpdata.object_property = *pRequired; - rpdata.array_index = BACNET_ARRAY_ALL; - len = Credential_Data_Input_Read_Property(&rpdata); - zassert_not_equal(len, BACNET_STATUS_ERROR, NULL); - if (len > 0) { - test_len = bacapp_decode_application_data(rpdata.application_data, - (uint8_t)rpdata.application_data_len, &value); - if (len != test_len) { - printf("property '%s': failed to decode!\n", - bactext_property_name(rpdata.object_property)); - } - if (rpdata.object_property == PROP_PRIORITY_ARRAY) { - /* FIXME: known fail to decode */ - len = test_len; - } - zassert_true(test_len >= 0, NULL); - } else { - printf("property '%s': failed to read!\n", - bactext_property_name(rpdata.object_property)); - } - pRequired++; - } - while ((*pOptional) != -1) { - rpdata.object_property = *pOptional; - rpdata.array_index = BACNET_ARRAY_ALL; - len = Credential_Data_Input_Read_Property(&rpdata); - zassert_not_equal(len, BACNET_STATUS_ERROR, NULL); - if (len > 0) { - test_len = bacapp_decode_application_data(rpdata.application_data, - (uint8_t)rpdata.application_data_len, &value); - zassert_true(test_len >= 0, NULL); - } else { - printf("property '%s': failed to read!\n", - bactext_property_name(rpdata.object_property)); - } - pOptional++; - } + bacnet_object_properties_read_write_test( + OBJECT_CREDENTIAL_DATA_INPUT, + object_instance, + Credential_Data_Input_Property_Lists, + Credential_Data_Input_Read_Property, + Credential_Data_Input_Write_Property, + skip_fail_property_list); } /** * @} diff --git a/test/bacnet/basic/object/netport/CMakeLists.txt b/test/bacnet/basic/object/netport/CMakeLists.txt index c4de36d9..c5194498 100644 --- a/test/bacnet/basic/object/netport/CMakeLists.txt +++ b/test/bacnet/basic/object/netport/CMakeLists.txt @@ -27,6 +27,7 @@ add_compile_definitions( include_directories( ${SRC_DIR} + ${TST_DIR}/bacnet/basic/object ${TST_DIR}/ztest/include ) @@ -61,6 +62,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/special_event.c # Test and test library files ./src/main.c + ${TST_DIR}/bacnet/basic/object/property_test.c ${ZTST_DIR}/ztest_mock.c ${ZTST_DIR}/ztest.c ) diff --git a/test/bacnet/basic/object/netport/src/main.c b/test/bacnet/basic/object/netport/src/main.c index 39c47b54..e84b14c9 100644 --- a/test/bacnet/basic/object/netport/src/main.c +++ b/test/bacnet/basic/object/netport/src/main.c @@ -1,16 +1,15 @@ -/* - * Copyright (c) 2020 Legrand North America, LLC. +/** + * @file + * @brief Unit test for object + * @author Steve Karg + * @date February 2024 * * SPDX-License-Identifier: MIT */ - -/* @file - * @brief test BACnet integer encode/decode APIs - */ - #include #include #include +#include /** * @addtogroup bacnet_tests @@ -26,23 +25,18 @@ ZTEST(netport_tests, test_network_port) static void test_network_port(void) #endif { - uint8_t apdu[MAX_APDU] = { 0 }; - int len = 0; - int test_len = 0; - BACNET_READ_PROPERTY_DATA rpdata; - /* for decode value data */ - BACNET_APPLICATION_DATA_VALUE value; - const int *pRequired = NULL; - const int *pOptional = NULL; - const int *pProprietary = NULL; unsigned port = 0; + bool status = false; unsigned count = 0; uint32_t object_instance = 0; - bool status = false; uint8_t port_type[] = { PORT_TYPE_ETHERNET, PORT_TYPE_ARCNET, PORT_TYPE_MSTP, PORT_TYPE_PTP, PORT_TYPE_LONTALK, PORT_TYPE_BIP, PORT_TYPE_ZIGBEE, PORT_TYPE_VIRTUAL, PORT_TYPE_NON_BACNET, PORT_TYPE_BIP6, PORT_TYPE_MAX }; + const int known_fail_property_list[] = { PROP_IP_DNS_SERVER, + PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE, + PROP_BBMD_FOREIGN_DEVICE_TABLE, PROP_FD_BBMD_ADDRESS, + PROP_IPV6_DNS_SERVER, -1 }; while (port_type[port] != PORT_TYPE_MAX) { object_instance = 1234; @@ -53,43 +47,13 @@ static void test_network_port(void) Network_Port_Init(); count = Network_Port_Count(); zassert_true(count > 0, NULL); - rpdata.application_data = &apdu[0]; - rpdata.application_data_len = sizeof(apdu); - rpdata.object_type = OBJECT_NETWORK_PORT; - rpdata.object_instance = object_instance; - Network_Port_Property_Lists(&pRequired, &pOptional, &pProprietary); - while ((*pRequired) != -1) { - rpdata.object_property = *pRequired; - rpdata.array_index = BACNET_ARRAY_ALL; - len = Network_Port_Read_Property(&rpdata); - zassert_not_equal(len, BACNET_STATUS_ERROR, NULL); - if (len > 0) { - test_len = bacapp_decode_application_data( - rpdata.application_data, - (uint8_t)rpdata.application_data_len, &value); - zassert_true(test_len >= 0, NULL); - if (test_len < 0) { - printf("\n"); - } - } - pRequired++; - } - while ((*pOptional) != -1) { - rpdata.object_property = *pOptional; - rpdata.array_index = BACNET_ARRAY_ALL; - len = Network_Port_Read_Property(&rpdata); - zassert_not_equal(len, BACNET_STATUS_ERROR, NULL); - if (len > 0) { - test_len = bacapp_decode_application_data( - rpdata.application_data, - (uint8_t)rpdata.application_data_len, &value); - zassert_true(test_len >= 0, NULL); - if (test_len < 0) { - printf("\n"); - } - } - pOptional++; - } + bacnet_object_properties_read_write_test( + OBJECT_NETWORK_PORT, + object_instance, + Network_Port_Property_Lists, + Network_Port_Read_Property, + Network_Port_Write_Property, + known_fail_property_list); port++; } @@ -99,15 +63,12 @@ static void test_network_port(void) * @} */ - #if defined(CONFIG_ZTEST_NEW_API) ZTEST_SUITE(netport_tests, NULL, NULL, NULL, NULL, NULL); #else void test_main(void) { - ztest_test_suite(netport_tests, - ztest_unit_test(test_network_port) - ); + ztest_test_suite(netport_tests, ztest_unit_test(test_network_port)); ztest_run_test_suite(netport_tests); } diff --git a/test/bacnet/basic/object/property_test.c b/test/bacnet/basic/object/property_test.c new file mode 100644 index 00000000..6cbd4676 --- /dev/null +++ b/test/bacnet/basic/object/property_test.c @@ -0,0 +1,210 @@ +/** + * @file + * @brief Unit test for object property read/write + * @author Steve Karg + * @date February 2024 + * + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include +#include + +/** + * @brief Perform a read/write test on a property + * @param rpdata [in,out] The structure to hold the read property request + * @param read_property [in] The function to read the property + * @param write_property [in] The function to write the property + * @param skip_fail_property_list [in] The list of properties that + * are known to fail to decode after reading + * @return true if the property was written successfully, false if not + */ +bool bacnet_object_property_write_test(BACNET_WRITE_PROPERTY_DATA *wpdata, + write_property_function write_property, + const int *skip_fail_property_list) +{ + bool status = false; + int len = 0; + int test_len = 0; + + (void)skip_fail_property_list; + if (wpdata && write_property) { + status = write_property(wpdata); + if (!status) { + /* verify WriteProperty property is known */ + zassert_not_equal(wpdata->error_code, ERROR_CODE_UNKNOWN_PROPERTY, + "property '%s': WriteProperty Unknown!\n", + bactext_property_name(wpdata->object_property)); + } + } + + return status; +} + +/** + * @brief Initialize the write property parameter structure data from the + * read property parameter structure data and the length of the property value + * @param wpdata [in,out] The structure to hold the write property request + * @param rpdata [in] The structure to hold the read property request + */ +void bacnet_object_property_write_parameter_init( + BACNET_WRITE_PROPERTY_DATA *wpdata, + BACNET_READ_PROPERTY_DATA *rpdata, + int len) +{ + if (wpdata && rpdata) { + /* WriteProperty parameters */ + wpdata->object_type = rpdata->object_type; + wpdata->object_instance = rpdata->object_instance; + wpdata->object_property = rpdata->object_property; + wpdata->array_index = rpdata->array_index; + memcpy(&wpdata->application_data, rpdata->application_data, MAX_APDU); + wpdata->application_data_len = len; + wpdata->error_code = ERROR_CODE_SUCCESS; + } +} + +/** + * @brief Perform a read/write test on a property + * @param rpdata [in,out] The structure to hold the read property request + * @param read_property [in] The function to read the property + * @param write_property [in] The function to write the property + * @param skip_fail_property_list [in] The list of properties that + * are known to fail to decode after reading + * @return length of the property value that was read + */ +int bacnet_object_property_read_test(BACNET_READ_PROPERTY_DATA *rpdata, + read_property_function read_property, + const int *skip_fail_property_list) +{ + bool status = false; + int len = 0; + int test_len = 0; + int apdu_len = 0; + int read_len = 0; + uint8_t *apdu; + BACNET_ARRAY_INDEX array_index = 0; + BACNET_WRITE_PROPERTY_DATA wpdata = { 0 }; + BACNET_APPLICATION_DATA_VALUE value = { 0 }; + + read_len = read_property(rpdata); + if ((read_len == BACNET_STATUS_ERROR) && + (rpdata->error_class == ERROR_CLASS_PROPERTY) && + (rpdata->error_code == ERROR_CODE_READ_ACCESS_DENIED)) { + /* read-only is a valid response for some properties */ + } else if (read_len > 0) { + /* validate the data from the read request */ + apdu = rpdata->application_data; + apdu_len = read_len; + while (apdu_len) { + len = bacapp_decode_known_property(apdu, apdu_len, &value, + rpdata->object_type, rpdata->object_property); + if (len > 0) { + test_len += len; + if ((len < apdu_len) && + (rpdata->array_index == BACNET_ARRAY_ALL)) { + /* more data, therefore, this is an array */ + array_index = 1; + } + if (array_index > 0) { + apdu += len; + apdu_len -= len; + array_index++; + } else { + break; + } + } else { + printf("property '%s': failed to decode! len=%d\n", + bactext_property_name(rpdata->object_property), + len); + break; + } + } + if (read_len != test_len) { + printf("property '%s': failed to decode! %d!=%d\n", + bactext_property_name(rpdata->object_property), test_len, + read_len); + } + if (property_list_member( + skip_fail_property_list, rpdata->object_property)) { + /* FIXME: known fail to decode */ + test_len = read_len; + } + zassert_true(test_len == read_len, NULL); + } else if (read_len == 0) { + /* empty response is valid for some properties */ + } else { + zassert_not_equal(len, BACNET_STATUS_ERROR, + "property '%s': failed to read!\n", + bactext_property_name(rpdata->object_property)); + } + + return len; +} + +/** + * @brief Test all the properties of an object for read/write + * + * @param object_type The type of object to test + * @param object_instance The instance number of the object to test + * @param property_list The function to get the list of properties + * @param read_property The function to read the property + * @param write_property The function to write the property + * @param skip_fail_property_list The list of properties that + * are known to fail to decode after reading + */ +void bacnet_object_properties_read_write_test(BACNET_OBJECT_TYPE object_type, + uint32_t object_instance, + rpm_property_lists_function property_list, + read_property_function read_property, + write_property_function write_property, + const int *skip_fail_property_list) +{ + uint8_t apdu[MAX_APDU] = { 0 }; + BACNET_READ_PROPERTY_DATA rpdata = { 0 }; + BACNET_WRITE_PROPERTY_DATA wpdata = { 0 }; + const int *pRequired = NULL; + const int *pOptional = NULL; + const int *pProprietary = NULL; + unsigned count = 0; + int len = 0; + + /* ReadProperty parameters */ + rpdata.application_data = &apdu[0]; + rpdata.application_data_len = sizeof(apdu); + rpdata.object_type = object_type; + rpdata.object_instance = object_instance; + property_list(&pRequired, &pOptional, &pProprietary); + while ((*pRequired) != -1) { + rpdata.object_property = *pRequired; + rpdata.array_index = BACNET_ARRAY_ALL; + len = bacnet_object_property_read_test( + &rpdata, read_property, skip_fail_property_list); + bacnet_object_property_write_parameter_init(&wpdata, &rpdata, len); + bacnet_object_property_write_test( + &wpdata, write_property, skip_fail_property_list); + pRequired++; + } + while ((*pOptional) != -1) { + rpdata.object_property = *pOptional; + rpdata.array_index = BACNET_ARRAY_ALL; + bacnet_object_property_read_test( + &rpdata, read_property, skip_fail_property_list); + bacnet_object_property_write_parameter_init(&wpdata, &rpdata, len); + bacnet_object_property_write_test( + &wpdata, write_property, skip_fail_property_list); + pOptional++; + } + while ((*pProprietary) != -1) { + rpdata.object_property = *pProprietary; + rpdata.array_index = BACNET_ARRAY_ALL; + bacnet_object_property_read_test( + &rpdata, read_property, skip_fail_property_list); + bacnet_object_property_write_parameter_init(&wpdata, &rpdata, len); + bacnet_object_property_write_test( + &wpdata, write_property, skip_fail_property_list); + pProprietary++; + } +} diff --git a/test/bacnet/basic/object/property_test.h b/test/bacnet/basic/object/property_test.h new file mode 100644 index 00000000..6f2e9b99 --- /dev/null +++ b/test/bacnet/basic/object/property_test.h @@ -0,0 +1,39 @@ +/** + * @file + * @brief Unit test for object property read/write + * @author Steve Karg + * @date February 2024 + * + * SPDX-License-Identifier: MIT + */ +#ifndef _BACNET_PROPERTY_TEST_H_ +#define _BACNET_PROPERTY_TEST_H_ +#include +#include +#include +#include + +void bacnet_object_properties_read_write_test( + BACNET_OBJECT_TYPE object_type, + uint32_t object_instance, + rpm_property_lists_function property_list, + read_property_function read_property, + write_property_function write_property, + const int *skip_fail_property_list); + +int bacnet_object_property_read_test( + BACNET_READ_PROPERTY_DATA *rpdata, + read_property_function read_property, + const int *skip_fail_property_list); + +bool bacnet_object_property_write_test( + BACNET_WRITE_PROPERTY_DATA *wpdata, + write_property_function write_property, + const int *skip_fail_property_list); + +void bacnet_object_property_write_parameter_init( + BACNET_WRITE_PROPERTY_DATA *wpdata, + BACNET_READ_PROPERTY_DATA *rpdata, + int len); + +#endif diff --git a/test/bacnet/basic/object/schedule/CMakeLists.txt b/test/bacnet/basic/object/schedule/CMakeLists.txt index 09a46e07..40288010 100644 --- a/test/bacnet/basic/object/schedule/CMakeLists.txt +++ b/test/bacnet/basic/object/schedule/CMakeLists.txt @@ -27,6 +27,7 @@ add_compile_definitions( include_directories( ${SRC_DIR} + ${TST_DIR}/bacnet/basic/object ${TST_DIR}/ztest/include ) @@ -50,6 +51,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/indtext.c ${SRC_DIR}/bacnet/hostnport.c ${SRC_DIR}/bacnet/lighting.c + ${SRC_DIR}/bacnet/proplist.c ${SRC_DIR}/bacnet/timestamp.c ${SRC_DIR}/bacnet/wp.c ${SRC_DIR}/bacnet/weeklyschedule.c @@ -58,6 +60,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/special_event.c # Test and test library files ./src/main.c + ${TST_DIR}/bacnet/basic/object/property_test.c ${ZTST_DIR}/ztest_mock.c ${ZTST_DIR}/ztest.c ) diff --git a/test/bacnet/basic/object/schedule/src/main.c b/test/bacnet/basic/object/schedule/src/main.c index b848bb66..4d26b3bc 100644 --- a/test/bacnet/basic/object/schedule/src/main.c +++ b/test/bacnet/basic/object/schedule/src/main.c @@ -9,7 +9,7 @@ #include #include -#include +#include /** * @addtogroup bacnet_tests @@ -25,70 +25,22 @@ ZTEST(schedule_tests, testSchedule) static void testSchedule(void) #endif { - uint8_t apdu[MAX_APDU] = { 0 }; - int len = 0; - int test_len = 0; - BACNET_READ_PROPERTY_DATA rpdata; - /* for decode value data */ - BACNET_APPLICATION_DATA_VALUE value; - const int *pRequired = NULL; - const int *pOptional = NULL; - const int *pProprietary = NULL; unsigned count = 0; - bool status = false; + uint32_t object_instance = 0; + const int skip_fail_property_list[] = { + PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES, -1 }; Schedule_Init(); count = Schedule_Count(); zassert_true(count > 0, NULL); - rpdata.application_data = &apdu[0]; - rpdata.application_data_len = sizeof(apdu); - rpdata.object_type = OBJECT_SCHEDULE; - rpdata.object_instance = Schedule_Index_To_Instance(0);; - status = Schedule_Valid_Instance(rpdata.object_instance); - zassert_true(status, NULL); - Schedule_Property_Lists(&pRequired, &pOptional, &pProprietary); - while ((*pRequired) != -1) { - rpdata.object_property = *pRequired; - rpdata.array_index = BACNET_ARRAY_ALL; - len = Schedule_Read_Property(&rpdata); - zassert_not_equal(len, BACNET_STATUS_ERROR, NULL); - if (len > 0) { - test_len = bacapp_decode_application_data(rpdata.application_data, - (uint8_t)rpdata.application_data_len, &value); - if (len != test_len) { - printf("property '%s': failed to decode!\n", - bactext_property_name(rpdata.object_property)); - } - if (rpdata.object_property == PROP_PRIORITY_ARRAY) { - /* FIXME: known fail to decode */ - len = test_len; - } - zassert_true(test_len >= 0, NULL); - } else { - printf("property '%s': failed to read!\n", - bactext_property_name(rpdata.object_property)); - } - pRequired++; - } - while ((*pOptional) != -1) { - rpdata.object_property = *pOptional; - rpdata.array_index = BACNET_ARRAY_ALL; - len = Schedule_Read_Property(&rpdata); - zassert_not_equal(len, BACNET_STATUS_ERROR, NULL); - if (len > 0) { - test_len = bacapp_decode_application_data(rpdata.application_data, - (uint8_t)rpdata.application_data_len, &value); - if (len != test_len) { - printf("property '%s': failed to decode!\n", - bactext_property_name(rpdata.object_property)); - } - zassert_true(test_len >= 0, NULL); - } else { - printf("property '%s': failed to read!\n", - bactext_property_name(rpdata.object_property)); - } - pOptional++; - } + object_instance = Schedule_Index_To_Instance(0); + bacnet_object_properties_read_write_test( + OBJECT_SCHEDULE, + object_instance, + Schedule_Property_Lists, + Schedule_Read_Property, + Schedule_Write_Property, + skip_fail_property_list); } /** * @} diff --git a/test/bacnet/basic/object/trendlog/CMakeLists.txt b/test/bacnet/basic/object/trendlog/CMakeLists.txt index c9ec1098..37e9efd4 100644 --- a/test/bacnet/basic/object/trendlog/CMakeLists.txt +++ b/test/bacnet/basic/object/trendlog/CMakeLists.txt @@ -27,6 +27,7 @@ add_compile_definitions( include_directories( ${SRC_DIR} + ${TST_DIR}/bacnet/basic/object ${TST_DIR}/ztest/include ) @@ -50,6 +51,7 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/indtext.c ${SRC_DIR}/bacnet/hostnport.c ${SRC_DIR}/bacnet/lighting.c + ${SRC_DIR}/bacnet/proplist.c ${SRC_DIR}/bacnet/timestamp.c ${SRC_DIR}/bacnet/wp.c ${SRC_DIR}/bacnet/weeklyschedule.c @@ -59,6 +61,7 @@ add_executable(${PROJECT_NAME} # Test and test library files ./src/main.c ../mock/device_mock.c + ${TST_DIR}/bacnet/basic/object/property_test.c ${ZTST_DIR}/ztest_mock.c ${ZTST_DIR}/ztest.c ) diff --git a/test/bacnet/basic/object/trendlog/src/main.c b/test/bacnet/basic/object/trendlog/src/main.c index f2d89814..b7fdfe29 100644 --- a/test/bacnet/basic/object/trendlog/src/main.c +++ b/test/bacnet/basic/object/trendlog/src/main.c @@ -9,7 +9,7 @@ #include #include -#include +#include /** * @addtogroup bacnet_tests @@ -21,70 +21,24 @@ */ static void test_Trend_Log_ReadProperty(void) { - uint8_t apdu[MAX_APDU] = { 0 }; - int len = 0; - int test_len = 0; - BACNET_READ_PROPERTY_DATA rpdata; - /* for decode value data */ - BACNET_APPLICATION_DATA_VALUE value; - const int *pRequired = NULL; - const int *pOptional = NULL; - const int *pProprietary = NULL; unsigned count = 0; + uint32_t object_instance = 0; bool status = false; + const int known_fail_property_list[] = { -1 }; Trend_Log_Init(); count = Trend_Log_Count(); zassert_true(count > 0, NULL); - rpdata.application_data = &apdu[0]; - rpdata.application_data_len = sizeof(apdu); - rpdata.object_type = OBJECT_TRENDLOG; - rpdata.object_instance = Trend_Log_Index_To_Instance(0);; - status = Trend_Log_Valid_Instance(rpdata.object_instance); + object_instance = Trend_Log_Index_To_Instance(0); + status = Trend_Log_Valid_Instance(object_instance); zassert_true(status, NULL); - Trend_Log_Property_Lists(&pRequired, &pOptional, &pProprietary); - while ((*pRequired) != -1) { - rpdata.object_property = *pRequired; - rpdata.array_index = BACNET_ARRAY_ALL; - len = Trend_Log_Read_Property(&rpdata); - if (len > 0) { - zassert_not_equal(len, BACNET_STATUS_ERROR, NULL); - test_len = bacapp_decode_application_data(rpdata.application_data, - (uint8_t)rpdata.application_data_len, &value); - if (len != test_len) { - printf("property '%s': failed to decode!\n", - bactext_property_name(rpdata.object_property)); - } - if (rpdata.object_property == PROP_PRIORITY_ARRAY) { - /* FIXME: known fail to decode */ - len = test_len; - } - zassert_true(test_len >= 0, NULL); - } else { - printf("property '%s': failed to read!\n", - bactext_property_name(rpdata.object_property)); - } - pRequired++; - } - while ((*pOptional) != -1) { - rpdata.object_property = *pOptional; - rpdata.array_index = BACNET_ARRAY_ALL; - len = Trend_Log_Read_Property(&rpdata); - zassert_not_equal(len, BACNET_STATUS_ERROR, NULL); - if (len > 0) { - test_len = bacapp_decode_application_data(rpdata.application_data, - (uint8_t)rpdata.application_data_len, &value); - if (len != test_len) { - printf("property '%s': failed to decode!\n", - bactext_property_name(rpdata.object_property)); - } - zassert_true(test_len >= 0, NULL); - } else { - printf("property '%s': failed to read!\n", - bactext_property_name(rpdata.object_property)); - } - pOptional++; - } + bacnet_object_properties_read_write_test( + OBJECT_TRENDLOG, + object_instance, + Trend_Log_Property_Lists, + Trend_Log_Read_Property, + Trend_Log_Write_Property, + known_fail_property_list); } /** * @} diff --git a/zephyr/tests/bacnet/basic/object/command/CMakeLists.txt b/zephyr/tests/bacnet/basic/object/command/CMakeLists.txt index 9f6c1a31..c8983f54 100644 --- a/zephyr/tests/bacnet/basic/object/command/CMakeLists.txt +++ b/zephyr/tests/bacnet/basic/object/command/CMakeLists.txt @@ -20,12 +20,17 @@ get_filename_component(BACNET_NAME ${BACNET_BASE} NAME) # Update include path for this module list(APPEND BACNET_INCLUDE ${BACNET_BASE}/src) +set(TEST_OBJECT_SRC ${BACNET_BASE}/test/bacnet/basic/object) +list(APPEND TEST_OBJECT_INCLUDE ${TEST_OBJECT_SRC}) + if(BOARD STREQUAL unit_testing) file(RELATIVE_PATH BACNET_INCLUDE $ENV{ZEPHYR_BASE} ${BACNET_BASE}/src) - list(APPEND INCLUDE ${BACNET_INCLUDE}) + file(RELATIVE_PATH TEST_OBJECT_INCLUDE $ENV{ZEPHYR_BASE} ${TEST_OBJECT_SRC}) + list(APPEND INCLUDE ${BACNET_INCLUDE} ${TEST_OBJECT_INCLUDE}) list(APPEND SOURCES ${BACNET_SRC_PATH}.c ${BACNET_TEST_PATH}/src/main.c + ${TEST_OBJECT_SRC}/property_test.c ) get_filename_component(BACNET_OBJECT_SRC ${BACNET_SRC_PATH} PATH) @@ -46,6 +51,7 @@ if(BOARD STREQUAL unit_testing) ${BACNET_SRC}/bactext.c ${BACNET_SRC}/indtext.c ${BACNET_SRC}/lighting.c + ${BACNET_SRC}/proplist.c ${BACNET_SRC}/wp.c ${BACNET_SRC}/hostnport.c ${BACNET_SRC}/dailyschedule.c @@ -63,7 +69,9 @@ else() find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(${BACNET_NAME}) - target_include_directories(app PRIVATE ${BACNET_INCLUDE}) + target_include_directories(app PRIVATE + ${BACNET_INCLUDE} + ${TEST_OBJECT_INCLUDE}) target_sources(app PRIVATE ${BACNET_TEST_PATH}/src/main.c ) diff --git a/zephyr/tests/bacnet/basic/object/credential_data_input/CMakeLists.txt b/zephyr/tests/bacnet/basic/object/credential_data_input/CMakeLists.txt index cbb5609e..e1695d81 100644 --- a/zephyr/tests/bacnet/basic/object/credential_data_input/CMakeLists.txt +++ b/zephyr/tests/bacnet/basic/object/credential_data_input/CMakeLists.txt @@ -20,12 +20,17 @@ get_filename_component(BACNET_NAME ${BACNET_BASE} NAME) # Update include path for this module list(APPEND BACNET_INCLUDE ${BACNET_BASE}/src) +set(TEST_OBJECT_SRC ${BACNET_BASE}/test/bacnet/basic/object) +list(APPEND TEST_OBJECT_INCLUDE ${TEST_OBJECT_SRC}) + if(BOARD STREQUAL unit_testing) file(RELATIVE_PATH BACNET_INCLUDE $ENV{ZEPHYR_BASE} ${BACNET_BASE}/src) - list(APPEND INCLUDE ${BACNET_INCLUDE}) + file(RELATIVE_PATH TEST_OBJECT_INCLUDE $ENV{ZEPHYR_BASE} ${TEST_OBJECT_SRC}) + list(APPEND INCLUDE ${BACNET_INCLUDE} ${TEST_OBJECT_INCLUDE}) list(APPEND SOURCES ${BACNET_SRC_PATH}.c ${BACNET_TEST_PATH}/src/main.c + ${TEST_OBJECT_SRC}/property_test.c ) get_filename_component(BACNET_OBJECT_SRC ${BACNET_SRC_PATH} PATH) @@ -46,6 +51,7 @@ if(BOARD STREQUAL unit_testing) ${BACNET_SRC}/bactext.c ${BACNET_SRC}/indtext.c ${BACNET_SRC}/lighting.c + ${BACNET_SRC}/proplist.c ${BACNET_SRC}/wp.c ${BACNET_SRC}/authentication_factor.c ${BACNET_SRC}/authentication_factor_format.c @@ -65,7 +71,9 @@ else() find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(${BACNET_NAME}) - target_include_directories(app PRIVATE ${BACNET_INCLUDE}) + target_include_directories(app PRIVATE + ${BACNET_INCLUDE} + ${TEST_OBJECT_INCLUDE}) target_sources(app PRIVATE ${BACNET_TEST_PATH}/src/main.c ) diff --git a/zephyr/tests/bacnet/basic/object/netport/CMakeLists.txt b/zephyr/tests/bacnet/basic/object/netport/CMakeLists.txt index ad43fdb2..1c83a3e9 100644 --- a/zephyr/tests/bacnet/basic/object/netport/CMakeLists.txt +++ b/zephyr/tests/bacnet/basic/object/netport/CMakeLists.txt @@ -26,6 +26,8 @@ if(BOARD STREQUAL unit_testing) list(APPEND SOURCES ${BACNET_SRC_PATH}.c ${BACNET_TEST_PATH}/src/main.c + ${BACNET_TEST_PATH}/../property_test.c + ${BACNET_TEST_PATH}/../property_test.h ) get_filename_component(BACNET_OBJECT_SRC ${BACNET_SRC_PATH} PATH) @@ -46,6 +48,7 @@ if(BOARD STREQUAL unit_testing) ${BACNET_SRC}/bactext.c ${BACNET_SRC}/indtext.c ${BACNET_SRC}/lighting.c + ${BACNET_SRC}/proplist.c ${BACNET_SRC}/wp.c ${BACNET_SRC}/proplist.c ${BACNET_SRC}/datalink/bvlc.c diff --git a/zephyr/tests/bacnet/basic/object/schedule/CMakeLists.txt b/zephyr/tests/bacnet/basic/object/schedule/CMakeLists.txt index 615bd184..da3d331a 100644 --- a/zephyr/tests/bacnet/basic/object/schedule/CMakeLists.txt +++ b/zephyr/tests/bacnet/basic/object/schedule/CMakeLists.txt @@ -20,12 +20,17 @@ get_filename_component(BACNET_NAME ${BACNET_BASE} NAME) # Update include path for this module list(APPEND BACNET_INCLUDE ${BACNET_BASE}/src) +set(TEST_OBJECT_SRC ${BACNET_BASE}/test/bacnet/basic/object) +list(APPEND TEST_OBJECT_INCLUDE ${TEST_OBJECT_SRC}) + if(BOARD STREQUAL unit_testing) file(RELATIVE_PATH BACNET_INCLUDE $ENV{ZEPHYR_BASE} ${BACNET_BASE}/src) - list(APPEND INCLUDE ${BACNET_INCLUDE}) + file(RELATIVE_PATH TEST_OBJECT_INCLUDE $ENV{ZEPHYR_BASE} ${TEST_OBJECT_SRC}) + list(APPEND INCLUDE ${BACNET_INCLUDE} ${TEST_OBJECT_INCLUDE}) list(APPEND SOURCES ${BACNET_SRC_PATH}.c ${BACNET_TEST_PATH}/src/main.c + ${TEST_OBJECT_SRC}/property_test.c ) get_filename_component(BACNET_OBJECT_SRC ${BACNET_SRC_PATH} PATH) @@ -46,6 +51,7 @@ if(BOARD STREQUAL unit_testing) ${BACNET_SRC}/bactext.c ${BACNET_SRC}/indtext.c ${BACNET_SRC}/lighting.c + ${BACNET_SRC}/proplist.c ${BACNET_SRC}/wp.c ${BACNET_SRC}/bactimevalue.c ${BACNET_SRC}/hostnport.c @@ -64,7 +70,9 @@ else() find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(${BACNET_NAME}) - target_include_directories(app PRIVATE ${BACNET_INCLUDE}) + target_include_directories(app PRIVATE + ${BACNET_INCLUDE} + ${TEST_OBJECT_INCLUDE}) target_sources(app PRIVATE ${BACNET_TEST_PATH}/src/main.c )