diff --git a/src/bacnet/event.c b/src/bacnet/event.c index 67b060e8..5a6b53fe 100644 --- a/src/bacnet/event.c +++ b/src/bacnet/event.c @@ -40,6 +40,182 @@ /** @file event.c Encode/Decode Event Notifications */ +/** + * Parse the array of complex-event-type notification parameters + * + * @param len - parse position inside APDU + * @param apdu_len - APDU total length + * @param apdu - apdu buffer + * @param data - the event data struct to store the results in + * @return new value of "len", or negative on error + */ +static int parse_complex_event_type_values(int len, unsigned apdu_len, uint8_t *apdu, BACNET_EVENT_NOTIFICATION_DATA *data) +{ + /* + BACnetPropertyValue ::= SEQUENCE { + property-identifier [0] BACnetPropertyIdentifier, + property-array-index [1] Unsigned OPTIONAL, -- used only with array datatypes + -- if omitted with an array the entire array is referenced + property-value [2] ABSTRACT-SYNTAX.&Type, -- any datatype appropriate for the specified property + priority [3] Unsigned (1..16) OPTIONAL -- used only when property is commandable + } + */ + + // TODO this is mostly copied from "cov_notify_decode_service_request" - extract to a common function? + + uint8_t tag_number = 0; + uint32_t len_value = 0; + uint32_t property = 0; + BACNET_UNSIGNED_INTEGER decoded_value = 0; + BACNET_APPLICATION_DATA_VALUE *app_data = NULL; + int app_len = 0; + +#if (BACNET_DECODE_COMPLEX_EVENT_TYPE_PARAMETERS == 1) + /* we want to extract the values */ + BACNET_PROPERTY_VALUE *values = data->notificationParams.complexEventType.values; + bacapp_property_value_list_init(values, BACNET_COMPLEX_EVENT_TYPE_MAX_PARAMETERS); + + BACNET_PROPERTY_VALUE *value = values; + + for(;;) { + /* tag 0 - propertyIdentifier */ + if (len >= (int)apdu_len) { + return -1; + } + if (decode_is_context_tag(&apdu[len], 0)) { + len += decode_tag_number_and_value( + &apdu[len], &tag_number, &len_value); + len += decode_enumerated(&apdu[len], len_value, &property); + value->propertyIdentifier = (BACNET_PROPERTY_ID)property; + } else { + return -1; + } + /* tag 1 - propertyArrayIndex OPTIONAL */ + if (len >= (int)apdu_len) { + return -1; + } + if (decode_is_context_tag(&apdu[len], 1)) { + len += decode_tag_number_and_value( + &apdu[len], &tag_number, &len_value); + len += decode_unsigned(&apdu[len], len_value, &decoded_value); + value->propertyArrayIndex = decoded_value; + } else { + value->propertyArrayIndex = BACNET_ARRAY_ALL; + } + /* tag 2: opening context tag - value */ + if (len >= (int)apdu_len) { + return -1; + } + if (!decode_is_opening_tag_number(&apdu[len], 2)) { + return -1; + } + /* a tag number of 2 is not extended so only one octet */ + len++; + app_data = &value->value; + while (!decode_is_closing_tag_number(&apdu[len], 2)) { + if (app_data == NULL) { + /* out of room to store more values */ + return -1; + } + app_len = bacapp_decode_application_data( + &apdu[len], apdu_len - len, app_data); + if (app_len < 0) { + return -1; + } + len += app_len; + + app_data = app_data->next; + } + /* a tag number of 2 is not extended so only one octet */ + len++; + /* tag 3 - priority OPTIONAL */ + if (len >= (int)apdu_len) { + return -1; + } + if (decode_is_context_tag(&apdu[len], 3)) { + len += decode_tag_number_and_value( + &apdu[len], &tag_number, &len_value); + len += decode_unsigned(&apdu[len], len_value, &decoded_value); + value->priority = (uint8_t)decoded_value; + } else { + value->priority = BACNET_NO_PRIORITY; + } + /* end of list? */ + if (decode_is_closing_tag_number(&apdu[len], 6)) { + break; + } + value = value->next; + if (value == NULL) { + /* out of room to store more values */ + return BACNET_STATUS_ERROR; + } + } +#else + // we just want to discard the complex values + BACNET_PROPERTY_VALUE dummyValue; + bacapp_property_value_list_init(&dummyValue, 1); + BACNET_PROPERTY_VALUE *value = &dummyValue; + + for(;;) { + /* tag 0 - propertyIdentifier */ + if (len >= (int)apdu_len) { + return -1; + } + if (decode_is_context_tag(&apdu[len], 0)) { + len += decode_tag_number_and_value( + &apdu[len], &tag_number, &len_value); + len += decode_enumerated(&apdu[len], len_value, &property); + } else { + return -1; + } + /* tag 1 - propertyArrayIndex OPTIONAL */ + if (len >= (int)apdu_len) { + return -1; + } + if (decode_is_context_tag(&apdu[len], 1)) { + len += decode_tag_number_and_value( + &apdu[len], &tag_number, &len_value); + len += decode_unsigned(&apdu[len], len_value, &decoded_value); + } + /* tag 2: opening context tag - value */ + if (len >= (int)apdu_len) { + return -1; + } + if (!decode_is_opening_tag_number(&apdu[len], 2)) { + return -1; + } + /* a tag number of 2 is not extended so only one octet */ + len++; + while (!decode_is_closing_tag_number(&apdu[len], 2)) { + app_data = &value->value; + app_len = bacapp_decode_application_data( + &apdu[len], apdu_len - len, app_data); + if (app_len < 0) { + return -1; + } + len += app_len; + } + /* a tag number of 2 is not extended so only one octet */ + len++; + /* tag 3 - priority OPTIONAL */ + if (len >= (int)apdu_len) { + return -1; + } + if (decode_is_context_tag(&apdu[len], 3)) { + len += decode_tag_number_and_value( + &apdu[len], &tag_number, &len_value); + len += decode_unsigned(&apdu[len], len_value, &decoded_value); + } + /* end of list? */ + if (decode_is_closing_tag_number(&apdu[len], 6)) { + break; + } + } +#endif + + return len; +} + int uevent_notify_encode_apdu( uint8_t *apdu, BACNET_EVENT_NOTIFICATION_DATA *data) { @@ -513,6 +689,7 @@ int event_notify_decode_service_request( uint32_t enum_value = 0; uint32_t len_value = 0; uint8_t tag_number = 0; + bool is_complex_event_type = false; if (apdu_len && data) { /* tag 0 - processIdentifier */ @@ -660,459 +837,468 @@ int event_notify_decode_service_request( if (decode_is_opening_tag_number( &apdu[len], (uint8_t)data->eventType)) { len++; + switch (data->eventType) { + case EVENT_CHANGE_OF_BITSTRING: + if (-1 == + (section_length = decode_context_bitstring( + &apdu[len], 0, + &data->notificationParams.changeOfBitstring + .referencedBitString))) { + return -1; + } + len += section_length; + + if (-1 == + (section_length = + decode_context_bitstring(&apdu[len], 1, + &data->notificationParams + .changeOfBitstring.statusFlags))) { + return -1; + } + len += section_length; + + break; + + case EVENT_CHANGE_OF_STATE: + if (-1 == + (section_length = + bacapp_decode_context_property_state( + &apdu[len], 0, + &data->notificationParams.changeOfState + .newState))) { + return -1; + } + len += section_length; + + if (-1 == + (section_length = + decode_context_bitstring(&apdu[len], 1, + &data->notificationParams.changeOfState + .statusFlags))) { + return -1; + } + len += section_length; + + break; + + case EVENT_CHANGE_OF_VALUE: + if (!decode_is_opening_tag_number(&apdu[len], 0)) { + return -1; + } + len++; + + if (decode_is_context_tag( + &apdu[len], CHANGE_OF_VALUE_BITS)) { + if (-1 == + (section_length = decode_context_bitstring( + &apdu[len], 0, + &data->notificationParams.changeOfValue + .newValue.changedBits))) { + return -1; + } + + len += section_length; + data->notificationParams.changeOfValue.tag = + CHANGE_OF_VALUE_BITS; + } else if (decode_is_context_tag( + &apdu[len], CHANGE_OF_VALUE_REAL)) { + if (-1 == + (section_length = decode_context_real( + &apdu[len], 1, + &data->notificationParams.changeOfValue + .newValue.changeValue))) { + return -1; + } + + len += section_length; + data->notificationParams.changeOfValue.tag = + CHANGE_OF_VALUE_REAL; + } else { + return -1; + } + if (!decode_is_closing_tag_number(&apdu[len], 0)) { + return -1; + } + len++; + + if (-1 == + (section_length = + decode_context_bitstring(&apdu[len], 1, + &data->notificationParams.changeOfValue + .statusFlags))) { + return -1; + } + len += section_length; + break; + + case EVENT_COMMAND_FAILURE: + if (!decode_is_opening_tag_number(&apdu[len], 0)) { + return -1; + } + len++; + + if (-1 == + (section_length = decode_tag_number_and_value( + &apdu[len], &tag_number, &len_value))) { + return -1; + } + len += section_length; + + switch (tag_number) { + case BACNET_APPLICATION_TAG_ENUMERATED: + if (-1 == + (section_length = decode_enumerated( + &apdu[len], len_value, &enum_value))) { + return -1; + } + data->notificationParams.commandFailure + .commandValue.binaryValue = enum_value; + break; + + case BACNET_APPLICATION_TAG_UNSIGNED_INT: + if (-1 == + (section_length = decode_unsigned( + &apdu[len], len_value, + &data->notificationParams + .commandFailure.commandValue + .unsignedValue))) { + return -1; + } + break; + + default: + return 0; + } + len += section_length; + + if (!decode_is_closing_tag_number(&apdu[len], 0)) { + return -1; + } + len++; + + if (-1 == + (section_length = + decode_context_bitstring(&apdu[len], 1, + &data->notificationParams.commandFailure + .statusFlags))) { + return -1; + } + len += section_length; + + if (!decode_is_opening_tag_number(&apdu[len], 2)) { + return -1; + } + len++; + + if (-1 == + (section_length = decode_tag_number_and_value( + &apdu[len], &tag_number, &len_value))) { + return -1; + } + len += section_length; + + switch (tag_number) { + case BACNET_APPLICATION_TAG_ENUMERATED: + if (-1 == + (section_length = decode_enumerated( + &apdu[len], len_value, &enum_value))) { + return -1; + } + data->notificationParams.commandFailure + .feedbackValue.binaryValue = enum_value; + break; + + case BACNET_APPLICATION_TAG_UNSIGNED_INT: + if (-1 == + (section_length = decode_unsigned( + &apdu[len], len_value, + &data->notificationParams + .commandFailure.feedbackValue + .unsignedValue))) { + return -1; + } + break; + + default: + return 0; + } + len += section_length; + + if (!decode_is_closing_tag_number(&apdu[len], 2)) { + return -1; + } + len++; + + break; + + case EVENT_FLOATING_LIMIT: + if (-1 == + (section_length = decode_context_real(&apdu[len], 0, + &data->notificationParams.floatingLimit + .referenceValue))) { + return -1; + } + len += section_length; + + if (-1 == + (section_length = + decode_context_bitstring(&apdu[len], 1, + &data->notificationParams.floatingLimit + .statusFlags))) { + return -1; + } + len += section_length; + if (-1 == + (section_length = decode_context_real(&apdu[len], 2, + &data->notificationParams.floatingLimit + .setPointValue))) { + return -1; + } + len += section_length; + + if (-1 == + (section_length = decode_context_real(&apdu[len], 3, + &data->notificationParams.floatingLimit + .errorLimit))) { + return -1; + } + len += section_length; + break; + + case EVENT_OUT_OF_RANGE: + if (-1 == + (section_length = decode_context_real(&apdu[len], 0, + &data->notificationParams.outOfRange + .exceedingValue))) { + return -1; + } + len += section_length; + + if (-1 == + (section_length = + decode_context_bitstring(&apdu[len], 1, + &data->notificationParams.outOfRange + .statusFlags))) { + return -1; + } + len += section_length; + if (-1 == + (section_length = decode_context_real(&apdu[len], 2, + &data->notificationParams.outOfRange + .deadband))) { + return -1; + } + len += section_length; + + if (-1 == + (section_length = decode_context_real(&apdu[len], 3, + &data->notificationParams.outOfRange + .exceededLimit))) { + return -1; + } + len += section_length; + break; + + case EVENT_CHANGE_OF_LIFE_SAFETY: + if (-1 == + (section_length = decode_context_enumerated( + &apdu[len], 0, &enum_value))) { + return -1; + } + data->notificationParams.changeOfLifeSafety.newState = + (BACNET_LIFE_SAFETY_STATE)enum_value; + len += section_length; + + if (-1 == + (section_length = decode_context_enumerated( + &apdu[len], 1, &enum_value))) { + return -1; + } + data->notificationParams.changeOfLifeSafety.newMode = + (BACNET_LIFE_SAFETY_MODE)enum_value; + len += section_length; + + if (-1 == + (section_length = decode_context_bitstring( + &apdu[len], 2, + &data->notificationParams.changeOfLifeSafety + .statusFlags))) { + return -1; + } + len += section_length; + + if (-1 == + (section_length = decode_context_enumerated( + &apdu[len], 3, &enum_value))) { + return -1; + } + data->notificationParams.changeOfLifeSafety + .operationExpected = + (BACNET_LIFE_SAFETY_OPERATION)enum_value; + len += section_length; + break; + + case EVENT_BUFFER_READY: + /* Tag 0 - bufferProperty */ + if (-1 == + (section_length = + bacapp_decode_context_device_obj_property_ref( + &apdu[len], 0, + &data->notificationParams.bufferReady + .bufferProperty))) { + return -1; + } + len += section_length; + /* Tag 1 - PreviousNotification */ + section_length = bacnet_unsigned_context_decode( + &apdu[len], apdu_len - len, 1, &unsigned_value); + if (section_length > 0) { + len += section_length; + if (unsigned_value <= UINT32_MAX) { + data->notificationParams.bufferReady + .previousNotification = + (uint32_t)unsigned_value; + } else { + return BACNET_STATUS_ERROR; + } + } else { + return BACNET_STATUS_ERROR; + } + /* Tag 2 - currentNotification */ + section_length = bacnet_unsigned_context_decode( + &apdu[len], apdu_len - len, 2, &unsigned_value); + if (section_length > 0) { + len += section_length; + if (unsigned_value <= UINT32_MAX) { + data->notificationParams.bufferReady + .currentNotification = + (uint32_t)unsigned_value; + } else { + return BACNET_STATUS_ERROR; + } + } else { + return BACNET_STATUS_ERROR; + } + break; + + case EVENT_UNSIGNED_RANGE: + /* Tag 0 - PreviousNotification */ + section_length = bacnet_unsigned_context_decode( + &apdu[len], apdu_len - len, 0, &unsigned_value); + if (section_length > 0) { + len += section_length; + if (unsigned_value <= UINT32_MAX) { + data->notificationParams.unsignedRange + .exceedingValue = (uint32_t)unsigned_value; + } else { + return BACNET_STATUS_ERROR; + } + } else { + return BACNET_STATUS_ERROR; + } + /* Tag 1 - statusFlags */ + if (-1 == + (section_length = + decode_context_bitstring(&apdu[len], 1, + &data->notificationParams.unsignedRange + .statusFlags))) { + return -1; + } + len += section_length; + /* Tag 2 - exceededLimit */ + section_length = bacnet_unsigned_context_decode( + &apdu[len], apdu_len - len, 2, &unsigned_value); + if (section_length > 0) { + len += section_length; + if (unsigned_value <= UINT32_MAX) { + data->notificationParams.unsignedRange + .exceededLimit = (uint32_t)unsigned_value; + } else { + return BACNET_STATUS_ERROR; + } + } else { + return BACNET_STATUS_ERROR; + } + break; + + case EVENT_ACCESS_EVENT: + if (-1 == + (section_length = decode_context_enumerated( + &apdu[len], 0, &enum_value))) { + return -1; + } + data->notificationParams.accessEvent.accessEvent = + enum_value; + len += section_length; + if (-1 == + (section_length = + decode_context_bitstring(&apdu[len], 1, + &data->notificationParams.accessEvent + .statusFlags))) { + return -1; + } + len += section_length; + + if (-1 == + (section_length = + decode_context_unsigned(&apdu[len], 2, + &data->notificationParams.accessEvent + .accessEventTag))) { + return -1; + } + len += section_length; + + if (-1 == + (section_length = bacapp_decode_context_timestamp( + &apdu[len], 3, + &data->notificationParams.accessEvent + .accessEventTime))) { + return -1; + } + len += section_length; + + if (-1 == + (section_length = + bacapp_decode_context_device_obj_ref( + &apdu[len], 4, + &data->notificationParams.accessEvent + .accessCredential))) { + return -1; + } + len += section_length; + + if (!decode_is_closing_tag(&apdu[len])) { + if (-1 == + (section_length = + bacapp_decode_context_authentication_factor( + &apdu[len], 5, + &data->notificationParams + .accessEvent + .authenticationFactor))) { + return -1; + } + len += section_length; + } + break; + + default: + return -1; + } + } else if (decode_is_opening_tag_number(&apdu[len], 6)) { + /* complex-event-type [6] SEQUENCE OF BACnetPropertyValue */ + len++; + is_complex_event_type = true; + + len = parse_complex_event_type_values(len, apdu_len, apdu, data); + if (len < 0) { + return -1; + } } else { return -1; } - switch (data->eventType) { - case EVENT_CHANGE_OF_BITSTRING: - if (-1 == - (section_length = decode_context_bitstring( - &apdu[len], 0, - &data->notificationParams.changeOfBitstring - .referencedBitString))) { - return -1; - } - len += section_length; - - if (-1 == - (section_length = - decode_context_bitstring(&apdu[len], 1, - &data->notificationParams - .changeOfBitstring.statusFlags))) { - return -1; - } - len += section_length; - - break; - - case EVENT_CHANGE_OF_STATE: - if (-1 == - (section_length = - bacapp_decode_context_property_state( - &apdu[len], 0, - &data->notificationParams.changeOfState - .newState))) { - return -1; - } - len += section_length; - - if (-1 == - (section_length = - decode_context_bitstring(&apdu[len], 1, - &data->notificationParams.changeOfState - .statusFlags))) { - return -1; - } - len += section_length; - - break; - - case EVENT_CHANGE_OF_VALUE: - if (!decode_is_opening_tag_number(&apdu[len], 0)) { - return -1; - } - len++; - - if (decode_is_context_tag( - &apdu[len], CHANGE_OF_VALUE_BITS)) { - if (-1 == - (section_length = decode_context_bitstring( - &apdu[len], 0, - &data->notificationParams.changeOfValue - .newValue.changedBits))) { - return -1; - } - - len += section_length; - data->notificationParams.changeOfValue.tag = - CHANGE_OF_VALUE_BITS; - } else if (decode_is_context_tag( - &apdu[len], CHANGE_OF_VALUE_REAL)) { - if (-1 == - (section_length = decode_context_real( - &apdu[len], 1, - &data->notificationParams.changeOfValue - .newValue.changeValue))) { - return -1; - } - - len += section_length; - data->notificationParams.changeOfValue.tag = - CHANGE_OF_VALUE_REAL; - } else { - return -1; - } - if (!decode_is_closing_tag_number(&apdu[len], 0)) { - return -1; - } - len++; - - if (-1 == - (section_length = - decode_context_bitstring(&apdu[len], 1, - &data->notificationParams.changeOfValue - .statusFlags))) { - return -1; - } - len += section_length; - break; - - case EVENT_COMMAND_FAILURE: - if (!decode_is_opening_tag_number(&apdu[len], 0)) { - return -1; - } - len++; - - if (-1 == - (section_length = decode_tag_number_and_value( - &apdu[len], &tag_number, &len_value))) { - return -1; - } - len += section_length; - - switch (tag_number) { - case BACNET_APPLICATION_TAG_ENUMERATED: - if (-1 == - (section_length = decode_enumerated( - &apdu[len], len_value, &enum_value))) { - return -1; - } - data->notificationParams.commandFailure - .commandValue.binaryValue = enum_value; - break; - - case BACNET_APPLICATION_TAG_UNSIGNED_INT: - if (-1 == - (section_length = decode_unsigned( - &apdu[len], len_value, - &data->notificationParams - .commandFailure.commandValue - .unsignedValue))) { - return -1; - } - break; - - default: - return 0; - } - len += section_length; - - if (!decode_is_closing_tag_number(&apdu[len], 0)) { - return -1; - } - len++; - - if (-1 == - (section_length = - decode_context_bitstring(&apdu[len], 1, - &data->notificationParams.commandFailure - .statusFlags))) { - return -1; - } - len += section_length; - - if (!decode_is_opening_tag_number(&apdu[len], 2)) { - return -1; - } - len++; - - if (-1 == - (section_length = decode_tag_number_and_value( - &apdu[len], &tag_number, &len_value))) { - return -1; - } - len += section_length; - - switch (tag_number) { - case BACNET_APPLICATION_TAG_ENUMERATED: - if (-1 == - (section_length = decode_enumerated( - &apdu[len], len_value, &enum_value))) { - return -1; - } - data->notificationParams.commandFailure - .feedbackValue.binaryValue = enum_value; - break; - - case BACNET_APPLICATION_TAG_UNSIGNED_INT: - if (-1 == - (section_length = decode_unsigned( - &apdu[len], len_value, - &data->notificationParams - .commandFailure.feedbackValue - .unsignedValue))) { - return -1; - } - break; - - default: - return 0; - } - len += section_length; - - if (!decode_is_closing_tag_number(&apdu[len], 2)) { - return -1; - } - len++; - - break; - - case EVENT_FLOATING_LIMIT: - if (-1 == - (section_length = decode_context_real(&apdu[len], 0, - &data->notificationParams.floatingLimit - .referenceValue))) { - return -1; - } - len += section_length; - - if (-1 == - (section_length = - decode_context_bitstring(&apdu[len], 1, - &data->notificationParams.floatingLimit - .statusFlags))) { - return -1; - } - len += section_length; - if (-1 == - (section_length = decode_context_real(&apdu[len], 2, - &data->notificationParams.floatingLimit - .setPointValue))) { - return -1; - } - len += section_length; - - if (-1 == - (section_length = decode_context_real(&apdu[len], 3, - &data->notificationParams.floatingLimit - .errorLimit))) { - return -1; - } - len += section_length; - break; - - case EVENT_OUT_OF_RANGE: - if (-1 == - (section_length = decode_context_real(&apdu[len], 0, - &data->notificationParams.outOfRange - .exceedingValue))) { - return -1; - } - len += section_length; - - if (-1 == - (section_length = - decode_context_bitstring(&apdu[len], 1, - &data->notificationParams.outOfRange - .statusFlags))) { - return -1; - } - len += section_length; - if (-1 == - (section_length = decode_context_real(&apdu[len], 2, - &data->notificationParams.outOfRange - .deadband))) { - return -1; - } - len += section_length; - - if (-1 == - (section_length = decode_context_real(&apdu[len], 3, - &data->notificationParams.outOfRange - .exceededLimit))) { - return -1; - } - len += section_length; - break; - - case EVENT_CHANGE_OF_LIFE_SAFETY: - if (-1 == - (section_length = decode_context_enumerated( - &apdu[len], 0, &enum_value))) { - return -1; - } - data->notificationParams.changeOfLifeSafety.newState = - (BACNET_LIFE_SAFETY_STATE)enum_value; - len += section_length; - - if (-1 == - (section_length = decode_context_enumerated( - &apdu[len], 1, &enum_value))) { - return -1; - } - data->notificationParams.changeOfLifeSafety.newMode = - (BACNET_LIFE_SAFETY_MODE)enum_value; - len += section_length; - - if (-1 == - (section_length = decode_context_bitstring( - &apdu[len], 2, - &data->notificationParams.changeOfLifeSafety - .statusFlags))) { - return -1; - } - len += section_length; - - if (-1 == - (section_length = decode_context_enumerated( - &apdu[len], 3, &enum_value))) { - return -1; - } - data->notificationParams.changeOfLifeSafety - .operationExpected = - (BACNET_LIFE_SAFETY_OPERATION)enum_value; - len += section_length; - break; - - case EVENT_BUFFER_READY: - /* Tag 0 - bufferProperty */ - if (-1 == - (section_length = - bacapp_decode_context_device_obj_property_ref( - &apdu[len], 0, - &data->notificationParams.bufferReady - .bufferProperty))) { - return -1; - } - len += section_length; - /* Tag 1 - PreviousNotification */ - section_length = bacnet_unsigned_context_decode( - &apdu[len], apdu_len - len, 1, &unsigned_value); - if (section_length > 0) { - len += section_length; - if (unsigned_value <= UINT32_MAX) { - data->notificationParams.bufferReady - .previousNotification = - (uint32_t)unsigned_value; - } else { - return BACNET_STATUS_ERROR; - } - } else { - return BACNET_STATUS_ERROR; - } - /* Tag 2 - currentNotification */ - section_length = bacnet_unsigned_context_decode( - &apdu[len], apdu_len - len, 2, &unsigned_value); - if (section_length > 0) { - len += section_length; - if (unsigned_value <= UINT32_MAX) { - data->notificationParams.bufferReady - .currentNotification = - (uint32_t)unsigned_value; - } else { - return BACNET_STATUS_ERROR; - } - } else { - return BACNET_STATUS_ERROR; - } - break; - - case EVENT_UNSIGNED_RANGE: - /* Tag 0 - PreviousNotification */ - section_length = bacnet_unsigned_context_decode( - &apdu[len], apdu_len - len, 0, &unsigned_value); - if (section_length > 0) { - len += section_length; - if (unsigned_value <= UINT32_MAX) { - data->notificationParams.unsignedRange - .exceedingValue = (uint32_t)unsigned_value; - } else { - return BACNET_STATUS_ERROR; - } - } else { - return BACNET_STATUS_ERROR; - } - /* Tag 1 - statusFlags */ - if (-1 == - (section_length = - decode_context_bitstring(&apdu[len], 1, - &data->notificationParams.unsignedRange - .statusFlags))) { - return -1; - } - len += section_length; - /* Tag 2 - exceededLimit */ - section_length = bacnet_unsigned_context_decode( - &apdu[len], apdu_len - len, 2, &unsigned_value); - if (section_length > 0) { - len += section_length; - if (unsigned_value <= UINT32_MAX) { - data->notificationParams.unsignedRange - .exceededLimit = (uint32_t)unsigned_value; - } else { - return BACNET_STATUS_ERROR; - } - } else { - return BACNET_STATUS_ERROR; - } - break; - - case EVENT_ACCESS_EVENT: - if (-1 == - (section_length = decode_context_enumerated( - &apdu[len], 0, &enum_value))) { - return -1; - } - data->notificationParams.accessEvent.accessEvent = - enum_value; - len += section_length; - if (-1 == - (section_length = - decode_context_bitstring(&apdu[len], 1, - &data->notificationParams.accessEvent - .statusFlags))) { - return -1; - } - len += section_length; - - if (-1 == - (section_length = - decode_context_unsigned(&apdu[len], 2, - &data->notificationParams.accessEvent - .accessEventTag))) { - return -1; - } - len += section_length; - - if (-1 == - (section_length = bacapp_decode_context_timestamp( - &apdu[len], 3, - &data->notificationParams.accessEvent - .accessEventTime))) { - return -1; - } - len += section_length; - - if (-1 == - (section_length = - bacapp_decode_context_device_obj_ref( - &apdu[len], 4, - &data->notificationParams.accessEvent - .accessCredential))) { - return -1; - } - len += section_length; - - if (!decode_is_closing_tag(&apdu[len])) { - if (-1 == - (section_length = - bacapp_decode_context_authentication_factor( - &apdu[len], 5, - &data->notificationParams - .accessEvent - .authenticationFactor))) { - return -1; - } - len += section_length; - } - break; - - default: - return -1; - } if (decode_is_closing_tag_number( - &apdu[len], (uint8_t)data->eventType)) { + &apdu[len], is_complex_event_type ? 6 : (uint8_t)data->eventType)) { len++; } else { return -1; diff --git a/src/bacnet/event.h b/src/bacnet/event.h index 62673e61..ad086c19 100644 --- a/src/bacnet/event.h +++ b/src/bacnet/event.h @@ -48,6 +48,20 @@ typedef enum { ** Based on UnconfirmedEventNotification-Request */ + +// TODO make these configurable from env? + +/** Enable decoding of complex-event-type property-values. If set to 0, the values are decoded and discarded. */ +#ifndef BACNET_DECODE_COMPLEX_EVENT_TYPE_PARAMETERS +#define BACNET_DECODE_COMPLEX_EVENT_TYPE_PARAMETERS 1 +#endif + +/** Max complex-event-type property-values to decode. Events with more values fail to decode. */ +#ifndef BACNET_COMPLEX_EVENT_TYPE_MAX_PARAMETERS +#define BACNET_COMPLEX_EVENT_TYPE_MAX_PARAMETERS 5 +#endif + + typedef struct BACnet_Event_Notification_Data { uint32_t processIdentifier; BACNET_OBJECT_ID initiatingObjectIdentifier; @@ -168,6 +182,14 @@ typedef struct BACnet_Event_Notification_Data { /* OPTIONAL - Set authenticationFactor.format_type to AUTHENTICATION_FACTOR_MAX if not being used */ } accessEvent; +#if (BACNET_DECODE_COMPLEX_EVENT_TYPE_PARAMETERS == 1) + /* + * complex-event-type - a sequence of values, used for proprietary event types + */ + struct { + BACNET_PROPERTY_VALUE values[BACNET_COMPLEX_EVENT_TYPE_MAX_PARAMETERS]; + } complexEventType; +#endif } notificationParams; } BACNET_EVENT_NOTIFICATION_DATA; diff --git a/test/bacnet/event/CMakeLists.txt b/test/bacnet/event/CMakeLists.txt index cc703706..0039d235 100644 --- a/test/bacnet/event/CMakeLists.txt +++ b/test/bacnet/event/CMakeLists.txt @@ -35,16 +35,28 @@ add_executable(${PROJECT_NAME} ${SRC_DIR}/bacnet/event.c # Support files and stubs (pathname alphabetical) ${SRC_DIR}/bacnet/authentication_factor.c + ${SRC_DIR}/bacnet/bacaddr.c + ${SRC_DIR}/bacnet/bacapp.c ${SRC_DIR}/bacnet/bacdcode.c + ${SRC_DIR}/bacnet/bacdest.c + ${SRC_DIR}/bacnet/bacdevobjpropref.c ${SRC_DIR}/bacnet/bacint.c ${SRC_DIR}/bacnet/bacreal.c ${SRC_DIR}/bacnet/bacstr.c ${SRC_DIR}/bacnet/bacpropstates.c - ${SRC_DIR}/bacnet/bacdevobjpropref.c ${SRC_DIR}/bacnet/basic/sys/bigend.c ${SRC_DIR}/bacnet/datetime.c ${SRC_DIR}/bacnet/basic/sys/days.c ${SRC_DIR}/bacnet/timestamp.c + # Dependencies of bacapp.c + ${SRC_DIR}/bacnet/bactext.c + ${SRC_DIR}/bacnet/indtext.c + ${SRC_DIR}/bacnet/weeklyschedule.c + ${SRC_DIR}/bacnet/bactimevalue.c + ${SRC_DIR}/bacnet/dailyschedule.c + ${SRC_DIR}/bacnet/lighting.c + ${SRC_DIR}/bacnet/timestamp.c + ${SRC_DIR}/bacnet/hostnport.c # Test and test library files ./src/main.c ${ZTST_DIR}/ztest_mock.c diff --git a/zephyr/tests/bacnet/event/CMakeLists.txt b/zephyr/tests/bacnet/event/CMakeLists.txt index 867185a3..70d00ca9 100644 --- a/zephyr/tests/bacnet/event/CMakeLists.txt +++ b/zephyr/tests/bacnet/event/CMakeLists.txt @@ -30,17 +30,29 @@ if(BOARD STREQUAL unit_testing) get_filename_component(BACNET_SRC ${BACNET_SRC_PATH} PATH) list(APPEND SOURCES + ${BACNET_SRC}/bacaddr.c + ${BACNET_SRC}/bacapp.c + ${BACNET_SRC}/bacstr.c ${BACNET_SRC}/bacdcode.c + ${BACNET_SRC}/bacdest.c ${BACNET_SRC}/bacstr.c ${BACNET_SRC}/bacint.c ${BACNET_SRC}/bacreal.c ${BACNET_SRC}/datetime.c - ${BACNET_SRC}/timestamp.c ${BACNET_SRC}/basic/sys/days.c ${BACNET_SRC}/bacdevobjpropref.c ${BACNET_SRC}/authentication_factor.c ${BACNET_SRC}/bacpropstates.c - ) + # Dependencies of bacapp.c + ${BACNET_SRC}/bactext.c + ${BACNET_SRC}/indtext.c + ${BACNET_SRC}/weeklyschedule.c + ${BACNET_SRC}/bactimevalue.c + ${BACNET_SRC}/dailyschedule.c + ${BACNET_SRC}/lighting.c + ${BACNET_SRC}/timestamp.c + ${BACNET_SRC}/hostnport.c + ) set(CONF_FILE "${CONF_FILE};prj.unit_testing.conf") find_package(Zephyr COMPONENTS unittest REQUIRED HINTS $ENV{ZEPHYR_BASE})