From f1eaa4e154dc06b2997bd58e02351974975cac3e Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Mon, 2 Sep 2024 08:21:48 -0500 Subject: [PATCH] [WIP] fixing BACnetAccessRule encoding and decoding. --- src/bacnet/access_rule.c | 227 ++++++++++++++++++++++++--------------- src/bacnet/access_rule.h | 14 ++- 2 files changed, 156 insertions(+), 85 deletions(-) diff --git a/src/bacnet/access_rule.c b/src/bacnet/access_rule.c index d3168dba..1b0fc757 100644 --- a/src/bacnet/access_rule.c +++ b/src/bacnet/access_rule.c @@ -10,143 +10,202 @@ #include "bacnet/access_rule.h" #include "bacnet/bacdcode.h" +/** + * @brief Encode the BACnetAccessRule + * + * BACnetAccessRule ::= SEQUENCE { + * time-range-specifier [0] ENUMERATED { + * specified (0), + * always (1) + * }, + * time-range[1] BACnetDeviceObjectPropertyReference OPTIONAL, + * -- to be present if time-range-specifier has the value "specified" + * location-specifier [2] ENUMERATED { + * specified (0), + * all (1) + * }, + * location [3] BACnetDeviceObjectReference OPTIONAL, + * -- to be present if location-specifier has the value "specified" + * enable [4] BOOLEAN + * } + * + * @param apdu Pointer to the buffer for encoding, or NULL for length + * @param rule Pointer to the data to be encoded + * @return number of bytes encoded + */ int bacapp_encode_access_rule(uint8_t *apdu, const BACNET_ACCESS_RULE *rule) { int len; int apdu_len = 0; - len = encode_context_enumerated(&apdu[0], 0, rule->time_range_specifier); + len = encode_context_enumerated(apdu, 0, rule->time_range_specifier); apdu_len += len; - + if (apdu) { + apdu += len; + } if (rule->time_range_specifier == TIME_RANGE_SPECIFIER_SPECIFIED) { len = bacapp_encode_context_device_obj_property_ref( - &apdu[apdu_len], 1, &rule->time_range); - if (len > 0) { - apdu_len += len; - } else { - return -1; + apdu, 1, &rule->time_range); + apdu_len += len; + if (apdu) { + apdu += len; } } - - len = - encode_context_enumerated(&apdu[apdu_len], 2, rule->location_specifier); + len = encode_context_enumerated(apdu, 2, rule->location_specifier); apdu_len += len; - + if (apdu) { + apdu += len; + } if (rule->location_specifier == LOCATION_SPECIFIER_SPECIFIED) { - len = bacapp_encode_context_device_obj_property_ref( - &apdu[apdu_len], 3, &rule->location); - if (len > 0) { - apdu_len += len; - } else { - return -1; + len = bacapp_encode_context_device_obj_ref(apdu, 3, &rule->location); + apdu_len += len; + if (apdu) { + apdu += len; } } - - len = encode_context_boolean(&apdu[apdu_len], 4, rule->enable); + len = encode_context_boolean(apdu, 4, rule->enable); apdu_len += len; return apdu_len; } +/** + * @brief Encode the BACnetAccessRule as Context Tagged + * @param apdu Pointer to the buffer for encoding, or NULL for length + * @param tag_number Tag number + * @param rule Pointer to the data to be encoded + * @return number of bytes encoded + */ int bacapp_encode_context_access_rule( uint8_t *apdu, uint8_t tag_number, const BACNET_ACCESS_RULE *rule) { int len; int apdu_len = 0; - len = encode_opening_tag(&apdu[apdu_len], tag_number); + len = encode_opening_tag(apdu, tag_number); apdu_len += len; - - len = bacapp_encode_access_rule(&apdu[apdu_len], rule); + if (apdu) { + apdu += len; + } + len = bacapp_encode_access_rule(apdu, rule); apdu_len += len; - - len = encode_closing_tag(&apdu[apdu_len], tag_number); + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, tag_number); apdu_len += len; return apdu_len; } -int bacapp_decode_access_rule(const uint8_t *apdu, BACNET_ACCESS_RULE *rule) +/** + * @brief Decode the BACnetAccessRule + * @param apdu Pointer to the buffer for decoding. + * @param apdu_size The size of the buffer for decoding. + * @param data Pointer to the data to be stored + * @return number of bytes decoded or BACNET_STATUS_ERROR on error + */ +int bacnet_access_rule_decode( + const uint8_t *apdu, size_t apdu_size, BACNET_ACCESS_RULE *data) { int len; int apdu_len = 0; - uint32_t time_range_specifier = rule->time_range_specifier; - uint32_t location_specifier = rule->location_specifier; + uint32_t enumerated_value = 0, time_range_specifier = 0, + location_specifier = 0; + BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *reference = NULL; + BACNET_DEVICE_OBJECT_REFERENCE *location_reference = NULL; + bool boolean_value = false; - if (decode_is_context_tag(&apdu[apdu_len], 0)) { - len = decode_context_enumerated( - &apdu[apdu_len], 0, &time_range_specifier); - if (len < 0) { - return -1; - } else if (time_range_specifier < TIME_RANGE_SPECIFIER_MAX) { - apdu_len += len; - rule->time_range_specifier = + /* time-range-specifier [0] ENUMERATED { + specified (0), + always (1) + } + */ + len = bacnet_enumerated_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 0, &enumerated_value); + if (len <= 0) { + return BACNET_STATUS_ERROR; + } else if (enumerated_value < TIME_RANGE_SPECIFIER_MAX) { + time_range_specifier = enumerated_value; + if (data) { + data->time_range_specifier = (BACNET_ACCESS_RULE_TIME_RANGE_SPECIFIER)time_range_specifier; - } else { - return -1; } } else { - return -1; + return BACNET_STATUS_ERROR; } - - if (rule->time_range_specifier == TIME_RANGE_SPECIFIER_SPECIFIED) { - if (decode_is_context_tag(&apdu[apdu_len], 1)) { - len = bacapp_decode_context_device_obj_property_ref( - &apdu[apdu_len], 1, &rule->time_range); - if (len < 0) { - return -1; - } else { - apdu_len += len; - } - } else { - return -1; + apdu_len += len; + /* time-range[1] BACnetDeviceObjectPropertyReference OPTIONAL, + -- to be present if time-range-specifier has the value "specified" */ + if (time_range_specifier == TIME_RANGE_SPECIFIER_SPECIFIED) { + if (data) { + reference = &data->time_range; } + len = bacnet_device_object_property_reference_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 1, reference); + if (len <= 0) { + return BACNET_STATUS_ERROR; + } + apdu_len += len; } - - if (decode_is_context_tag(&apdu[apdu_len], 2)) { - len = - decode_context_enumerated(&apdu[apdu_len], 2, &location_specifier); - if (len < 0) { - return -1; - } else if (location_specifier < LOCATION_SPECIFIER_MAX) { - apdu_len += len; - rule->location_specifier = + /* time-range-specifier [0] ENUMERATED { + specified (0), + always (1) + } + */ + len = bacnet_enumerated_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 2, &enumerated_value); + if (len <= 0) { + return BACNET_STATUS_ERROR; + } else if (enumerated_value < LOCATION_SPECIFIER_MAX) { + location_specifier = enumerated_value; + if (data) { + data->location_specifier = (BACNET_ACCESS_RULE_LOCATION_SPECIFIER)location_specifier; - } else { - return -1; } } else { - return -1; + return BACNET_STATUS_ERROR; } - - if (rule->location_specifier == LOCATION_SPECIFIER_SPECIFIED) { - if (decode_is_context_tag(&apdu[apdu_len], 3)) { - len = bacapp_decode_context_device_obj_property_ref( - &apdu[apdu_len], 3, &rule->location); - if (len < 0) { - return -1; - } else { - apdu_len += len; - } - } else { - return -1; + apdu_len += len; + /* location [3] BACnetDeviceObjectReference OPTIONAL, + -- to be present if location-specifier has the value "specified" */ + if (location_specifier == LOCATION_SPECIFIER_SPECIFIED) { + if (data) { + location_reference = &data->location; } - } - - if (decode_is_context_tag(&apdu[apdu_len], 4)) { - len = decode_context_boolean2(&apdu[apdu_len], 4, &rule->enable); - if (len < 0) { - return -1; - } else { - apdu_len += len; + len = bacnet_device_object_reference_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 3, location_reference); + if (len <= 0) { + return BACNET_STATUS_ERROR; } - } else { - return -1; + apdu_len += len; } + /* enable [4] BOOLEAN */ + len = bacnet_boolean_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 4, &boolean_value); + if (len <= 0) { + return BACNET_STATUS_ERROR; + } + if (data) { + data->enable = boolean_value; + } + apdu_len += len; return apdu_len; } +/** + * @brief Decode the BACnetAccessRule + * @param apdu Pointer to the buffer for decoding. + * @param rule Pointer to the data to be stored + * @return number of bytes decoded + * @deprecated Use bacapp_access_rule_decode() instead + */ +int bacapp_decode_access_rule(const uint8_t *apdu, BACNET_ACCESS_RULE *rule) +{ + return bacnet_access_rule_decode(apdu, MAX_APDU, rule); +} + int bacapp_decode_context_access_rule( const uint8_t *apdu, uint8_t tag_number, BACNET_ACCESS_RULE *rule) { diff --git a/src/bacnet/access_rule.h b/src/bacnet/access_rule.h index efd84584..04a884c7 100644 --- a/src/bacnet/access_rule.h +++ b/src/bacnet/access_rule.h @@ -32,7 +32,7 @@ typedef struct { BACNET_ACCESS_RULE_TIME_RANGE_SPECIFIER time_range_specifier; BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE time_range; BACNET_ACCESS_RULE_LOCATION_SPECIFIER location_specifier; - BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE location; + BACNET_DEVICE_OBJECT_REFERENCE location; bool enable; } BACNET_ACCESS_RULE; @@ -45,12 +45,24 @@ int bacapp_encode_access_rule(uint8_t *apdu, const BACNET_ACCESS_RULE *rule); BACNET_STACK_EXPORT int bacapp_encode_context_access_rule( uint8_t *apdu, uint8_t tag_number, const BACNET_ACCESS_RULE *rule); +BACNET_STACK_DEPRECATED("Use bacnet_access_rule_decode() instead") BACNET_STACK_EXPORT int bacapp_decode_access_rule(const uint8_t *apdu, BACNET_ACCESS_RULE *rule); +BACNET_STACK_DEPRECATED("Use bacnet_access_rule_context_decode() instead") BACNET_STACK_EXPORT int bacapp_decode_context_access_rule( const uint8_t *apdu, uint8_t tag_number, BACNET_ACCESS_RULE *rule); +BACNET_STACK_EXPORT +int bacnet_access_rule_decode( + const uint8_t *apdu, size_t apdu_size, BACNET_ACCESS_RULE *data); +BACNET_STACK_EXPORT +int bacnet_access_rule_context_decode( + const uint8_t *apdu, + size_t apdu_size, + uint8_t tag_number, + BACNET_ACCESS_RULE *data); + #ifdef __cplusplus } #endif /* __cplusplus */