Files
bacnet_stack/src/bacnet/event.c
T
Steve Karg 35f3964b5a Secured event decoding by refactoring deprecated functions. (#1126)
* Secured event and authentication decoding by removing deprecated functions.

* Added extended, discrete-value, double-out-of-range, signed-out-of-range, unsigned-out-of-range, change-of-characterstring, change-of-status-flags, change-of-reliability, and change-of-timer event notification encode, decode, and unit testing with #ifdef disabled by default.
2025-11-05 21:41:30 -06:00

3117 lines
126 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"
#include "bacnet/bacapp.h"
/** @file event.c Encode/Decode Event Notifications */
/**
* @brief Encode the unconfirmed EventNotification 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 ConfirmedEventNotification 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;
}
#if BACNET_EVENT_CHANGE_OF_STATUS_FLAGS_ENABLED
/**
* @brief Encode the EXTENDED event parameter
* @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
*/
static int event_extended_parameter_encode(
uint8_t *apdu, const BACNET_EVENT_EXTENDED_PARAMETER *value)
{
int apdu_len = 0; /* total length of the apdu, return value */
if (!value) {
return 0;
}
switch (value->tag) {
case BACNET_APPLICATION_TAG_NULL:
if (apdu) {
apdu[0] = value->tag;
}
apdu_len++;
break;
case BACNET_APPLICATION_TAG_BOOLEAN:
apdu_len = encode_application_boolean(apdu, value->type.Boolean);
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
apdu_len =
encode_application_unsigned(apdu, value->type.Unsigned_Int);
break;
case BACNET_APPLICATION_TAG_SIGNED_INT:
apdu_len = encode_application_signed(apdu, value->type.Signed_Int);
break;
case BACNET_APPLICATION_TAG_REAL:
apdu_len = encode_application_real(apdu, value->type.Real);
break;
case BACNET_APPLICATION_TAG_DOUBLE:
apdu_len = encode_application_double(apdu, value->type.Double);
break;
case BACNET_APPLICATION_TAG_OCTET_STRING:
apdu_len =
encode_application_octet_string(apdu, value->type.Octet_String);
break;
case BACNET_APPLICATION_TAG_CHARACTER_STRING:
apdu_len = encode_application_character_string(
apdu, value->type.Character_String);
break;
case BACNET_APPLICATION_TAG_BIT_STRING:
apdu_len =
encode_application_bitstring(apdu, value->type.Bit_String);
break;
case BACNET_APPLICATION_TAG_ENUMERATED:
apdu_len =
encode_application_enumerated(apdu, value->type.Enumerated);
break;
case BACNET_APPLICATION_TAG_DATE:
apdu_len = encode_application_date(apdu, &value->type.Date);
break;
case BACNET_APPLICATION_TAG_TIME:
apdu_len = encode_application_time(apdu, &value->type.Time);
break;
case BACNET_APPLICATION_TAG_OBJECT_ID:
apdu_len = encode_application_object_id(
apdu, value->type.Object_Id.type,
value->type.Object_Id.instance);
break;
case BACNET_APPLICATION_TAG_PROPERTY_VALUE:
apdu_len = bacapp_property_value_context_encode(
apdu, 0, value->type.Property_Value);
break;
default:
break;
}
return apdu_len;
}
#endif
/**
* @brief Decode the EXTENDED event parameter from a buffer
* @param apdu - the APDU buffer
* @param apdu_size - the size of the APDU buffer
* @param value - BACnetDeviceObjectPropertyValue to decode into
* @return number of bytes decoded or BACNET_STATUS_ERROR on failure.
*/
static int event_extended_parameter_decode(
const uint8_t *apdu,
uint32_t apdu_size,
BACNET_EVENT_EXTENDED_PARAMETER *value)
{
int len, apdu_len = 0;
BACNET_TAG tag = { 0 };
if (!value) {
return 0;
}
len = bacnet_tag_decode(&apdu[apdu_len], apdu_size - apdu_len, &tag);
if (len > 0) {
apdu_len += len;
if (tag.application) {
switch (tag.number) {
case BACNET_APPLICATION_TAG_NULL:
len = 0;
break;
case BACNET_APPLICATION_TAG_BOOLEAN:
value->type.Boolean = decode_boolean(tag.len_value_type);
len = 0;
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
len = bacnet_unsigned_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, &value->type.Unsigned_Int);
break;
case BACNET_APPLICATION_TAG_SIGNED_INT:
len = bacnet_signed_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, &value->type.Signed_Int);
break;
case BACNET_APPLICATION_TAG_REAL:
len = bacnet_real_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, &value->type.Real);
break;
case BACNET_APPLICATION_TAG_DOUBLE:
len = bacnet_double_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, &value->type.Double);
break;
case BACNET_APPLICATION_TAG_OCTET_STRING:
len = bacnet_octet_string_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, value->type.Octet_String);
break;
case BACNET_APPLICATION_TAG_CHARACTER_STRING:
len = bacnet_character_string_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, value->type.Character_String);
break;
case BACNET_APPLICATION_TAG_BIT_STRING:
len = bacnet_bitstring_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, value->type.Bit_String);
break;
case BACNET_APPLICATION_TAG_ENUMERATED:
len = bacnet_enumerated_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, &value->type.Enumerated);
break;
case BACNET_APPLICATION_TAG_DATE:
len = bacnet_date_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, &value->type.Date);
break;
case BACNET_APPLICATION_TAG_TIME:
len = bacnet_time_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, &value->type.Time);
break;
case BACNET_APPLICATION_TAG_OBJECT_ID:
len = bacnet_object_id_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, &value->type.Object_Id.type,
&value->type.Object_Id.instance);
break;
default:
len = 0;
break;
}
if ((len == 0) && (tag.number != BACNET_APPLICATION_TAG_NULL) &&
(tag.number != BACNET_APPLICATION_TAG_BOOLEAN) &&
(tag.number != BACNET_APPLICATION_TAG_OCTET_STRING)) {
/* tags that have a valid zero length */
/* indicate that we were not able to decode the value */
value->tag = MAX_BACNET_APPLICATION_TAG;
} else {
value->tag = tag.number;
if (len >= 0) {
apdu_len += len;
} else {
apdu_len = BACNET_STATUS_ERROR;
}
}
} else if (tag.opening) {
switch (tag.number) {
case 0:
len = bacapp_property_value_decode(
&apdu[apdu_len], apdu_size - apdu_len,
value->type.Property_Value);
if (len > 0) {
apdu_len += len;
value->tag = BACNET_APPLICATION_TAG_PROPERTY_VALUE;
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len,
tag.number, &len)) {
apdu_len += len;
} else {
apdu_len = BACNET_STATUS_ERROR;
}
} else {
apdu_len = BACNET_STATUS_ERROR;
}
break;
default:
value->tag = MAX_BACNET_APPLICATION_TAG;
break;
}
}
}
return apdu_len;
}
#if BACNET_EVENT_CHANGE_OF_DISCRETE_VALUE_ENABLED
/**
* @brief Encode the DISCRETE_VALUE event
* @param apdu Pointer to the buffer for encoding into
* @param data Pointer to the DISCRETE_VALUE used for encoding values
* @return number of bytes encoded, or zero if unable to encode
*/
static int event_discrete_value_encode(
uint8_t *apdu, const BACNET_EVENT_DISCRETE_VALUE *value)
{
int apdu_len = 0; /* total length of the apdu, return value */
if (!value) {
return 0;
}
switch (value->tag) {
case BACNET_APPLICATION_TAG_BOOLEAN:
apdu_len = encode_application_boolean(apdu, value->type.Boolean);
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
apdu_len =
encode_application_unsigned(apdu, value->type.Unsigned_Int);
break;
case BACNET_APPLICATION_TAG_SIGNED_INT:
apdu_len = encode_application_signed(apdu, value->type.Signed_Int);
break;
case BACNET_APPLICATION_TAG_OCTET_STRING:
apdu_len =
encode_application_octet_string(apdu, value->type.Octet_String);
break;
case BACNET_APPLICATION_TAG_CHARACTER_STRING:
apdu_len = encode_application_character_string(
apdu, value->type.Character_String);
break;
case BACNET_APPLICATION_TAG_ENUMERATED:
apdu_len =
encode_application_enumerated(apdu, value->type.Enumerated);
break;
case BACNET_APPLICATION_TAG_DATE:
apdu_len = encode_application_date(apdu, &value->type.Date);
break;
case BACNET_APPLICATION_TAG_TIME:
apdu_len = encode_application_time(apdu, &value->type.Time);
break;
case BACNET_APPLICATION_TAG_OBJECT_ID:
apdu_len = encode_application_object_id(
apdu, value->type.Object_Id.type,
value->type.Object_Id.instance);
break;
case BACNET_APPLICATION_TAG_DATETIME:
apdu_len =
bacapp_encode_context_datetime(apdu, 0, &value->type.Date_Time);
break;
default:
break;
}
return apdu_len;
}
#endif
/**
* @brief Decode a DISCRETE_VALUE from a buffer
* @param apdu - the APDU buffer
* @param apdu_size - the size of the APDU buffer
* @param value - DISCRETE_VALUE to decode into
* @return number of bytes decoded or BACNET_STATUS_ERROR on failure.
*/
static int event_discrete_value_decode(
const uint8_t *apdu, uint32_t apdu_size, BACNET_EVENT_DISCRETE_VALUE *value)
{
int len, apdu_len = 0;
BACNET_TAG tag = { 0 };
if (!value) {
return 0;
}
len = bacnet_tag_decode(&apdu[apdu_len], apdu_size - apdu_len, &tag);
if (len > 0) {
apdu_len += len;
if (tag.application) {
switch (tag.number) {
case BACNET_APPLICATION_TAG_BOOLEAN:
len = 0;
value->type.Boolean = decode_boolean(tag.len_value_type);
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
len = bacnet_unsigned_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, &value->type.Unsigned_Int);
break;
case BACNET_APPLICATION_TAG_SIGNED_INT:
len = bacnet_signed_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, &value->type.Signed_Int);
break;
case BACNET_APPLICATION_TAG_OCTET_STRING:
len = bacnet_octet_string_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, value->type.Octet_String);
break;
case BACNET_APPLICATION_TAG_CHARACTER_STRING:
len = bacnet_character_string_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, value->type.Character_String);
break;
case BACNET_APPLICATION_TAG_ENUMERATED:
len = bacnet_enumerated_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, &value->type.Enumerated);
break;
case BACNET_APPLICATION_TAG_DATE:
len = bacnet_date_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, &value->type.Date);
break;
case BACNET_APPLICATION_TAG_TIME:
len = bacnet_time_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, &value->type.Time);
break;
case BACNET_APPLICATION_TAG_OBJECT_ID:
len = bacnet_object_id_decode(
&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, &value->type.Object_Id.type,
&value->type.Object_Id.instance);
break;
default:
len = 0;
break;
}
if ((len == 0) && (tag.number != BACNET_APPLICATION_TAG_NULL) &&
(tag.number != BACNET_APPLICATION_TAG_BOOLEAN) &&
(tag.number != BACNET_APPLICATION_TAG_OCTET_STRING)) {
/* tags that have a valid zero length */
/* indicate that we were not able to decode the value */
value->tag = MAX_BACNET_APPLICATION_TAG;
} else {
value->tag = tag.number;
if (len >= 0) {
apdu_len += len;
} else {
apdu_len = BACNET_STATUS_ERROR;
}
}
} else if (tag.opening) {
switch (tag.number) {
case 0:
len = bacnet_datetime_decode(
&apdu[apdu_len], apdu_size - apdu_len,
&value->type.Date_Time);
if (len > 0) {
apdu_len += len;
value->tag = BACNET_APPLICATION_TAG_DATETIME;
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len,
tag.number, &len)) {
apdu_len += len;
} else {
apdu_len = BACNET_STATUS_ERROR;
}
} else {
apdu_len = BACNET_STATUS_ERROR;
}
break;
default:
value->tag = MAX_BACNET_APPLICATION_TAG;
break;
}
}
}
return apdu_len;
}
/**
* @brief Encode the EventNotification 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 */
const BACNET_PROPERTY_VALUE *value = NULL;
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;
#if BACNET_EVENT_DOUBLE_OUT_OF_RANGE_ENABLED
case EVENT_DOUBLE_OUT_OF_RANGE:
/* double-out-of-range[14] SEQUENCE */
len = encode_opening_tag(apdu, 14);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* exceeding-value[0] Double */
len = encode_context_double(
apdu, 0,
data->notificationParams.doubleOutOfRange
.exceedingValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* status-flags[1] BACnetStatusFlags */
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.doubleOutOfRange.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* deadband[2] Double */
len = encode_context_double(
apdu, 2,
data->notificationParams.doubleOutOfRange.deadband);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* exceeded-limit[3] Double */
len = encode_context_double(
apdu, 3,
data->notificationParams.doubleOutOfRange
.exceededLimit);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 14);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
#endif
#if BACNET_EVENT_SIGNED_OUT_OF_RANGE_ENABLED
case EVENT_SIGNED_OUT_OF_RANGE:
/* signed-out-of-range[15] SEQUENCE */
len = encode_opening_tag(apdu, 15);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* exceeding-value[0] Integer */
len = encode_context_signed(
apdu, 0,
data->notificationParams.signedOutOfRange
.exceedingValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* status-flags[1] BACnetStatusFlags */
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.signedOutOfRange.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* deadband[2] Unsigned */
len = encode_context_unsigned(
apdu, 2,
data->notificationParams.signedOutOfRange.deadband);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* exceeded-limit[3] Integer */
len = encode_context_signed(
apdu, 3,
data->notificationParams.signedOutOfRange
.exceededLimit);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 15);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
#endif
#if BACNET_EVENT_UNSIGNED_OUT_OF_RANGE_ENABLED
case EVENT_UNSIGNED_OUT_OF_RANGE:
/* unsigned-out-of-range[16] SEQUENCE */
len = encode_opening_tag(apdu, EVENT_UNSIGNED_OUT_OF_RANGE);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* exceeding-value[0] Unsigned */
len = encode_context_unsigned(
apdu, 0,
data->notificationParams.unsignedOutOfRange
.exceedingValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* status-flags[1] BACnetStatusFlags */
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.unsignedOutOfRange
.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* deadband[2] Unsigned */
len = encode_context_unsigned(
apdu, 2,
data->notificationParams.unsignedOutOfRange.deadband);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* exceeded-limit[3] Unsigned */
len = encode_context_unsigned(
apdu, 3,
data->notificationParams.unsignedOutOfRange
.exceededLimit);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, EVENT_UNSIGNED_OUT_OF_RANGE);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
#endif
#if BACNET_EVENT_CHANGE_OF_CHARACTERSTRING_ENABLED
case EVENT_CHANGE_OF_CHARACTERSTRING:
len = encode_opening_tag(
apdu, EVENT_CHANGE_OF_CHARACTERSTRING);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* changed-value [0] CharacterString */
len = encode_context_character_string(
apdu, 0,
data->notificationParams.changeOfCharacterstring
.changedValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* status-flags[1] BACnetStatusFlags */
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.changeOfCharacterstring
.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* alarm-value [2] CharacterString */
len = encode_context_character_string(
apdu, 2,
data->notificationParams.changeOfCharacterstring
.alarmValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(
apdu, EVENT_CHANGE_OF_CHARACTERSTRING);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
#endif
#if BACNET_EVENT_CHANGE_OF_STATUS_FLAGS_ENABLED
case EVENT_CHANGE_OF_STATUS_FLAGS:
len =
encode_opening_tag(apdu, EVENT_CHANGE_OF_STATUS_FLAGS);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* present-value [0] ABSTRACT-SYNTAX.&Type OPTIONAL */
if (data->notificationParams.changeOfStatusFlags
.presentValue.tag !=
BACNET_APPLICATION_TAG_EMPTYLIST) {
len = encode_opening_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = event_extended_parameter_encode(
apdu,
&data->notificationParams.changeOfStatusFlags
.presentValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
}
/* referenced-flags[1] BACnetStatusFlags */
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.changeOfStatusFlags
.referencedFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
len =
encode_closing_tag(apdu, EVENT_CHANGE_OF_STATUS_FLAGS);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
#endif
#if BACNET_EVENT_CHANGE_OF_RELIABILITY_ENABLED
case EVENT_CHANGE_OF_RELIABILITY:
len = encode_opening_tag(apdu, EVENT_CHANGE_OF_RELIABILITY);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* reliability [0] BACnetReliability */
len = encode_context_enumerated(
apdu, 0,
data->notificationParams.changeOfReliability
.reliability);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* status-flags [1] BACnetStatusFlags */
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.changeOfReliability
.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* property-values [2] SEQUENCE OF BACnetPropertyValue */
len = encode_opening_tag(apdu, 2);
apdu_len += len;
if (apdu) {
apdu += len;
}
value = data->notificationParams.changeOfReliability
.propertyValues;
while (value) {
len = bacapp_property_value_encode(apdu, value);
apdu_len += len;
if (apdu) {
apdu += len;
}
value = value->next;
}
len = encode_closing_tag(apdu, 2);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, EVENT_CHANGE_OF_RELIABILITY);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
#endif
#if BACNET_EVENT_CHANGE_OF_DISCRETE_VALUE_ENABLED
case EVENT_CHANGE_OF_DISCRETE_VALUE:
/* change-of-discrete-value [21] SEQUENCE */
len = encode_opening_tag(
apdu, EVENT_CHANGE_OF_DISCRETE_VALUE);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* new-value [0] CHOICE */
len = encode_opening_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = event_discrete_value_encode(
apdu,
&data->notificationParams.changeOfDiscreteValue
.newValue);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* status-flags[1] BACnetStatusFlags */
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.changeOfDiscreteValue
.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(
apdu, EVENT_CHANGE_OF_DISCRETE_VALUE);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
#endif
#if BACNET_EVENT_CHANGE_OF_TIMER_ENABLED
case EVENT_CHANGE_OF_TIMER:
/* change-of-timer [22] SEQUENCE */
len = encode_opening_tag(apdu, EVENT_CHANGE_OF_TIMER);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* new-state [0] BACnetTimerState */
len = encode_context_enumerated(
apdu, 0,
data->notificationParams.changeOfTimer.newState);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* status-flags [1] BACnetStatusFlags */
len = encode_context_bitstring(
apdu, 1,
&data->notificationParams.changeOfTimer.statusFlags);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* update-time [2] BACnetDateTime */
len = bacapp_encode_context_datetime(
apdu, 2,
&data->notificationParams.changeOfTimer.updateTime);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* last-state-change [3] BACnetTimerTransition OPTIONAL */
if (data->notificationParams.changeOfTimer.lastStateChange <
TIMER_TRANSITION_MAX) {
len = encode_context_enumerated(
apdu, 3,
data->notificationParams.changeOfTimer
.lastStateChange);
apdu_len += len;
if (apdu) {
apdu += len;
}
}
/* initial-timeout [4] Unsigned OPTIONAL */
if (data->notificationParams.changeOfTimer.initialTimeout >
0) {
len = encode_context_enumerated(
apdu, 4,
data->notificationParams.changeOfTimer
.initialTimeout);
apdu_len += len;
if (apdu) {
apdu += len;
}
}
/* expiration-time [5] BACnetDateTime OPTIONAL */
if (!datetime_wildcard(
&data->notificationParams.changeOfTimer
.expirationTime)) {
len = bacapp_encode_context_datetime(
apdu, 5,
&data->notificationParams.changeOfTimer
.expirationTime);
apdu_len += len;
if (apdu) {
apdu += len;
}
}
len = encode_closing_tag(apdu, EVENT_CHANGE_OF_TIMER);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
#endif
case EVENT_NONE:
len = encode_opening_tag(apdu, EVENT_NONE);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, EVENT_NONE);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
#if BACNET_EVENT_EXTENDED_ENABLED
case EVENT_EXTENDED:
len = encode_opening_tag(apdu, EVENT_EXTENDED);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* vendor-id [0] Unsigned16 */
len = encode_context_unsigned(
apdu, 0, data->notificationParams.extended.vendorID);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* extended-event-type [1] Unsigned */
len = encode_context_unsigned(
apdu, 1,
data->notificationParams.extended.extendedEventType);
apdu_len += len;
if (apdu) {
apdu += len;
}
/* parameters [2] SEQUENCE OF CHOICE */
len = encode_opening_tag(apdu, 2);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = event_extended_parameter_encode(
apdu, &data->notificationParams.extended.parameters);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, 2);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_closing_tag(apdu, EVENT_EXTENDED);
apdu_len += len;
if (apdu) {
apdu += len;
}
break;
#endif
default:
if (data->eventType >= EVENT_PROPRIETARY_MIN &&
data->eventType <= EVENT_PROPRIETARY_MAX) {
len =
encode_opening_tag(apdu, EVENT_COMPLEX_EVENT_TYPE);
apdu_len += len;
if (apdu) {
apdu += len;
}
#if BACNET_DECODE_COMPLEX_EVENT_TYPE_PARAMETERS
value =
data->notificationParams.complexEventType.values;
#endif
while (value) {
len = bacapp_property_value_encode(apdu, value);
apdu_len += len;
if (apdu) {
apdu += len;
}
value = value->next;
}
len =
encode_closing_tag(apdu, EVENT_COMPLEX_EVENT_TYPE);
apdu_len += len;
if (apdu) {
apdu += len;
}
} else {
/* FIXME: add or enable an encoder for event type */
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.
* @details Confirmed and Unconfirmed are the same encoding
* UnconfirmedEventNotification-Request ::= SEQUENCE {
* ConfirmedEventNotification-Request ::= SEQUENCE {
* process-identifier[0] Unsigned32,
* initiating-device-identifier[1] BACnetObjectIdentifier,
* event-object-identifier[2] BACnetObjectIdentifier,
* timestamp[3] BACnetTimeStamp,
* notification-class[4] Unsigned,
* priority[5] Unsigned8,
* event-type[6] BACnetEventType,
* message-text[7] CharacterString OPTIONAL,
* notify-type[8] BACnetNotifyType,
* ack-required[9] Boolean OPTIONAL,
* from-state[10] BACnetEventState OPTIONAL,
* to-state[11] BACnetEventState,
* event-values[12] BACnetNotificationParameters OPTIONAL
* }
*
* @param apdu Pointer to the buffer.
* @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 BACNET_STATUS_ERROR on error.
*/
int event_notify_decode_service_request(
const uint8_t *apdu,
unsigned apdu_size,
BACNET_EVENT_NOTIFICATION_DATA *data)
{
int apdu_len = 0; /* return value */
int len = 0, tag_len = 0;
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
BACNET_OBJECT_ID object_id = { 0 };
BACNET_TIMESTAMP timestamp_value = { 0 };
BACNET_CHARACTER_STRING *cstring = NULL;
BACNET_BIT_STRING *bstring = NULL;
BACNET_PROPERTY_STATE *property_state = NULL;
BACNET_NOTIFY_TYPE notify_type = NOTIFY_MAX;
BACNET_EVENT_TYPE event_type = EVENT_NONE;
BACNET_DEVICE_OBJECT_REFERENCE *dev_obj_ref = NULL;
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *dev_obj_prop_ref = NULL;
BACNET_AUTHENTICATION_FACTOR *auth_factor = NULL;
BACNET_PROPERTY_VALUE *property_value = NULL;
BACNET_EVENT_EXTENDED_PARAMETER *parameter_value = NULL;
BACNET_EVENT_DISCRETE_VALUE *discrete_value = NULL;
BACNET_DATE_TIME *datetime_value = NULL;
bool boolean_value = false;
float real_value = 0.0f;
double double_value = 0.0;
int32_t signed_value = 0;
uint32_t enum_value = 0;
if (apdu_size) {
/* process-identifier[0] Unsigned32 */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &unsigned_value);
if (len > 0) {
apdu_len += len;
if (unsigned_value <= UINT32_MAX) {
if (data) {
data->processIdentifier = (uint32_t)unsigned_value;
}
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
/* initiating-device-identifier[1] BACnetObjectIdentifier */
len = bacnet_object_id_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, &object_id.type,
&object_id.instance);
if (len > 0) {
apdu_len += len;
if (data) {
data->initiatingObjectIdentifier.type = object_id.type;
data->initiatingObjectIdentifier.instance = object_id.instance;
}
} else {
return BACNET_STATUS_ERROR;
}
/* event-object-identifier[2] BACnetObjectIdentifier */
len = bacnet_object_id_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2, &object_id.type,
&object_id.instance);
if (len > 0) {
apdu_len += len;
if (data) {
data->eventObjectIdentifier.type = object_id.type;
data->eventObjectIdentifier.instance = object_id.instance;
}
} else {
return BACNET_STATUS_ERROR;
}
/* timestamp[3] BACnetTimeStamp */
len = bacnet_timestamp_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 3, &timestamp_value);
if (len > 0) {
apdu_len += len;
if (data) {
bacapp_timestamp_copy(&data->timeStamp, &timestamp_value);
}
} else {
return BACNET_STATUS_ERROR;
}
/* notification-class[4] Unsigned */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 4, &unsigned_value);
if (len > 0) {
apdu_len += len;
if (unsigned_value <= UINT32_MAX) {
if (data) {
data->notificationClass = (uint32_t)unsigned_value;
}
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
/* priority[5] Unsigned8 */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 5, &unsigned_value);
if (len > 0) {
apdu_len += len;
if (unsigned_value <= UINT8_MAX) {
if (data) {
data->priority = (uint8_t)unsigned_value;
}
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
/* event-type[6] BACnetEventType */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 6, &enum_value);
if (len > 0) {
apdu_len += len;
if (enum_value <= EVENT_PROPRIETARY_MAX) {
event_type = (BACNET_EVENT_TYPE)enum_value;
if (data) {
data->eventType = event_type;
}
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
/* message-text[7] CharacterString OPTIONAL */
if (data) {
cstring = data->messageText;
} else {
cstring = NULL;
}
len = bacnet_character_string_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 7, cstring);
if (len > 0) {
apdu_len += len;
} else if (len == 0) {
/* OPTIONAL - set default */
characterstring_init_ansi(cstring, "");
} else {
return BACNET_STATUS_ERROR;
}
/* notify-type[8] BACnetNotifyType */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 8, &enum_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->notifyType = (BACNET_NOTIFY_TYPE)enum_value;
if (enum_value >= NOTIFY_MAX) {
enum_value = NOTIFY_MAX;
}
notify_type = enum_value;
}
} else {
return BACNET_STATUS_ERROR;
}
if ((notify_type == NOTIFY_ALARM) || (notify_type == NOTIFY_EVENT)) {
/* ack-required[9] Boolean OPTIONAL */
len = bacnet_boolean_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 9, &boolean_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->ackRequired = boolean_value;
}
} else if (len == 0) {
/* OPTIONAL - set default */
if (data) {
data->ackRequired = false;
}
} else {
return BACNET_STATUS_ERROR;
}
/* from-state[10] BACnetEventState OPTIONAL */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 10, &enum_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->fromState = (BACNET_EVENT_STATE)enum_value;
}
} else if (len == 0) {
/* OPTIONAL - set default out of range */
if (data) {
data->fromState = EVENT_STATE_MAX;
}
} else {
return BACNET_STATUS_ERROR;
}
}
/* to-state[11] BACnetEventState */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 11, &enum_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->toState = (BACNET_EVENT_STATE)enum_value;
}
} else {
return BACNET_STATUS_ERROR;
}
}
if ((notify_type == NOTIFY_ALARM) || (notify_type == NOTIFY_EVENT)) {
/* event-values[12] BACnetNotificationParameters OPTIONAL */
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 12, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
if (event_type >= EVENT_PROPRIETARY_MIN) {
/* complex-event-type [6] SEQUENCE OF BACnetPropertyValue */
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len,
EVENT_COMPLEX_EVENT_TYPE, &len)) {
apdu_len += len;
if (data) {
#if BACNET_DECODE_COMPLEX_EVENT_TYPE_PARAMETERS
property_value =
data->notificationParams.complexEventType.values;
#endif
}
bacapp_property_value_list_init(
property_value, BACNET_COMPLEX_EVENT_TYPE_MAX_PARAMETERS);
while (apdu_len < apdu_size) {
len = bacapp_property_value_decode(
&apdu[apdu_len], apdu_size - apdu_len, property_value);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* end of list? */
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len,
EVENT_COMPLEX_EVENT_TYPE, &len)) {
apdu_len += len;
if (property_value) {
/* mark the end of the list */
property_value->next = NULL;
}
break;
}
/* is there another slot in the data store? */
if (property_value) {
property_value = property_value->next;
}
}
} else {
return BACNET_STATUS_ERROR;
}
} else if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len,
(uint8_t)event_type, &len)) {
/* BACnetNotificationParameters */
apdu_len += len;
switch (event_type) {
case EVENT_CHANGE_OF_BITSTRING:
/* change-of-bitstring [0] SEQUENCE */
/* referenced-bitstring[0] BitString */
if (data) {
bstring = &data->notificationParams.changeOfBitstring
.referencedBitString;
} else {
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[1] BACnetStatusFlags */
if (data) {
bstring = &data->notificationParams.changeOfBitstring
.statusFlags;
} else {
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_CHANGE_OF_STATE:
/* change-of-state [1] SEQUENCE */
/* new-state[0] BACnetEventState */
if (data) {
property_state =
&data->notificationParams.changeOfState.newState;
} else {
property_state = NULL;
}
len = bacapp_decode_context_property_state(
&apdu[apdu_len], 0, property_state);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[1] BACnetStatusFlags */
if (data) {
bstring =
&data->notificationParams.changeOfState.statusFlags;
} else {
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_CHANGE_OF_VALUE:
/* change-of-value [2] SEQUENCE */
/* new-value [0] CHOICE */
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* changed-bits[0] BitString */
if (data) {
bstring = &data->notificationParams.changeOfValue
.newValue.changedBits;
} else {
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, bstring);
if (len > 0) {
apdu_len += len;
if (data) {
data->notificationParams.changeOfValue.tag =
CHANGE_OF_VALUE_BITS;
}
} else if (len < 0) {
return BACNET_STATUS_ERROR;
} else {
/* changed-value[1] Real */
len = bacnet_real_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1,
&real_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->notificationParams.changeOfValue.newValue
.changeValue = real_value;
data->notificationParams.changeOfValue.tag =
CHANGE_OF_VALUE_REAL;
}
} else {
return BACNET_STATUS_ERROR;
}
}
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags [1] BACnetStatusFlags*/
if (data) {
bstring =
&data->notificationParams.changeOfValue.statusFlags;
} else {
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_COMMAND_FAILURE:
/* command-failure [3] SEQUENCE */
/* command-value [0] ABSTRACT-SYNTAX.&Type
-- depends on ref property */
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
len = bacnet_enumerated_application_decode(
&apdu[apdu_len], apdu_size - apdu_len, &enum_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->notificationParams.commandFailure.commandValue
.binaryValue = enum_value;
data->notificationParams.commandFailure.tag =
COMMAND_FAILURE_BINARY_PV;
}
} else if (len < 0) {
return BACNET_STATUS_ERROR;
}
if (len == 0) {
len = bacnet_unsigned_application_decode(
&apdu[apdu_len], apdu_size - apdu_len,
&unsigned_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->notificationParams.commandFailure
.commandValue.unsignedValue =
unsigned_value;
data->notificationParams.commandFailure.tag =
COMMAND_FAILURE_UNSIGNED;
}
} else {
return BACNET_STATUS_ERROR;
}
}
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[1] BACnetStatusFlags */
if (data) {
bstring = &data->notificationParams.commandFailure
.statusFlags;
} else {
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* feedback-value[2] ABSTRACT-SYNTAX.&Type
-- depends on ref property */
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 2, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
if (data->notificationParams.commandFailure.tag ==
COMMAND_FAILURE_BINARY_PV) {
len = bacnet_enumerated_application_decode(
&apdu[apdu_len], apdu_size - apdu_len, &enum_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->notificationParams.commandFailure
.feedbackValue.binaryValue = enum_value;
}
} else if (len < 0) {
return BACNET_STATUS_ERROR;
}
} else {
len = bacnet_unsigned_application_decode(
&apdu[apdu_len], apdu_size - apdu_len,
&unsigned_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->notificationParams.commandFailure
.feedbackValue.unsignedValue =
unsigned_value;
}
} else {
return BACNET_STATUS_ERROR;
}
}
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 2, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_FLOATING_LIMIT:
/* floating-limit [4] SEQUENCE*/
/* reference-value[0] Real */
len = bacnet_real_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &real_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->notificationParams.floatingLimit
.referenceValue = real_value;
}
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[1] BACnetStatusFlags */
if (data) {
bstring =
&data->notificationParams.floatingLimit.statusFlags;
} else {
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* setpoint-value[2] Real */
len = bacnet_real_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2, &real_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->notificationParams.floatingLimit
.setPointValue = real_value;
}
} else {
return BACNET_STATUS_ERROR;
}
/* error-limit[3] Real */
len = bacnet_real_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 3, &real_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->notificationParams.floatingLimit.errorLimit =
real_value;
}
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_OUT_OF_RANGE:
/* out-of-range [5] SEQUENCE */
/* exceeding-value[0] Real */
len = bacnet_real_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &real_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->notificationParams.outOfRange.exceedingValue =
real_value;
}
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[1] BACnetStatusFlags */
if (data) {
bstring =
&data->notificationParams.outOfRange.statusFlags;
} else {
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* deadband[2] Real */
len = bacnet_real_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2, &real_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->notificationParams.outOfRange.deadband =
real_value;
}
} else {
return BACNET_STATUS_ERROR;
}
/* exceeded-limit[3] Real */
len = bacnet_real_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 3, &real_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->notificationParams.outOfRange.exceededLimit =
real_value;
}
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_CHANGE_OF_LIFE_SAFETY:
/* change-of-life-safety [8] SEQUENCE */
/* new-state[0] BACnetLifeSafetyState */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &enum_value);
if (len > 0) {
apdu_len += len;
if (enum_value > LIFE_SAFETY_STATE_PROPRIETARY_MAX) {
enum_value = LIFE_SAFETY_STATE_PROPRIETARY_MAX;
}
if (data) {
data->notificationParams.changeOfLifeSafety
.newState =
(BACNET_LIFE_SAFETY_STATE)enum_value;
}
} else {
return BACNET_STATUS_ERROR;
}
/* new-mode[1] BACnetLifeSafetyMode */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, &enum_value);
if (len > 0) {
apdu_len += len;
if (enum_value > LIFE_SAFETY_MODE_PROPRIETARY_MAX) {
enum_value = LIFE_SAFETY_MODE_PROPRIETARY_MAX;
}
if (data) {
data->notificationParams.changeOfLifeSafety
.newMode = (BACNET_LIFE_SAFETY_MODE)enum_value;
}
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[2] BACnetStatusFlags */
if (data) {
bstring = &data->notificationParams.changeOfLifeSafety
.statusFlags;
} else {
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* operation-expected[3] BACnetLifeSafetyOperation */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 3, &enum_value);
if (len > 0) {
apdu_len += len;
if (enum_value > LIFE_SAFETY_OP_PROPRIETARY_MAX) {
enum_value = LIFE_SAFETY_OP_PROPRIETARY_MAX;
}
if (data) {
data->notificationParams.changeOfLifeSafety
.operationExpected =
(BACNET_LIFE_SAFETY_OPERATION)enum_value;
}
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_EXTENDED:
/* extended [9] SEQUENCE */
/* vendor-id[0] Unsigned16 */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0,
&unsigned_value);
if (len > 0) {
apdu_len += len;
if (unsigned_value <= UINT16_MAX) {
#if BACNET_EVENT_EXTENDED_ENABLED
if (data) {
data->notificationParams.extended.vendorID =
(uint16_t)unsigned_value;
}
#endif
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
/* extended-event-type[1] Unsigned */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1,
&unsigned_value);
if (len > 0) {
apdu_len += len;
if (data) {
#if BACNET_EVENT_EXTENDED_ENABLED
data->notificationParams.extended
.extendedEventType = unsigned_value;
#endif
}
} else {
return BACNET_STATUS_ERROR;
}
/* parameters[2] SEQUENCE OF CHOICE */
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 2, &len)) {
apdu_len += len;
#if BACNET_EVENT_EXTENDED_ENABLED
if (data) {
parameter_value =
&data->notificationParams.extended.parameters;
} else
#endif
{
parameter_value = NULL;
}
len = event_extended_parameter_decode(
&apdu[apdu_len], apdu_size - apdu_len,
parameter_value);
if (len < 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 2,
&len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_BUFFER_READY:
/* buffer-ready [10] SEQUENCE */
/* buffer-property[0] BACnetDeviceObjectPropertyReference */
if (data) {
dev_obj_prop_ref = &data->notificationParams.bufferReady
.bufferProperty;
} else {
dev_obj_prop_ref = NULL;
}
len =
bacnet_device_object_property_reference_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0,
dev_obj_prop_ref);
if (len <= 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
/* previous-notification[1] Unsigned32 */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1,
&unsigned_value);
if (len > 0) {
apdu_len += len;
if (unsigned_value <= UINT32_MAX) {
if (data) {
data->notificationParams.bufferReady
.previousNotification =
(uint32_t)unsigned_value;
}
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
/* current-notification[2] Unsigned32 */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2,
&unsigned_value);
if (len > 0) {
apdu_len += len;
if (unsigned_value <= UINT32_MAX) {
if (data) {
data->notificationParams.bufferReady
.currentNotification =
(uint32_t)unsigned_value;
}
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_UNSIGNED_RANGE:
/* unsigned-range[11] SEQUENCE*/
/* exceeding-value[0] Unsigned */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0,
&unsigned_value);
if (len > 0) {
apdu_len += len;
if (unsigned_value <= UINT32_MAX) {
if (data) {
data->notificationParams.unsignedRange
.exceedingValue = (uint32_t)unsigned_value;
}
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[1] BACnetStatusFlags */
if (data) {
bstring =
&data->notificationParams.unsignedRange.statusFlags;
} else {
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* exceeded-limit[2] Unsigned */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2,
&unsigned_value);
if (len > 0) {
apdu_len += len;
if (unsigned_value <= UINT32_MAX) {
if (data) {
data->notificationParams.unsignedRange
.exceededLimit = (uint32_t)unsigned_value;
}
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_ACCESS_EVENT:
/* access-event[13] SEQUENCE */
/* access-event[0] BACnetAccessEvent */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &enum_value);
if (len > 0) {
apdu_len += len;
if (enum_value > ACCESS_EVENT_PROPRIETARY_MAX) {
enum_value = ACCESS_EVENT_PROPRIETARY_MAX;
}
if (data) {
data->notificationParams.accessEvent.accessEvent =
(BACNET_ACCESS_EVENT)enum_value;
}
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[1] BACnetStatusFlags */
if (data) {
bstring =
&data->notificationParams.accessEvent.statusFlags;
} else {
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* access-event-tag[2] Unsigned */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2,
&unsigned_value);
if (len > 0) {
apdu_len += len;
if (data) {
data->notificationParams.accessEvent
.accessEventTag = unsigned_value;
}
} else {
return BACNET_STATUS_ERROR;
}
/* access-event-time[3] BACnetTimeStamp */
len = bacnet_timestamp_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 3,
&timestamp_value);
if (len > 0) {
apdu_len += len;
if (data) {
bacapp_timestamp_copy(
&data->notificationParams.accessEvent
.accessEventTime,
&timestamp_value);
}
} else {
return BACNET_STATUS_ERROR;
}
/* access-credential[4] BACnetDeviceObjectReference */
if (data) {
dev_obj_ref = &data->notificationParams.accessEvent
.accessCredential;
} else {
dev_obj_ref = NULL;
}
len = bacnet_device_object_reference_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 4, dev_obj_ref);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* authentication-factor[5] BACnetAuthenticationFactor
* OPTIONAL */
if (data) {
auth_factor = &data->notificationParams.accessEvent
.authenticationFactor;
} else {
auth_factor = NULL;
}
len = bacnet_authentication_factor_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 5, auth_factor);
if (len > 0) {
apdu_len += len;
} else if (len == 0) {
/* OPTIONAL - set default */
if (data) {
data->notificationParams.accessEvent
.authenticationFactor.format_type =
AUTHENTICATION_FACTOR_MAX;
}
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_DOUBLE_OUT_OF_RANGE:
/* double-out-of-range[14] SEQUENCE */
/* exceeding-value[0] Double */
len = bacnet_double_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0,
&double_value);
if (len > 0) {
apdu_len += len;
if (data) {
#if BACNET_EVENT_DOUBLE_OUT_OF_RANGE_ENABLED
data->notificationParams.doubleOutOfRange
.exceedingValue = double_value;
#endif
}
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[1] BACnetStatusFlags */
#if BACNET_EVENT_DOUBLE_OUT_OF_RANGE_ENABLED
if (data) {
bstring = &data->notificationParams.doubleOutOfRange
.statusFlags;
} else
#endif
{
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* deadband[2] Double */
len = bacnet_double_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2,
&double_value);
if (len > 0) {
apdu_len += len;
if (data) {
#if BACNET_EVENT_DOUBLE_OUT_OF_RANGE_ENABLED
data->notificationParams.doubleOutOfRange.deadband =
double_value;
#endif
}
} else {
return BACNET_STATUS_ERROR;
}
/* exceeded-limit[3] Double */
len = bacnet_double_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 3,
&double_value);
if (len > 0) {
apdu_len += len;
if (data) {
#if BACNET_EVENT_DOUBLE_OUT_OF_RANGE_ENABLED
data->notificationParams.doubleOutOfRange
.exceededLimit = double_value;
#endif
}
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_SIGNED_OUT_OF_RANGE:
/* signed-out-of-range[15] SEQUENCE */
/* exceeding-value[0] Integer */
len = bacnet_signed_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0,
&signed_value);
if (len > 0) {
apdu_len += len;
if (data) {
#if BACNET_EVENT_SIGNED_OUT_OF_RANGE_ENABLED
data->notificationParams.signedOutOfRange
.exceedingValue = signed_value;
#endif
}
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[1] BACnetStatusFlags */
#if BACNET_EVENT_SIGNED_OUT_OF_RANGE_ENABLED
if (data) {
bstring = &data->notificationParams.signedOutOfRange
.statusFlags;
} else
#endif
{
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* deadband[2] Unsigned */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2,
&unsigned_value);
if (len > 0) {
apdu_len += len;
if (data) {
#if BACNET_EVENT_SIGNED_OUT_OF_RANGE_ENABLED
data->notificationParams.signedOutOfRange.deadband =
unsigned_value;
#endif
}
} else {
return BACNET_STATUS_ERROR;
}
/* exceeded-limit[3] Integer */
len = bacnet_signed_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 3,
&signed_value);
if (len > 0) {
apdu_len += len;
if (data) {
#if BACNET_EVENT_SIGNED_OUT_OF_RANGE_ENABLED
data->notificationParams.signedOutOfRange
.exceededLimit = signed_value;
#endif
}
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_UNSIGNED_OUT_OF_RANGE:
/* unsigned-out-of-range[16] SEQUENCE */
/* exceeding-value[0] Unsigned */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0,
&unsigned_value);
if (len > 0) {
apdu_len += len;
if (data) {
#if BACNET_EVENT_UNSIGNED_OUT_OF_RANGE_ENABLED
data->notificationParams.unsignedOutOfRange
.exceedingValue = unsigned_value;
#endif
}
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[1] BACnetStatusFlags */
#if BACNET_EVENT_UNSIGNED_OUT_OF_RANGE_ENABLED
if (data) {
bstring = &data->notificationParams.unsignedOutOfRange
.statusFlags;
} else
#endif
{
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* deadband[2] Unsigned */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2,
&unsigned_value);
if (len > 0) {
apdu_len += len;
if (data) {
#if BACNET_EVENT_UNSIGNED_OUT_OF_RANGE_ENABLED
data->notificationParams.unsignedOutOfRange
.deadband = unsigned_value;
#endif
}
} else {
return BACNET_STATUS_ERROR;
}
/* exceeded-limit[3] Unsigned */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 3,
&unsigned_value);
if (len > 0) {
apdu_len += len;
if (data) {
#if BACNET_EVENT_UNSIGNED_OUT_OF_RANGE_ENABLED
data->notificationParams.unsignedOutOfRange
.exceededLimit = unsigned_value;
#endif
}
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_CHANGE_OF_CHARACTERSTRING:
/* change-of-characterstring [17] SEQUENCE */
/* changed-value[0] CharacterString */
#if BACNET_EVENT_CHANGE_OF_CHARACTERSTRING_ENABLED
if (data) {
cstring = data->notificationParams
.changeOfCharacterstring.changedValue;
} else
#endif
{
cstring = NULL;
}
len = bacnet_character_string_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, cstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[1] BACnetStatusFlags */
#if BACNET_EVENT_CHANGE_OF_CHARACTERSTRING_ENABLED
if (data) {
bstring = &data->notificationParams
.changeOfCharacterstring.statusFlags;
} else
#endif
{
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* alarm-value[2] CharacterString */
#if BACNET_EVENT_CHANGE_OF_CHARACTERSTRING_ENABLED
if (data) {
cstring = data->notificationParams
.changeOfCharacterstring.alarmValue;
} else
#endif
{
cstring = NULL;
}
len = bacnet_character_string_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2, cstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_CHANGE_OF_STATUS_FLAGS:
/* change-of-status-flags[18] SEQUENCE */
/* present-value[0] ABSTRACT-SYNTAX.&Type OPTIONAL,
-- depends on referenced property */
#if BACNET_EVENT_CHANGE_OF_STATUS_FLAGS_ENABLED
if (data) {
parameter_value =
&data->notificationParams.changeOfStatusFlags
.presentValue;
} else
#endif
{
parameter_value = NULL;
}
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
apdu_len += len;
len = event_extended_parameter_decode(
&apdu[apdu_len], apdu_size - apdu_len,
parameter_value);
if (len < 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0,
&len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
} else {
/* OPTIONAL */
if (parameter_value) {
#if BACNET_EVENT_CHANGE_OF_STATUS_FLAGS_ENABLED
parameter_value->tag =
BACNET_APPLICATION_TAG_EMPTYLIST;
#endif
}
}
/* referenced-flags[1] BACnetStatusFlags*/
#if BACNET_EVENT_CHANGE_OF_STATUS_FLAGS_ENABLED
if (data) {
bstring = &data->notificationParams.changeOfStatusFlags
.referencedFlags;
} else
#endif
{
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_CHANGE_OF_RELIABILITY:
/* change-of-reliability[19] SEQUENCE */
/* reliability[0] BACnetReliability */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &enum_value);
if (len > 0) {
apdu_len += len;
if (enum_value > RELIABILITY_PROPRIETARY_MAX) {
enum_value = RELIABILITY_PROPRIETARY_MAX;
}
#if BACNET_EVENT_CHANGE_OF_RELIABILITY_ENABLED
if (data) {
data->notificationParams.changeOfReliability
.reliability = enum_value;
}
#endif
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[1] BACnetStatusFlags */
#if BACNET_EVENT_CHANGE_OF_RELIABILITY_ENABLED
if (data) {
bstring = &data->notificationParams.changeOfReliability
.statusFlags;
} else
#endif
{
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* property-values[2] SEQUENCE OF BACnetPropertyValue */
#if BACNET_EVENT_CHANGE_OF_RELIABILITY_ENABLED
if (data) {
property_value =
data->notificationParams.changeOfReliability
.propertyValues;
} else
#endif
{
property_value = NULL;
}
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 2, &len)) {
apdu_len += len;
while (apdu_len < apdu_size) {
len = bacapp_property_value_decode(
&apdu[apdu_len], apdu_size - apdu_len,
property_value);
if (len >= 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* end of list? */
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 2,
&len)) {
apdu_len += len;
#if BACNET_EVENT_CHANGE_OF_RELIABILITY_ENABLED
if (property_value) {
/* mark the end of the list */
property_value->next = NULL;
}
#endif
break;
}
#if BACNET_EVENT_CHANGE_OF_RELIABILITY_ENABLED
if (property_value) {
/* load the next value store */
property_value = property_value->next;
}
#endif
}
}
break;
case EVENT_NONE:
/* -- CHOICE [20] has been intentionally omitted.
It parallels the 'none' event type CHOICE[20] of
the BACnetEventParameter production which was
introduced for the case an object does not apply
an event algorithm */
break;
case EVENT_CHANGE_OF_DISCRETE_VALUE:
/* change-of-discrete-value [21] SEQUENCE */
/* new-value [0] CHOICE */
if (bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
apdu_len += len;
#if BACNET_EVENT_CHANGE_OF_DISCRETE_VALUE_ENABLED
if (data) {
discrete_value =
&data->notificationParams.changeOfDiscreteValue
.newValue;
} else
#endif
{
discrete_value = NULL;
}
len = event_discrete_value_decode(
&apdu[apdu_len], apdu_size - apdu_len,
discrete_value);
if (len < 0) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0,
&tag_len)) {
apdu_len += tag_len;
} else {
return BACNET_STATUS_ERROR;
}
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[1] BACnetStatusFlags*/
#if BACNET_EVENT_CHANGE_OF_DISCRETE_VALUE_ENABLED
if (data) {
bstring = &data->notificationParams
.changeOfDiscreteValue.statusFlags;
} else
#endif
{
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
break;
case EVENT_CHANGE_OF_TIMER:
/* change-of-timer [22] SEQUENCE */
/* new-state[0] BACnetTimerState */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 0, &enum_value);
if (len > 0) {
apdu_len += len;
if (data) {
if (enum_value > TIMER_STATE_MAX) {
enum_value = TIMER_STATE_MAX;
}
#if BACNET_EVENT_CHANGE_OF_TIMER_ENABLED
data->notificationParams.changeOfTimer.newState =
enum_value;
#endif
}
} else {
return BACNET_STATUS_ERROR;
}
/* status-flags[1] BACnetStatusFlags */
#if BACNET_EVENT_CHANGE_OF_TIMER_ENABLED
if (data) {
bstring =
&data->notificationParams.changeOfTimer.statusFlags;
} else
#endif
{
bstring = NULL;
}
len = bacnet_bitstring_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, bstring);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* update-time[2] BACnetDateTime */
#if BACNET_EVENT_CHANGE_OF_TIMER_ENABLED
if (data) {
datetime_value =
&data->notificationParams.changeOfTimer.updateTime;
} else
#endif
{
datetime_value = NULL;
}
len = bacnet_datetime_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 2,
datetime_value);
if (len > 0) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
/* last-state-change[3] BACnetTimerTransition OPTIONAL */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 3, &enum_value);
if (len > 0) {
apdu_len += len;
if (enum_value > TIMER_TRANSITION_MAX) {
enum_value = TIMER_TRANSITION_MAX;
}
#if BACNET_EVENT_CHANGE_OF_TIMER_ENABLED
data->notificationParams.changeOfTimer.lastStateChange =
enum_value;
#endif
} else if (len == 0) {
/* OPTIONAL - set default */
#if BACNET_EVENT_CHANGE_OF_TIMER_ENABLED
data->notificationParams.changeOfTimer.lastStateChange =
TIMER_TRANSITION_MAX;
#endif
} else {
return BACNET_STATUS_ERROR;
}
/* initial-timeout[4] Unsigned OPTIONAL */
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 4,
&unsigned_value);
if (len > 0) {
apdu_len += len;
if (data) {
#if BACNET_EVENT_CHANGE_OF_TIMER_ENABLED
data->notificationParams.changeOfTimer
.initialTimeout = unsigned_value;
#endif
}
} else if (len == 0) {
/* OPTIONAL - set default */
if (data) {
#if BACNET_EVENT_CHANGE_OF_TIMER_ENABLED
data->notificationParams.changeOfTimer
.initialTimeout = 0;
#endif
}
} else {
return BACNET_STATUS_ERROR;
}
/* expiration-time[5] BACnetDateTime OPTIONAL */
#if BACNET_EVENT_CHANGE_OF_TIMER_ENABLED
if (data) {
datetime_value = &data->notificationParams.changeOfTimer
.expirationTime;
} else
#endif
{
datetime_value = NULL;
}
len = bacnet_datetime_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 5,
datetime_value);
if (len > 0) {
apdu_len += len;
} else if (len == 0) {
/* OPTIONAL - set default */
datetime_wildcard_set(datetime_value);
} else {
return BACNET_STATUS_ERROR;
}
break;
default:
return BACNET_STATUS_ERROR;
}
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, (uint8_t)event_type,
&len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
}
if (bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 12, &len)) {
apdu_len += len;
} else {
return BACNET_STATUS_ERROR;
}
}
return apdu_len;
}