From 90714c094c4a5991ca6071ee20e51cfc2a4702fe Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Fri, 19 Jul 2024 16:45:09 -0500 Subject: [PATCH] Fixed BACnetHostNPort known property decoding. (#700) * Fixed BACnetHostNPort known property decoding. * Added BDT-Entry and FDT-Entry to BACapp for known property encoding/decoding. --- src/bacnet/bacapp.c | 396 ++++++++++---- src/bacnet/bacapp.h | 6 + src/bacnet/bacenum.h | 6 +- src/bacnet/bactext.c | 5 +- src/bacnet/basic/npdu/h_npdu.c | 35 +- src/bacnet/basic/npdu/h_npdu.h | 3 +- src/bacnet/basic/object/netport.c | 638 +++++++++++++--------- src/bacnet/config.h | 8 +- src/bacnet/datalink/bvlc6.c | 263 ++++++--- src/bacnet/datalink/bvlc6.h | 14 + src/bacnet/datetime.c | 23 +- src/bacnet/datetime.h | 3 + src/bacnet/hostnport.c | 867 ++++++++++++++++++++++++++++-- src/bacnet/hostnport.h | 111 ++++ test/bacnet/bacapp/src/main.c | 77 ++- zephyr/CMakeLists.txt | 2 + zephyr/Kconfig | 12 + 17 files changed, 1942 insertions(+), 527 deletions(-) diff --git a/src/bacnet/bacapp.c b/src/bacnet/bacapp.c index f473642c..ec4af7e6 100644 --- a/src/bacnet/bacapp.c +++ b/src/bacnet/bacapp.c @@ -146,8 +146,9 @@ int bacapp_encode_application_data( #endif #if defined(BACAPP_OBJECT_ID) case BACNET_APPLICATION_TAG_OBJECT_ID: - apdu_len = encode_application_object_id(apdu, - value->type.Object_Id.type, value->type.Object_Id.instance); + apdu_len = encode_application_object_id( + apdu, value->type.Object_Id.type, + value->type.Object_Id.instance); break; #endif case BACNET_APPLICATION_TAG_EMPTYLIST: @@ -239,6 +240,20 @@ int bacapp_encode_application_data( apdu_len = bacnet_destination_encode(apdu, &value->type.Destination); break; +#endif +#if defined(BACAPP_BDT_ENTRY) + case BACNET_APPLICATION_TAG_BDT_ENTRY: + /* BACnetBDTEntry */ + apdu_len = + bacnet_bdt_entry_encode(apdu, &value->type.BDT_Entry); + break; +#endif +#if defined(BACAPP_FDT_ENTRY) + case BACNET_APPLICATION_TAG_FDT_ENTRY: + /* BACnetFDTEntry */ + apdu_len = + bacnet_fdt_entry_encode(apdu, &value->type.FDT_Entry); + break; #endif default: break; @@ -262,7 +277,8 @@ int bacapp_encode_application_data( * 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_data_decode(uint8_t *apdu, +int bacapp_data_decode( + uint8_t *apdu, uint32_t apdu_size, uint8_t tag_data_type, uint32_t len_value_type, @@ -314,8 +330,9 @@ int bacapp_data_decode(uint8_t *apdu, #endif #if defined(BACAPP_CHARACTER_STRING) case BACNET_APPLICATION_TAG_CHARACTER_STRING: - len = bacnet_character_string_decode(apdu, apdu_size, - 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) @@ -344,7 +361,8 @@ int bacapp_data_decode(uint8_t *apdu, #endif #if defined(BACAPP_OBJECT_ID) case BACNET_APPLICATION_TAG_OBJECT_ID: { - len = bacnet_object_id_decode(apdu, apdu_size, len_value_type, + len = bacnet_object_id_decode( + apdu, apdu_size, len_value_type, &value->type.Object_Id.type, &value->type.Object_Id.instance); } break; @@ -413,8 +431,9 @@ int bacapp_data_decode(uint8_t *apdu, #if defined(BACAPP_DEVICE_OBJECT_PROPERTY_REFERENCE) case BACNET_APPLICATION_TAG_DEVICE_OBJECT_PROPERTY_REFERENCE: /* BACnetDeviceObjectPropertyReference */ - len = bacnet_device_object_property_reference_decode(apdu, - apdu_size, &value->type.Device_Object_Property_Reference); + len = bacnet_device_object_property_reference_decode( + apdu, apdu_size, + &value->type.Device_Object_Property_Reference); break; #endif #if defined(BACAPP_DEVICE_OBJECT_REFERENCE) @@ -437,6 +456,20 @@ int bacapp_data_decode(uint8_t *apdu, len = bacnet_destination_decode( apdu, apdu_size, &value->type.Destination); break; +#endif +#if defined(BACAPP_BDT_ENTRY) + case BACNET_APPLICATION_TAG_BDT_ENTRY: + /* BACnetBDTEntry */ + len = bacnet_bdt_entry_decode( + apdu, apdu_size, NULL, &value->type.BDT_Entry); + break; +#endif +#if defined(BACAPP_FDT_ENTRY) + case BACNET_APPLICATION_TAG_FDT_ENTRY: + /* BACnetFDTEntry */ + len = bacnet_fdt_entry_decode( + apdu, apdu_size, NULL, &value->type.FDT_Entry); + break; #endif default: break; @@ -466,7 +499,8 @@ int bacapp_data_decode(uint8_t *apdu, * @return Number of octets consumed * @deprecated Use bacapp_data_decode() instead. */ -int bacapp_decode_data(uint8_t *apdu, +int bacapp_decode_data( + uint8_t *apdu, uint8_t tag_data_type, uint32_t len_value_type, BACNET_APPLICATION_DATA_VALUE *value) @@ -500,8 +534,9 @@ int bacapp_decode_application_data( value->context_specific = false; 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); + 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 { @@ -530,7 +565,8 @@ int bacapp_decode_application_data( ** */ -bool bacapp_decode_application_data_safe(uint8_t *new_apdu, +bool bacapp_decode_application_data_safe( + uint8_t *new_apdu, uint32_t new_apdu_len, BACNET_APPLICATION_DATA_VALUE *value) { @@ -563,8 +599,9 @@ bool bacapp_decode_application_data_safe(uint8_t *new_apdu, 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); + 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; @@ -642,7 +679,8 @@ int bacapp_decode_application_data_len(uint8_t *apdu, unsigned apdu_size) return apdu_len; } -int bacapp_encode_context_data_value(uint8_t *apdu, +int bacapp_encode_context_data_value( + uint8_t *apdu, uint8_t context_tag_number, BACNET_APPLICATION_DATA_VALUE *value) { @@ -723,8 +761,9 @@ int bacapp_encode_context_data_value(uint8_t *apdu, #endif #if defined(BACAPP_OBJECT_ID) case BACNET_APPLICATION_TAG_OBJECT_ID: - apdu_len = encode_context_object_id(apdu, context_tag_number, - value->type.Object_Id.type, value->type.Object_Id.instance); + apdu_len = encode_context_object_id( + apdu, context_tag_number, value->type.Object_Id.type, + value->type.Object_Id.instance); break; #endif #if defined(BACAPP_TIMESTAMP) @@ -795,23 +834,25 @@ int bacapp_encode_context_data_value(uint8_t *apdu, #if defined(BACAPP_DEVICE_OBJECT_PROPERTY_REFERENCE) case BACNET_APPLICATION_TAG_DEVICE_OBJECT_PROPERTY_REFERENCE: /* BACnetDeviceObjectPropertyReference */ - apdu_len = bacapp_encode_context_device_obj_property_ref(apdu, - context_tag_number, + apdu_len = bacapp_encode_context_device_obj_property_ref( + apdu, context_tag_number, &value->type.Device_Object_Property_Reference); break; #endif #if defined(BACAPP_DEVICE_OBJECT_REFERENCE) case BACNET_APPLICATION_TAG_DEVICE_OBJECT_REFERENCE: /* BACnetDeviceObjectReference */ - apdu_len = bacapp_encode_context_device_obj_ref(apdu, - context_tag_number, &value->type.Device_Object_Reference); + apdu_len = bacapp_encode_context_device_obj_ref( + apdu, context_tag_number, + &value->type.Device_Object_Reference); break; #endif #if defined(BACAPP_OBJECT_PROPERTY_REFERENCE) case BACNET_APPLICATION_TAG_OBJECT_PROPERTY_REFERENCE: /* BACnetObjectPropertyReference */ - apdu_len = bacapp_encode_context_obj_property_ref(apdu, - context_tag_number, &value->type.Object_Property_Reference); + apdu_len = bacapp_encode_context_obj_property_ref( + apdu, context_tag_number, + &value->type.Object_Property_Reference); break; #endif #if defined(BACAPP_DESTINATION) @@ -820,6 +861,20 @@ int bacapp_encode_context_data_value(uint8_t *apdu, apdu_len = bacnet_destination_context_encode( apdu, context_tag_number, &value->type.Destination); break; +#endif +#if defined(BACAPP_BDT_ENTRY) + case BACNET_APPLICATION_TAG_BDT_ENTRY: + /* BACnetBDTEntry */ + apdu_len = bacnet_bdt_entry_context_encode( + apdu, context_tag_number, &value->type.BDT_Entry); + break; +#endif +#if defined(BACAPP_FDT_ENTRY) + case BACNET_APPLICATION_TAG_FDT_ENTRY: + /* BACnetFDTEntry */ + apdu_len = bacnet_fdt_entry_context_encode( + apdu, context_tag_number, &value->type.FDT_Entry); + break; #endif default: break; @@ -830,8 +885,8 @@ int bacapp_encode_context_data_value(uint8_t *apdu, } /* returns the fixed tag type for certain context tagged properties */ -BACNET_APPLICATION_TAG bacapp_context_tag_type( - BACNET_PROPERTY_ID property, uint8_t tag_number) +BACNET_APPLICATION_TAG +bacapp_context_tag_type(BACNET_PROPERTY_ID property, uint8_t tag_number) { BACNET_APPLICATION_TAG tag = MAX_BACNET_APPLICATION_TAG; @@ -1132,7 +1187,8 @@ BACNET_APPLICATION_TAG bacapp_context_tag_type( return tag; } -int bacapp_encode_context_data(uint8_t *apdu, +int bacapp_encode_context_data( + uint8_t *apdu, BACNET_APPLICATION_DATA_VALUE *value, BACNET_PROPERTY_ID property) { @@ -1163,7 +1219,8 @@ int bacapp_encode_context_data(uint8_t *apdu, * @param property - context property identifier * @return number of bytes decoded, or #BACNET_STATUS_ERROR */ -int bacapp_decode_context_data(uint8_t *apdu, +int bacapp_decode_context_data( + uint8_t *apdu, unsigned apdu_size, BACNET_APPLICATION_DATA_VALUE *value, BACNET_PROPERTY_ID property) @@ -1187,8 +1244,9 @@ int bacapp_decode_context_data(uint8_t *apdu, value->context_tag = tag.number; value->tag = bacapp_context_tag_type(property, tag.number); if (value->tag != MAX_BACNET_APPLICATION_TAG) { - len = bacapp_data_decode(&apdu[apdu_len], apdu_size - apdu_len, - value->tag, tag.len_value_type, value); + 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 { @@ -1218,7 +1276,8 @@ int bacapp_decode_context_data(uint8_t *apdu, * @param property - context property identifier * @return number of bytes decoded, or #BACNET_STATUS_ERROR */ -int bacapp_decode_generic_property(uint8_t *apdu, +int bacapp_decode_generic_property( + uint8_t *apdu, int apdu_size, BACNET_APPLICATION_DATA_VALUE *value, BACNET_PROPERTY_ID prop) @@ -1247,7 +1306,8 @@ int bacapp_decode_generic_property(uint8_t *apdu, * @param property - context property identifier * @return number of bytes decoded, or #BACNET_STATUS_ERROR */ -static int decode_priority_value(uint8_t *apdu, +static int decode_priority_value( + uint8_t *apdu, unsigned apdu_size, BACNET_APPLICATION_DATA_VALUE *value, BACNET_PROPERTY_ID property) @@ -1407,8 +1467,21 @@ int bacapp_known_property_tag( return -1; case PROP_ACTION: + /* FIXME: BACnetActionCommand */ return -1; + case PROP_FD_BBMD_ADDRESS: + case PROP_BACNET_IP_GLOBAL_ADDRESS: + /* BACnetHostNPort */ + return BACNET_APPLICATION_TAG_HOST_N_PORT; + + case PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE: + /* BACnetBDTEntry */ + return BACNET_APPLICATION_TAG_BDT_ENTRY; + case PROP_BBMD_FOREIGN_DEVICE_TABLE: + /* BACnetFDTEntry */ + return BACNET_APPLICATION_TAG_FDT_ENTRY; + default: return -1; } @@ -1424,7 +1497,8 @@ int bacapp_known_property_tag( * @return number of bytes decoded, or BACNET_STATUS_ERROR if errors occur * @note number of bytes can be 0 for empty lists, etc. */ -int bacapp_decode_known_property(uint8_t *apdu, +int bacapp_decode_known_property( + uint8_t *apdu, int max_apdu_len, BACNET_APPLICATION_DATA_VALUE *value, BACNET_OBJECT_TYPE object_type, @@ -1495,8 +1569,9 @@ int bacapp_decode_known_property(uint8_t *apdu, case PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES: #ifdef BACAPP_DEVICE_OBJECT_PROPERTY_REFERENCE /* Properties using BACnetDeviceObjectPropertyReference */ - len = bacnet_device_object_property_reference_decode(apdu, - max_apdu_len, &value->type.Device_Object_Property_Reference); + len = bacnet_device_object_property_reference_decode( + apdu, max_apdu_len, + &value->type.Device_Object_Property_Reference); #endif break; @@ -1599,6 +1674,28 @@ int bacapp_decode_known_property(uint8_t *apdu, /* BACnetDateRange (Schedule) */ len = bacnet_daterange_decode( apdu, max_apdu_len, &value->type.Date_Range); +#endif + break; + case PROP_FD_BBMD_ADDRESS: + case PROP_BACNET_IP_GLOBAL_ADDRESS: +#ifdef BACAPP_HOST_N_PORT + /* BACnetHostNPort */ + len = host_n_port_decode( + apdu, max_apdu_len, NULL, &value->type.Host_Address); +#endif + break; + case PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE: +#ifdef BACAPP_BDT_ENTRY + /* BACnetBDTEntry */ + len = bacnet_bdt_entry_decode( + apdu, max_apdu_len, NULL, &value->type.BDT_Entry); +#endif + break; + case PROP_BBMD_FOREIGN_DEVICE_TABLE: +#ifdef BACAPP_FDT_ENTRY + /* BACnetFDTEntry */ + len = bacnet_fdt_entry_decode( + apdu, max_apdu_len, NULL, &value->type.FDT_Entry); #endif break; @@ -1680,7 +1777,8 @@ int bacapp_encode_data(uint8_t *apdu, BACNET_APPLICATION_DATA_VALUE *value) return apdu_len; } -bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE *dest_value, +bool bacapp_copy( + BACNET_APPLICATION_DATA_VALUE *dest_value, BACNET_APPLICATION_DATA_VALUE *src_value) { bool status = false; /* return value, assume failure */ @@ -1720,13 +1818,15 @@ bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE *dest_value, #endif #if defined(BACAPP_OCTET_STRING) case BACNET_APPLICATION_TAG_OCTET_STRING: - octetstring_copy(&dest_value->type.Octet_String, + octetstring_copy( + &dest_value->type.Octet_String, &src_value->type.Octet_String); break; #endif #if defined(BACAPP_CHARACTER_STRING) case BACNET_APPLICATION_TAG_CHARACTER_STRING: - characterstring_copy(&dest_value->type.Character_String, + characterstring_copy( + &dest_value->type.Character_String, &src_value->type.Character_String); break; #endif @@ -1762,7 +1862,8 @@ bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE *dest_value, break; #endif default: - memcpy(&dest_value->type, &src_value->type, + memcpy( + &dest_value->type, &src_value->type, sizeof(src_value->type)); status = true; break; @@ -1942,9 +2043,9 @@ static int bacapp_snprintf_date(char *str, size_t str_len, BACNET_DATE *bdate) * @param btime - date value to print * @return number of characters written * @note 135.1-4.4 Notational Rules for Parameter Values - * (k) times are represented as hours, minutes, seconds, hundredths - * in the format hh:mm:ss.xx: 2:05:44.00, 16:54:59.99. - * Any "wild card" field is shown by an asterisk (X'2A'): 16:54:*.*; + * (k) times are represented as hours, minutes, seconds, hundredths + * in the format hh:mm:ss.xx: 2:05:44.00, 16:54:59.99. + * Any "wild card" field is shown by an asterisk (X'2A'): 16:54:*.*; */ static int bacapp_snprintf_time(char *str, size_t str_len, BACNET_TIME *btime) { @@ -1991,7 +2092,8 @@ static int bacapp_snprintf_time(char *str, size_t str_len, BACNET_TIME *btime) * @param arrayIndex - index of the weekly schedule to print * @return number of characters written */ -static int bacapp_snprintf_weeklyschedule(char *str, +static int bacapp_snprintf_weeklyschedule( + char *str, size_t str_len, BACNET_WEEKLY_SCHEDULE *ws, BACNET_ARRAY_INDEX arrayIndex) @@ -2002,8 +2104,8 @@ static int bacapp_snprintf_weeklyschedule(char *str, BACNET_OBJECT_PROPERTY_VALUE dummyPropValue; BACNET_APPLICATION_DATA_VALUE dummyDataValue; - const char *weekdaynames[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", - "Sun" }; + const char *weekdaynames[7] = { "Mon", "Tue", "Wed", "Thu", + "Fri", "Sat", "Sun" }; const int loopend = ((arrayIndex == BACNET_ARRAY_ALL) ? 7 : 1); /* Find what inner type it uses */ @@ -2034,7 +2136,8 @@ static int bacapp_snprintf_weeklyschedule(char *str, if (arrayIndex == BACNET_ARRAY_ALL) { slen = snprintf(str, str_len, "%s: [", weekdaynames[wi]); } else { - slen = snprintf(str, str_len, "%s: [", + slen = snprintf( + str, str_len, "%s: [", (arrayIndex >= 1 && arrayIndex <= 7) ? weekdaynames[arrayIndex - 1] : "???"); @@ -2113,7 +2216,8 @@ int bacapp_snprintf_value( #endif #if defined(BACAPP_UNSIGNED) case BACNET_APPLICATION_TAG_UNSIGNED_INT: - ret_val = snprintf(str, str_len, "%lu", + ret_val = snprintf( + str, str_len, "%lu", (unsigned long)value->type.Unsigned_Int); break; #endif @@ -2226,41 +2330,50 @@ int bacapp_snprintf_value( if (char_str) { ret_val = snprintf(str, str_len, "%s", char_str); } else { - ret_val = snprintf(str, str_len, "%lu", + ret_val = snprintf( + str, str_len, "%lu", (unsigned long)value->type.Enumerated); } break; case PROP_OBJECT_TYPE: if (value->type.Enumerated <= BACNET_OBJECT_TYPE_LAST) { - ret_val = snprintf(str, str_len, "%s", + ret_val = snprintf( + str, str_len, "%s", bactext_object_type_name( value->type.Enumerated)); - } else if (value->type.Enumerated <= + } else if ( + value->type.Enumerated <= BACNET_OBJECT_TYPE_RESERVED_MAX) { - ret_val = snprintf(str, str_len, "reserved %lu", + ret_val = snprintf( + str, str_len, "reserved %lu", (unsigned long)value->type.Enumerated); } else { - ret_val = snprintf(str, str_len, "proprietary %lu", + ret_val = snprintf( + str, str_len, "proprietary %lu", (unsigned long)value->type.Enumerated); } break; case PROP_EVENT_STATE: - ret_val = snprintf(str, str_len, "%s", + ret_val = snprintf( + str, str_len, "%s", bactext_event_state_name(value->type.Enumerated)); break; case PROP_UNITS: if (bactext_engineering_unit_name_proprietary( (unsigned)value->type.Enumerated)) { - ret_val = snprintf(str, str_len, "proprietary %lu", + ret_val = snprintf( + str, str_len, "proprietary %lu", (unsigned long)value->type.Enumerated); } else { - ret_val = snprintf(str, str_len, "%s", + ret_val = snprintf( + str, str_len, "%s", bactext_engineering_unit_name( value->type.Enumerated)); } break; case PROP_POLARITY: - ret_val = snprintf(str, str_len, "%s", + ret_val = snprintf( + str, str_len, "%s", bactext_binary_polarity_name( value->type.Enumerated)); break; @@ -2270,49 +2383,59 @@ int bacapp_snprintf_value( case OBJECT_BINARY_INPUT: case OBJECT_BINARY_OUTPUT: case OBJECT_BINARY_VALUE: - ret_val = snprintf(str, str_len, "%s", + ret_val = snprintf( + str, str_len, "%s", bactext_binary_present_value_name( value->type.Enumerated)); break; case OBJECT_BINARY_LIGHTING_OUTPUT: - ret_val = snprintf(str, str_len, "%s", + ret_val = snprintf( + str, str_len, "%s", bactext_binary_lighting_pv_name( value->type.Enumerated)); break; default: - ret_val = snprintf(str, str_len, "%lu", + ret_val = snprintf( + str, str_len, "%lu", (unsigned long)value->type.Enumerated); break; } break; case PROP_RELIABILITY: - ret_val = snprintf(str, str_len, "%s", + ret_val = snprintf( + str, str_len, "%s", bactext_reliability_name(value->type.Enumerated)); break; case PROP_SYSTEM_STATUS: - ret_val = snprintf(str, str_len, "%s", + ret_val = snprintf( + str, str_len, "%s", bactext_device_status_name(value->type.Enumerated)); break; case PROP_SEGMENTATION_SUPPORTED: - ret_val = snprintf(str, str_len, "%s", + ret_val = snprintf( + str, str_len, "%s", bactext_segmentation_name(value->type.Enumerated)); break; case PROP_NODE_TYPE: - ret_val = snprintf(str, str_len, "%s", + ret_val = snprintf( + str, str_len, "%s", bactext_node_type_name(value->type.Enumerated)); break; case PROP_TRANSITION: - ret_val = snprintf(str, str_len, "%s", + ret_val = snprintf( + str, str_len, "%s", bactext_lighting_transition( value->type.Enumerated)); break; case PROP_IN_PROGRESS: - ret_val = snprintf(str, str_len, "%s", + ret_val = snprintf( + str, str_len, "%s", bactext_lighting_in_progress( value->type.Enumerated)); break; default: - ret_val = snprintf(str, str_len, "%lu", + ret_val = snprintf( + str, str_len, "%lu", (unsigned long)value->type.Enumerated); break; } @@ -2333,18 +2456,23 @@ int bacapp_snprintf_value( slen = snprintf(str, str_len, "("); ret_val += bacapp_snprintf_shift(slen, &str, &str_len); if (value->type.Object_Id.type <= BACNET_OBJECT_TYPE_LAST) { - slen = snprintf(str, str_len, "%s, ", + slen = snprintf( + str, str_len, "%s, ", bactext_object_type_name(value->type.Object_Id.type)); - } else if (value->type.Object_Id.type < + } else if ( + value->type.Object_Id.type < BACNET_OBJECT_TYPE_RESERVED_MAX) { - slen = snprintf(str, str_len, "reserved %u, ", + slen = snprintf( + str, str_len, "reserved %u, ", (unsigned)value->type.Object_Id.type); } else { - slen = snprintf(str, str_len, "proprietary %u, ", + slen = snprintf( + str, str_len, "proprietary %u, ", (unsigned)value->type.Object_Id.type); } ret_val += bacapp_snprintf_shift(slen, &str, &str_len); - slen = snprintf(str, str_len, "%lu)", + slen = snprintf( + str, str_len, "%lu)", (unsigned long)value->type.Object_Id.instance); ret_val += slen; break; @@ -2363,8 +2491,8 @@ int bacapp_snprintf_value( #endif #if defined(BACAPP_TIMESTAMP) case BACNET_APPLICATION_TAG_TIMESTAMP: - slen = bacapp_timestamp_to_ascii(str, str_len, - &value->type.Time_Stamp); + slen = bacapp_timestamp_to_ascii( + str, str_len, &value->type.Time_Stamp); ret_val += slen; break; #endif @@ -2398,7 +2526,8 @@ int bacapp_snprintf_value( /* BACnetColorCommand */ slen = snprintf(str, str_len, "("); ret_val += bacapp_snprintf_shift(slen, &str, &str_len); - slen = snprintf(str, str_len, "%s", + slen = snprintf( + str, str_len, "%s", bactext_color_operation_name( value->type.Color_Command.operation)); ret_val += bacapp_snprintf_shift(slen, &str, &str_len); @@ -2410,8 +2539,9 @@ int bacapp_snprintf_value( #if defined(BACAPP_WEEKLY_SCHEDULE) case BACNET_APPLICATION_TAG_WEEKLY_SCHEDULE: /* BACnetWeeklySchedule */ - ret_val = bacapp_snprintf_weeklyschedule(str, str_len, - &value->type.Weekly_Schedule, object_value->array_index); + ret_val = bacapp_snprintf_weeklyschedule( + str, str_len, &value->type.Weekly_Schedule, + object_value->array_index); break; #endif #if defined(BACAPP_SPECIAL_EVENT) @@ -2433,9 +2563,10 @@ int bacapp_snprintf_value( uint8_t *octet_str; octet_str = octetstring_value( &value->type.Host_Address.host.ip_address); - slen = snprintf(str, str_len, "%u.%u.%u.%u:%u", - (unsigned)octet_str[0], (unsigned)octet_str[1], - (unsigned)octet_str[2], (unsigned)octet_str[3], + slen = snprintf( + str, str_len, "%u.%u.%u.%u:%u", (unsigned)octet_str[0], + (unsigned)octet_str[1], (unsigned)octet_str[2], + (unsigned)octet_str[3], (unsigned)value->type.Host_Address.port); ret_val += slen; } else if (value->type.Host_Address.host_name) { @@ -2464,6 +2595,18 @@ int bacapp_snprintf_value( ret_val = bacnet_destination_to_ascii( &value->type.Destination, str, str_len); break; +#endif +#if defined(BACAPP_BDT_ENTRY) + case BACNET_APPLICATION_TAG_BDT_ENTRY: + ret_val = bacnet_bdt_entry_to_ascii( + str, str_len, &value->type.BDT_Entry); + break; +#endif +#if defined(BACAPP_FDT_ENTRY) + case BACNET_APPLICATION_TAG_FDT_ENTRY: + ret_val = bacnet_fdt_entry_to_ascii( + str, str_len, &value->type.FDT_Entry); + break; #endif default: ret_val = @@ -2565,8 +2708,8 @@ static char *trim(char *str, const char *trimmedchars) } #if defined(BACAPP_WEEKLY_SCHEDULE) -static bool parse_weeklyschedule( - char *str, BACNET_APPLICATION_DATA_VALUE *value) +static bool +parse_weeklyschedule(char *str, BACNET_APPLICATION_DATA_VALUE *value) { char *chunk, *comma, *space, *t, *v, *colonpos, *sqpos; int daynum = 0, tvnum = 0; @@ -2744,7 +2887,8 @@ static bool strtod_checked(const char *s, double *out) /* used to load the app data struct with the proper data converted from a command line argument. "argv" is not const to allow using strtok internally. It MAY be modified. */ -bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number, +bool bacapp_parse_application_data( + BACNET_APPLICATION_TAG tag_number, char *argv, BACNET_APPLICATION_DATA_VALUE *value) { @@ -2767,7 +2911,8 @@ bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number, if (strcasecmp(argv, "true") == 0 || strcasecmp(argv, "active") == 0) { value->type.Boolean = true; - } else if (strcasecmp(argv, "false") == 0 || + } else if ( + strcasecmp(argv, "false") == 0 || strcasecmp(argv, "inactive") == 0) { value->type.Boolean = false; } else { @@ -2854,8 +2999,9 @@ bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number, count = sscanf(argv, "%4d/%3d/%3d:%3d", &year, &month, &day, &wday); if (count == 3) { - datetime_set_date(&value->type.Date, (uint16_t)year, - (uint8_t)month, (uint8_t)day); + datetime_set_date( + &value->type.Date, (uint16_t)year, (uint8_t)month, + (uint8_t)day); } else if (count == 4) { value->type.Date.year = (uint16_t)year; value->type.Date.month = (uint8_t)month; @@ -2951,6 +3097,18 @@ bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number, status = bacnet_destination_from_ascii( &value->type.Destination, argv); break; +#endif +#if defined(BACAPP_BDT_ENTRY) + case BACNET_APPLICATION_TAG_BDT_ENTRY: + status = + bacnet_bdt_entry_from_ascii(&value->type.BDT_Entry, argv); + break; +#endif +#if defined(BACAPP_FDT_ENTRY) + case BACNET_APPLICATION_TAG_FDT_ENTRY: + status = + bacnet_fdt_entry_from_ascii(&value->type.FDT_Entry, argv); + break; #endif default: break; @@ -2961,7 +3119,8 @@ bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number, return status; } #else -bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number, +bool bacapp_parse_application_data( + BACNET_APPLICATION_TAG tag_number, char *argv, BACNET_APPLICATION_DATA_VALUE *value) { @@ -3170,8 +3329,9 @@ int bacapp_property_value_decode( if (bacnet_is_context_tag_number( &apdu[apdu_len], apdu_size - apdu_len, 1, &len, &len_value_type)) { apdu_len += len; - len = bacnet_unsigned_decode(&apdu[apdu_len], apdu_size - apdu_len, - len_value_type, &unsigned_value); + len = bacnet_unsigned_decode( + &apdu[apdu_len], apdu_size - apdu_len, len_value_type, + &unsigned_value); if (len > 0) { if (unsigned_value > UINT32_MAX) { return BACNET_STATUS_ERROR; @@ -3214,7 +3374,8 @@ int bacapp_property_value_decode( However, it returns the len between the tags. Therefore, store the length of the opening tag first */ tag_len = len; - len = bacapp_data_len(&apdu[apdu_len], apdu_size - apdu_len, + len = bacapp_data_len( + &apdu[apdu_len], apdu_size - apdu_len, (BACNET_PROPERTY_ID)property_identifier); apdu_len += len; /* add the opening tag length to the totals */ @@ -3233,8 +3394,9 @@ int bacapp_property_value_decode( if (bacnet_is_context_tag_number( &apdu[apdu_len], apdu_size - apdu_len, 3, &len, &len_value_type)) { apdu_len += len; - len = bacnet_unsigned_decode(&apdu[apdu_len], apdu_size - apdu_len, - len_value_type, &unsigned_value); + len = bacnet_unsigned_decode( + &apdu[apdu_len], apdu_size - apdu_len, len_value_type, + &unsigned_value); if (len > 0) { if (unsigned_value > UINT8_MAX) { return BACNET_STATUS_ERROR; @@ -3258,7 +3420,8 @@ int bacapp_property_value_decode( /* generic - can be used by other unit tests returns true if matching or same, false if different */ -bool bacapp_same_value(BACNET_APPLICATION_DATA_VALUE *value, +bool bacapp_same_value( + BACNET_APPLICATION_DATA_VALUE *value, BACNET_APPLICATION_DATA_VALUE *test_value) { bool status = false; /*return value */ @@ -3342,16 +3505,17 @@ bool bacapp_same_value(BACNET_APPLICATION_DATA_VALUE *value, #if defined(BACAPP_OBJECT_ID) case BACNET_APPLICATION_TAG_OBJECT_ID: if ((test_value->type.Object_Id.type == - value->type.Object_Id.type) && + value->type.Object_Id.type) && (test_value->type.Object_Id.instance == - value->type.Object_Id.instance)) { + value->type.Object_Id.instance)) { status = true; } break; #endif #if defined(BACAPP_CHARACTER_STRING) case BACNET_APPLICATION_TAG_CHARACTER_STRING: - status = characterstring_same(&value->type.Character_String, + status = characterstring_same( + &value->type.Character_String, &test_value->type.Character_String); break; #endif @@ -3367,6 +3531,12 @@ bool bacapp_same_value(BACNET_APPLICATION_DATA_VALUE *value, &value->type.Bit_String, &test_value->type.Bit_String); break; #endif +#if defined(BACAPP_DATERANGE) + case BACNET_APPLICATION_TAG_DATERANGE: + status = bacnet_daterange_same( + &value->type.Date_Range, &test_value->type.Date_Range); + break; +#endif #if defined(BACAPP_TIMESTAMP) case BACNET_APPLICATION_TAG_TIMESTAMP: status = bacapp_timestamp_same( @@ -3375,15 +3545,17 @@ bool bacapp_same_value(BACNET_APPLICATION_DATA_VALUE *value, #endif #if defined(BACAPP_DATETIME) case BACNET_APPLICATION_TAG_DATETIME: - if (datetime_compare(&value->type.Date_Time, - &test_value->type.Date_Time) == 0) { + if (datetime_compare( + &value->type.Date_Time, &test_value->type.Date_Time) == + 0) { status = true; } break; #endif #if defined(BACAPP_LIGHTING_COMMAND) case BACNET_APPLICATION_TAG_LIGHTING_COMMAND: - status = lighting_command_same(&value->type.Lighting_Command, + status = lighting_command_same( + &value->type.Lighting_Command, &test_value->type.Lighting_Command); break; #endif @@ -3397,29 +3569,32 @@ bool bacapp_same_value(BACNET_APPLICATION_DATA_VALUE *value, #if defined(BACAPP_COLOR_COMMAND) case BACNET_APPLICATION_TAG_COLOR_COMMAND: /* BACnetColorCommand */ - status = color_command_same(&value->type.Color_Command, + status = color_command_same( + &value->type.Color_Command, &test_value->type.Color_Command); break; #endif #if defined(BACAPP_WEEKLY_SCHEDULE) case BACNET_APPLICATION_TAG_WEEKLY_SCHEDULE: /* BACnetWeeklySchedule */ - status = - bacnet_weeklyschedule_same(&value->type.Weekly_Schedule, - &test_value->type.Weekly_Schedule); + status = bacnet_weeklyschedule_same( + &value->type.Weekly_Schedule, + &test_value->type.Weekly_Schedule); break; #endif #if defined(BACAPP_CALENDAR_ENTRY) case BACNET_APPLICATION_TAG_CALENDAR_ENTRY: /* BACnetCalendarEntry */ - status = bacnet_calendar_entry_same(&value->type.Calendar_Entry, + status = bacnet_calendar_entry_same( + &value->type.Calendar_Entry, &test_value->type.Calendar_Entry); break; #endif #if defined(BACAPP_SPECIAL_EVENT) case BACNET_APPLICATION_TAG_SPECIAL_EVENT: /* BACnetSpecialEvent */ - status = bacnet_special_event_same(&value->type.Special_Event, + status = bacnet_special_event_same( + &value->type.Special_Event, &test_value->type.Special_Event); break; #endif @@ -3456,6 +3631,21 @@ bool bacapp_same_value(BACNET_APPLICATION_DATA_VALUE *value, &value->type.Destination, &test_value->type.Destination); break; #endif +#if defined(BACAPP_BDT_ENTRY) + case BACNET_APPLICATION_TAG_BDT_ENTRY: + status = bacnet_bdt_entry_same( + &value->type.BDT_Entry, &test_value->type.BDT_Entry); + break; +#endif +#if defined(BACAPP_FDT_ENTRY) + case BACNET_APPLICATION_TAG_FDT_ENTRY: + status = bacnet_fdt_entry_same( + &value->type.FDT_Entry, &test_value->type.FDT_Entry); + break; +#endif + case BACNET_APPLICATION_TAG_EMPTYLIST: + status = true; + break; default: status = false; break; diff --git a/src/bacnet/bacapp.h b/src/bacnet/bacapp.h index 38b8f44d..78c5bc2c 100644 --- a/src/bacnet/bacapp.h +++ b/src/bacnet/bacapp.h @@ -135,6 +135,12 @@ typedef struct BACnet_Application_Data_Value { #endif #if defined (BACAPP_SPECIAL_EVENT) BACNET_SPECIAL_EVENT Special_Event; +#endif +#if defined (BACAPP_BDT_ENTRY) + BACNET_BDT_ENTRY BDT_Entry; +#endif +#if defined (BACAPP_FDT_ENTRY) + BACNET_FDT_ENTRY FDT_Entry; #endif } type; /* simple linked list if needed */ diff --git a/src/bacnet/bacenum.h b/src/bacnet/bacenum.h index e9c1afe8..a4ff99d9 100644 --- a/src/bacnet/bacenum.h +++ b/src/bacnet/bacenum.h @@ -1461,7 +1461,11 @@ typedef enum { /* BACnetxyColor */ BACNET_APPLICATION_TAG_XY_COLOR, /* BACnetColorCommand */ - BACNET_APPLICATION_TAG_COLOR_COMMAND + BACNET_APPLICATION_TAG_COLOR_COMMAND, + /* BACnetBDTEntry */ + BACNET_APPLICATION_TAG_BDT_ENTRY, + /* BACnetFDTEntry */ + BACNET_APPLICATION_TAG_FDT_ENTRY } BACNET_APPLICATION_TAG; /* note: these are not the real values, */ diff --git a/src/bacnet/bactext.c b/src/bacnet/bactext.c index 88f3da11..3edf8cf3 100644 --- a/src/bacnet/bactext.c +++ b/src/bacnet/bactext.c @@ -166,7 +166,10 @@ INDTEXT_DATA bacnet_application_tag_names[] = { { BACNET_APPLICATION_TAG_NULL, { BACNET_APPLICATION_TAG_READ_ACCESS_SPECIFICATION, "BACnetReadAccessSpecification" }, { BACNET_APPLICATION_TAG_LIGHTING_COMMAND, "BACnetLightingCommand" }, - { BACNET_APPLICATION_TAG_HOST_N_PORT, "BACnetHostNPort" }, { 0, NULL } }; + { BACNET_APPLICATION_TAG_HOST_N_PORT, "BACnetHostNPort" }, + { BACNET_APPLICATION_TAG_BDT_ENTRY, "BACnetBDTEntry" }, + { BACNET_APPLICATION_TAG_FDT_ENTRY, "BACnetFDTEntry" }, + { 0, NULL } }; const char *bactext_application_tag_name(unsigned index) { diff --git a/src/bacnet/basic/npdu/h_npdu.c b/src/bacnet/basic/npdu/h_npdu.c index 3b66144a..848c92d3 100644 --- a/src/bacnet/basic/npdu/h_npdu.c +++ b/src/bacnet/basic/npdu/h_npdu.c @@ -84,8 +84,9 @@ int npdu_send_network_number_is( transmit a local broadcast Network-Number-Is message back to the source device. */ datalink_get_my_address(&my_address); - npdu_encode_npdu_network(&npdu_data, NETWORK_MESSAGE_NETWORK_NUMBER_IS, - data_expecting_reply, MESSAGE_PRIORITY_NORMAL); + npdu_encode_npdu_network( + &npdu_data, NETWORK_MESSAGE_NETWORK_NUMBER_IS, data_expecting_reply, + MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(pdu, dst, &my_address, &npdu_data); if ((pdu_len > 0) && (pdu_len <= MAX_NPDU)) { len = encode_unsigned16(&pdu[pdu_len], net); @@ -119,7 +120,8 @@ int npdu_send_what_is_network_number(BACNET_ADDRESS *dst) datalink_get_broadcast_address(&daddr); } datalink_get_my_address(&saddr); - npdu_encode_npdu_network(&npdu_data, NETWORK_MESSAGE_WHAT_IS_NETWORK_NUMBER, + npdu_encode_npdu_network( + &npdu_data, NETWORK_MESSAGE_WHAT_IS_NETWORK_NUMBER, data_expecting_reply, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(pdu, &daddr, &saddr, &npdu_data); @@ -145,7 +147,8 @@ int npdu_send_what_is_network_number(BACNET_ADDRESS *dst) * bytes that have already been decoded. * @param npdu_len [in] The length of the remaining NPDU message in npdu[]. */ -static void network_control_handler(BACNET_ADDRESS *src, +static void network_control_handler( + BACNET_ADDRESS *src, BACNET_NPDU_DATA *npdu_data, uint8_t *npdu, uint16_t npdu_len) @@ -198,8 +201,7 @@ static void network_control_handler(BACNET_ADDRESS *src, NETWORK_MESSAGE_ASHRAE_RESERVED_MIN) && (npdu_data->network_message_type <= NETWORK_MESSAGE_ASHRAE_RESERVED_MAX)) { - npdu_send_reject_message_to_network( - src, dnet, status); + npdu_send_reject_message_to_network(src, dnet); } } @@ -242,7 +244,8 @@ void npdu_handler(BACNET_ADDRESS *src, uint8_t *pdu, uint16_t pdu_len) bacnet_npdu_decode(&pdu[0], pdu_len, &dest, src, &npdu_data); if (npdu_data.network_layer_message) { if ((dest.net == 0) || (dest.net == BACNET_BROADCAST_NETWORK)) { - network_control_handler(src, &npdu_data, &pdu[apdu_offset], + network_control_handler( + src, &npdu_data, &pdu[apdu_offset], (uint16_t)(pdu_len - apdu_offset)); } else { debug_printf("NPDU: message for router. Discarded!\n"); @@ -254,17 +257,18 @@ void npdu_handler(BACNET_ADDRESS *src, uint8_t *pdu, uint16_t pdu_len) routing information cause they are not for us */ if ((dest.net == BACNET_BROADCAST_NETWORK) && ((pdu[apdu_offset] & 0xF0) == - PDU_TYPE_CONFIRMED_SERVICE_REQUEST)) { + PDU_TYPE_CONFIRMED_SERVICE_REQUEST)) { /* hack for 5.4.5.1 - IDLE */ /* ConfirmedBroadcastReceived */ /* then enter IDLE - ignore the PDU */ } else { - if (npdu_data.data_expecting_reply ) { + if (npdu_data.data_expecting_reply) { apdu_network_priority_set(npdu_data.priority); } else { apdu_network_priority_set(MESSAGE_PRIORITY_NORMAL); } - apdu_handler(src, &pdu[apdu_offset], + apdu_handler( + src, &pdu[apdu_offset], (uint16_t)(pdu_len - apdu_offset)); } } else { @@ -275,7 +279,8 @@ void npdu_handler(BACNET_ADDRESS *src, uint8_t *pdu, uint16_t pdu_len) } } else { #if PRINT_ENABLED - printf("NPDU: BACnet Protocol Version=%u. Discarded!\n", + printf( + "NPDU: BACnet Protocol Version=%u. Discarded!\n", (unsigned)pdu[0]); #endif } @@ -288,11 +293,9 @@ void npdu_handler(BACNET_ADDRESS *src, uint8_t *pdu, uint16_t pdu_len) * * @param dst - the destination address for the message * @param net - local network number - * @param status - 0=learned, 1=assigned * @return number of bytes sent */ -int npdu_send_reject_message_to_network( - BACNET_ADDRESS *dst, uint16_t net, uint8_t status) +int npdu_send_reject_message_to_network(BACNET_ADDRESS *dst, uint16_t net) { uint16_t len = 0; int pdu_len = 0; @@ -303,8 +306,8 @@ int npdu_send_reject_message_to_network( uint8_t pdu[MAX_NPDU + 2 + 1] = { 0 }; datalink_get_my_address(&my_address); - npdu_encode_npdu_network(&npdu_data, - NETWORK_MESSAGE_REJECT_MESSAGE_TO_NETWORK, + npdu_encode_npdu_network( + &npdu_data, NETWORK_MESSAGE_REJECT_MESSAGE_TO_NETWORK, data_expecting_reply, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(pdu, dst, &my_address, &npdu_data); pdu[pdu_len++] = NETWORK_REJECT_UNKNOWN_MESSAGE_TYPE; diff --git a/src/bacnet/basic/npdu/h_npdu.h b/src/bacnet/basic/npdu/h_npdu.h index 53ecc9e5..1c7e52c5 100644 --- a/src/bacnet/basic/npdu/h_npdu.h +++ b/src/bacnet/basic/npdu/h_npdu.h @@ -87,8 +87,7 @@ extern "C" { BACNET_STACK_EXPORT int npdu_send_reject_message_to_network( BACNET_ADDRESS *dst, - uint16_t net, - uint8_t status); + uint16_t net); #ifdef __cplusplus } diff --git a/src/bacnet/basic/object/netport.c b/src/bacnet/basic/object/netport.c index 678e49aa..d1d4a5a0 100644 --- a/src/bacnet/basic/object/netport.c +++ b/src/bacnet/basic/object/netport.c @@ -51,7 +51,7 @@ #include "bacnet/basic/object/netport.h" #if defined(BACDL_BIP6) || defined(BACDL_ALL) -#include "bacnet/datalink/bvlc6.h" +#include "bacnet/datalink/bvlc6.h" #endif #ifndef BBMD_ENABLED @@ -93,13 +93,13 @@ struct bacnet_ipv6_port { uint8_t IP_DHCP_Server[IPV6_ADDR_SIZE]; uint16_t Port; BACNET_IP_MODE Mode; - bool Auto_Addressing_Enable; + bool Auto_Addressing_Enable; char Zone_Index[ZONE_INDEX_SIZE]; bool BBMD_Accept_FD_Registrations; void *BBMD_BD_Table; void *BBMD_FD_Table; /* used for foreign device registration to remote BBMD */ - uint8_t BBMD_IP_Address[16]; + uint8_t BBMD_IP_Address[16]; uint16_t BBMD_Port; uint16_t BBMD_Lifetime; }; @@ -138,49 +138,74 @@ struct object_data { static struct object_data Object_List[BACNET_NETWORK_PORTS_MAX]; /* These three arrays are used by the ReadPropertyMultiple handler */ -static const int Network_Port_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, - PROP_OBJECT_NAME, PROP_OBJECT_TYPE, PROP_STATUS_FLAGS, PROP_RELIABILITY, - PROP_OUT_OF_SERVICE, PROP_NETWORK_TYPE, PROP_PROTOCOL_LEVEL, - PROP_NETWORK_NUMBER, PROP_NETWORK_NUMBER_QUALITY, PROP_CHANGES_PENDING, - PROP_APDU_LENGTH, PROP_LINK_SPEED, -1 }; +static const int Network_Port_Properties_Required[] = { + PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, PROP_STATUS_FLAGS, + PROP_RELIABILITY, PROP_OUT_OF_SERVICE, + PROP_NETWORK_TYPE, PROP_PROTOCOL_LEVEL, + PROP_NETWORK_NUMBER, PROP_NETWORK_NUMBER_QUALITY, + PROP_CHANGES_PENDING, PROP_APDU_LENGTH, + PROP_LINK_SPEED, -1 +}; static const int Ethernet_Port_Properties_Optional[] = { PROP_MAC_ADDRESS, -1 }; static const int MSTP_Port_Properties_Optional[] = { PROP_MAC_ADDRESS, - PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, -1 }; + PROP_MAX_MASTER, + PROP_MAX_INFO_FRAMES, -1 }; -static const int BIP_Port_Properties_Optional[] = { PROP_MAC_ADDRESS, - PROP_BACNET_IP_MODE, PROP_IP_ADDRESS, PROP_BACNET_IP_UDP_PORT, - PROP_IP_SUBNET_MASK, PROP_IP_DEFAULT_GATEWAY, PROP_IP_DNS_SERVER, +static const int BIP_Port_Properties_Optional[] = { + PROP_MAC_ADDRESS, + PROP_BACNET_IP_MODE, + PROP_IP_ADDRESS, + PROP_BACNET_IP_UDP_PORT, + PROP_IP_SUBNET_MASK, + PROP_IP_DEFAULT_GATEWAY, + PROP_IP_DNS_SERVER, PROP_IP_DHCP_ENABLE, -#if (defined(BACDL_ALL) || defined(BACDL_BIP)) && (BBMD_ENABLED || BBMD_CLIENT_ENABLED) +#if (defined(BACDL_ALL) || defined(BACDL_BIP)) && \ + (BBMD_ENABLED || BBMD_CLIENT_ENABLED) #if (BBMD_ENABLED) - PROP_BBMD_ACCEPT_FD_REGISTRATIONS, PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE, + PROP_BBMD_ACCEPT_FD_REGISTRATIONS, + PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE, PROP_BBMD_FOREIGN_DEVICE_TABLE, #endif #if (BBMD_CLIENT_ENABLED) - PROP_FD_BBMD_ADDRESS, PROP_FD_SUBSCRIPTION_LIFETIME, + PROP_FD_BBMD_ADDRESS, + PROP_FD_SUBSCRIPTION_LIFETIME, #endif #endif - -1 }; + -1 +}; -static const int BIP6_Port_Properties_Optional[] = { PROP_MAC_ADDRESS, - PROP_BACNET_IPV6_MODE, PROP_IPV6_ADDRESS, PROP_IPV6_PREFIX_LENGTH, - PROP_BACNET_IPV6_UDP_PORT, PROP_IPV6_DEFAULT_GATEWAY, - PROP_BACNET_IPV6_MULTICAST_ADDRESS, PROP_IPV6_DNS_SERVER, - PROP_IPV6_AUTO_ADDRESSING_ENABLE, PROP_IPV6_DHCP_LEASE_TIME, - PROP_IPV6_DHCP_LEASE_TIME_REMAINING, PROP_IPV6_DHCP_SERVER, +static const int BIP6_Port_Properties_Optional[] = { + PROP_MAC_ADDRESS, + PROP_BACNET_IPV6_MODE, + PROP_IPV6_ADDRESS, + PROP_IPV6_PREFIX_LENGTH, + PROP_BACNET_IPV6_UDP_PORT, + PROP_IPV6_DEFAULT_GATEWAY, + PROP_BACNET_IPV6_MULTICAST_ADDRESS, + PROP_IPV6_DNS_SERVER, + PROP_IPV6_AUTO_ADDRESSING_ENABLE, + PROP_IPV6_DHCP_LEASE_TIME, + PROP_IPV6_DHCP_LEASE_TIME_REMAINING, + PROP_IPV6_DHCP_SERVER, PROP_IPV6_ZONE_INDEX, -#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) && (BBMD_ENABLED || BBMD_CLIENT_ENABLED) +#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) && \ + (BBMD_ENABLED || BBMD_CLIENT_ENABLED) #if (BBMD_ENABLED) - PROP_BBMD_ACCEPT_FD_REGISTRATIONS, PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE, + PROP_BBMD_ACCEPT_FD_REGISTRATIONS, + PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE, PROP_BBMD_FOREIGN_DEVICE_TABLE, #endif #if (BBMD_CLIENT_ENABLED) - PROP_FD_BBMD_ADDRESS, PROP_FD_SUBSCRIPTION_LIFETIME, + PROP_FD_BBMD_ADDRESS, + PROP_FD_SUBSCRIPTION_LIFETIME, #endif #endif - -1 }; + -1 +}; static const int Network_Port_Properties_Proprietary[] = { -1 }; @@ -196,7 +221,8 @@ static const int Network_Port_Properties_Proprietary[] = { -1 }; * @param pProprietary - pointer to list of int terminated by -1, of * BACnet proprietary properties for this object. */ -void Network_Port_Property_List(uint32_t object_instance, +void Network_Port_Property_List( + uint32_t object_instance, const int **pRequired, const int **pOptional, const int **pProprietary) @@ -257,16 +283,15 @@ void Network_Port_Property_Lists( * @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) +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); + 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); @@ -725,8 +750,8 @@ bool Network_Port_MAC_Address( uint8_t mac_len = 0; if (mac_address) { - mac_len = Network_Port_MAC_Address_Value(object_instance, - mac_address->value, sizeof(mac_address->value)); + mac_len = Network_Port_MAC_Address_Value( + object_instance, mac_address->value, sizeof(mac_address->value)); } return mac_len > 0; @@ -1256,17 +1281,17 @@ bool Network_Port_IP_Gateway_Set( */ bool Network_Port_IP_DHCP_Enable(uint32_t object_instance) { - bool dhcp_enable = false; - unsigned index = 0; + bool dhcp_enable = false; + unsigned index = 0; - index = Network_Port_Instance_To_Index(object_instance); - if (index < BACNET_NETWORK_PORTS_MAX) { - if (Object_List[index].Network_Type == PORT_TYPE_BIP) { - dhcp_enable = Object_List[index].Network.IPv4.IP_DHCP_Enable; - } - } + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + if (Object_List[index].Network_Type == PORT_TYPE_BIP) { + dhcp_enable = Object_List[index].Network.IPv4.IP_DHCP_Enable; + } + } - return dhcp_enable; + return dhcp_enable; } /** @@ -1279,18 +1304,18 @@ bool Network_Port_IP_DHCP_Enable(uint32_t object_instance) */ bool Network_Port_IP_DHCP_Enable_Set(uint32_t object_instance, bool value) { - bool status = false; - unsigned index = 0; + bool status = false; + unsigned index = 0; - index = Network_Port_Instance_To_Index(object_instance); - if (index < BACNET_NETWORK_PORTS_MAX) { - if (Object_List[index].Network_Type == PORT_TYPE_BIP) { - Object_List[index].Network.IPv4.IP_DHCP_Enable = value; - status = true; - } - } + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + if (Object_List[index].Network_Type == PORT_TYPE_BIP) { + Object_List[index].Network.IPv4.IP_DHCP_Enable = value; + status = true; + } + } - return status; + return status; } /** @@ -1304,7 +1329,8 @@ bool Network_Port_IP_DHCP_Enable_Set(uint32_t object_instance, bool value) * * @return true if ip-address was retrieved */ -bool Network_Port_IP_DNS_Server(uint32_t object_instance, +bool Network_Port_IP_DNS_Server( + uint32_t object_instance, unsigned dns_index, BACNET_OCTET_STRING *ip_address) { @@ -1315,7 +1341,8 @@ bool Network_Port_IP_DNS_Server(uint32_t object_instance, if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP) { if (dns_index < BIP_DNS_MAX) { - status = octetstring_init(ip_address, + status = octetstring_init( + ip_address, &Object_List[index] .Network.IPv4.IP_DNS_Server[dns_index][0], 4); @@ -1366,7 +1393,8 @@ static int Network_Port_IP_DNS_Server_Encode( * * @return true if ip-address was set */ -bool Network_Port_IP_DNS_Server_Set(uint32_t object_instance, +bool Network_Port_IP_DNS_Server_Set( + uint32_t object_instance, unsigned dns_index, uint8_t a, uint8_t b, @@ -1648,7 +1676,8 @@ bool Network_Port_BBMD_FD_Table_Set(uint32_t object_instance, void *fdt_head) return status; } -#if (defined(BACDL_BIP) || defined(BACDL_ALL)) && (BBMD_ENABLED || BBMD_CLIENT_ENABLED) +#if (defined(BACDL_BIP) || defined(BACDL_ALL)) && \ + (BBMD_ENABLED || BBMD_CLIENT_ENABLED) /** * For a given object instance-number, gets the ip-address and port * Note: depends on Network_Type being set for this object @@ -1668,8 +1697,8 @@ static bool Network_Port_Remote_BBMD_IP_Address_And_Port( index = Network_Port_Instance_To_Index(object_instance); if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP) { - bvlc_address_set(addr, - Object_List[index].Network.IPv4.BBMD_IP_Address[0], + bvlc_address_set( + addr, Object_List[index].Network.IPv4.BBMD_IP_Address[0], Object_List[index].Network.IPv4.BBMD_IP_Address[1], Object_List[index].Network.IPv4.BBMD_IP_Address[2], Object_List[index].Network.IPv4.BBMD_IP_Address[3]); @@ -1745,10 +1774,10 @@ bool Network_Port_Remote_BBMD_IP_Address_Set( index = Network_Port_Instance_To_Index(object_instance); if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP) { - if((Object_List[index].Network.IPv4.BBMD_IP_Address[0] != a) || - (Object_List[index].Network.IPv4.BBMD_IP_Address[1] != b) || - (Object_List[index].Network.IPv4.BBMD_IP_Address[2] != c) || - (Object_List[index].Network.IPv4.BBMD_IP_Address[3] != d)) { + if ((Object_List[index].Network.IPv4.BBMD_IP_Address[0] != a) || + (Object_List[index].Network.IPv4.BBMD_IP_Address[1] != b) || + (Object_List[index].Network.IPv4.BBMD_IP_Address[2] != c) || + (Object_List[index].Network.IPv4.BBMD_IP_Address[3] != d)) { Object_List[index].Changes_Pending = true; } Object_List[index].Network.IPv4.BBMD_IP_Address[0] = a; @@ -1922,7 +1951,6 @@ bool Network_Port_BBMD_IP6_Accept_FD_Registrations_Set( return status; } - /** * For a given object instance-number, returns the BBMD-BD-Table head * property value @@ -1956,7 +1984,8 @@ void *Network_Port_BBMD_IP6_BD_Table(uint32_t object_instance) * @return true if the Broadcast Distribution Table linked list head * property value was set */ -bool Network_Port_BBMD_IP6_BD_Table_Set(uint32_t object_instance, void *bdt_head) +bool Network_Port_BBMD_IP6_BD_Table_Set( + uint32_t object_instance, void *bdt_head) { bool status = false; unsigned index = 0; @@ -2007,7 +2036,8 @@ void *Network_Port_BBMD_IP6_FD_Table(uint32_t object_instance) * * @return true if the BBMD-Accept-FD-Registrations property value was set */ -bool Network_Port_BBMD_IP6_FD_Table_Set(uint32_t object_instance, void *fdt_head) +bool Network_Port_BBMD_IP6_FD_Table_Set( + uint32_t object_instance, void *fdt_head) { bool status = false; unsigned index = 0; @@ -2046,7 +2076,10 @@ static bool Network_Port_Remote_BBMD_IP6_Address_And_Port( index = Network_Port_Instance_To_Index(object_instance); if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { - memcpy(addr->address, Object_List[index].Network.IPv6.BBMD_IP_Address, sizeof(addr->address)); + memcpy( + addr->address, + Object_List[index].Network.IPv6.BBMD_IP_Address, + sizeof(addr->address)); addr->port = Object_List[index].Network.IPv6.BBMD_Port; status = true; } @@ -2077,8 +2110,10 @@ bool Network_Port_Remote_BBMD_IP6_Address( if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { if (addr) { - memcpy(addr, Object_List[index].Network.IPv6.BBMD_IP_Address, IP6_ADDRESS_MAX); - status = true; + memcpy( + addr, Object_List[index].Network.IPv6.BBMD_IP_Address, + IP6_ADDRESS_MAX); + status = true; } } } @@ -2104,8 +2139,12 @@ bool Network_Port_Remote_BBMD_IP6_Address_Set( index = Network_Port_Instance_To_Index(object_instance); if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { - if(memcmp(Object_List[index].Network.IPv6.BBMD_IP_Address, addr, IP6_ADDRESS_MAX)) { - memcpy(Object_List[index].Network.IPv6.BBMD_IP_Address, addr, IP6_ADDRESS_MAX); + if (memcmp( + Object_List[index].Network.IPv6.BBMD_IP_Address, addr, + IP6_ADDRESS_MAX)) { + memcpy( + Object_List[index].Network.IPv6.BBMD_IP_Address, addr, + IP6_ADDRESS_MAX); Object_List[index].Changes_Pending = true; } status = true; @@ -2290,8 +2329,9 @@ bool Network_Port_IPv6_Address( index = Network_Port_Instance_To_Index(object_instance); if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { - status = octetstring_init(ip_address, - &Object_List[index].Network.IPv6.IP_Address[0], IPV6_ADDR_SIZE); + status = octetstring_init( + ip_address, &Object_List[index].Network.IPv6.IP_Address[0], + IPV6_ADDR_SIZE); } } @@ -2400,8 +2440,9 @@ bool Network_Port_IPv6_Gateway( index = Network_Port_Instance_To_Index(object_instance); if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { - status = octetstring_init(ip_address, - &Object_List[index].Network.IPv6.IP_Gateway[0], IPV6_ADDR_SIZE); + status = octetstring_init( + ip_address, &Object_List[index].Network.IPv6.IP_Gateway[0], + IPV6_ADDR_SIZE); } } @@ -2448,7 +2489,8 @@ bool Network_Port_IPv6_Gateway_Set( * * @return true if ip-address was retrieved */ -bool Network_Port_IPv6_DNS_Server(uint32_t object_instance, +bool Network_Port_IPv6_DNS_Server( + uint32_t object_instance, unsigned dns_index, BACNET_OCTET_STRING *ip_address) { @@ -2459,7 +2501,8 @@ bool Network_Port_IPv6_DNS_Server(uint32_t object_instance, if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { if (dns_index < BIP_DNS_MAX) { - status = octetstring_init(ip_address, + status = octetstring_init( + ip_address, &Object_List[index] .Network.IPv6.IP_DNS_Server[dns_index][0], IPV6_ADDR_SIZE); @@ -2547,7 +2590,8 @@ bool Network_Port_IPv6_Multicast_Address( index = Network_Port_Instance_To_Index(object_instance); if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { - status = octetstring_init(ip_address, + status = octetstring_init( + ip_address, &Object_List[index].Network.IPv6.IP_Multicast_Address[0], IPV6_ADDR_SIZE); } @@ -2605,8 +2649,8 @@ bool Network_Port_IPv6_DHCP_Server( index = Network_Port_Instance_To_Index(object_instance); if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { - status = octetstring_init(ip_address, - &Object_List[index].Network.IPv6.IP_DHCP_Server[0], + status = octetstring_init( + ip_address, &Object_List[index].Network.IPv6.IP_DHCP_Server[0], IPV6_ADDR_SIZE); } } @@ -2723,8 +2767,8 @@ bool Network_Port_IPv6_Zone_Index( } /** - * For a given object instance-number, returns the BACnet IPv6 Auto Addressing Enable - * property value + * For a given object instance-number, returns the BACnet IPv6 Auto Addressing + * Enable property value * * @param object_instance - object-instance number of the object * @@ -2746,15 +2790,17 @@ bool Network_Port_IPv6_Auto_Addressing_Enable(uint32_t object_instance) } /** - * For a given object instance-number, sets the BACnet/IP6 Auto Addressing Enable - * Note: depends on Network_Type being set to PORT_TYPE_BIP6 for this object + * For a given object instance-number, sets the BACnet/IP6 Auto Addressing + * Enable Note: depends on Network_Type being set to PORT_TYPE_BIP6 for this + * object * * @param object_instance - object-instance number of the object * @param value - BACnet/IP6 Audo Addressing Enable (default false) * * @return true if values are within range and property is set. */ -bool Network_Port_IPv6_Auto_Addressing_Enable_Set(uint32_t object_instance, bool value) +bool Network_Port_IPv6_Auto_Addressing_Enable_Set( + uint32_t object_instance, bool value) { bool status = false; unsigned index = 0; @@ -2762,7 +2808,8 @@ bool Network_Port_IPv6_Auto_Addressing_Enable_Set(uint32_t object_instance, bool index = Network_Port_Instance_To_Index(object_instance); if (index < BACNET_NETWORK_PORTS_MAX) { if (Object_List[index].Network_Type == PORT_TYPE_BIP6) { - if (Object_List[index].Network.IPv6.Auto_Addressing_Enable != value) { + if (Object_List[index].Network.IPv6.Auto_Addressing_Enable != + value) { Object_List[index].Changes_Pending = true; } Object_List[index].Network.IPv6.Auto_Addressing_Enable = value; @@ -2792,14 +2839,95 @@ bool Network_Port_IPv6_Gateway_Zone_Index_Set( if (index < BACNET_NETWORK_PORTS_MAX) { if ((Object_List[index].Network_Type == PORT_TYPE_BIP6) && (zone_index)) { - snprintf(&Object_List[index].Network.IPv6.Zone_Index[0], - ZONE_INDEX_SIZE, "%s", zone_index); + snprintf( + &Object_List[index].Network.IPv6.Zone_Index[0], ZONE_INDEX_SIZE, + "%s", zone_index); } } return status; } +/** + * @brief Write the FD BBMD Address + * @param object_instance [in] BACnet network port object instance number + * @param value [in] BACnet IP address and port + * @param error_class [out] BACnet error class + * @param error_code [out] BACnet error code + * @return true if the value was written + */ +static bool Network_Port_FD_BBMD_Address_Write( + uint32_t object_instance, + BACNET_HOST_N_PORT *value, + BACNET_ERROR_CLASS *error_class, + BACNET_ERROR_CODE *error_code) +{ + bool status = false; + + if (!error_class || !error_code) { + return status; + } + if (!value) { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + return status; + } + switch (Network_Port_Type(object_instance)) { +#if (defined(BACDL_ALL) || defined(BACDL_BIP)) + case PORT_TYPE_BIP: + if (Network_Port_BIP_Mode(object_instance) != + BACNET_IP_MODE_FOREIGN) { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + break; + } else if (value->host.ip_address.length == 4) { + status = Network_Port_Remote_BBMD_IP_Address_Set( + object_instance, value->host.ip_address.value[0], + value->host.ip_address.value[1], + value->host.ip_address.value[2], + value->host.ip_address.value[3]); + if (status) { + status = Network_Port_Remote_BBMD_BIP_Port_Set( + object_instance, value->port); + } + } + if (!status) { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + break; +#endif +#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) + case PORT_TYPE_BIP6: + if (Network_Port_BIP6_Mode(object_instance) != + BACNET_IP_MODE_FOREIGN) { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + break; + } else if (value->host.ip_address.length == 16) { + status = Network_Port_Remote_BBMD_IP6_Address_Set( + object_instance, &value->host.ip_address.value[0]); + + if (status) { + status = Network_Port_Remote_BBMD_BIP6_Port_Set( + object_instance, value->port); + } + } + if (!status) { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + break; +#endif + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + break; + } + + return status; +} + /** * For a given object instance-number, gets the MS/TP Max_Info_Frames value * Note: depends on Network_Type being set to PORT_TYPE_MSTP for this object @@ -2897,7 +3025,8 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) BACNET_BIT_STRING bit_string; BACNET_OCTET_STRING octet_string; BACNET_CHARACTER_STRING char_string; -#if (defined(BACDL_ALL) || defined(BACDL_BIP)) && (BBMD_ENABLED || BBMD_CLIENT_ENABLED) +#if (defined(BACDL_ALL) || defined(BACDL_BIP)) && \ + (BBMD_ENABLED || BBMD_CLIENT_ENABLED) BACNET_IP_ADDRESS ip_address; #endif #if (defined(BACDL_ALL) || defined(BACDL_BIP6)) && (BBMD_CLIENT_ENABLED) @@ -2908,7 +3037,7 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) const int *pOptional = NULL; const int *pProprietary = NULL; - uint8_t network_type = PORT_TYPE_NON_BACNET; + uint8_t network_type = PORT_TYPE_NON_BACNET; unsigned int index = 0; if ((rpdata == NULL) || (rpdata->application_data == NULL) || @@ -2917,11 +3046,12 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) } #if (!BBMD_CLIENT_ENABLED) - (void) network_type; + (void)network_type; #endif - if ((index = Network_Port_Instance_To_Index(rpdata->object_instance)) < BACNET_NETWORK_PORTS_MAX) { - network_type = Object_List[index].Network_Type; + if ((index = Network_Port_Instance_To_Index(rpdata->object_instance)) < + BACNET_NETWORK_PORTS_MAX) { + network_type = Object_List[index].Network_Type; } Network_Port_Property_List( @@ -3001,7 +3131,8 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) &apdu[0], Network_Port_Link_Speed(rpdata->object_instance)); break; case PROP_CHANGES_PENDING: - apdu_len = encode_application_boolean(&apdu[0], + apdu_len = encode_application_boolean( + &apdu[0], Network_Port_Changes_Pending(rpdata->object_instance)); break; case PROP_APDU_LENGTH: @@ -3009,11 +3140,13 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) &apdu[0], Network_Port_APDU_Length(rpdata->object_instance)); break; case PROP_MAX_MASTER: - apdu_len = encode_application_unsigned(&apdu[0], + apdu_len = encode_application_unsigned( + &apdu[0], Network_Port_MSTP_Max_Master(rpdata->object_instance)); break; case PROP_MAX_INFO_FRAMES: - apdu_len = encode_application_unsigned(&apdu[0], + apdu_len = encode_application_unsigned( + &apdu[0], Network_Port_MSTP_Max_Info_Frames(rpdata->object_instance)); break; case PROP_BACNET_IP_MODE: @@ -3041,9 +3174,10 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) &apdu[0], Network_Port_IP_DHCP_Enable(rpdata->object_instance)); break; case PROP_IP_DNS_SERVER: - apdu_len = bacnet_array_encode(rpdata->object_instance, - rpdata->array_index, Network_Port_IP_DNS_Server_Encode, - BIP_DNS_MAX, apdu, apdu_size); + apdu_len = bacnet_array_encode( + rpdata->object_instance, rpdata->array_index, + Network_Port_IP_DNS_Server_Encode, BIP_DNS_MAX, apdu, + apdu_size); if (apdu_len == BACNET_STATUS_ABORT) { rpdata->error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; @@ -3053,105 +3187,114 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) apdu_len = BACNET_STATUS_ERROR; } break; -#if (defined(BACDL_BIP) || defined (BACDL_BIP6) || defined(BACDL_ALL)) && (BBMD_ENABLED || BBMD_CLIENT_ENABLED) +#if (defined(BACDL_BIP) || defined(BACDL_BIP6) || defined(BACDL_ALL)) && \ + (BBMD_ENABLED || BBMD_CLIENT_ENABLED) #if (BBMD_ENABLED) case PROP_BBMD_ACCEPT_FD_REGISTRATIONS: - apdu_len = encode_application_boolean(&apdu[0], + apdu_len = encode_application_boolean( + &apdu[0], Network_Port_BBMD_Accept_FD_Registrations( rpdata->object_instance)); break; case PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE: - switch(network_type) { + switch (network_type) { #if (defined(BACDL_ALL) || defined(BACDL_BIP)) - case PORT_TYPE_BIP: - apdu_len = bvlc_broadcast_distribution_table_encode(&apdu[0], - rpdata->application_data_len, - Network_Port_BBMD_BD_Table(rpdata->object_instance)); - break; + case PORT_TYPE_BIP: + apdu_len = bvlc_broadcast_distribution_table_encode( + &apdu[0], rpdata->application_data_len, + Network_Port_BBMD_BD_Table(rpdata->object_instance)); + break; #endif #if (defined(BACDL_ALL) || defined(BACDL_BIP6)) - case PORT_TYPE_BIP6: - apdu_len = bvlc6_broadcast_distribution_table_encode(&apdu[0], - rpdata->application_data_len, - Network_Port_BBMD_IP6_BD_Table(rpdata->object_instance)); - break; + case PORT_TYPE_BIP6: + apdu_len = bvlc6_broadcast_distribution_table_encode( + &apdu[0], rpdata->application_data_len, + Network_Port_BBMD_IP6_BD_Table( + rpdata->object_instance)); + break; #endif - default: - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - break; + default: + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = BACNET_STATUS_ERROR; + break; } break; case PROP_BBMD_FOREIGN_DEVICE_TABLE: - switch(network_type) { + switch (network_type) { #if (defined(BACDL_ALL) || defined(BACDL_BIP)) - case PORT_TYPE_BIP: - apdu_len = bvlc_foreign_device_table_encode(&apdu[0], - rpdata->application_data_len, - Network_Port_BBMD_FD_Table(rpdata->object_instance)); - break; + case PORT_TYPE_BIP: + apdu_len = bvlc_foreign_device_table_encode( + &apdu[0], rpdata->application_data_len, + Network_Port_BBMD_FD_Table(rpdata->object_instance)); + break; #endif #if (defined(BACDL_ALL) || defined(BACDL_BIP6)) - case PORT_TYPE_BIP6: - apdu_len = bvlc6_foreign_device_table_encode(&apdu[0], - rpdata->application_data_len, - Network_Port_BBMD_IP6_FD_Table(rpdata->object_instance)); - break; + case PORT_TYPE_BIP6: + apdu_len = bvlc6_foreign_device_table_encode( + &apdu[0], rpdata->application_data_len, + Network_Port_BBMD_IP6_FD_Table( + rpdata->object_instance)); + break; #endif - default: - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - break; + default: + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = BACNET_STATUS_ERROR; + break; } break; #endif /* BBMD_ENABLED */ #if (BBMD_CLIENT_ENABLED) case PROP_FD_BBMD_ADDRESS: - switch(network_type) { -#if (defined(BACDL_BIP) || defined(BACDL_ALL)) && (BBMD_ENABLED || BBMD_CLIENT_ENABLED) - case PORT_TYPE_BIP: - Network_Port_Remote_BBMD_IP_Address_And_Port( - rpdata->object_instance, &ip_address); - apdu_len = bvlc_foreign_device_bbmd_host_address_encode( - &apdu[0], apdu_size, &ip_address); - break; + switch (network_type) { +#if (defined(BACDL_BIP) || defined(BACDL_ALL)) && \ + (BBMD_ENABLED || BBMD_CLIENT_ENABLED) + case PORT_TYPE_BIP: + Network_Port_Remote_BBMD_IP_Address_And_Port( + rpdata->object_instance, &ip_address); + apdu_len = bvlc_foreign_device_bbmd_host_address_encode( + &apdu[0], apdu_size, &ip_address); + break; #endif #if (defined(BACDL_ALL) || defined(BACDL_BIP6)) - case PORT_TYPE_BIP6: - Network_Port_Remote_BBMD_IP6_Address_And_Port( - rpdata->object_instance, &ip6_address); - apdu_len = bvlc6_foreign_device_bbmd_host_address_encode( - &apdu[0], apdu_size, &ip6_address); - break; + case PORT_TYPE_BIP6: + Network_Port_Remote_BBMD_IP6_Address_And_Port( + rpdata->object_instance, &ip6_address); + apdu_len = bvlc6_foreign_device_bbmd_host_address_encode( + &apdu[0], apdu_size, &ip6_address); + break; #endif - default: - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - break; + default: + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = BACNET_STATUS_ERROR; + break; } break; case PROP_FD_SUBSCRIPTION_LIFETIME: - switch(network_type) { + switch (network_type) { #if (defined(BACDL_ALL) || defined(BACDL_BIP)) - case PORT_TYPE_BIP: - apdu_len = encode_application_unsigned(&apdu[0], - Network_Port_Remote_BBMD_BIP_Lifetime(rpdata->object_instance)); - break; + case PORT_TYPE_BIP: + apdu_len = encode_application_unsigned( + &apdu[0], + Network_Port_Remote_BBMD_BIP_Lifetime( + rpdata->object_instance)); + break; #endif #if (defined(BACDL_ALL) || defined(BACDL_BIP6)) - case PORT_TYPE_BIP6: - apdu_len = encode_application_unsigned(&apdu[0], - Network_Port_Remote_BBMD_BIP6_Lifetime(rpdata->object_instance)); - break; + case PORT_TYPE_BIP6: + apdu_len = encode_application_unsigned( + &apdu[0], + Network_Port_Remote_BBMD_BIP6_Lifetime( + rpdata->object_instance)); + break; #endif - default: - rpdata->error_class = ERROR_CLASS_PROPERTY; - rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = BACNET_STATUS_ERROR; - break; + default: + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = BACNET_STATUS_ERROR; + break; } break; #endif @@ -3165,7 +3308,8 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) apdu_len = encode_application_octet_string(&apdu[0], &octet_string); break; case PROP_IPV6_PREFIX_LENGTH: - apdu_len = encode_application_unsigned(&apdu[0], + apdu_len = encode_application_unsigned( + &apdu[0], Network_Port_IPv6_Subnet_Prefix(rpdata->object_instance)); break; case PROP_BACNET_IPV6_UDP_PORT: @@ -3182,9 +3326,10 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) apdu_len = encode_application_octet_string(&apdu[0], &octet_string); break; case PROP_IPV6_DNS_SERVER: - apdu_len = bacnet_array_encode(rpdata->object_instance, - rpdata->array_index, Network_Port_IPv6_DNS_Server_Encode, - BIP_DNS_MAX, apdu, apdu_size); + apdu_len = bacnet_array_encode( + rpdata->object_instance, rpdata->array_index, + Network_Port_IPv6_DNS_Server_Encode, BIP_DNS_MAX, apdu, + apdu_size); if (apdu_len == BACNET_STATUS_ABORT) { rpdata->error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; @@ -3195,7 +3340,10 @@ int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) } break; case PROP_IPV6_AUTO_ADDRESSING_ENABLE: - apdu_len = encode_application_boolean(&apdu[0], Network_Port_IPv6_Auto_Addressing_Enable(rpdata->object_instance)); + apdu_len = encode_application_boolean( + &apdu[0], + Network_Port_IPv6_Auto_Addressing_Enable( + rpdata->object_instance)); break; case PROP_IPV6_DHCP_LEASE_TIME: apdu_len = encode_application_unsigned(&apdu[0], 0); @@ -3258,7 +3406,8 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) wp_data->application_data, wp_data->application_data_len, &value); #else len = bacapp_decode_generic_property( - wp_data->application_data, wp_data->application_data_len, &value, wp_data->object_property); + wp_data->application_data, wp_data->application_data_len, &value, + wp_data->object_property); #endif if (len < 0) { /* error while decoding - a value larger than we can handle */ @@ -3317,110 +3466,73 @@ bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) break; #if (BBMD_CLIENT_ENABLED) case PROP_FD_BBMD_ADDRESS: - if(write_property_type_valid( wp_data, &value, BACNET_APPLICATION_TAG_HOST_N_PORT)) { - switch(Network_Port_Type(wp_data->object_instance)) { -#if (defined(BACDL_ALL) || defined(BACDL_BIP)) - case PORT_TYPE_BIP: - if(Network_Port_BIP_Mode(wp_data->object_instance) == BACNET_IP_MODE_FOREIGN) { - if(value.type.Host_Address.host.ip_address.length == 4) { - status = Network_Port_Remote_BBMD_IP_Address_Set( - wp_data->object_instance, - value.type.Host_Address.host.ip_address.value[0], - value.type.Host_Address.host.ip_address.value[1], - value.type.Host_Address.host.ip_address.value[2], - value.type.Host_Address.host.ip_address.value[3]); - - if(status) { - status = Network_Port_Remote_BBMD_BIP_Port_Set(wp_data->object_instance, value.type.Host_Address.port); - } - } - - if (!status) { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } - } else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } - break; -#endif -#if (defined(BACDL_ALL) || defined(BACDL_BIP6)) - case PORT_TYPE_BIP6: - if(Network_Port_BIP_Mode(wp_data->object_instance) == BACNET_IP_MODE_FOREIGN) { - if(value.type.Host_Address.host.ip_address.length == 16) { - status = Network_Port_Remote_BBMD_IP6_Address_Set( - wp_data->object_instance, - &value.type.Host_Address.host.ip_address.value[0]); - - if(status) { - status = Network_Port_Remote_BBMD_BIP6_Port_Set(wp_data->object_instance, value.type.Host_Address.port); - } - } - - if (!status) { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } - } else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } - break; -#endif - default: - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - break; - } + if (write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_HOST_N_PORT)) { + status = Network_Port_FD_BBMD_Address_Write( + wp_data->object_instance, &value.type.Host_Address, + &wp_data->error_class, &wp_data->error_code); } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } break; case PROP_FD_SUBSCRIPTION_LIFETIME: - if(write_property_type_valid(wp_data, &value, BACNET_APPLICATION_TAG_UNSIGNED_INT)) { - if (value.type.Unsigned_Int <= 65535) { - switch(Network_Port_Type(wp_data->object_instance)) { + if (write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_UNSIGNED_INT)) { + if (value.type.Unsigned_Int <= 65535) { + switch (Network_Port_Type(wp_data->object_instance)) { #if (defined(BACDL_ALL) || defined(BACDL_BIP)) - case PORT_TYPE_BIP: - if(Network_Port_BIP_Mode(wp_data->object_instance) == BACNET_IP_MODE_FOREIGN) { - status = Network_Port_Remote_BBMD_BIP_Lifetime_Set( - wp_data->object_instance, value.type.Unsigned_Int); - if (!status) { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } - } else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } - break; + case PORT_TYPE_BIP: + if (Network_Port_BIP_Mode( + wp_data->object_instance) == + BACNET_IP_MODE_FOREIGN) { + status = + Network_Port_Remote_BBMD_BIP_Lifetime_Set( + wp_data->object_instance, + value.type.Unsigned_Int); + if (!status) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = + ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = + ERROR_CODE_WRITE_ACCESS_DENIED; + } + break; #endif #if (defined(BACDL_ALL) || defined(BACDL_BIP6)) - case PORT_TYPE_BIP6: - if(Network_Port_BIP6_Mode(wp_data->object_instance) == BACNET_IP_MODE_FOREIGN) { - status = Network_Port_Remote_BBMD_BIP6_Lifetime_Set( - wp_data->object_instance, value.type.Unsigned_Int); - if (!status) { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } - } else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } - break; + case PORT_TYPE_BIP6: + if (Network_Port_BIP6_Mode( + wp_data->object_instance) == + BACNET_IP_MODE_FOREIGN) { + status = + Network_Port_Remote_BBMD_BIP6_Lifetime_Set( + wp_data->object_instance, + value.type.Unsigned_Int); + if (!status) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = + ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = + ERROR_CODE_WRITE_ACCESS_DENIED; + } + break; #endif - default: + default: + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = + ERROR_CODE_INVALID_ARRAY_INDEX; + break; + } + } else { wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - break; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } - } else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } } break; #endif diff --git a/src/bacnet/config.h b/src/bacnet/config.h index dbbbf78a..131b4989 100644 --- a/src/bacnet/config.h +++ b/src/bacnet/config.h @@ -162,6 +162,8 @@ defined(BACAPP_DEVICE_OBJECT_REFERENCE) || \ defined(BACAPP_OBJECT_PROPERTY_REFERENCE) || \ defined(BACAPP_DESTINATION) || \ + defined(BACAPP_BDT_ENTRY) || \ + defined(BACAPP_FDT_ENTRY) || \ defined(BACAPP_TYPES_EXTRA)) #define BACAPP_ALL #endif @@ -202,6 +204,8 @@ #define BACAPP_DEVICE_OBJECT_REFERENCE #define BACAPP_OBJECT_PROPERTY_REFERENCE #define BACAPP_DESTINATION +#define BACAPP_BDT_ENTRY +#define BACAPP_FDT_ENTRY #endif #if defined(BACAPP_DOUBLE) || \ @@ -217,7 +221,9 @@ defined(BACAPP_DEVICE_OBJECT_PROPERTY_REFERENCE) || \ defined(BACAPP_DEVICE_OBJECT_REFERENCE) || \ defined(BACAPP_OBJECT_PROPERTY_REFERENCE) || \ - defined(BACAPP_DESTINATION) + defined(BACAPP_DESTINATION) || \ + defined(BACAPP_BDT_ENTRY) || \ + defined(BACAPP_FDT_ENTRY) #define BACAPP_COMPLEX_TYPES #endif diff --git a/src/bacnet/datalink/bvlc6.c b/src/bacnet/datalink/bvlc6.c index 7e631e87..1b121691 100644 --- a/src/bacnet/datalink/bvlc6.c +++ b/src/bacnet/datalink/bvlc6.c @@ -1604,9 +1604,7 @@ int bvlc6_foreign_device_bbmd_host_address_encode( } /** - * @brief Encode the Broadcast-Distribution-Table for Network Port object - * - * BACnetLIST of BACnetBDTEntry + * @brief Encode one Broadcast-Distribution-Table entry for Network Port object * * BACnetBDTEntry ::= SEQUENCE { * bbmd-address [0] BACnetHostNPort, @@ -1620,56 +1618,164 @@ int bvlc6_foreign_device_bbmd_host_address_encode( * broadcast-mask [1] OCTET STRING -- shall be present if BACnet/IP, and absent for BACnet/IPv6 * } * + * @param apdu - the APDU buffer, or NULL for length + * @param bdt_head - one BACnetBDTEntry + * @return length of the APDU buffer + */ +int bvlc6_broadcast_distribution_table_entry_encode(uint8_t *apdu, + BACNET_IP6_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry) +{ + int len = 0; + int apdu_len = 0; + int entry_size = 0; + BACNET_OCTET_STRING octet_string; + + if (bdt_entry) { + /* bbmd-address [0] BACnetHostNPort - opening */ + len = encode_opening_tag(apdu, 0); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* host [0] BACnetHostAddress - opening */ + len = encode_opening_tag(apdu, 0); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* CHOICE - ip-address [1] OCTET STRING */ + octetstring_init(&octet_string, &bdt_entry->bip6_address.address[0], + IP6_ADDRESS_MAX); + len = + encode_context_octet_string(apdu, 1, &octet_string); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* host [0] BACnetHostAddress - closing */ + len = encode_closing_tag(apdu, 0); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* port [1] Unsigned16 */ + len = encode_context_unsigned( + apdu, 1, bdt_entry->bip6_address.port); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* bbmd-address [0] BACnetHostNPort - closing */ + len = encode_closing_tag(apdu, 0); + apdu_len += len; + } + + return apdu_len; +} + +/** + * @brief Encode the Broadcast-Distribution-Table for Network Port object + * + * BACnetLIST of BACnetBDTEntry + * * @param apdu - the APDU buffer * @param apdu_size - the APDU buffer size * @param bdt_head - head of the BDT linked list * @return length of the APDU buffer */ +int bvlc6_broadcast_distribution_table_list_encode(uint8_t *apdu, + BACNET_IP6_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_head) +{ + int len = 0; + int apdu_len = 0; + BACNET_IP6_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry; + + bdt_entry = bdt_head; + while (bdt_entry) { + if (bdt_entry->valid) { + len = bvlc6_broadcast_distribution_table_entry_encode( + apdu, bdt_entry); + apdu_len += len; + if (apdu) { + apdu += len; + } + } else { + len = 0; + } + /* next entry */ + bdt_entry = bdt_entry->next; + } + + return apdu_len; +} + +/** + * @brief Encode the Broadcast-Distribution-Table for Network Port object + * @param apdu - the APDU buffer + * @param apdu_size - the APDU buffer size + * @param bdt_head - head of the BDT linked list + * @return length of the APDU buffer, or BACNET_STATUS_ERROR on error + */ int bvlc6_broadcast_distribution_table_encode(uint8_t *apdu, uint16_t apdu_size, BACNET_IP6_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_head) { int len = 0; - int apdu_len = 0; - int entry_size = 0; - BACNET_OCTET_STRING octet_string; - BACNET_IP6_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry; - bdt_entry = bdt_head; - while (bdt_entry) { - if (bdt_entry->valid) { - /* bbmd-address [0] BACnetHostNPort - opening */ - len = encode_opening_tag(&apdu[apdu_len], 0); - apdu_len += len; - /* host [0] BACnetHostAddress - opening */ - len = encode_opening_tag(&apdu[apdu_len], 0); - apdu_len += len; - /* CHOICE - ip-address [1] OCTET STRING */ - octetstring_init(&octet_string, &bdt_entry->bip6_address.address[0], - IP6_ADDRESS_MAX); - len = - encode_context_octet_string(&apdu[apdu_len], 1, &octet_string); - apdu_len += len; - /* host [0] BACnetHostAddress - closing */ - len = encode_closing_tag(&apdu[apdu_len], 0); - apdu_len += len; - /* port [1] Unsigned16 */ - len = encode_context_unsigned( - &apdu[apdu_len], 1, bdt_entry->bip6_address.port); - apdu_len += len; - /* bbmd-address [0] BACnetHostNPort - closing */ - len = encode_closing_tag(&apdu[apdu_len], 0); - apdu_len += len; + len = bvlc6_broadcast_distribution_table_list_encode(NULL, + bdt_head); + if (len <= apdu_size) { + len = bvlc6_broadcast_distribution_table_list_encode(apdu, + bdt_head); + } else { + len = BACNET_STATUS_ERROR; + } + + return len; +} + +/** + * @brief Encode the Foreign_Device-Table for Network Port object + * + * BACnetFDTEntry ::= SEQUENCE { + * bacnetip-address [0] OCTET STRING, -- the 6-octet B/IP or 18-octet B/IPv6 address of the registrant + * time-to-live [1] Unsigned16, -- time to live in seconds + * remaining-time-to-live [2] Unsigned16 -- remaining time in seconds + * } + * + * @param apdu - the APDU buffer, or NULL for length + * @param fdt_head - head of the BDT linked list + * @return length of the APDU buffer + */ +int bvlc6_foreign_device_table_entry_encode(uint8_t *apdu, + BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY *fdt_entry) +{ + int len = 0; + int apdu_len = 0; + BACNET_OCTET_STRING octet_string = { 0 }; + + if (fdt_entry) { + /* bacnetip-address [0] OCTET STRING */ + len = bvlc6_encode_address(octetstring_value(&octet_string), + octetstring_capacity(&octet_string), &fdt_entry->bip6_address); + octetstring_truncate(&octet_string, len); + len = + encode_context_octet_string(apdu, 0, &octet_string); + apdu_len += len; + if (apdu) { + apdu += len; } - if (!entry_size) { - entry_size = apdu_len; - } - /* next entry */ - bdt_entry = bdt_entry->next; - if ((apdu_len + entry_size) > apdu_size) { - /* check for available space */ - break; + /* time-to-live [1] Unsigned16 */ + len = encode_context_unsigned( + apdu, 1, fdt_entry->ttl_seconds); + apdu_len += len; + if (apdu) { + apdu += len; } + /* remaining-time-to-live [2] Unsigned16 */ + len = encode_context_unsigned( + apdu, 2, fdt_entry->ttl_seconds_remaining); + apdu_len += len; } return apdu_len; @@ -1680,12 +1786,35 @@ int bvlc6_broadcast_distribution_table_encode(uint8_t *apdu, * * BACnetLIST of BACnetFDTEntry * - * BACnetFDTEntry ::= SEQUENCE { - * bacnetip-address [0] OCTET STRING, -- the 6-octet B/IP or 18-octet B/IPv6 address of the registrant - * time-to-live [1] Unsigned16, -- time to live in seconds - * remaining-time-to-live [2] Unsigned16 -- remaining time in seconds - * } - * + * @param apdu - the APDU buffer, or NULL for length + * @param fdt_head - head of the BDT linked list + * @return length of the APDU buffer + */ +int bvlc6_foreign_device_table_list_encode(uint8_t *apdu, + BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY *fdt_head) +{ + int len = 0; + int apdu_len = 0; + BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY *fdt_entry; + + fdt_entry = fdt_head; + while (fdt_entry) { + if (fdt_entry->valid) { + len = bvlc6_foreign_device_table_entry_encode(apdu, fdt_entry); + apdu_len += len; + if (apdu) { + apdu += len; + } + } + /* next entry */ + fdt_entry = fdt_entry->next; + } + + return apdu_len; +} + +/** + * @brief Encode the Foreign_Device-Table for Network Port object * @param apdu - the APDU buffer * @param apdu_size - the APDU buffer size * @param fdt_head - head of the BDT linked list @@ -1696,41 +1825,15 @@ int bvlc6_foreign_device_table_encode(uint8_t *apdu, BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY *fdt_head) { int len = 0; - int apdu_len = 0; - int entry_size = 0; - BACNET_OCTET_STRING octet_string = { 0 }; - BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY *fdt_entry; - fdt_entry = fdt_head; - while (fdt_entry) { - if (fdt_entry->valid) { - /* bacnetip-address [0] OCTET STRING */ - len = bvlc6_encode_address(octetstring_value(&octet_string), - octetstring_capacity(&octet_string), &fdt_entry->bip6_address); - octetstring_truncate(&octet_string, len); - len = - encode_context_octet_string(&apdu[apdu_len], 0, &octet_string); - apdu_len += len; - /* time-to-live [1] Unsigned16 */ - len = encode_context_unsigned( - &apdu[apdu_len], 1, fdt_entry->ttl_seconds); - apdu_len += len; - /* remaining-time-to-live [2] Unsigned16 */ - len = encode_context_unsigned( - &apdu[apdu_len], 2, fdt_entry->ttl_seconds_remaining); - apdu_len += len; - } - if (!entry_size) { - entry_size = apdu_len; - } - /* next entry */ - fdt_entry = fdt_entry->next; - if ((apdu_len + entry_size) > apdu_size) { - /* check for available space */ - break; - } + len = bvlc6_foreign_device_table_list_encode(NULL, + fdt_head); + if (len <= apdu_size) { + len = bvlc6_foreign_device_table_list_encode(apdu, + fdt_head); + } else { + len = BACNET_STATUS_ERROR; } - return apdu_len; + return len; } - diff --git a/src/bacnet/datalink/bvlc6.h b/src/bacnet/datalink/bvlc6.h index 6778251a..11a665ec 100644 --- a/src/bacnet/datalink/bvlc6.h +++ b/src/bacnet/datalink/bvlc6.h @@ -425,10 +425,24 @@ extern "C" { int bvlc6_foreign_device_bbmd_host_address_encode(uint8_t *apdu, uint16_t apdu_size, BACNET_IP6_ADDRESS *ip6_address); + + BACNET_STACK_EXPORT + int bvlc6_broadcast_distribution_table_entry_encode(uint8_t *apdu, + BACNET_IP6_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_entry); + BACNET_STACK_EXPORT + int bvlc6_broadcast_distribution_table_list_encode(uint8_t *apdu, + BACNET_IP6_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_head); BACNET_STACK_EXPORT int bvlc6_broadcast_distribution_table_encode(uint8_t *apdu, uint16_t apdu_size, BACNET_IP6_BROADCAST_DISTRIBUTION_TABLE_ENTRY *bdt_head); + + BACNET_STACK_EXPORT + int bvlc6_foreign_device_table_entry_encode(uint8_t *apdu, + BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY *fdt_entry); + BACNET_STACK_EXPORT + int bvlc6_foreign_device_table_list_encode(uint8_t *apdu, + BACNET_IP6_FOREIGN_DEVICE_TABLE_ENTRY *fdt_head); BACNET_STACK_EXPORT int bvlc6_foreign_device_table_encode(uint8_t *apdu, uint16_t apdu_size, diff --git a/src/bacnet/datetime.c b/src/bacnet/datetime.c index 4785643a..93c04daf 100644 --- a/src/bacnet/datetime.c +++ b/src/bacnet/datetime.c @@ -298,7 +298,7 @@ bool datetime_is_valid(BACNET_DATE *bdate, BACNET_TIME *btime) * @param date1 - Pointer to a BACNET_DATE structure * @param date2 - Pointer to a BACNET_DATE structure * - * @return -/0/+ + * @return -/0=same/+ */ int datetime_compare_date(BACNET_DATE *date1, BACNET_DATE *date2) { @@ -1175,6 +1175,27 @@ int bacapp_decode_context_datetime( return bacnet_datetime_context_decode(apdu, MAX_APDU, tag_number, value); } +/** + * @brief Compare BACnetDateRange complex data types + * @param value1 - complex data value 1 structure + * @param value2 - complex data value 2 structure + * @return true if the two complex data values are the same + */ +bool bacnet_daterange_same(BACNET_DATE_RANGE *value1, + BACNET_DATE_RANGE *value2) +{ + bool status = false; + + if (value1 && value2) { + if ((datetime_compare_date(&value1->startdate, &value2->startdate) == 0) && + (datetime_compare_date(&value1->enddate, &value2->enddate) == 0)) { + status = true; + } + } + + return status; +} + /** * @brief Encode BACnetDateRange complex data type * diff --git a/src/bacnet/datetime.h b/src/bacnet/datetime.h index 29dd8bd6..3ad8d11c 100644 --- a/src/bacnet/datetime.h +++ b/src/bacnet/datetime.h @@ -284,6 +284,9 @@ int bacapp_decode_context_datetime(uint8_t *apdu, BACNET_DATE_TIME *value); BACNET_STACK_EXPORT +bool bacnet_daterange_same(BACNET_DATE_RANGE *value1, + BACNET_DATE_RANGE *value2); +BACNET_STACK_EXPORT int bacnet_daterange_encode(uint8_t *apdu, BACNET_DATE_RANGE *value); BACNET_STACK_EXPORT int bacnet_daterange_decode(uint8_t *apdu, diff --git a/src/bacnet/hostnport.c b/src/bacnet/hostnport.c index a8fb8199..605b57f1 100644 --- a/src/bacnet/hostnport.c +++ b/src/bacnet/hostnport.c @@ -19,6 +19,33 @@ #include "bacnet/hostnport.h" #include "bacnet/bacdcode.h" +/** + * @brief Encode the BACnetHostAddress CHOICE + * @param apdu - the APDU buffer + * @param address - IP address and port number + * @return length of the encoded APDU buffer + */ +int host_n_port_address_encode(uint8_t *apdu, BACNET_HOST_N_PORT *address) +{ + int len = 0; + + if (address) { + if (address->host_ip_address) { + /* CHOICE - ip-address [1] OCTET STRING */ + len = + encode_context_octet_string(apdu, 1, &address->host.ip_address); + } else if (address->host_name) { + /* CHOICE - name [2] CharacterString */ + len = encode_context_character_string(apdu, 2, &address->host.name); + } else { + /* CHOICE - none [0] NULL */ + len = encode_context_null(apdu, 0); + } + } + + return len; +} + /** * @brief Encode a BACnetHostNPort complex data type * @@ -50,17 +77,8 @@ int host_n_port_encode(uint8_t *apdu, BACNET_HOST_N_PORT *address) if (apdu) { apdu += len; } - if (address->host_ip_address) { - /* CHOICE - ip-address [1] OCTET STRING */ - len = - encode_context_octet_string(apdu, 1, &address->host.ip_address); - } else if (address->host_name) { - /* CHOICE - name [2] CharacterString */ - len = encode_context_character_string(apdu, 2, &address->host.name); - } else { - /* CHOICE - none [0] NULL */ - len = encode_context_null(apdu, 0); - } + /* BACnetHostAddress ::= CHOICE */ + len = host_n_port_address_encode(apdu, address); apdu_len += len; if (apdu) { apdu += len; @@ -111,28 +129,15 @@ int host_n_port_context_encode( } /** - * @brief Decode the BACnetHostNPort complex data - * - * BACnetHostNPort ::= SEQUENCE { - * host [0] BACnetHostAddress, - * BACnetHostAddress ::= CHOICE { - * BACnetHostAddress ::= CHOICE { - * none [0] NULL, - * ip-address [1] OCTET STRING, - * -- 4 octets for B/IP or 16 octets for B/IPv6 - * name [2] CharacterString - * -- Internet host name (see RFC 1123) - * } - * port [1] Unsigned16 - * } - * + * @brief Decode the BACnetHostAddress * @param apdu - the APDU buffer * @param apdu_size - the APDU buffer length * @param error_code - error or reject or abort when error occurs - * @param ip_address - IP address and port number - * @return length of the APDU buffer decoded, or ERROR, REJECT, or ABORT + * @param address - IP address and port number + * @return length of the APDU buffer decoded, or BACNET_STATUS_REJECT */ -int host_n_port_decode(uint8_t *apdu, +int host_n_port_address_decode( + uint8_t *apdu, uint32_t apdu_size, BACNET_ERROR_CODE *error_code, BACNET_HOST_N_PORT *address) @@ -141,21 +146,11 @@ int host_n_port_decode(uint8_t *apdu, BACNET_OCTET_STRING *octet_string = NULL; BACNET_CHARACTER_STRING *char_string = NULL; BACNET_TAG tag = { 0 }; - BACNET_UNSIGNED_INTEGER unsigned_value = 0; /* default reject code */ if (error_code) { *error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER; } - /* host [0] BACnetHostAddress - opening */ - if (!bacnet_is_opening_tag_number( - &apdu[apdu_len], apdu_size - apdu_len, 0, &len)) { - if (error_code) { - *error_code = ERROR_CODE_REJECT_INVALID_TAG; - } - return BACNET_STATUS_REJECT; - } - apdu_len += len; len = bacnet_tag_decode(&apdu[apdu_len], apdu_size - apdu_len, &tag); if (len <= 0) { if (error_code) { @@ -177,8 +172,9 @@ int host_n_port_decode(uint8_t *apdu, address->host_name = false; octet_string = &address->host.ip_address; } - len = bacnet_octet_string_decode(&apdu[apdu_len], apdu_size - apdu_len, - tag.len_value_type, octet_string); + len = bacnet_octet_string_decode( + &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, + octet_string); if (len < 0) { if (error_code) { *error_code = ERROR_CODE_REJECT_BUFFER_OVERFLOW; @@ -192,8 +188,9 @@ int host_n_port_decode(uint8_t *apdu, address->host_name = true; char_string = &address->host.name; } - len = bacnet_character_string_decode(&apdu[apdu_len], - apdu_size - apdu_len, tag.len_value_type, char_string); + len = bacnet_character_string_decode( + &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, + char_string); if (len == 0) { if (error_code) { *error_code = ERROR_CODE_REJECT_BUFFER_OVERFLOW; @@ -207,6 +204,61 @@ int host_n_port_decode(uint8_t *apdu, } return BACNET_STATUS_REJECT; } + + return apdu_len; +} + +/** + * @brief Decode the BACnetHostNPort complex data + * + * BACnetHostNPort ::= SEQUENCE { + * host [0] BACnetHostAddress, + * BACnetHostAddress ::= CHOICE { + * none [0] NULL, + * ip-address [1] OCTET STRING, + * -- 4 octets for B/IP or 16 octets for B/IPv6 + * name [2] CharacterString + * -- Internet host name (see RFC 1123) + * } + * port [1] Unsigned16 + * } + * + * @param apdu - the APDU buffer + * @param apdu_size - the APDU buffer length + * @param error_code - error or reject or abort when error occurs + * @param ip_address - IP address and port number + * @return length of the APDU buffer decoded, or ERROR, REJECT, or ABORT + */ +int host_n_port_decode( + uint8_t *apdu, + uint32_t apdu_size, + BACNET_ERROR_CODE *error_code, + BACNET_HOST_N_PORT *address) +{ + int apdu_len = 0, len = 0; + BACNET_UNSIGNED_INTEGER unsigned_value = 0; + + /* default reject code */ + if (error_code) { + *error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER; + } + /* host [0] BACnetHostAddress - opening */ + if (!bacnet_is_opening_tag_number( + &apdu[apdu_len], apdu_size - apdu_len, 0, &len)) { + if (error_code) { + *error_code = ERROR_CODE_REJECT_INVALID_TAG; + } + return BACNET_STATUS_REJECT; + } + apdu_len += len; + /* BACnetHostAddress ::= CHOICE */ + len = host_n_port_address_decode( + &apdu[apdu_len], apdu_size - apdu_len, error_code, address); + if (len > 0) { + apdu_len += len; + } else { + return BACNET_STATUS_REJECT; + } /* host [0] BACnetHostAddress - closing */ if (!bacnet_is_closing_tag_number( &apdu[apdu_len], apdu_size - apdu_len, 0, &len)) { @@ -254,7 +306,8 @@ int host_n_port_decode(uint8_t *apdu, * @param address - IP address and port number * @return length of the APDU buffer decoded, or ERROR, REJECT, or ABORT */ -int host_n_port_context_decode(uint8_t *apdu, +int host_n_port_context_decode( + uint8_t *apdu, uint32_t apdu_size, uint8_t tag_number, BACNET_ERROR_CODE *error_code, @@ -276,8 +329,8 @@ int host_n_port_context_decode(uint8_t *apdu, return BACNET_STATUS_REJECT; } apdu_len += len; - len = host_n_port_decode(&apdu[apdu_len], apdu_size - apdu_len, - error_code, address); + len = host_n_port_decode( + &apdu[apdu_len], apdu_size - apdu_len, error_code, address); if (len > 0) { apdu_len += len; } else { @@ -369,8 +422,7 @@ bool host_n_port_from_ascii(BACNET_HOST_N_PORT *value, const char *argv) unsigned a[4] = { 0 }, p = 0; int count; - count = sscanf(argv, "%3u.%3u.%3u.%3u:%5u", &a[0], &a[1], &a[2], - &a[3], &p); + count = sscanf(argv, "%3u.%3u.%3u.%3u:%5u", &a[0], &a[1], &a[2], &a[3], &p); if ((count == 4) || (count == 5)) { uint8_t address[4]; value->host_ip_address = true; @@ -379,8 +431,7 @@ bool host_n_port_from_ascii(BACNET_HOST_N_PORT *value, const char *argv) address[1] = (uint8_t)a[1]; address[2] = (uint8_t)a[2]; address[3] = (uint8_t)a[3]; - octetstring_init( - &value->host.ip_address, address, 4); + octetstring_init(&value->host.ip_address, address, 4); if (count == 4) { value->port = 0xBAC0U; } else { @@ -393,3 +444,719 @@ bool host_n_port_from_ascii(BACNET_HOST_N_PORT *value, const char *argv) return status; } + +/** + * @brief Encode the BACnetBDTEntry complex data + * + * BACnetBDTEntry ::= SEQUENCE { + * bbmd-address [0] BACnetHostNPort, + * broadcast-mask [1] OCTET STRING OPTIONAL + * -- shall be present if BACnet/IP, and absent for BACnet/IPv6 + * } + * + * @param apdu - the APDU buffer, or NULL for length + * @param entry - BACnet BDT entry + * @return length of the encoded APDU buffer + */ +int bacnet_bdt_entry_encode(uint8_t *apdu, BACNET_BDT_ENTRY *entry) +{ + int len = 0; + int apdu_len = 0; + + if (entry) { + /* bbmd-address [0] BACnetHostNPort - opening */ + len = encode_opening_tag(apdu, 0); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* BACnetHostNPort ::= SEQUENCE */ + len = host_n_port_encode(apdu, &entry->bbmd_address); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* bbmd-address [0] BACnetHostNPort - closing */ + len = encode_closing_tag(apdu, 0); + apdu_len += len; + if (apdu) { + apdu += len; + } + if (octetstring_length(&entry->broadcast_mask) > 0) { + /* broadcast-mask [1] OCTET STRING */ + len = encode_context_octet_string(apdu, 1, &entry->broadcast_mask); + apdu_len += len; + } + } + + return apdu_len; +} + +/** + * @brief Encode the BACnetBDTEntry complex data + * @param apdu - the APDU buffer, or NULL for length + * @param tag_number - context tag number to be encoded + * @param entry - BACnet BDT entry + * @return length of the encoded APDU buffer + */ +int bacnet_bdt_entry_context_encode( + uint8_t *apdu, uint8_t tag_number, BACNET_BDT_ENTRY *entry) +{ + int len = 0; + int apdu_len = 0; + + if (entry) { + len = encode_opening_tag(apdu, tag_number); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = bacnet_bdt_entry_encode(apdu, entry); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, tag_number); + apdu_len += len; + } + + return apdu_len; +} + +int bacnet_bdt_entry_decode( + uint8_t *apdu, + uint32_t apdu_size, + BACNET_ERROR_CODE *error_code, + BACNET_BDT_ENTRY *address) +{ + int apdu_len = 0, len = 0; + + /* default reject code */ + if (error_code) { + *error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER; + } + /* bbmd-address [0] BACnetHostNPort - opening */ + if (!bacnet_is_opening_tag_number(&apdu[apdu_len], apdu_size, 0, &len)) { + if (error_code) { + *error_code = ERROR_CODE_REJECT_INVALID_TAG; + } + return BACNET_STATUS_REJECT; + } + apdu_len += len; + /* BACnetHostNPort ::= SEQUENCE */ + len = host_n_port_decode( + &apdu[apdu_len], apdu_size-apdu_len, error_code, &address->bbmd_address); + if (len > 0) { + apdu_len += len; + } else { + return BACNET_STATUS_REJECT; + } + /* bbmd-address [0] BACnetHostNPort - closing */ + if (!bacnet_is_closing_tag_number(&apdu[apdu_len], apdu_size-apdu_len, 0, &len)) { + if (error_code) { + *error_code = ERROR_CODE_REJECT_INVALID_TAG; + } + return BACNET_STATUS_REJECT; + } + apdu_len += len; + /* broadcast-mask [1] OCTET STRING */ + len = bacnet_octet_string_context_decode( + &apdu[apdu_len], apdu_size-apdu_len, 1, &address->broadcast_mask); + if (len > 0) { + apdu_len += len; + } + + return apdu_len; +} + +/** + * @brief Copy the BACnetBDTEntry complex data + * @param dst - destination structure + * @param src - source structure + * @return true if successfully copied + */ +bool bacnet_bdt_entry_copy(BACNET_BDT_ENTRY *dst, BACNET_BDT_ENTRY *src) +{ + bool status = false; + + if (dst && src) { + status = host_n_port_copy(&dst->bbmd_address, &src->bbmd_address); + if (!status) { + status = + octetstring_copy(&dst->broadcast_mask, &src->broadcast_mask); + } + } + + return status; +} + +/** + * @brief Compare the BACnetBDTEntry complex data + * @param dst - destination structure + * @param src - source structure + * @return true if both are the same + */ +bool bacnet_bdt_entry_same(BACNET_BDT_ENTRY *dst, BACNET_BDT_ENTRY *src) +{ + bool status = false; + + if (dst && src) { + status = host_n_port_same(&dst->bbmd_address, &src->bbmd_address); + if (status) { + status = octetstring_value_same( + &dst->broadcast_mask, &src->broadcast_mask); + } + } + + return status; +} + +/** + * @brief Parse value from ASCII string (as entered by user) + * @param value - struct to populate with data from the ASCII string + * @param argv - ASCII string, zero terminated + * @return true on success + */ +bool bacnet_bdt_entry_from_ascii(BACNET_BDT_ENTRY *value, const char *argv) +{ + bool status = false; + unsigned a[16] = { 0 }, p = 0, m[4]; + int count; + + if (!argv) { + return false; + } + if (!value) { + return false; + } + count = sscanf( + argv, "%3u.%3u.%3u.%3u:%5u,%3u.%3u.%3u.%3u", &a[0], &a[1], &a[2], &a[3], + &p, &m[0], &m[1], &m[2], &m[3]); + if ((count == 4) || (count == 5) || (count == 8) || (count == 9)) { + uint8_t address[4]; + + value->bbmd_address.host_ip_address = true; + value->bbmd_address.host_name = false; + address[0] = (uint8_t)a[0]; + address[1] = (uint8_t)a[1]; + address[2] = (uint8_t)a[2]; + address[3] = (uint8_t)a[3]; + octetstring_init(&value->bbmd_address.host.ip_address, address, 4); + if ((count == 4) || (count == 8)) { + value->bbmd_address.port = 0xBAC0U; + } else if (count == 5) { + value->bbmd_address.port = (uint16_t)p; + octetstring_init(&value->broadcast_mask, NULL, 0); + } else { + value->bbmd_address.port = (uint16_t)p; + address[0] = (uint8_t)m[0]; + address[1] = (uint8_t)m[1]; + address[2] = (uint8_t)m[2]; + address[3] = (uint8_t)m[3]; + octetstring_init(&value->broadcast_mask, address, 4); + } + status = true; + } + if (!status) { + count = sscanf( + argv, + "%02x%02x:%02x%02x:%02x%02x:%02x%02x:" + "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%5u", + &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7], &a[8], + &a[9], &a[10], &a[11], &a[12], &a[13], &a[14], &a[15], &p); + if ((count == 16) || (count == 17)) { + uint8_t address[16]; + + value->bbmd_address.host_ip_address = true; + value->bbmd_address.host_name = false; + address[0] = (uint8_t)a[0]; + address[1] = (uint8_t)a[1]; + address[2] = (uint8_t)a[2]; + address[3] = (uint8_t)a[3]; + address[4] = (uint8_t)a[4]; + address[5] = (uint8_t)a[5]; + address[6] = (uint8_t)a[6]; + address[7] = (uint8_t)a[7]; + address[8] = (uint8_t)a[8]; + address[9] = (uint8_t)a[9]; + address[10] = (uint8_t)a[10]; + address[11] = (uint8_t)a[11]; + address[12] = (uint8_t)a[12]; + address[13] = (uint8_t)a[13]; + address[14] = (uint8_t)a[14]; + address[15] = (uint8_t)a[15]; + octetstring_init(&value->bbmd_address.host.ip_address, address, 16); + if (count == 16) { + value->bbmd_address.port = 0xBAC0U; + } else { + value->bbmd_address.port = (uint16_t)p; + } + status = true; + } + } + if (!status) { + const char *name, *port; + int name_len; + + port = strchr(argv, ':'); + if (port) { + name_len = port - argv; + port++; + p = strtol(port, NULL, 10); + } else { + name_len = strlen(argv); + p = 0xBAC0U; + } + name = argv; + if (name && isalnum(name[0])) { + value->bbmd_address.host_ip_address = false; + value->bbmd_address.host_name = true; + characterstring_init(&value->bbmd_address.host.name, + CHARACTER_ANSI_X34, + name, name_len); + } else { + value->bbmd_address.host_ip_address = false; + value->bbmd_address.host_name = false; + } + value->bbmd_address.port = p; + status = true; + } + + return status; +} + +/** + * @brief Convert the BACnetFDTEntry complex data to ASCII string + * @param str - destination string + * @param str_size - size of the destination string + * @param value - BACnet FDT entry + * @return length of the ASCII string + */ +int bacnet_bdt_entry_to_ascii( + char *str, size_t str_size, BACNET_BDT_ENTRY *value) +{ + int len = 0; + int ip_len = 0; + + if (value->bbmd_address.host_ip_address) { + ip_len = octetstring_length(&value->bbmd_address.host.ip_address); + if (ip_len == 4) { + len = snprintf( + str, str_size, "%u.%u.%u.%u:%u,%u.%u.%u.%u", + value->bbmd_address.host.ip_address.value[0], + value->bbmd_address.host.ip_address.value[1], + value->bbmd_address.host.ip_address.value[2], + value->bbmd_address.host.ip_address.value[3], + value->bbmd_address.port, value->broadcast_mask.value[0], + value->broadcast_mask.value[1], value->broadcast_mask.value[2], + value->broadcast_mask.value[3]); + } else if (ip_len == 16) { + len = snprintf( + str, str_size, + "%02x%02x:%02x%02x:%02x%02x:%02x%02x:" + "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%u", + value->bbmd_address.host.ip_address.value[0], + value->bbmd_address.host.ip_address.value[1], + value->bbmd_address.host.ip_address.value[2], + value->bbmd_address.host.ip_address.value[3], + value->bbmd_address.host.ip_address.value[4], + value->bbmd_address.host.ip_address.value[5], + value->bbmd_address.host.ip_address.value[6], + value->bbmd_address.host.ip_address.value[7], + value->bbmd_address.host.ip_address.value[8], + value->bbmd_address.host.ip_address.value[9], + value->bbmd_address.host.ip_address.value[10], + value->bbmd_address.host.ip_address.value[11], + value->bbmd_address.host.ip_address.value[12], + value->bbmd_address.host.ip_address.value[13], + value->bbmd_address.host.ip_address.value[14], + value->bbmd_address.host.ip_address.value[15], + value->bbmd_address.port); + } + } else if (value->bbmd_address.host_name) { + len = snprintf( + str, str_size, "%*s:%u", + (int)characterstring_length(&value->bbmd_address.host.name), + characterstring_value(&value->bbmd_address.host.name), + value->bbmd_address.port); + } + + return len; +} + +/** + * @brief Encode the BACnetFDTEntry complex data + * + * BACnetFDTEntry ::= SEQUENCE { + * bacnetip-address [0] OCTET STRING, + * -- the 6-octet B/IP or 18-octet B/IPv6 address of the registrant + * time-to-live [1] Unsigned16, + * -- time to live in seconds at the time of registration + * remaining-time-to-live [2] Unsigned16 + * -- remaining time to live in seconds, incl. grace period + * } + * + * @param apdu - the APDU buffer, or NULL for length + * @param entry - BACnet FDT entry + * @return length of the encoded APDU buffer + */ +int bacnet_fdt_entry_encode(uint8_t *apdu, BACNET_FDT_ENTRY *entry) +{ + int len = 0; + int apdu_len = 0; + + if (entry) { + /* bacnetip-address [0] OCTET STRING */ + len = encode_context_octet_string(apdu, 0, &entry->bacnetip_address); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* time-to-live [1] Unsigned16 */ + len = encode_context_unsigned(apdu, 1, entry->time_to_live); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* remaining-time-to-live [2] Unsigned16 */ + len = encode_context_unsigned(apdu, 2, entry->remaining_time_to_live); + apdu_len += len; + } + + return apdu_len; +} + +/** + * @brief Encode the BACnetFDTEntry complex data with context tag + * @param apdu - the APDU buffer, or NULL for length + * @param tag_number - context tag number to be encoded + * @param entry - BACnet FDT entry + * @return length of the encoded APDU buffer + */ +int bacnet_fdt_entry_context_encode( + uint8_t *apdu, uint8_t tag_number, BACNET_FDT_ENTRY *entry) +{ + int len = 0; + int apdu_len = 0; + + if (entry) { + len = encode_opening_tag(apdu, tag_number); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = bacnet_fdt_entry_encode(apdu, entry); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, tag_number); + apdu_len += len; + } + + return apdu_len; +} + +/** + * @brief Decode the BACnetFDTEntry complex data + * @param apdu - the APDU buffer + * @param apdu_size - the APDU buffer length + * @param error_code - error or reject or abort when error occurs + * @param address - BACnet FDT entry + * @return length of the APDU buffer decoded, or BACNET_STATUS_REJECT + */ +int bacnet_fdt_entry_decode( + uint8_t *apdu, + uint32_t apdu_size, + BACNET_ERROR_CODE *error_code, + BACNET_FDT_ENTRY *entry) +{ + int apdu_len = 0, len = 0; + BACNET_UNSIGNED_INTEGER unsigned_value = 0; + + /* default reject code */ + if (error_code) { + *error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER; + } + /* bacnetip-address [0] OCTET STRING */ + len = bacnet_octet_string_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 0, + &entry->bacnetip_address); + if (len > 0) { + apdu_len += len; + } else { + return BACNET_STATUS_REJECT; + } + /* time-to-live [1] Unsigned16 */ + len = bacnet_unsigned_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 1, &unsigned_value); + if ((len > 0) && (unsigned_value <= UINT16_MAX)) { + entry->time_to_live = unsigned_value; + apdu_len += len; + } else { + if (error_code) { + *error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE; + } + return BACNET_STATUS_REJECT; + } + /* remaining-time-to-live [2] Unsigned16 */ + len = bacnet_unsigned_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 2, + &unsigned_value); + if ((len > 0) && (unsigned_value <= UINT16_MAX)) { + entry->remaining_time_to_live = unsigned_value; + apdu_len += len; + } else { + if (error_code) { + *error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE; + } + return BACNET_STATUS_REJECT; + } + + return apdu_len; +} + +/** + * @brief Decode the BACnetFDTEntry complex data with context tag + * @param apdu - the APDU buffer + * @param apdu_size - the APDU buffer length + * @param tag_number - context tag number to be decoded + * @param error_code - error or reject or abort when error occurs + * @param address - BACnet FDT entry + * @return length of the APDU buffer decoded, or BACNET_STATUS_REJECT + */ +int bacnet_fdt_entry_context_decode( + uint8_t *apdu, + uint32_t apdu_size, + uint8_t tag_number, + BACNET_ERROR_CODE *error_code, + BACNET_FDT_ENTRY *address) +{ + int len = 0; + int apdu_len = 0; + + /* default reject code */ + if (error_code) { + *error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER; + } + if (!bacnet_is_opening_tag_number( + &apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) { + if (error_code) { + *error_code = ERROR_CODE_REJECT_INVALID_TAG; + } + return BACNET_STATUS_REJECT; + } + apdu_len += len; + len = bacnet_fdt_entry_decode( + &apdu[apdu_len], apdu_size - apdu_len, error_code, address); + if (len > 0) { + apdu_len += len; + } else { + if (error_code) { + *error_code = ERROR_CODE_REJECT_OTHER; + } + return BACNET_STATUS_REJECT; + } + if (!bacnet_is_closing_tag_number( + &apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) { + if (error_code) { + *error_code = ERROR_CODE_REJECT_INVALID_TAG; + } + return BACNET_STATUS_REJECT; + } + apdu_len += len; + + return apdu_len; +} + +/** + * @brief Copy the BACnetFDTEntry complex data + * @param dst - destination structure + * @param src - source structure + * @return true if successfully copied + */ +bool bacnet_fdt_entry_copy(BACNET_FDT_ENTRY *dst, BACNET_FDT_ENTRY *src) +{ + bool status = false; + + if (dst && src) { + status = + octetstring_copy(&dst->bacnetip_address, &src->bacnetip_address); + dst->time_to_live = src->time_to_live; + dst->remaining_time_to_live = src->remaining_time_to_live; + } + + return status; +} + +/** + * @brief Compare the BACnetFDTEntry complex data + * @param dst - destination structure + * @param src - source structure + * @return true if both are the same + */ +bool bacnet_fdt_entry_same(BACNET_FDT_ENTRY *dst, BACNET_FDT_ENTRY *src) +{ + bool status = false; + + if (dst && src) { + status = octetstring_value_same( + &dst->bacnetip_address, &src->bacnetip_address); + if (status) { + if (dst->time_to_live != src->time_to_live) { + status = false; + } + } + if (status) { + if (dst->remaining_time_to_live != src->remaining_time_to_live) { + status = false; + } + } + } + + return status; +} + +/** + * @brief Parse value from ASCII string (as entered by user) + * @param value - struct to populate with data from the ASCII string + * @param argv - ASCII string, zero terminated + * @return true on success + */ +bool bacnet_fdt_entry_from_ascii(BACNET_FDT_ENTRY *value, const char *argv) +{ + bool status = false; + unsigned a[18] = { 0 }, p = 0, ttl = 0, rttl = 0; + int count; + + if (!argv) { + return false; + } + if (!value) { + return false; + } + count = sscanf( + argv, "%3u.%3u.%3u.%3u:%5u,%5u,%5u", &a[0], &a[1], &a[2], &a[3], &p, + &ttl, &rttl); + if ((count == 4) || (count == 5) || (count == 6) || (count == 7)) { + uint8_t address[6]; + + address[0] = (uint8_t)a[0]; + address[1] = (uint8_t)a[1]; + address[2] = (uint8_t)a[2]; + address[3] = (uint8_t)a[3]; + + if (count == 4) { + p = 0xBAC0U; + value->time_to_live = 0; + value->remaining_time_to_live = 0; + } else if (count == 5) { + value->time_to_live = 0; + value->remaining_time_to_live = 0; + } else if (count == 6) { + value->time_to_live = (uint16_t)ttl; + } else { + value->time_to_live = (uint16_t)ttl; + value->remaining_time_to_live = (uint16_t)rttl; + } + address[4] = (uint8_t)p >> 8; + address[5] = (uint8_t)p & 0xFF; + octetstring_init(&value->bacnetip_address, address, 6); + status = true; + } else { + count = sscanf( + argv, + "%02x%02x:%02x%02x:%02x%02x:%02x%02x:" + "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%5u,%5u,%5u", + &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7], &a[8], + &a[9], &a[10], &a[11], &a[12], &a[13], &a[14], &a[15], &p, &ttl, + &rttl); + if ((count == 16) || (count == 17) || (count == 18) || (count == 19)) { + uint8_t address[18]; + + address[0] = (uint8_t)a[0]; + address[1] = (uint8_t)a[1]; + address[2] = (uint8_t)a[2]; + address[3] = (uint8_t)a[3]; + address[4] = (uint8_t)a[4]; + address[5] = (uint8_t)a[5]; + address[6] = (uint8_t)a[6]; + address[7] = (uint8_t)a[7]; + address[8] = (uint8_t)a[8]; + address[9] = (uint8_t)a[9]; + address[10] = (uint8_t)a[10]; + address[11] = (uint8_t)a[11]; + address[12] = (uint8_t)a[12]; + address[13] = (uint8_t)a[13]; + address[14] = (uint8_t)a[14]; + address[15] = (uint8_t)a[15]; + if (count == 16) { + p = 0xBAC0U; + value->time_to_live = 0; + value->remaining_time_to_live = 0; + } else if (count == 17) { + value->time_to_live = 0; + value->remaining_time_to_live = 0; + } else if (count == 18) { + value->time_to_live = (uint16_t)ttl; + } else { + value->time_to_live = (uint16_t)ttl; + value->remaining_time_to_live = (uint16_t)rttl; + } + address[16] = (uint8_t)p >> 8; + address[17] = (uint8_t)p & 0xFF; + octetstring_init(&value->bacnetip_address, address, 18); + status = true; + } else { + status = false; + } + } + + return status; +} + +/** + * @brief Convert the BACnetFDTEntry complex data to ASCII string + * @param str - destination string + * @param str_size - size of the destination string + * @param value - BACnet FDT entry + * @return length of the ASCII string + */ +int bacnet_fdt_entry_to_ascii( + char *str, size_t str_size, BACNET_FDT_ENTRY *value) +{ + int len = 0; + int ip_len = 0; + + ip_len = octetstring_length(&value->bacnetip_address); + if (ip_len == 6) { + len = snprintf( + str, str_size, "%u.%u.%u.%u:%u,%u,%u", + value->bacnetip_address.value[0], value->bacnetip_address.value[1], + value->bacnetip_address.value[2], value->bacnetip_address.value[3], + (value->bacnetip_address.value[4] << 8) | + value->bacnetip_address.value[5], + value->time_to_live, value->remaining_time_to_live); + } else if (ip_len == 18) { + len = snprintf( + str, str_size, + "%02x%02x:%02x%02x:%02x%02x:%02x%02x:" + "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%u,%u,%u", + value->bacnetip_address.value[0], value->bacnetip_address.value[1], + value->bacnetip_address.value[2], value->bacnetip_address.value[3], + value->bacnetip_address.value[4], value->bacnetip_address.value[5], + value->bacnetip_address.value[6], value->bacnetip_address.value[7], + value->bacnetip_address.value[8], value->bacnetip_address.value[9], + value->bacnetip_address.value[10], + value->bacnetip_address.value[11], + value->bacnetip_address.value[12], + value->bacnetip_address.value[13], + value->bacnetip_address.value[14], + value->bacnetip_address.value[15], + (value->bacnetip_address.value[16] << 8) | + value->bacnetip_address.value[17], + value->time_to_live, value->remaining_time_to_live); + } + + return len; +} diff --git a/src/bacnet/hostnport.h b/src/bacnet/hostnport.h index 29f83ff0..67fd0367 100644 --- a/src/bacnet/hostnport.h +++ b/src/bacnet/hostnport.h @@ -42,11 +42,43 @@ typedef struct BACnetHostNPort { uint16_t port; } BACNET_HOST_N_PORT; +/** + * BACnetBDTEntry ::= SEQUENCE { + * bbmd-address [0] BACnetHostNPort, + * broadcast-mask [1] OCTET STRING OPTIONAL + * -- shall be present if BACnet/IP, and absent for BACnet/IPv6 + * } + */ +typedef struct BACnetBDTEntry { + BACNET_HOST_N_PORT bbmd_address; + BACNET_OCTET_STRING broadcast_mask; +} BACNET_BDT_ENTRY; + +/** + * BACnetFDTEntry ::= SEQUENCE { + * bacnetip-address [0] OCTET STRING, + * -- the 6-octet B/IP or 18-octet B/IPv6 address of the registrant + * time-to-live [1] Unsigned16, + * -- time to live in seconds at the time of registration + * remaining-time-to-live [2] Unsigned16 + * -- remaining time to live in seconds, incl. grace period + * } + */ +typedef struct BACnetFDTEntry { + BACNET_OCTET_STRING bacnetip_address; + uint16_t time_to_live; + uint16_t remaining_time_to_live; +} BACNET_FDT_ENTRY; + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ BACNET_STACK_EXPORT + int host_n_port_address_encode( + uint8_t *apdu, + BACNET_HOST_N_PORT *address); + BACNET_STACK_EXPORT int host_n_port_encode( uint8_t * apdu, BACNET_HOST_N_PORT *address); @@ -56,6 +88,11 @@ extern "C" { uint8_t tag_number, BACNET_HOST_N_PORT *address); BACNET_STACK_EXPORT + int host_n_port_address_decode(uint8_t *apdu, + uint32_t apdu_size, + BACNET_ERROR_CODE *error_code, + BACNET_HOST_N_PORT *address); + BACNET_STACK_EXPORT int host_n_port_decode(uint8_t *apdu, uint32_t apdu_len, BACNET_ERROR_CODE *error_code, @@ -79,6 +116,80 @@ extern "C" { BACNET_HOST_N_PORT *value, const char *argv); + BACNET_STACK_EXPORT + int bacnet_bdt_entry_encode( + uint8_t * apdu, + BACNET_BDT_ENTRY *entry); + BACNET_STACK_EXPORT + int bacnet_bdt_entry_context_encode( + uint8_t * apdu, + uint8_t tag_number, + BACNET_BDT_ENTRY *entry); + BACNET_STACK_EXPORT + int bacnet_bdt_entry_decode(uint8_t *apdu, + uint32_t apdu_len, + BACNET_ERROR_CODE *error_code, + BACNET_BDT_ENTRY *address); + BACNET_STACK_EXPORT + int bacnet_bdt_entry_context_decode(uint8_t *apdu, + uint32_t apdu_size, + uint8_t tag_number, + BACNET_ERROR_CODE *error_code, + BACNET_BDT_ENTRY *address); + BACNET_STACK_EXPORT + bool bacnet_bdt_entry_copy( + BACNET_BDT_ENTRY * dst, + BACNET_BDT_ENTRY * src); + BACNET_STACK_EXPORT + bool bacnet_bdt_entry_same( + BACNET_BDT_ENTRY * dst, + BACNET_BDT_ENTRY * src); + BACNET_STACK_EXPORT + bool bacnet_bdt_entry_from_ascii( + BACNET_BDT_ENTRY *value, + const char *argv); + BACNET_STACK_EXPORT + int bacnet_bdt_entry_to_ascii( + char *str, size_t str_size, + BACNET_BDT_ENTRY *value); + + BACNET_STACK_EXPORT + int bacnet_fdt_entry_encode( + uint8_t * apdu, + BACNET_FDT_ENTRY *entry); + BACNET_STACK_EXPORT + int bacnet_fdt_entry_context_encode( + uint8_t * apdu, + uint8_t tag_number, + BACNET_FDT_ENTRY *entry); + BACNET_STACK_EXPORT + int bacnet_fdt_entry_decode(uint8_t *apdu, + uint32_t apdu_len, + BACNET_ERROR_CODE *error_code, + BACNET_FDT_ENTRY *address); + BACNET_STACK_EXPORT + int bacnet_fdt_entry_context_decode(uint8_t *apdu, + uint32_t apdu_size, + uint8_t tag_number, + BACNET_ERROR_CODE *error_code, + BACNET_FDT_ENTRY *address); + BACNET_STACK_EXPORT + bool bacnet_fdt_entry_copy( + BACNET_FDT_ENTRY * dst, + BACNET_FDT_ENTRY * src); + BACNET_STACK_EXPORT + bool bacnet_fdt_entry_same( + BACNET_FDT_ENTRY * dst, + BACNET_FDT_ENTRY * src); + BACNET_STACK_EXPORT + bool bacnet_fdt_entry_from_ascii( + BACNET_FDT_ENTRY *value, + const char *argv); + BACNET_STACK_EXPORT + int bacnet_fdt_entry_to_ascii( + char *str, size_t str_size, + BACNET_FDT_ENTRY *value); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/test/bacnet/bacapp/src/main.c b/test/bacnet/bacapp/src/main.c index d30ffc35..6206413d 100644 --- a/test/bacnet/bacapp/src/main.c +++ b/test/bacnet/bacapp/src/main.c @@ -54,8 +54,49 @@ static const BACNET_APPLICATION_TAG tag_list[] = { BACNET_APPLICATION_TAG_OBJECT_ID, #endif #if defined(BACAPP_TYPES_EXTRA) + BACNET_APPLICATION_TAG_EMPTYLIST, + /* BACnetWeeknday */ + /* BACNET_APPLICATION_TAG_WEEKNDAY, --> not implemented! */ + /* BACnetDateRange */ + BACNET_APPLICATION_TAG_DATERANGE, + /* BACnetDateTime */ + BACNET_APPLICATION_TAG_DATETIME, + /* BACnetTimeStamp */ + BACNET_APPLICATION_TAG_TIMESTAMP, + /* Error Class, Error Code */ + /* BACNET_APPLICATION_TAG_ERROR, --> not implemented! */ + /* BACnetDeviceObjectPropertyReference */ + BACNET_APPLICATION_TAG_DEVICE_OBJECT_PROPERTY_REFERENCE, + /* BACnetDeviceObjectReference */ + BACNET_APPLICATION_TAG_DEVICE_OBJECT_REFERENCE, + /* BACnetObjectPropertyReference */ + BACNET_APPLICATION_TAG_OBJECT_PROPERTY_REFERENCE, + /* BACnetDestination (Recipient_List) */ + BACNET_APPLICATION_TAG_DESTINATION, + /* BACnetRecipient */ + /* BACNET_APPLICATION_TAG_RECIPIENT, --> not implemented! */ + /* BACnetCOVSubscription */ + /* BACNET_APPLICATION_TAG_COV_SUBSCRIPTION, --> not implemented! */ + /* BACnetCalendarEntry */ + BACNET_APPLICATION_TAG_CALENDAR_ENTRY, + /* BACnetWeeklySchedule */ + BACNET_APPLICATION_TAG_WEEKLY_SCHEDULE, + /* BACnetSpecialEvent */ + BACNET_APPLICATION_TAG_SPECIAL_EVENT, + /* BACnetReadAccessSpecification */ + /* BACNET_APPLICATION_TAG_READ_ACCESS_SPECIFICATION, --> not implemented! */ + /* BACnetLightingCommand */ BACNET_APPLICATION_TAG_LIGHTING_COMMAND, + /* BACnetHostNPort */ BACNET_APPLICATION_TAG_HOST_N_PORT, + /* BACnetxyColor */ + BACNET_APPLICATION_TAG_XY_COLOR, + /* BACnetColorCommand */ + BACNET_APPLICATION_TAG_COLOR_COMMAND, + /* BACnetBDTEntry */ + BACNET_APPLICATION_TAG_BDT_ENTRY, + /* BACnetFDTEntry */ + BACNET_APPLICATION_TAG_FDT_ENTRY #endif }; @@ -882,23 +923,33 @@ verifyBACnetApplicationDataValue(BACNET_APPLICATION_DATA_VALUE *value) /** * @brief Test */ -static bool verifyBACnetComplexDataValue( - BACNET_APPLICATION_DATA_VALUE *value, BACNET_PROPERTY_ID prop) +static void verifyBACnetComplexDataValue( + BACNET_APPLICATION_DATA_VALUE *value, + BACNET_OBJECT_TYPE object_type, + BACNET_PROPERTY_ID prop) { uint8_t apdu[480] = { 0 }; int apdu_len = 0; int null_len = 0; BACNET_APPLICATION_DATA_VALUE test_value = { 0 }; + bool status = false; 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); + zassert_equal(apdu_len, null_len, "encoded length=%d", apdu_len); apdu_len = - bacapp_decode_generic_property(&apdu[0], apdu_len, &test_value, prop); - zassert_true(apdu_len != BACNET_STATUS_ERROR, NULL); + bacapp_decode_known_property(&apdu[0], apdu_len, &test_value, + object_type, prop); + zassert_true(apdu_len != BACNET_STATUS_ERROR, "decoded length=%d", apdu_len); + zassert_true(apdu_len > 0, "decoded length=%d", apdu_len); - return bacapp_same_value(value, &test_value); + status = bacapp_same_value(value, &test_value); + if (!status) { + null_len = 0; + } + zassert_true(status, "bacapp: same-value of tag=%s[%u]\n", + bactext_application_tag_name(value->tag), value->tag); } /** @@ -1154,9 +1205,17 @@ static void testBACnetApplicationData(void) status = bacapp_parse_application_data( BACNET_APPLICATION_TAG_HOST_N_PORT, "192.168.1.1:47808", &value); zassert_true(status, NULL); - status = verifyBACnetComplexDataValue(&value, PROP_FD_BBMD_ADDRESS); - status = - verifyBACnetComplexDataValue(&value, PROP_BACNET_IP_GLOBAL_ADDRESS); + verifyBACnetComplexDataValue(&value, OBJECT_NETWORK_PORT, + PROP_FD_BBMD_ADDRESS); + verifyBACnetComplexDataValue(&value, OBJECT_NETWORK_PORT, + PROP_BACNET_IP_GLOBAL_ADDRESS); + + status = bacapp_parse_application_data( + BACNET_APPLICATION_TAG_BDT_ENTRY, "192.168.1.1:47808,255.255.255.255", + &value); + zassert_true(status, NULL); + verifyBACnetComplexDataValue(&value, OBJECT_NETWORK_PORT, + PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE); return; } diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 0114d381..94541a2a 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -520,5 +520,7 @@ zephyr_compile_definitions( $<$:BACAPP_DEVICE_OBJECT_REFERENCE> $<$:BACAPP_OBJECT_PROPERTY_REFERENCE> $<$:BACAPP_DESTINATION> + $<$:BACAPP_BDT_ENTRY> + $<$:BACAPP_FDT_ENTRY> ) \ No newline at end of file diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 395e19a7..223f6000 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -255,6 +255,18 @@ config BACAPP_DESTINATION help BACnet data types supported for WriteProperty: DESTINATION +config BACAPP_BDT_ENTRY + bool "BACnet data types supported for WriteProperty: BDT_ENTRY" + default false + help + BACnet data types supported for WriteProperty: BDT_ENTRY + +config BACAPP_FDT_ENTRY + bool "BACnet data types supported for WriteProperty: FDT_ENTRY" + default false + help + BACnet data types supported for WriteProperty: FDT_ENTRY + config BACAPP_PRINT_ENABLED bool "BACnet app print" default false