35f3964b5a
* 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.
3117 lines
126 KiB
C
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, ×tamp_value);
|
|
if (len > 0) {
|
|
apdu_len += len;
|
|
if (data) {
|
|
bacapp_timestamp_copy(&data->timeStamp, ×tamp_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,
|
|
×tamp_value);
|
|
if (len > 0) {
|
|
apdu_len += len;
|
|
if (data) {
|
|
bacapp_timestamp_copy(
|
|
&data->notificationParams.accessEvent
|
|
.accessEventTime,
|
|
×tamp_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;
|
|
}
|