Feature/add create object service (#476)
Added BACnet CreateObject and DeleteObject services * refactored codec for BACnetPropertyValue into bacapp module * added unit tests for BACnetPropertyValue * refactored COV and Events to use BACnetPropertyValue codec API * added unit tests for COV * added overrun safe decoders for tag numbers and boolean context * added unit tests and codecs for CreateObject and DeleteObject services * added APDU service handers and senders for CreateObject and DeleteObject services * added command line apps bacco and bacdo for CreateObject and DeleteObject services * added CreateObject and DeleteObject service handling in example server app and device object * added new BACnetRejectReason, Error Class, and BACnetAbortReason enumerations and conversions --------- Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
+238
-243
@@ -50,88 +50,94 @@ Unconfirmed COV Notification
|
||||
*/
|
||||
|
||||
/**
|
||||
* Encode APDU for notification.
|
||||
*
|
||||
* @param apdu Pointer to the buffer.
|
||||
* @brief Encode APDU for COV Notification.
|
||||
* @param apdu Pointer to the buffer, or NULL for length
|
||||
* @param data Pointer to the data to encode.
|
||||
*
|
||||
* @return bytes encoded or zero on error.
|
||||
*/
|
||||
static int notify_encode_apdu(
|
||||
uint8_t *apdu, unsigned max_apdu_len, BACNET_COV_DATA *data)
|
||||
int cov_notify_encode_apdu(uint8_t *apdu, BACNET_COV_DATA *data)
|
||||
{
|
||||
int len = 0; /* length of each encoding */
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
BACNET_PROPERTY_VALUE *value = NULL; /* value in list */
|
||||
BACNET_APPLICATION_DATA_VALUE *app_data = NULL;
|
||||
|
||||
(void)max_apdu_len;
|
||||
if (apdu) {
|
||||
/* tag 0 - subscriberProcessIdentifier */
|
||||
len = encode_context_unsigned(
|
||||
&apdu[apdu_len], 0, data->subscriberProcessIdentifier);
|
||||
len =
|
||||
encode_context_unsigned(apdu, 0, data->subscriberProcessIdentifier);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu += len;
|
||||
}
|
||||
/* tag 1 - initiatingDeviceIdentifier */
|
||||
len = encode_context_object_id(&apdu[apdu_len], 1, OBJECT_DEVICE,
|
||||
data->initiatingDeviceIdentifier);
|
||||
len = encode_context_object_id(
|
||||
apdu, 1, OBJECT_DEVICE, data->initiatingDeviceIdentifier);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu += len;
|
||||
}
|
||||
/* tag 2 - monitoredObjectIdentifier */
|
||||
len = encode_context_object_id(&apdu[apdu_len], 2,
|
||||
len = encode_context_object_id(apdu, 2,
|
||||
data->monitoredObjectIdentifier.type,
|
||||
data->monitoredObjectIdentifier.instance);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu += len;
|
||||
}
|
||||
/* tag 3 - timeRemaining */
|
||||
len = encode_context_unsigned(&apdu[apdu_len], 3, data->timeRemaining);
|
||||
len = encode_context_unsigned(apdu, 3, data->timeRemaining);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu += len;
|
||||
}
|
||||
/* tag 4 - listOfValues */
|
||||
len = encode_opening_tag(&apdu[apdu_len], 4);
|
||||
len = encode_opening_tag(apdu, 4);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu += len;
|
||||
}
|
||||
/* the first value includes a pointer to the next value, etc */
|
||||
/* FIXME: for small implementations, we might try a partial
|
||||
approach like the rpm.c where the values are encoded with
|
||||
a separate function */
|
||||
value = data->listOfValues;
|
||||
while (value != NULL) {
|
||||
/* tag 0 - propertyIdentifier */
|
||||
len = encode_context_enumerated(
|
||||
&apdu[apdu_len], 0, value->propertyIdentifier);
|
||||
len = bacapp_property_value_encode(apdu, value);
|
||||
apdu_len += len;
|
||||
/* tag 1 - propertyArrayIndex OPTIONAL */
|
||||
if (value->propertyArrayIndex != BACNET_ARRAY_ALL) {
|
||||
len = encode_context_unsigned(
|
||||
&apdu[apdu_len], 1, value->propertyArrayIndex);
|
||||
apdu_len += len;
|
||||
}
|
||||
/* tag 2 - value */
|
||||
/* abstract syntax gets enclosed in a context tag */
|
||||
len = encode_opening_tag(&apdu[apdu_len], 2);
|
||||
apdu_len += len;
|
||||
app_data = &value->value;
|
||||
while (app_data != NULL) {
|
||||
len = bacapp_encode_application_data(&apdu[apdu_len], app_data);
|
||||
apdu_len += len;
|
||||
app_data = app_data->next;
|
||||
}
|
||||
|
||||
len = encode_closing_tag(&apdu[apdu_len], 2);
|
||||
apdu_len += len;
|
||||
/* tag 3 - priority OPTIONAL */
|
||||
if (value->priority != BACNET_NO_PRIORITY) {
|
||||
len = encode_context_unsigned(
|
||||
&apdu[apdu_len], 3, value->priority);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu += len;
|
||||
}
|
||||
/* is there another one to encode? */
|
||||
/* FIXME: check to see if there is room in the APDU */
|
||||
value = value->next;
|
||||
}
|
||||
len = encode_closing_tag(&apdu[apdu_len], 4);
|
||||
len = encode_closing_tag(apdu, 4);
|
||||
apdu_len += len;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode APDU for notification.
|
||||
*
|
||||
* @param apdu Pointer to the buffer for encoding into
|
||||
* @param apdu_size number of bytes available in the buffer
|
||||
* @param data Pointer to the data to encode.
|
||||
*
|
||||
* @return bytes encoded or zero if unable to encode
|
||||
*/
|
||||
static int notify_encode_apdu(
|
||||
uint8_t *apdu, unsigned apdu_size, BACNET_COV_DATA *data)
|
||||
{
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
|
||||
apdu_len = cov_notify_encode_apdu(NULL, data);
|
||||
if (apdu_len > apdu_size) {
|
||||
apdu_len = 0;
|
||||
} else {
|
||||
apdu_len = cov_notify_encode_apdu(apdu, data);
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode APDU for confirmed notification.
|
||||
*
|
||||
@@ -158,7 +164,7 @@ int ccov_notify_encode_apdu(uint8_t *apdu,
|
||||
apdu_len = 4;
|
||||
len =
|
||||
notify_encode_apdu(&apdu[apdu_len], max_apdu_len - apdu_len, data);
|
||||
if (len < 0) {
|
||||
if (len <= 0) {
|
||||
/* return the error */
|
||||
apdu_len = len;
|
||||
} else {
|
||||
@@ -190,7 +196,7 @@ int ucov_notify_encode_apdu(
|
||||
apdu_len = 2;
|
||||
len =
|
||||
notify_encode_apdu(&apdu[apdu_len], max_apdu_len - apdu_len, data);
|
||||
if (len < 0) {
|
||||
if (len <= 0) {
|
||||
/* return the error */
|
||||
apdu_len = len;
|
||||
} else {
|
||||
@@ -202,164 +208,120 @@ int ucov_notify_encode_apdu(
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the COV-service request only.
|
||||
* Note: COV and Unconfirmed COV are the same.
|
||||
* @brief Decode the COV-service request only.
|
||||
*
|
||||
* ConfirmedCOVNotification-Request ::= SEQUENCE {
|
||||
* subscriber-process-identifier [0] Unsigned32,
|
||||
* initiating-device-identifier [1] BACnetObjectIdentifier,
|
||||
* monitored-object-identifier [2] BACnetObjectIdentifier,
|
||||
* time-remaining [3] Unsigned,
|
||||
* list-of-values [4] SEQUENCE OF BACnetPropertyValue
|
||||
* }
|
||||
*
|
||||
* @note: COV and Unconfirmed COV are the same.
|
||||
* @param apdu Pointer to the buffer.
|
||||
* @param apdu_len Count of valid bytes in the buffer.
|
||||
* @param data Pointer to the data to store the decoded values.
|
||||
* @param apdu_size Number of valid bytes in the buffer.
|
||||
* @param data Pointer to the data to store the decoded values, or NULL
|
||||
*
|
||||
* @return Bytes decoded or Zero/BACNET_STATUS_ERROR on error.
|
||||
* @return Bytes decoded or BACNET_STATUS_ERROR on error.
|
||||
*/
|
||||
int cov_notify_decode_service_request(
|
||||
uint8_t *apdu, unsigned apdu_len, BACNET_COV_DATA *data)
|
||||
uint8_t *apdu, unsigned apdu_size, BACNET_COV_DATA *data)
|
||||
{
|
||||
int len = 0; /* return value */
|
||||
int app_len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
BACNET_UNSIGNED_INTEGER decoded_value = 0; /* for decoding */
|
||||
BACNET_OBJECT_TYPE decoded_type = OBJECT_NONE; /* for decoding */
|
||||
uint32_t property = 0; /* for decoding */
|
||||
BACNET_PROPERTY_VALUE *value = NULL; /* value in list */
|
||||
BACNET_APPLICATION_DATA_VALUE *app_data = NULL;
|
||||
int value_len = 0, tag_len = 0;
|
||||
BACNET_UNSIGNED_INTEGER decoded_value = 0;
|
||||
BACNET_OBJECT_TYPE decoded_type = OBJECT_NONE;
|
||||
uint32_t decoded_instance = 0;
|
||||
BACNET_PROPERTY_ID property_identifier = PROP_ALL;
|
||||
BACNET_PROPERTY_VALUE *value = NULL;
|
||||
|
||||
if ((apdu_len > 2) && data) {
|
||||
/* tag 0 - subscriberProcessIdentifier */
|
||||
if (decode_is_context_tag(&apdu[len], 0)) {
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
/* subscriber-process-identifier [0] Unsigned32 */
|
||||
value_len = bacnet_unsigned_context_decode(
|
||||
&apdu[len], apdu_size - len, 0, &decoded_value);
|
||||
if (value_len > 0) {
|
||||
if (data) {
|
||||
data->subscriberProcessIdentifier = decoded_value;
|
||||
} else {
|
||||
}
|
||||
len += value_len;
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* initiating-device-identifier [1] BACnetObjectIdentifier */
|
||||
value_len = bacnet_object_id_context_decode(
|
||||
&apdu[len], apdu_size - len, 1, &decoded_type, &decoded_instance);
|
||||
if (value_len > 0) {
|
||||
if (decoded_type != OBJECT_DEVICE) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* tag 1 - initiatingDeviceIdentifier */
|
||||
if (len >= (int)apdu_len) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
if (data) {
|
||||
data->initiatingDeviceIdentifier = decoded_instance;
|
||||
}
|
||||
if (decode_is_context_tag(&apdu[len], 1)) {
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
len += decode_object_id(
|
||||
&apdu[len], &decoded_type, &data->initiatingDeviceIdentifier);
|
||||
if (decoded_type != OBJECT_DEVICE) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* tag 2 - monitoredObjectIdentifier */
|
||||
if (len >= (int)apdu_len) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (decode_is_context_tag(&apdu[len], 2)) {
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
len += decode_object_id(&apdu[len], &decoded_type,
|
||||
&data->monitoredObjectIdentifier.instance);
|
||||
len += value_len;
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* monitored-object-identifier [2] BACnetObjectIdentifier */
|
||||
value_len = bacnet_object_id_context_decode(
|
||||
&apdu[len], apdu_size - len, 2, &decoded_type, &decoded_instance);
|
||||
if (value_len > 0) {
|
||||
if (data) {
|
||||
data->monitoredObjectIdentifier.type = decoded_type;
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
data->monitoredObjectIdentifier.instance = decoded_instance;
|
||||
}
|
||||
/* tag 3 - timeRemaining */
|
||||
if (len >= (int)apdu_len) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (decode_is_context_tag(&apdu[len], 3)) {
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
len += value_len;
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* time-remaining [3] Unsigned */
|
||||
value_len = bacnet_unsigned_context_decode(
|
||||
&apdu[len], apdu_size - len, 3, &decoded_value);
|
||||
if (value_len > 0) {
|
||||
if (data) {
|
||||
data->timeRemaining = decoded_value;
|
||||
}
|
||||
len += value_len;
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* list-of-values [4] SEQUENCE OF BACnetPropertyValue */
|
||||
if (bacnet_is_opening_tag_number(
|
||||
&apdu[len], apdu_size - len, 4, &tag_len)) {
|
||||
if (data) {
|
||||
len += tag_len;
|
||||
/* the first value includes a pointer to the next value, etc */
|
||||
value = data->listOfValues;
|
||||
while (value != NULL) {
|
||||
value_len = bacapp_property_value_decode(
|
||||
&apdu[len], apdu_size - len, value);
|
||||
if (value_len == BACNET_STATUS_ERROR) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
} else {
|
||||
len += value_len;
|
||||
}
|
||||
/* end of list? */
|
||||
if (bacnet_is_closing_tag_number(
|
||||
&apdu[len], apdu_size - len, 4, &tag_len)) {
|
||||
len += tag_len;
|
||||
value->next = NULL;
|
||||
break;
|
||||
}
|
||||
/* is there another one to decode? */
|
||||
value = value->next;
|
||||
if (value == NULL) {
|
||||
/* out of room to store next value */
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* tag 4: opening context tag - listOfValues */
|
||||
if (!decode_is_opening_tag_number(&apdu[len], 4)) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* a tag number of 4 is not extended so only one octet */
|
||||
len++;
|
||||
/* the first value includes a pointer to the next value, etc */
|
||||
value = data->listOfValues;
|
||||
if (value == NULL) {
|
||||
/* no space to store any values */
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
while (value != NULL) {
|
||||
/* tag 0 - propertyIdentifier */
|
||||
if (len >= (int)apdu_len) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (decode_is_context_tag(&apdu[len], 0)) {
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
len += decode_enumerated(&apdu[len], len_value, &property);
|
||||
value->propertyIdentifier = (BACNET_PROPERTY_ID)property;
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* tag 1 - propertyArrayIndex OPTIONAL */
|
||||
if (len >= (int)apdu_len) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (decode_is_context_tag(&apdu[len], 1)) {
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
value->propertyArrayIndex = decoded_value;
|
||||
} else {
|
||||
value->propertyArrayIndex = BACNET_ARRAY_ALL;
|
||||
}
|
||||
/* tag 2: opening context tag - value */
|
||||
if (len >= (int)apdu_len) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (!decode_is_opening_tag_number(&apdu[len], 2)) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* a tag number of 2 is not extended so only one octet */
|
||||
len++;
|
||||
app_data = &value->value;
|
||||
while (!decode_is_closing_tag_number(&apdu[len], 2)) {
|
||||
if (app_data == NULL) {
|
||||
/* out of room to store more values */
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
app_len = bacapp_decode_application_data(
|
||||
&apdu[len], apdu_len - len, app_data);
|
||||
if (app_len < 0) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
len += app_len;
|
||||
|
||||
app_data = app_data->next;
|
||||
}
|
||||
/* a tag number of 2 is not extended so only one octet */
|
||||
len++;
|
||||
/* tag 3 - priority OPTIONAL */
|
||||
if (len >= (int)apdu_len) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (decode_is_context_tag(&apdu[len], 3)) {
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &decoded_value);
|
||||
value->priority = (uint8_t)decoded_value;
|
||||
} else {
|
||||
value->priority = BACNET_NO_PRIORITY;
|
||||
}
|
||||
/* end of list? */
|
||||
if (decode_is_closing_tag_number(&apdu[len], 4)) {
|
||||
value->next = NULL;
|
||||
break;
|
||||
}
|
||||
/* is there another one to decode? */
|
||||
value = value->next;
|
||||
if (value == NULL) {
|
||||
/* out of room to store more values */
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* this len function needs to start at the opening tag
|
||||
to match opening/closing tags like a stack.
|
||||
However, it returns the len between the tags. */
|
||||
value_len = bacapp_data_len(&apdu[len], apdu_size - len,
|
||||
(BACNET_PROPERTY_ID)property_identifier);
|
||||
len += value_len;
|
||||
/* add the opening tag length to the totals */
|
||||
len += tag_len;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,79 +404,112 @@ int cov_subscribe_encode_apdu(uint8_t *apdu,
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the subscribe-service request only.
|
||||
* @brief Decode the subscribe-service request only.
|
||||
*
|
||||
* SubscribeCOV-Request ::= SEQUENCE {
|
||||
* subscriberProcessIdentifier [0] Unsigned32,
|
||||
* monitoredObjectIdentifier [1] BACnetObjectIdentifier,
|
||||
* issueConfirmedNotifications [2] BOOLEAN OPTIONAL,
|
||||
* lifetime [3] Unsigned OPTIONAL
|
||||
* }
|
||||
*
|
||||
* @param apdu Pointer to the buffer.
|
||||
* @param apdu_len Count of valid bytes in the buffer.
|
||||
* @param apdu_size number of valid bytes in the buffer.
|
||||
* @param data Pointer to the data to store the decoded values.
|
||||
*
|
||||
* @return Bytes decoded or Zero/BACNET_STATUS_ERROR on error.
|
||||
*/
|
||||
int cov_subscribe_decode_service_request(
|
||||
uint8_t *apdu, unsigned apdu_len, BACNET_SUBSCRIBE_COV_DATA *data)
|
||||
uint8_t *apdu, unsigned apdu_size, BACNET_SUBSCRIBE_COV_DATA *data)
|
||||
{
|
||||
int len = 0; /* return value */
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
|
||||
int value_len = 0;
|
||||
BACNET_UNSIGNED_INTEGER decoded_value = 0;
|
||||
BACNET_OBJECT_TYPE decoded_type = OBJECT_NONE;
|
||||
uint32_t decoded_instance = 0;
|
||||
bool decoded_boolean = false;
|
||||
|
||||
if ((apdu_len > 2) && data) {
|
||||
/* tag 0 - subscriberProcessIdentifier */
|
||||
if (decode_is_context_tag(&apdu[len], 0)) {
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
len += decode_unsigned(&apdu[len], len_value, &unsigned_value);
|
||||
data->subscriberProcessIdentifier = unsigned_value;
|
||||
} else {
|
||||
/* subscriberProcessIdentifier [0] Unsigned32 */
|
||||
value_len = bacnet_unsigned_context_decode(
|
||||
&apdu[len], apdu_size - len, 0, &decoded_value);
|
||||
if (value_len > 0) {
|
||||
if (data) {
|
||||
data->subscriberProcessIdentifier = decoded_value;
|
||||
}
|
||||
len += value_len;
|
||||
} else {
|
||||
if (data) {
|
||||
data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
/* tag 1 - monitoredObjectIdentifier */
|
||||
if ((unsigned)len >= apdu_len) {
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
if (decode_is_context_tag(&apdu[len], 1)) {
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
len += decode_object_id(&apdu[len], &decoded_type,
|
||||
&data->monitoredObjectIdentifier.instance);
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* monitoredObjectIdentifier [1] BACnetObjectIdentifier */
|
||||
value_len = bacnet_object_id_context_decode(
|
||||
&apdu[len], apdu_size - len, 1, &decoded_type, &decoded_instance);
|
||||
if (value_len > 0) {
|
||||
if (data) {
|
||||
data->monitoredObjectIdentifier.type = decoded_type;
|
||||
} else {
|
||||
data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
return BACNET_STATUS_REJECT;
|
||||
data->monitoredObjectIdentifier.instance = decoded_instance;
|
||||
}
|
||||
/* optional parameters - if missing, means cancellation */
|
||||
if ((unsigned)len < apdu_len) {
|
||||
/* tag 2 - issueConfirmedNotifications - optional */
|
||||
if (decode_is_context_tag(&apdu[len], 2)) {
|
||||
data->cancellationRequest = false;
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
data->issueConfirmedNotifications =
|
||||
decode_context_boolean(&apdu[len]);
|
||||
len += len_value;
|
||||
} else {
|
||||
data->cancellationRequest = true;
|
||||
len += value_len;
|
||||
} else {
|
||||
if (data) {
|
||||
data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
}
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if ((unsigned)len < apdu_size) {
|
||||
if (data) {
|
||||
/* does not indicate a cancellation request */
|
||||
data->cancellationRequest = false;
|
||||
}
|
||||
/* issueConfirmedNotifications [2] BOOLEAN OPTIONAL */
|
||||
value_len = bacnet_boolean_context_decode(
|
||||
&apdu[len], apdu_size - len, 2, &decoded_boolean);
|
||||
if (value_len > 0) {
|
||||
if (data) {
|
||||
data->issueConfirmedNotifications = decoded_boolean;
|
||||
}
|
||||
/* tag 3 - lifetime - optional */
|
||||
if ((unsigned)len < apdu_len) {
|
||||
if (decode_is_context_tag(&apdu[len], 3)) {
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
len +=
|
||||
decode_unsigned(&apdu[len], len_value, &unsigned_value);
|
||||
data->lifetime = unsigned_value;
|
||||
} else {
|
||||
data->lifetime = 0;
|
||||
}
|
||||
} else {
|
||||
data->lifetime = 0;
|
||||
len += value_len;
|
||||
} else if (value_len == 0) {
|
||||
/* invalid tag */
|
||||
if (data) {
|
||||
data->issueConfirmedNotifications = false;
|
||||
}
|
||||
} else {
|
||||
if (data) {
|
||||
data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
}
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
} else {
|
||||
/* If both the 'Issue Confirmed Notifications' and
|
||||
'Lifetime' parameters are absent, then this shall
|
||||
indicate a cancellation request. */
|
||||
if (data) {
|
||||
data->cancellationRequest = true;
|
||||
}
|
||||
}
|
||||
if ((unsigned)len < apdu_size) {
|
||||
/* lifetime [3] Unsigned OPTIONAL */
|
||||
value_len = bacnet_unsigned_context_decode(
|
||||
&apdu[len], apdu_size - len, 3, &decoded_value);
|
||||
if (value_len > 0) {
|
||||
if (data) {
|
||||
data->lifetime = decoded_value;
|
||||
}
|
||||
len += value_len;
|
||||
} else {
|
||||
if (data) {
|
||||
data->error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
}
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
} else {
|
||||
if (data) {
|
||||
data->lifetime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user