Files
bacnet_stack/src/bacnet/event.c
T
Kari Argillander f806c5829b Run clang-format and enable CI check for it (#755)
* pre-commit: Update and enable clang-format check

There is newer version from clang-format so use that. We do not yet want
18 as that is little bit too new.

* Format some thing by hand which clang-format "breaks"

Clang-format will format some things little bit off in some cases.
Format some things by hand so we get cleaner end result.

* Run clang-format with

```
pre-commit run --all-files clang-format
```

We have already in previously checked places where clang-format does not
make good format and ignored those (hopefully most of the things).

---------

Co-authored-by: Kari Argillander <kari.argillander@fidelix.com>
2024-08-30 11:20:58 -05:00

1405 lines
56 KiB
C

/**
* @file
* @brief BACnet EventNotification encode and decode functions
* @author John Minack <minack@users.sourceforge.net>
* @author Steve Karg <skarg@users.sourceforge.net>
* @date 2008
* @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
*/
#include <assert.h>
#include "bacnet/event.h"
#include "bacnet/bacdcode.h"
#include "bacnet/npdu.h"
#include "bacnet/timestamp.h"
#include "bacnet/authentication_factor.h"
/** @file event.c Encode/Decode Event Notifications */
/**
* @brief Decode the array of complex-event-type notification parameters
* @param apdu - apdu buffer
* @param apdu_size - APDU total length
* @param data - the event data struct to store the results in
* @return number of apdu bytes decoded, or BACNET_STATUS_ERROR on error.
*/
static int complex_event_type_values_decode(
const uint8_t *apdu,
unsigned apdu_size,
BACNET_EVENT_NOTIFICATION_DATA *data)
{
int len = 0; /* return value */
BACNET_PROPERTY_VALUE *value;
int value_len = 0, tag_len = 0;
#if (BACNET_DECODE_COMPLEX_EVENT_TYPE_PARAMETERS == 1)
/* we want to extract the values */
value = data->notificationParams.complexEventType.values;
bacapp_property_value_list_init(
value, BACNET_COMPLEX_EVENT_TYPE_MAX_PARAMETERS);
#else
/* we just want to discard the complex values */
BACNET_PROPERTY_VALUE dummyValue;
bacapp_property_value_list_init(&dummyValue, 1);
value = &dummyValue;
#endif
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, 6, &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;
}
}
return len;
}
/**
* @brief Encode the unconfirmed COVNotification service request
* @param apdu Pointer to the buffer for encoding into
* @param data Pointer to the service data used for encoding values
* @return number of bytes encoded, or zero if unable to encode
*/
int uevent_notify_encode_apdu(
uint8_t *apdu, const BACNET_EVENT_NOTIFICATION_DATA *data)
{
int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */
if (apdu) {
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
apdu[1] = SERVICE_UNCONFIRMED_EVENT_NOTIFICATION; /* service choice */
}
len = 2;
apdu_len += len;
if (apdu) {
apdu += len;
}
len = event_notify_encode_service_request(apdu, data);
if (len > 0) {
apdu_len += len;
} else {
apdu_len = 0;
}
return apdu_len;
}
/**
* @brief Encode the confirmed COVNotification service request
* @param apdu Pointer to the buffer for encoding into
* @param invoke_id ID to invoke for notification
* @param data Pointer to the service data used for encoding values
* @return number of bytes encoded, or zero if unable to encode
*/
int cevent_notify_encode_apdu(
uint8_t *apdu,
uint8_t invoke_id,
const BACNET_EVENT_NOTIFICATION_DATA *data)
{
int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */
if (apdu) {
apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST;
apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU);
apdu[2] = invoke_id;
apdu[3] = SERVICE_CONFIRMED_EVENT_NOTIFICATION; /* service choice */
}
len = 4;
apdu_len += len;
if (apdu) {
apdu += len;
}
len = event_notify_encode_service_request(apdu, data);
if (len > 0) {
apdu_len += len;
} else {
apdu_len = 0;
}
return apdu_len;
}
/**
* @brief Encode the COVNotification service request
* @param apdu Pointer to the buffer for encoding into
* @param data Pointer to the service data used for encoding values
* @return number of bytes encoded, or zero if unable to encode
*/
int event_notify_encode_service_request(
uint8_t *apdu, const BACNET_EVENT_NOTIFICATION_DATA *data)
{
int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */
if (!data) {
return 0;
}
/* tag 0 - processIdentifier */
len = encode_context_unsigned(apdu, 0, data->processIdentifier);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* tag 1 - initiatingObjectIdentifier */
len = encode_context_object_id(
apdu, 1, data->initiatingObjectIdentifier.type,
data->initiatingObjectIdentifier.instance);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* tag 2 - eventObjectIdentifier */
len = encode_context_object_id(
apdu, 2, data->eventObjectIdentifier.type,
data->eventObjectIdentifier.instance);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* tag 3 - timeStamp */
len = bacapp_encode_context_timestamp(apdu, 3, &data->timeStamp);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* tag 4 - noticicationClass */
len = encode_context_unsigned(apdu, 4, data->notificationClass);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* tag 5 - priority */
len = encode_context_unsigned(apdu, 5, data->priority);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* tag 6 - eventType */
len = encode_context_enumerated(apdu, 6, data->eventType);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* tag 7 - messageText */
if (data->messageText) {
len = encode_context_character_string(apdu, 7, data->messageText);
apdu_len += len;
if (apdu) {
apdu += len;
}
}
/* tag 8 - notifyType */
len = encode_context_enumerated(apdu, 8, data->notifyType);
apdu_len += len;
if (apdu) {
apdu += len;
}
switch (data->notifyType) {
case NOTIFY_ALARM:
case NOTIFY_EVENT:
/* tag 9 - ackRequired */
len = encode_context_boolean(apdu, 9, data->ackRequired);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* tag 10 - fromState */
len = encode_context_enumerated(apdu, 10, data->fromState);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
default:
break;
}
/* tag 11 - toState */
len = encode_context_enumerated(apdu, 11, data->toState);
apdu_len += len;
if (apdu) {
apdu += len;
}
switch (data->notifyType) {
case NOTIFY_ALARM:
case NOTIFY_EVENT:
/* tag 12 - event values */
len = encode_opening_tag(apdu, 12);
apdu_len += len;
if (apdu) {
apdu += len;
}
switch (data->eventType) {
case EVENT_CHANGE_OF_BITSTRING:
len = encode_opening_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_bitstring(
apdu, 0,
&data->notificationParams.changeOfBitstring
.referencedBitString);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.changeOfBitstring
.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
case EVENT_CHANGE_OF_STATE:
len = encode_opening_tag(apdu, 1);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_opening_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = bacapp_encode_property_state(
apdu, &data->notificationParams.changeOfState.newState);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.changeOfState.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 1);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
case EVENT_CHANGE_OF_VALUE:
len = encode_opening_tag(apdu, 2);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_opening_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
switch (data->notificationParams.changeOfValue.tag) {
case CHANGE_OF_VALUE_REAL:
len = encode_context_real(
apdu, 1,
data->notificationParams.changeOfValue.newValue
.changeValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
case CHANGE_OF_VALUE_BITS:
len = encode_context_bitstring(
apdu, 0,
&data->notificationParams.changeOfValue.newValue
.changedBits);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
default:
return 0;
}
len = encode_closing_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.changeOfValue.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 2);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
case EVENT_COMMAND_FAILURE:
len = encode_opening_tag(apdu, 3);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_opening_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
switch (data->notificationParams.commandFailure.tag) {
case COMMAND_FAILURE_BINARY_PV:
len = encode_application_enumerated(
apdu,
data->notificationParams.commandFailure
.commandValue.binaryValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
case COMMAND_FAILURE_UNSIGNED:
len = encode_application_unsigned(
apdu,
data->notificationParams.commandFailure
.commandValue.unsignedValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
default:
return 0;
}
len = encode_closing_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.commandFailure.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_opening_tag(apdu, 2);
apdu_len += len;
if (apdu) {
apdu += len;
}
switch (data->notificationParams.commandFailure.tag) {
case COMMAND_FAILURE_BINARY_PV:
len = encode_application_enumerated(
apdu,
data->notificationParams.commandFailure
.feedbackValue.binaryValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
case COMMAND_FAILURE_UNSIGNED:
len = encode_application_unsigned(
apdu,
data->notificationParams.commandFailure
.feedbackValue.unsignedValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
default:
return 0;
}
len = encode_closing_tag(apdu, 2);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 3);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
case EVENT_FLOATING_LIMIT:
len = encode_opening_tag(apdu, 4);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_real(
apdu, 0,
data->notificationParams.floatingLimit.referenceValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.floatingLimit.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_real(
apdu, 2,
data->notificationParams.floatingLimit.setPointValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_real(
apdu, 3,
data->notificationParams.floatingLimit.errorLimit);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 4);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
case EVENT_OUT_OF_RANGE:
len = encode_opening_tag(apdu, 5);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_real(
apdu, 0,
data->notificationParams.outOfRange.exceedingValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.outOfRange.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_real(
apdu, 2, data->notificationParams.outOfRange.deadband);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_real(
apdu, 3,
data->notificationParams.outOfRange.exceededLimit);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 5);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
case EVENT_CHANGE_OF_LIFE_SAFETY:
len = encode_opening_tag(apdu, 8);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_enumerated(
apdu, 0,
data->notificationParams.changeOfLifeSafety.newState);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_enumerated(
apdu, 1,
data->notificationParams.changeOfLifeSafety.newMode);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_bitstring(
apdu, 2,
&data->notificationParams.changeOfLifeSafety
.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_enumerated(
apdu, 3,
data->notificationParams.changeOfLifeSafety
.operationExpected);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 8);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
case EVENT_BUFFER_READY:
len = encode_opening_tag(apdu, 10);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = bacapp_encode_context_device_obj_property_ref(
apdu, 0,
&data->notificationParams.bufferReady.bufferProperty);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_unsigned(
apdu, 1,
data->notificationParams.bufferReady
.previousNotification);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_unsigned(
apdu, 2,
data->notificationParams.bufferReady
.currentNotification);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 10);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
case EVENT_UNSIGNED_RANGE:
len = encode_opening_tag(apdu, 11);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_unsigned(
apdu, 0,
data->notificationParams.unsignedRange.exceedingValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.unsignedRange.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_unsigned(
apdu, 2,
data->notificationParams.unsignedRange.exceededLimit);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 11);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
case EVENT_ACCESS_EVENT:
len = encode_opening_tag(apdu, 13);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_enumerated(
apdu, 0,
data->notificationParams.accessEvent.accessEvent);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.accessEvent.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_context_unsigned(
apdu, 2,
data->notificationParams.accessEvent.accessEventTag);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = bacapp_encode_context_timestamp(
apdu, 3,
&data->notificationParams.accessEvent.accessEventTime);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = bacapp_encode_context_device_obj_ref(
apdu, 4,
&data->notificationParams.accessEvent.accessCredential);
apdu_len += len;
if (apdu) {
apdu += len;
}
if (data->notificationParams.accessEvent
.authenticationFactor.format_type <
AUTHENTICATION_FACTOR_MAX) {
len = bacapp_encode_context_authentication_factor(
apdu, 5,
&data->notificationParams.accessEvent
.authenticationFactor);
apdu_len += len;
if (apdu) {
apdu += len;
}
}
len = encode_closing_tag(apdu, 13);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
case EVENT_EXTENDED:
default:
assert(0);
break;
}
len = encode_closing_tag(apdu, 12);
apdu_len += len;
break;
case NOTIFY_ACK_NOTIFICATION:
/* FIXME: handle this case */
default:
break;
}
return apdu_len;
}
/**
* @brief Encode the EventNotification service request
* @param apdu Pointer to the buffer for encoding into
* @param apdu_size number of bytes available in the buffer
* @param data Pointer to the service data used for encoding values
* @return number of bytes encoded, or zero if unable to encode or too large
*/
size_t event_notification_service_request_encode(
uint8_t *apdu, size_t apdu_size, const BACNET_EVENT_NOTIFICATION_DATA *data)
{
size_t apdu_len = 0; /* total length of the apdu, return value */
apdu_len = event_notify_encode_service_request(NULL, data);
if (apdu_len > apdu_size) {
apdu_len = 0;
} else {
apdu_len = event_notify_encode_service_request(apdu, data);
}
return apdu_len;
}
/**
* @brief Decode the EventNotification service request only.
* @param apdu Pointer to the buffer.
* @param apdu_len Number of valid bytes in the buffer.
* @param data Pointer to the data to store the decoded values, or NULL
*
* @return Bytes decoded or BACNET_STATUS_ERROR on error.
*/
int event_notify_decode_service_request(
const uint8_t *apdu,
unsigned apdu_len,
BACNET_EVENT_NOTIFICATION_DATA *data)
{
int len = 0; /* return value */
int section_length = 0;
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
uint32_t enum_value = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
bool is_complex_event_type = false;
if (apdu_len && data) {
/* tag 0 - processIdentifier */
section_length = bacnet_unsigned_context_decode(
&apdu[len], apdu_len - len, 0, &unsigned_value);
if (section_length > 0) {
len += section_length;
if (unsigned_value <= UINT32_MAX) {
data->processIdentifier = (uint32_t)unsigned_value;
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
/* tag 1 - initiatingObjectIdentifier */
if ((section_length = decode_context_object_id(
&apdu[len], 1, &data->initiatingObjectIdentifier.type,
&data->initiatingObjectIdentifier.instance)) == -1) {
return -1;
} else {
len += section_length;
}
/* tag 2 - eventObjectIdentifier */
if ((section_length = decode_context_object_id(
&apdu[len], 2, &data->eventObjectIdentifier.type,
&data->eventObjectIdentifier.instance)) == -1) {
return -1;
} else {
len += section_length;
}
/* tag 3 - timeStamp */
if ((section_length = bacapp_decode_context_timestamp(
&apdu[len], 3, &data->timeStamp)) == -1) {
return -1;
} else {
len += section_length;
}
/* tag 4 - noticicationClass */
section_length = bacnet_unsigned_context_decode(
&apdu[len], apdu_len - len, 4, &unsigned_value);
if (section_length > 0) {
len += section_length;
if (unsigned_value <= UINT32_MAX) {
data->notificationClass = (uint32_t)unsigned_value;
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
/* tag 5 - priority */
section_length = bacnet_unsigned_context_decode(
&apdu[len], apdu_len - len, 5, &unsigned_value);
if (section_length > 0) {
len += section_length;
if (unsigned_value <= UINT8_MAX) {
data->priority = (uint8_t)unsigned_value;
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
/* tag 6 - eventType */
if ((section_length =
decode_context_enumerated(&apdu[len], 6, &enum_value)) == -1) {
return -1;
} else {
data->eventType = (BACNET_EVENT_TYPE)enum_value;
len += section_length;
}
/* tag 7 - messageText */
if (decode_is_context_tag(&apdu[len], 7)) {
if (data->messageText != NULL) {
if ((section_length = decode_context_character_string(
&apdu[len], 7, data->messageText)) == -1) {
/*FIXME This is an optional parameter */
return -1;
} else {
len += section_length;
}
} else {
return -1;
}
} else {
if (data->messageText != NULL) {
characterstring_init_ansi(data->messageText, "");
}
}
/* tag 8 - notifyType */
if ((section_length =
decode_context_enumerated(&apdu[len], 8, &enum_value)) == -1) {
return -1;
} else {
data->notifyType = (BACNET_NOTIFY_TYPE)enum_value;
len += section_length;
}
switch (data->notifyType) {
case NOTIFY_ALARM:
case NOTIFY_EVENT:
/* tag 9 - ackRequired */
section_length =
decode_context_boolean2(&apdu[len], 9, &data->ackRequired);
if (section_length == BACNET_STATUS_ERROR) {
return -1;
}
len += section_length;
/* tag 10 - fromState */
if ((section_length = decode_context_enumerated(
&apdu[len], 10, &enum_value)) == -1) {
return -1;
} else {
data->fromState = (BACNET_EVENT_STATE)enum_value;
len += section_length;
}
break;
/* In cases other than alarm and event
there's no data, so do not return an error
but continue normally */
case NOTIFY_ACK_NOTIFICATION:
default:
break;
}
/* tag 11 - toState */
if ((section_length = decode_context_enumerated(
&apdu[len], 11, &enum_value)) == -1) {
return -1;
} else {
data->toState = (BACNET_EVENT_STATE)enum_value;
len += section_length;
}
/* tag 12 - eventValues */
switch (data->notifyType) {
case NOTIFY_ALARM:
case NOTIFY_EVENT:
if (decode_is_opening_tag_number(&apdu[len], 12)) {
len++;
} else {
return -1;
}
if (decode_is_opening_tag_number(
&apdu[len], (uint8_t)data->eventType)) {
len++;
switch (data->eventType) {
case EVENT_CHANGE_OF_BITSTRING:
if (-1 ==
(section_length = decode_context_bitstring(
&apdu[len], 0,
&data->notificationParams.changeOfBitstring
.referencedBitString))) {
return -1;
}
len += section_length;
if (-1 ==
(section_length = decode_context_bitstring(
&apdu[len], 1,
&data->notificationParams.changeOfBitstring
.statusFlags))) {
return -1;
}
len += section_length;
break;
case EVENT_CHANGE_OF_STATE:
if (-1 ==
(section_length =
bacapp_decode_context_property_state(
&apdu[len], 0,
&data->notificationParams.changeOfState
.newState))) {
return -1;
}
len += section_length;
if (-1 ==
(section_length = decode_context_bitstring(
&apdu[len], 1,
&data->notificationParams.changeOfState
.statusFlags))) {
return -1;
}
len += section_length;
break;
case EVENT_CHANGE_OF_VALUE:
if (!decode_is_opening_tag_number(&apdu[len], 0)) {
return -1;
}
len++;
if (decode_is_context_tag(
&apdu[len], CHANGE_OF_VALUE_BITS)) {
if (-1 ==
(section_length = decode_context_bitstring(
&apdu[len], 0,
&data->notificationParams.changeOfValue
.newValue.changedBits))) {
return -1;
}
len += section_length;
data->notificationParams.changeOfValue.tag =
CHANGE_OF_VALUE_BITS;
} else if (decode_is_context_tag(
&apdu[len], CHANGE_OF_VALUE_REAL)) {
if (-1 ==
(section_length = decode_context_real(
&apdu[len], 1,
&data->notificationParams.changeOfValue
.newValue.changeValue))) {
return -1;
}
len += section_length;
data->notificationParams.changeOfValue.tag =
CHANGE_OF_VALUE_REAL;
} else {
return -1;
}
if (!decode_is_closing_tag_number(&apdu[len], 0)) {
return -1;
}
len++;
if (-1 ==
(section_length = decode_context_bitstring(
&apdu[len], 1,
&data->notificationParams.changeOfValue
.statusFlags))) {
return -1;
}
len += section_length;
break;
case EVENT_COMMAND_FAILURE:
if (!decode_is_opening_tag_number(&apdu[len], 0)) {
return -1;
}
len++;
if (-1 ==
(section_length = decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value))) {
return -1;
}
len += section_length;
switch (tag_number) {
case BACNET_APPLICATION_TAG_ENUMERATED:
if (-1 ==
(section_length = decode_enumerated(
&apdu[len], len_value,
&enum_value))) {
return -1;
}
data->notificationParams.commandFailure
.commandValue.binaryValue = enum_value;
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
if (-1 ==
(section_length = decode_unsigned(
&apdu[len], len_value,
&data->notificationParams
.commandFailure.commandValue
.unsignedValue))) {
return -1;
}
break;
default:
return 0;
}
len += section_length;
if (!decode_is_closing_tag_number(&apdu[len], 0)) {
return -1;
}
len++;
if (-1 ==
(section_length = decode_context_bitstring(
&apdu[len], 1,
&data->notificationParams.commandFailure
.statusFlags))) {
return -1;
}
len += section_length;
if (!decode_is_opening_tag_number(&apdu[len], 2)) {
return -1;
}
len++;
if (-1 ==
(section_length = decode_tag_number_and_value(
&apdu[len], &tag_number, &len_value))) {
return -1;
}
len += section_length;
switch (tag_number) {
case BACNET_APPLICATION_TAG_ENUMERATED:
if (-1 ==
(section_length = decode_enumerated(
&apdu[len], len_value,
&enum_value))) {
return -1;
}
data->notificationParams.commandFailure
.feedbackValue.binaryValue = enum_value;
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
if (-1 ==
(section_length = decode_unsigned(
&apdu[len], len_value,
&data->notificationParams
.commandFailure.feedbackValue
.unsignedValue))) {
return -1;
}
break;
default:
return 0;
}
len += section_length;
if (!decode_is_closing_tag_number(&apdu[len], 2)) {
return -1;
}
len++;
break;
case EVENT_FLOATING_LIMIT:
if (-1 ==
(section_length = decode_context_real(
&apdu[len], 0,
&data->notificationParams.floatingLimit
.referenceValue))) {
return -1;
}
len += section_length;
if (-1 ==
(section_length = decode_context_bitstring(
&apdu[len], 1,
&data->notificationParams.floatingLimit
.statusFlags))) {
return -1;
}
len += section_length;
if (-1 ==
(section_length = decode_context_real(
&apdu[len], 2,
&data->notificationParams.floatingLimit
.setPointValue))) {
return -1;
}
len += section_length;
if (-1 ==
(section_length = decode_context_real(
&apdu[len], 3,
&data->notificationParams.floatingLimit
.errorLimit))) {
return -1;
}
len += section_length;
break;
case EVENT_OUT_OF_RANGE:
if (-1 ==
(section_length = decode_context_real(
&apdu[len], 0,
&data->notificationParams.outOfRange
.exceedingValue))) {
return -1;
}
len += section_length;
if (-1 ==
(section_length = decode_context_bitstring(
&apdu[len], 1,
&data->notificationParams.outOfRange
.statusFlags))) {
return -1;
}
len += section_length;
if (-1 ==
(section_length = decode_context_real(
&apdu[len], 2,
&data->notificationParams.outOfRange
.deadband))) {
return -1;
}
len += section_length;
if (-1 ==
(section_length = decode_context_real(
&apdu[len], 3,
&data->notificationParams.outOfRange
.exceededLimit))) {
return -1;
}
len += section_length;
break;
case EVENT_CHANGE_OF_LIFE_SAFETY:
if (-1 ==
(section_length = decode_context_enumerated(
&apdu[len], 0, &enum_value))) {
return -1;
}
data->notificationParams.changeOfLifeSafety
.newState =
(BACNET_LIFE_SAFETY_STATE)enum_value;
len += section_length;
if (-1 ==
(section_length = decode_context_enumerated(
&apdu[len], 1, &enum_value))) {
return -1;
}
data->notificationParams.changeOfLifeSafety
.newMode = (BACNET_LIFE_SAFETY_MODE)enum_value;
len += section_length;
if (-1 ==
(section_length = decode_context_bitstring(
&apdu[len], 2,
&data->notificationParams
.changeOfLifeSafety.statusFlags))) {
return -1;
}
len += section_length;
if (-1 ==
(section_length = decode_context_enumerated(
&apdu[len], 3, &enum_value))) {
return -1;
}
data->notificationParams.changeOfLifeSafety
.operationExpected =
(BACNET_LIFE_SAFETY_OPERATION)enum_value;
len += section_length;
break;
case EVENT_BUFFER_READY:
/* Tag 0 - bufferProperty */
section_length =
bacnet_device_object_property_reference_context_decode(
&apdu[len], apdu_len - len, 0,
&data->notificationParams.bufferReady
.bufferProperty);
if (section_length <= 0) {
return -1;
}
len += section_length;
/* Tag 1 - PreviousNotification */
section_length = bacnet_unsigned_context_decode(
&apdu[len], apdu_len - len, 1, &unsigned_value);
if (section_length > 0) {
len += section_length;
if (unsigned_value <= UINT32_MAX) {
data->notificationParams.bufferReady
.previousNotification =
(uint32_t)unsigned_value;
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
/* Tag 2 - currentNotification */
section_length = bacnet_unsigned_context_decode(
&apdu[len], apdu_len - len, 2, &unsigned_value);
if (section_length > 0) {
len += section_length;
if (unsigned_value <= UINT32_MAX) {
data->notificationParams.bufferReady
.currentNotification =
(uint32_t)unsigned_value;
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_UNSIGNED_RANGE:
/* Tag 0 - PreviousNotification */
section_length = bacnet_unsigned_context_decode(
&apdu[len], apdu_len - len, 0, &unsigned_value);
if (section_length > 0) {
len += section_length;
if (unsigned_value <= UINT32_MAX) {
data->notificationParams.unsignedRange
.exceedingValue =
(uint32_t)unsigned_value;
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
/* Tag 1 - statusFlags */
if (-1 ==
(section_length = decode_context_bitstring(
&apdu[len], 1,
&data->notificationParams.unsignedRange
.statusFlags))) {
return -1;
}
len += section_length;
/* Tag 2 - exceededLimit */
section_length = bacnet_unsigned_context_decode(
&apdu[len], apdu_len - len, 2, &unsigned_value);
if (section_length > 0) {
len += section_length;
if (unsigned_value <= UINT32_MAX) {
data->notificationParams.unsignedRange
.exceededLimit =
(uint32_t)unsigned_value;
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_ACCESS_EVENT:
if (-1 ==
(section_length = decode_context_enumerated(
&apdu[len], 0, &enum_value))) {
return -1;
}
data->notificationParams.accessEvent.accessEvent =
enum_value;
len += section_length;
if (-1 ==
(section_length = decode_context_bitstring(
&apdu[len], 1,
&data->notificationParams.accessEvent
.statusFlags))) {
return -1;
}
len += section_length;
if (-1 ==
(section_length = decode_context_unsigned(
&apdu[len], 2,
&data->notificationParams.accessEvent
.accessEventTag))) {
return -1;
}
len += section_length;
if (-1 ==
(section_length =
bacapp_decode_context_timestamp(
&apdu[len], 3,
&data->notificationParams.accessEvent
.accessEventTime))) {
return -1;
}
len += section_length;
if (-1 ==
(section_length =
bacapp_decode_context_device_obj_ref(
&apdu[len], 4,
&data->notificationParams.accessEvent
.accessCredential))) {
return -1;
}
len += section_length;
if (!decode_is_closing_tag(&apdu[len])) {
if (-1 ==
(section_length =
bacapp_decode_context_authentication_factor(
&apdu[len], 5,
&data->notificationParams
.accessEvent
.authenticationFactor))) {
return -1;
}
len += section_length;
}
break;
default:
return -1;
}
} else if (decode_is_opening_tag_number(&apdu[len], 6)) {
/* complex-event-type [6] SEQUENCE OF BACnetPropertyValue */
len++;
is_complex_event_type = true;
len = complex_event_type_values_decode(
&apdu[len], apdu_len - len, data);
if (len < 0) {
return -1;
}
} else {
return -1;
}
if (decode_is_closing_tag_number(
&apdu[len],
is_complex_event_type ? 6 : (uint8_t)data->eventType)) {
len++;
} else {
return -1;
}
if (decode_is_closing_tag_number(&apdu[len], 12)) {
len++;
} else {
return -1;
}
break;
/* In cases other than alarm and event
there's no data, so do not return an error
but continue normally */
case NOTIFY_ACK_NOTIFICATION:
default:
break;
}
}
return len;
}