Refactor/cov subscriptions encoding decoding test (#1296)

* Add BACnetRecipientProcess type encoding and decoding functions with associated tests

* Refactor COV subscription encoding and decoding functions to reduce code size and reuse existing unit tested functions.

* Refactor COV subscription handling to simplify error checking
This commit is contained in:
Steve Karg
2026-04-20 10:53:55 -05:00
committed by GitHub
parent 52561f2336
commit b9149dd639
15 changed files with 1151 additions and 171 deletions
+169
View File
@@ -19,8 +19,177 @@ COV Subscribe
COV Subscribe Property
COV Notification
Unconfirmed COV Notification
COV Subscription
*/
/**
* @brief Encode APDU for COV Subscription.
*
* BACnetCOVSubscription ::= SEQUENCE {
* recipient[0] BACnetRecipientProcess,
* monitored-property-reference[1] BACnetObjectPropertyReference,
* issue-confirmed-notifications[2] Boolean,
* time-remaining[3] Unsigned,
* cov-increment[4] Real OPTIONAL-- used only with monitored
* -- properties with a numeric datatype
* }
*
* @param apdu Pointer to the buffer, or NULL for length
* @param data Pointer to the data to encode.
* @return number of bytes encoded, or zero on error.
*/
size_t
cov_subscription_encode(uint8_t *apdu, const BACNET_COV_SUBSCRIPTION *data)
{
int len;
size_t apdu_len = 0; /* total length of the apdu, return value */
if (!data) {
return 0;
}
/* Recipient [0] BACnetRecipientProcess */
len = bacnet_recipient_process_context_encode(apdu, 0, &data->recipient);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* MonitoredPropertyReference [1] BACnetObjectPropertyReference, */
len = bacapp_encode_context_obj_property_ref(
apdu, 1, &data->monitored_property_reference);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* IssueConfirmedNotifications [2] BOOLEAN, */
len = encode_context_boolean(apdu, 2, data->issue_confirmed_notifications);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* TimeRemaining [3] Unsigned, */
len = encode_context_unsigned(apdu, 3, data->time_remaining);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* cov-increment [4] Real OPTIONAL */
if (data->cov_increment_present) {
len = encode_context_real(apdu, 4, data->cov_increment);
apdu_len += len;
}
return apdu_len;
}
/**
* @brief Encode APDU for COV Subscription.
* @param apdu Pointer to the buffer, or NULL for length
* @param apdu_size number of bytes available in the buffer
* @param data Pointer to the data to encode.
* @return number of bytes encoded, or zero on error.
*/
size_t bacnet_cov_subscription_encode(
uint8_t *apdu, size_t apdu_size, const BACNET_COV_SUBSCRIPTION *data)
{
size_t apdu_len = 0; /* total length of the apdu, return value */
apdu_len = cov_subscription_encode(NULL, data);
if (apdu_len > apdu_size) {
apdu_len = 0;
} else {
apdu_len = cov_subscription_encode(apdu, data);
}
return apdu_len;
}
/**
* @brief Decode APDU for COV Subscription.
*
* BACnetCOVSubscription ::= SEQUENCE {
* recipient[0] BACnetRecipientProcess,
* monitored-property-reference[1] BACnetObjectPropertyReference,
* issue-confirmed-notifications[2] Boolean,
* time-remaining[3] Unsigned,
* cov-increment[4] Real OPTIONAL-- used only with monitored
* -- properties with a numeric datatype
* }
*
* @param apdu Pointer to the buffer for decoding.
* @param apdu_size number of bytes available in the buffer
* @param data Pointer to the data to decode into, or NULL for length only.
* @return Bytes decoded or BACNET_STATUS_ERROR on error.
*/
int bacnet_cov_subscription_decode(
const uint8_t *apdu, size_t apdu_size, BACNET_COV_SUBSCRIPTION *data)
{
int len = 0, apdu_len = 0;
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
BACNET_RECIPIENT_PROCESS recipient = { 0 };
BACNET_OBJECT_PROPERTY_REFERENCE monitored_property_reference = { 0 };
bool issue_confirmed_notifications = false;
float float_value = 1.0f;
bool cov_increment_present = false;
if (!apdu || (apdu_size == 0)) {
return 0;
}
/* Recipient [0] BACnetRecipientProcess */
len = bacnet_recipient_process_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &recipient);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
/* MonitoredPropertyReference [1] BACnetObjectPropertyReference */
len = bacapp_decode_context_obj_property_ref(
&apdu[apdu_len], apdu_size - apdu_len, 1,
&monitored_property_reference);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
/* IssueConfirmedNotifications [2] BOOLEAN */
len = bacnet_boolean_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2,
&issue_confirmed_notifications);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
/* TimeRemaining [3] Unsigned */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 3, &unsigned_value);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
/* CovIncrement [4] Real OPTIONAL */
len = bacnet_real_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 4, &float_value);
if (len < 0) {
return BACNET_STATUS_ERROR;
} else if (len == 0) {
/* not present - skip */
cov_increment_present = false;
} else {
cov_increment_present = true;
apdu_len += len;
}
/* copy into the data structure */
if (data) {
bacnet_recipient_process_copy(&data->recipient, &recipient);
bacnet_object_property_reference_copy(
&data->monitored_property_reference, &monitored_property_reference);
data->issue_confirmed_notifications = issue_confirmed_notifications;
data->time_remaining = unsigned_value;
data->cov_increment = float_value;
data->cov_increment_present = cov_increment_present;
}
return apdu_len;
}
/**
* @brief Encode APDU for COV Notification.
* @param apdu Pointer to the buffer, or NULL for length