From bb081d28da4b82d19bf35763649ef559554b8861 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Fri, 5 Jan 2024 08:59:45 -0600 Subject: [PATCH] Bugfix/service request refactor size check (#553) * refactor service requests from service header * add APDU size checking and length feature * add unit tests to check for length when passing NULL buffer --------- Co-authored-by: Steve Karg --- src/bacnet/arf.c | 22 + src/bacnet/arf.h | 5 + src/bacnet/authentication_factor.c | 53 +- src/bacnet/awf.c | 22 + src/bacnet/awf.h | 6 + src/bacnet/bacpropstates.c | 39 +- src/bacnet/basic/sys/platform.h | 10 + src/bacnet/cov.c | 469 +++++++----- src/bacnet/cov.h | 250 +++---- src/bacnet/create_object.c | 24 +- src/bacnet/create_object.h | 3 + src/bacnet/dcc.c | 108 ++- src/bacnet/dcc.h | 17 +- src/bacnet/delete_object.c | 27 + src/bacnet/delete_object.h | 5 + src/bacnet/event.c | 1018 ++++++++++++++++----------- src/bacnet/event.h | 6 + src/bacnet/getevent.c | 63 +- src/bacnet/getevent.h | 5 + src/bacnet/list_element.c | 26 +- src/bacnet/list_element.h | 3 + src/bacnet/lso.c | 103 ++- src/bacnet/lso.h | 32 +- src/bacnet/rd.c | 73 +- src/bacnet/rd.h | 12 +- src/bacnet/readrange.c | 251 ++++--- src/bacnet/readrange.h | 10 + src/bacnet/rp.c | 254 +++++-- src/bacnet/rp.h | 23 +- src/bacnet/wp.c | 150 ++-- src/bacnet/wp.h | 9 + test/bacnet/cov/src/main.c | 10 +- test/bacnet/dcc/src/main.c | 70 +- test/bacnet/event/src/main.c | 696 +++++++++--------- test/bacnet/getevent/src/main.c | 60 +- test/bacnet/list_element/src/main.c | 8 + test/bacnet/lso/src/main.c | 38 +- test/bacnet/rd/src/main.c | 8 +- test/bacnet/rp/src/main.c | 140 ++-- 39 files changed, 2614 insertions(+), 1514 deletions(-) diff --git a/src/bacnet/arf.c b/src/bacnet/arf.c index c51691d8..31d37f5e 100644 --- a/src/bacnet/arf.c +++ b/src/bacnet/arf.c @@ -121,6 +121,28 @@ int arf_service_encode_apdu(uint8_t *apdu, BACNET_ATOMIC_READ_FILE_DATA *data) return apdu_len; } +/** + * @brief Encode the AtomicReadFile service request + * @param apdu Pointer to the buffer for encoded values + * @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 atomicreadfile_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_ATOMIC_READ_FILE_DATA *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = arf_service_encode_apdu(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = arf_service_encode_apdu(apdu, data); + } + + return apdu_len; +} + /** * @brief Encode the AtomicReadFile service request * @param apdu Pointer to the buffer for decoding. diff --git a/src/bacnet/arf.h b/src/bacnet/arf.h index 3340a363..09b4b5b4 100644 --- a/src/bacnet/arf.h +++ b/src/bacnet/arf.h @@ -69,6 +69,11 @@ extern "C" { int arf_service_encode_apdu( uint8_t *apdu, BACNET_ATOMIC_READ_FILE_DATA *data); + BACNET_STACK_EXPORT + size_t atomicreadfile_service_request_encode( + uint8_t *apdu, + size_t apdu_size, + BACNET_ATOMIC_READ_FILE_DATA *data); /* decode the service request only */ BACNET_STACK_EXPORT diff --git a/src/bacnet/authentication_factor.c b/src/bacnet/authentication_factor.c index 921b87c3..9d4742c8 100644 --- a/src/bacnet/authentication_factor.c +++ b/src/bacnet/authentication_factor.c @@ -26,27 +26,37 @@ #include "bacnet/authentication_factor.h" #include "bacnet/bacdcode.h" +/** + * @brief Encode the BACnetAuthenticationFactor complex data + * @param apdu Pointer to the buffer for encoding into, or NULL for length + * @param data Pointer used for encoding the value + * @return number of bytes encoded, or zero if unable to encode + */ int bacapp_encode_authentication_factor( uint8_t *apdu, BACNET_AUTHENTICATION_FACTOR *af) { int len; int apdu_len = 0; - len = encode_context_enumerated(&apdu[apdu_len], 0, af->format_type); + len = encode_context_enumerated(apdu, 0, af->format_type); if (len < 0) { return -1; } else { apdu_len += len; + if (apdu) { + apdu += len; + } } - - len = encode_context_unsigned(&apdu[apdu_len], 1, af->format_class); + len = encode_context_unsigned(apdu, 1, af->format_class); if (len < 0) { return -1; } else { apdu_len += len; + if (apdu) { + apdu += len; + } } - - len = encode_context_octet_string(&apdu[apdu_len], 2, &af->value); + len = encode_context_octet_string(apdu, 2, &af->value); if (len < 0) { return -1; } else { @@ -56,24 +66,40 @@ int bacapp_encode_authentication_factor( return apdu_len; } +/** + * @brief Encode the BACnetAuthenticationFactor context tagged complex data + * @param apdu Pointer to the buffer for encoding into, or NULL for length + * @param data Pointer used for encoding the value + * @return number of bytes encoded, or zero if unable to encode + */ int bacapp_encode_context_authentication_factor( uint8_t *apdu, uint8_t tag, BACNET_AUTHENTICATION_FACTOR *af) { int len; int apdu_len = 0; - len = encode_opening_tag(&apdu[apdu_len], tag); + len = encode_opening_tag(apdu, tag); apdu_len += len; - - len = bacapp_encode_authentication_factor(&apdu[apdu_len], af); + if (apdu) { + apdu += len; + } + len = bacapp_encode_authentication_factor(apdu, af); apdu_len += len; - - len = encode_closing_tag(&apdu[apdu_len], tag); + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, tag); apdu_len += len; return apdu_len; } +/** + * @brief Decode the BACnetAuthenticationFactor complex data + * @param apdu Pointer to the buffer for decoding. + * @param af Pointer to the property decoded data to be stored + * @return Bytes decoded or BACNET_STATUS_REJECT on error. + */ int bacapp_decode_authentication_factor( uint8_t *apdu, BACNET_AUTHENTICATION_FACTOR *af) { @@ -123,6 +149,13 @@ int bacapp_decode_authentication_factor( return apdu_len; } +/** + * @brief Decode the context tagged BACnetAuthenticationFactor complex data + * @param apdu Pointer to the buffer for decoding. + * @param tag context tag number wrapping the complex data + * @param af Pointer to the property decoded data to be stored + * @return Bytes decoded or BACNET_STATUS_REJECT on error. + */ int bacapp_decode_context_authentication_factor( uint8_t *apdu, uint8_t tag, BACNET_AUTHENTICATION_FACTOR *af) { diff --git a/src/bacnet/awf.c b/src/bacnet/awf.c index b19e8bfa..a7fd9fcc 100644 --- a/src/bacnet/awf.c +++ b/src/bacnet/awf.c @@ -129,6 +129,28 @@ int awf_service_encode_apdu(uint8_t *apdu, BACNET_ATOMIC_WRITE_FILE_DATA *data) return apdu_len; } +/** + * @brief Encode the AtomicWriteFile service request + * @param apdu Pointer to the buffer for encoded values + * @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 + */ +int atomicwritefile_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_ATOMIC_WRITE_FILE_DATA *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = awf_service_encode_apdu(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = awf_service_encode_apdu(apdu, data); + } + + return apdu_len; +} + /** * @brief Encode the AtomicWriteFile service request * @param apdu Pointer to the buffer for decoding. diff --git a/src/bacnet/awf.h b/src/bacnet/awf.h index e8733bde..8ee569ca 100644 --- a/src/bacnet/awf.h +++ b/src/bacnet/awf.h @@ -58,6 +58,12 @@ extern "C" { uint8_t *apdu, BACNET_ATOMIC_WRITE_FILE_DATA *data); BACNET_STACK_EXPORT + int atomicwritefile_service_request_encode( + uint8_t *apdu, + size_t apdu_size, + BACNET_ATOMIC_WRITE_FILE_DATA *data); + + BACNET_STACK_EXPORT int awf_encode_apdu( uint8_t * apdu, uint8_t invoke_id, diff --git a/src/bacnet/bacpropstates.c b/src/bacnet/bacpropstates.c index 8625d7e7..71375780 100644 --- a/src/bacnet/bacpropstates.c +++ b/src/bacnet/bacpropstates.c @@ -210,83 +210,88 @@ int bacapp_decode_context_property_state( return len; } +/** + * @brief Encode the BACnetPropertyState + * @param apdu Pointer to the buffer for encoding into, or NULL for length + * @param value Pointer to the value used for encoding + * @return number of bytes encoded, or zero if unable to encode + */ int bacapp_encode_property_state(uint8_t *apdu, BACNET_PROPERTY_STATE *value) { int len = 0; /* length of each encoding */ - if (value && apdu) { + + if (value) { switch (value->tag) { case BOOLEAN_VALUE: len = encode_context_boolean( - &apdu[0], 0, value->state.booleanValue); + apdu, 0, value->state.booleanValue); break; case BINARY_VALUE: len = encode_context_enumerated( - &apdu[0], 1, value->state.binaryValue); + apdu, 1, value->state.binaryValue); break; case EVENT_TYPE: len = encode_context_enumerated( - &apdu[0], 2, value->state.eventType); + apdu, 2, value->state.eventType); break; case POLARITY: len = encode_context_enumerated( - &apdu[0], 3, value->state.polarity); + apdu, 3, value->state.polarity); break; case PROGRAM_CHANGE: len = encode_context_enumerated( - &apdu[0], 4, value->state.programChange); + apdu, 4, value->state.programChange); break; case PROGRAM_STATE: len = encode_context_enumerated( - &apdu[0], 5, value->state.programState); + apdu, 5, value->state.programState); break; case REASON_FOR_HALT: len = encode_context_enumerated( - &apdu[0], 6, value->state.programError); + apdu, 6, value->state.programError); break; case RELIABILITY: len = encode_context_enumerated( - &apdu[0], 7, value->state.reliability); + apdu, 7, value->state.reliability); break; case STATE: len = - encode_context_enumerated(&apdu[0], 8, value->state.state); + encode_context_enumerated(apdu, 8, value->state.state); break; case SYSTEM_STATUS: len = encode_context_enumerated( - &apdu[0], 9, value->state.systemStatus); + apdu, 9, value->state.systemStatus); break; case UNITS: len = - encode_context_enumerated(&apdu[0], 10, value->state.units); + encode_context_enumerated(apdu, 10, value->state.units); break; case UNSIGNED_VALUE: len = encode_context_unsigned( - &apdu[0], 11, value->state.unsignedValue); + apdu, 11, value->state.unsignedValue); break; case LIFE_SAFETY_MODE: len = encode_context_enumerated( - &apdu[0], 12, value->state.lifeSafetyMode); + apdu, 12, value->state.lifeSafetyMode); break; case LIFE_SAFETY_STATE: len = encode_context_enumerated( - &apdu[0], 13, value->state.lifeSafetyState); + apdu, 13, value->state.lifeSafetyState); break; - default: - /* FIXME: assert(0); - return a negative len? */ break; } } diff --git a/src/bacnet/basic/sys/platform.h b/src/bacnet/basic/sys/platform.h index 6d781eac..fb2736e2 100644 --- a/src/bacnet/basic/sys/platform.h +++ b/src/bacnet/basic/sys/platform.h @@ -46,6 +46,16 @@ # include # endif +/* some common min/max as defined in windef.h */ +#ifndef NOMINMAX +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#endif /* NOMINMAX */ + #if defined(__MINGW32__) #define BACNET_STACK_FALLTHROUGH() /* fall through */ #elif defined(__GNUC__) diff --git a/src/bacnet/cov.c b/src/bacnet/cov.c index 0872443b..72c2a1b8 100644 --- a/src/bacnet/cov.c +++ b/src/bacnet/cov.c @@ -36,7 +36,6 @@ #include "bacnet/bacdcode.h" #include "bacnet/bacdef.h" #include "bacnet/bacapp.h" -#include "bacnet/memcopy.h" /* me! */ #include "bacnet/cov.h" @@ -53,7 +52,7 @@ Unconfirmed COV Notification * @brief Encode APDU for COV Notification. * @param apdu Pointer to the buffer, or NULL for length * @param data Pointer to the data to encode. - * @return bytes encoded or zero on error. + * @return number of bytes encoded, or zero on error. */ int cov_notify_encode_apdu(uint8_t *apdu, BACNET_COV_DATA *data) { @@ -61,72 +60,71 @@ int cov_notify_encode_apdu(uint8_t *apdu, BACNET_COV_DATA *data) int apdu_len = 0; /* total length of the apdu, return value */ BACNET_PROPERTY_VALUE *value = NULL; /* value in list */ - if (apdu) { - /* tag 0 - subscriberProcessIdentifier */ - len = - encode_context_unsigned(apdu, 0, data->subscriberProcessIdentifier); - apdu_len += len; - if (apdu) { - apdu += len; - } - /* tag 1 - initiatingDeviceIdentifier */ - len = encode_context_object_id( - apdu, 1, OBJECT_DEVICE, data->initiatingDeviceIdentifier); - apdu_len += len; - if (apdu) { - apdu += len; - } - /* tag 2 - monitoredObjectIdentifier */ - len = encode_context_object_id(apdu, 2, - data->monitoredObjectIdentifier.type, - data->monitoredObjectIdentifier.instance); - apdu_len += len; - if (apdu) { - apdu += len; - } - /* tag 3 - timeRemaining */ - len = encode_context_unsigned(apdu, 3, data->timeRemaining); - apdu_len += len; - if (apdu) { - apdu += len; - } - /* tag 4 - listOfValues */ - len = encode_opening_tag(apdu, 4); - apdu_len += len; - if (apdu) { - apdu += len; - } - /* the first value includes a pointer to the next value, etc */ - value = data->listOfValues; - while (value != NULL) { - len = bacapp_property_value_encode(apdu, value); - apdu_len += len; - if (apdu) { - apdu += len; - } - /* is there another one to encode? */ - value = value->next; - } - len = encode_closing_tag(apdu, 4); - apdu_len += len; + if (!data) { + return 0; } + /* tag 0 - subscriberProcessIdentifier */ + len = + encode_context_unsigned(apdu, 0, data->subscriberProcessIdentifier); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* tag 1 - initiatingDeviceIdentifier */ + len = encode_context_object_id( + apdu, 1, OBJECT_DEVICE, data->initiatingDeviceIdentifier); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* tag 2 - monitoredObjectIdentifier */ + len = encode_context_object_id(apdu, 2, + data->monitoredObjectIdentifier.type, + data->monitoredObjectIdentifier.instance); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* tag 3 - timeRemaining */ + len = encode_context_unsigned(apdu, 3, data->timeRemaining); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* tag 4 - listOfValues */ + len = encode_opening_tag(apdu, 4); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* the first value includes a pointer to the next value, etc */ + value = data->listOfValues; + while (value != NULL) { + len = bacapp_property_value_encode(apdu, value); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* is there another one to encode? */ + value = value->next; + } + len = encode_closing_tag(apdu, 4); + apdu_len += len; return apdu_len; } /** - * Encode APDU for notification. - * + * @brief Encode the COVNotification 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 data to encode. - * - * @return bytes encoded or zero if unable to encode + * @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 */ -static int notify_encode_apdu( - uint8_t *apdu, unsigned apdu_size, BACNET_COV_DATA *data) +size_t cov_notify_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_COV_DATA *data) { - int apdu_len = 0; /* total length of the apdu, return value */ + size_t apdu_len = 0; /* total length of the apdu, return value */ apdu_len = cov_notify_encode_apdu(NULL, data); if (apdu_len > apdu_size) { @@ -141,67 +139,71 @@ static int notify_encode_apdu( /** * Encode APDU for confirmed notification. * - * @param apdu Pointer to the buffer. - * @param max_apdu_len Buffer size. + * @param apdu Pointer to the buffer, or NULL for length + * @param apdu_size number of bytes available in the buffer * @param invoke_id ID to invoke for notification * @param data Pointer to the data to encode. * * @return bytes encoded or zero on error. */ int ccov_notify_encode_apdu(uint8_t *apdu, - unsigned max_apdu_len, + unsigned apdu_size, uint8_t invoke_id, BACNET_COV_DATA *data) { int len = 0; /* length of each encoding */ - int apdu_len = BACNET_STATUS_ERROR; /* return value */ + int apdu_len = 0; /* return value */ - if (apdu && data && memcopylen(0, max_apdu_len, 4)) { + if (apdu && (apdu_size > 4)) { 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_COV_NOTIFICATION; - apdu_len = 4; - len = - notify_encode_apdu(&apdu[apdu_len], max_apdu_len - apdu_len, data); - if (len <= 0) { - /* return the error */ - apdu_len = len; - } else { - apdu_len += len; - } + } + len = 4; + apdu_len += len; + if (apdu) { + apdu += len; + } + len = cov_notify_service_request_encode( + apdu, apdu_size - apdu_len, data); + if (len > 0) { + apdu_len += len; + } else { + apdu_len = 0; } return apdu_len; } /** - * Encode APDU for unconfirmed notification. - * - * @param apdu Pointer to the buffer. - * @param max_apdu_len Buffer size. - * @param data Pointer to the data to encode. - * - * @return bytes encoded or zero on error. + * @brief Encode APDU for unconfirmed notification. + * @param apdu Pointer to the buffer for encoding into, or NULL for length + * @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 */ int ucov_notify_encode_apdu( - uint8_t *apdu, unsigned max_apdu_len, BACNET_COV_DATA *data) + uint8_t *apdu, unsigned apdu_size, BACNET_COV_DATA *data) { int len = 0; /* length of each encoding */ - int apdu_len = BACNET_STATUS_ERROR; /* return value */ + int apdu_len = 0; /* return value */ - if (apdu && data && memcopylen(0, max_apdu_len, 2)) { + if (apdu && (apdu_size > 2)) { apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST; - apdu[1] = SERVICE_UNCONFIRMED_COV_NOTIFICATION; /* service choice */ - apdu_len = 2; - len = - notify_encode_apdu(&apdu[apdu_len], max_apdu_len - apdu_len, data); - if (len <= 0) { - /* return the error */ - apdu_len = len; - } else { - apdu_len += len; - } + apdu[1] = SERVICE_UNCONFIRMED_COV_NOTIFICATION; + } + len = 2; + apdu_len += len; + if (apdu) { + apdu += len; + } + len = cov_notify_service_request_encode( + apdu, apdu_size - apdu_len, data); + if (len > 0) { + apdu_len += len; + } else { + apdu_len = 0; } return apdu_len; @@ -351,53 +353,110 @@ SubscribeCOV-Request ::= SEQUENCE { */ /** - * Encode the COV-service request. - * Note: COV and Unconfirmed COV are the same. - * + * @brief Encode APDU for SubscribeCOV-Request + * @note COV and Unconfirmed COV are the same encodings + * @param apdu Pointer to the buffer, or NULL for length + * @param data Pointer to the data to encode. + * @return number of bytes encoded, or zero on error. + */ +int cov_subscribe_apdu_encode(uint8_t *apdu, BACNET_SUBSCRIBE_COV_DATA *data) +{ + int len = 0; /* length of each encoding */ + int apdu_len = 0; /* total length of the apdu, return value */ + + /* tag 0 - subscriberProcessIdentifier */ + len = encode_context_unsigned(apdu, 0, data->subscriberProcessIdentifier); + apdu_len += len; + if (apdu) { + apdu += len; + } + + /* tag 1 - monitoredObjectIdentifier */ + len = + encode_context_object_id(apdu, 1, data->monitoredObjectIdentifier.type, + data->monitoredObjectIdentifier.instance); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* + If both the 'Issue Confirmed Notifications' and + 'Lifetime' parameters are absent, then this shall + indicate a cancellation request. + */ + if (!data->cancellationRequest) { + /* tag 2 - issueConfirmedNotifications */ + len = + encode_context_boolean(apdu, 2, data->issueConfirmedNotifications); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* tag 3 - lifetime */ + len = encode_context_unsigned(apdu, 3, data->lifetime); + apdu_len += len; + } + + return apdu_len; +} + +/** + * @brief Encode the SubscribeCOV service request + * @note COV and Unconfirmed COV are the same encodings + * @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 cov_subscribe_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_SUBSCRIBE_COV_DATA *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = cov_subscribe_apdu_encode(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = cov_subscribe_apdu_encode(apdu, data); + } + + return apdu_len; +} + +/** + * @brief Encode the COV-service request. + * @note COV and Unconfirmed COV are the same encodings * @param apdu Pointer to the buffer. + * @param apdu_size number of bytes available in the buffer * @param invoke_id Invoke ID * @param data Pointer to the data to store the decoded values. - * - * @return Bytes encoded or zero on error. + * @return number of bytes encoded, or zero if unable to encode or too large */ int cov_subscribe_encode_apdu(uint8_t *apdu, - unsigned max_apdu_len, + unsigned apdu_size, uint8_t invoke_id, BACNET_SUBSCRIBE_COV_DATA *data) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ - (void)max_apdu_len; - if (apdu && data) { + if (apdu && (apdu_size > 4)) { 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_SUBSCRIBE_COV; - apdu_len = 4; - /* tag 0 - subscriberProcessIdentifier */ - len = encode_context_unsigned( - &apdu[apdu_len], 0, data->subscriberProcessIdentifier); + } + len = 4; + apdu_len += len; + if (apdu) { + apdu += len; + } + len = + cov_subscribe_service_request_encode(apdu, apdu_size - apdu_len, data); + if (len > 0) { apdu_len += len; - /* tag 1 - monitoredObjectIdentifier */ - len = encode_context_object_id(&apdu[apdu_len], 1, - data->monitoredObjectIdentifier.type, - data->monitoredObjectIdentifier.instance); - apdu_len += len; - /* - If both the 'Issue Confirmed Notifications' and - 'Lifetime' parameters are absent, then this shall - indicate a cancellation request. - */ - if (!data->cancellationRequest) { - /* tag 2 - issueConfirmedNotifications */ - len = encode_context_boolean( - &apdu[apdu_len], 2, data->issueConfirmedNotifications); - apdu_len += len; - /* tag 3 - lifetime */ - len = encode_context_unsigned(&apdu[apdu_len], 3, data->lifetime); - apdu_len += len; - } + } else { + apdu_len = 0; } return apdu_len; @@ -534,67 +593,141 @@ BACnetPropertyReference ::= SEQUENCE { */ /** - * Encode the properties for subscription into the APDU. - * + * @brief Encode APDU for SubscribeCOVProperty request + * @param apdu Pointer to the buffer, or NULL for length + * @param data Pointer to the data to encode. + * @return bytes encoded or zero on error. + */ +int cov_subscribe_property_apdu_encode( + uint8_t *apdu, BACNET_SUBSCRIBE_COV_DATA *data) +{ + int len = 0; /* length of each encoding */ + int apdu_len = 0; /* total length of the apdu, return value */ + + if (!data) { + return 0; + } + /* tag 0 - subscriberProcessIdentifier */ + len = encode_context_unsigned(apdu, 0, data->subscriberProcessIdentifier); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* tag 1 - monitoredObjectIdentifier */ + len = + encode_context_object_id(apdu, 1, data->monitoredObjectIdentifier.type, + data->monitoredObjectIdentifier.instance); + apdu_len += len; + if (apdu) { + apdu += len; + } + if (!data->cancellationRequest) { + /* tag 2 - issueConfirmedNotifications */ + len = + encode_context_boolean(apdu, 2, data->issueConfirmedNotifications); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* tag 3 - lifetime */ + len = encode_context_unsigned(apdu, 3, data->lifetime); + apdu_len += len; + if (apdu) { + apdu += len; + } + } + /* tag 4 - monitoredPropertyIdentifier */ + len = encode_opening_tag(apdu, 4); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_enumerated( + apdu, 0, data->monitoredProperty.propertyIdentifier); + apdu_len += len; + if (apdu) { + apdu += len; + } + if (data->monitoredProperty.propertyArrayIndex != BACNET_ARRAY_ALL) { + len = encode_context_unsigned( + apdu, 1, data->monitoredProperty.propertyArrayIndex); + apdu_len += len; + if (apdu) { + apdu += len; + } + } + len = encode_closing_tag(apdu, 4); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* tag 5 - covIncrement */ + if (data->covIncrementPresent) { + len = encode_context_real(apdu, 5, data->covIncrement); + apdu_len += len; + } + + return apdu_len; +} + +/** + * @brief Encode the SubscribeCOVProperty 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 cov_subscribe_property_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_SUBSCRIBE_COV_DATA *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = cov_subscribe_property_apdu_encode(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = cov_subscribe_property_apdu_encode(apdu, data); + } + + return apdu_len; +} + +/** + * @brief Encode SubscribeCOVProperty request * @param apdu Pointer to the buffer. - * @param max_apdu_len Buffer size. + * @param apdu_size number of bytes available in the buffer * @param invoke_id Invoke Id. * @param data Pointer to the data to encode. - * - * @return Bytes decoded or Zero/BACNET_STATUS_ERROR on error. + * @return number of bytes encoded, or zero on error. */ int cov_subscribe_property_encode_apdu(uint8_t *apdu, - unsigned max_apdu_len, + unsigned apdu_size, uint8_t invoke_id, BACNET_SUBSCRIBE_COV_DATA *data) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ - (void)max_apdu_len; - if (apdu && data) { + if (!data) { + return 0; + } + if (apdu && (apdu_size > 4)) { 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_SUBSCRIBE_COV_PROPERTY; - apdu_len = 4; - /* tag 0 - subscriberProcessIdentifier */ - len = encode_context_unsigned( - &apdu[apdu_len], 0, data->subscriberProcessIdentifier); + } + len = 4; + apdu_len += len; + if (apdu) { + apdu += len; + } + len = cov_subscribe_property_service_request_encode( + apdu, apdu_size - apdu_len, data); + if (len > 0) { apdu_len += len; - /* tag 1 - monitoredObjectIdentifier */ - len = encode_context_object_id(&apdu[apdu_len], 1, - data->monitoredObjectIdentifier.type, - data->monitoredObjectIdentifier.instance); - apdu_len += len; - if (!data->cancellationRequest) { - /* tag 2 - issueConfirmedNotifications */ - len = encode_context_boolean( - &apdu[apdu_len], 2, data->issueConfirmedNotifications); - apdu_len += len; - /* tag 3 - lifetime */ - len = encode_context_unsigned(&apdu[apdu_len], 3, data->lifetime); - apdu_len += len; - } - /* tag 4 - monitoredPropertyIdentifier */ - len = encode_opening_tag(&apdu[apdu_len], 4); - apdu_len += len; - len = encode_context_enumerated( - &apdu[apdu_len], 0, data->monitoredProperty.propertyIdentifier); - apdu_len += len; - if (data->monitoredProperty.propertyArrayIndex != BACNET_ARRAY_ALL) { - len = encode_context_unsigned( - &apdu[apdu_len], 1, data->monitoredProperty.propertyArrayIndex); - apdu_len += len; - } - len = encode_closing_tag(&apdu[apdu_len], 4); - apdu_len += len; - - /* tag 5 - covIncrement */ - if (data->covIncrementPresent) { - len = encode_context_real(&apdu[apdu_len], 5, data->covIncrement); - apdu_len += len; - } + } else { + apdu_len = 0; } return apdu_len; diff --git a/src/bacnet/cov.h b/src/bacnet/cov.h index eebb318d..8159a057 100644 --- a/src/bacnet/cov.h +++ b/src/bacnet/cov.h @@ -1,26 +1,26 @@ /************************************************************************** -* -* Copyright (C) 2012 Steve Karg -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*********************************************************************/ + * + * Copyright (C) 2012 Steve Karg + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *********************************************************************/ #ifndef COV_H #define COV_H @@ -33,7 +33,7 @@ typedef struct BACnet_COV_Data { uint32_t subscriberProcessIdentifier; uint32_t initiatingDeviceIdentifier; BACNET_OBJECT_ID monitoredObjectIdentifier; - uint32_t timeRemaining; /* seconds */ + uint32_t timeRemaining; /* seconds */ /* simple linked list of values */ BACNET_PROPERTY_VALUE *listOfValues; } BACNET_COV_DATA; @@ -42,12 +42,12 @@ struct BACnet_Subscribe_COV_Data; typedef struct BACnet_Subscribe_COV_Data { uint32_t subscriberProcessIdentifier; BACNET_OBJECT_ID monitoredObjectIdentifier; - bool cancellationRequest; /* true if this is a cancellation request */ - bool issueConfirmedNotifications; /* optional */ - uint32_t lifetime; /* seconds, optional */ - bool covSubscribeToProperty; /* true to use per-property subscription */ + bool cancellationRequest; /* true if this is a cancellation request */ + bool issueConfirmedNotifications; /* optional */ + uint32_t lifetime; /* seconds, optional */ + bool covSubscribeToProperty; /* true to use per-property subscription */ BACNET_PROPERTY_REFERENCE monitoredProperty; - bool covIncrementPresent; /* true if present */ + bool covIncrementPresent; /* true if present */ float covIncrement; /* optional */ BACNET_ERROR_CLASS error_class; BACNET_ERROR_CODE error_code; @@ -55,8 +55,7 @@ typedef struct BACnet_Subscribe_COV_Data { } BACNET_SUBSCRIBE_COV_DATA; /* generic callback for COV notifications */ -typedef void (*BACnet_COV_Notification_Callback) - (BACNET_COV_DATA *cov_data); +typedef void (*BACnet_COV_Notification_Callback)(BACNET_COV_DATA *cov_data); struct BACnet_COV_Notification; typedef struct BACnet_COV_Notification { struct BACnet_COV_Notification *next; @@ -67,113 +66,114 @@ typedef struct BACnet_COV_Notification { extern "C" { #endif /* __cplusplus */ - BACNET_STACK_EXPORT - int cov_notify_encode_apdu( - uint8_t *apdu, BACNET_COV_DATA *data); +BACNET_STACK_EXPORT +size_t cov_notify_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_COV_DATA *data); - BACNET_STACK_EXPORT - int ucov_notify_encode_apdu( - uint8_t * apdu, - unsigned max_apdu_len, - BACNET_COV_DATA * data); +BACNET_STACK_EXPORT +int cov_notify_encode_apdu(uint8_t *apdu, BACNET_COV_DATA *data); - BACNET_STACK_EXPORT - int ucov_notify_decode_apdu( - uint8_t * apdu, - unsigned apdu_len, - BACNET_COV_DATA * data); +BACNET_STACK_EXPORT +int ucov_notify_encode_apdu( + uint8_t *apdu, unsigned max_apdu_len, BACNET_COV_DATA *data); - BACNET_STACK_EXPORT - int ucov_notify_send( - uint8_t * apdu, - unsigned max_apdu_len, - BACNET_COV_DATA * data); +BACNET_STACK_EXPORT +int ucov_notify_decode_apdu( + uint8_t *apdu, unsigned apdu_len, BACNET_COV_DATA *data); - BACNET_STACK_EXPORT - int ccov_notify_encode_apdu( - uint8_t * apdu, - unsigned max_apdu_len, - uint8_t invoke_id, - BACNET_COV_DATA * data); +BACNET_STACK_EXPORT +int ucov_notify_send( + uint8_t *apdu, unsigned max_apdu_len, BACNET_COV_DATA *data); - BACNET_STACK_EXPORT - int ccov_notify_decode_apdu( - uint8_t * apdu, - unsigned apdu_len, - uint8_t * invoke_id, - BACNET_COV_DATA * data); +BACNET_STACK_EXPORT +int ccov_notify_encode_apdu(uint8_t *apdu, + unsigned max_apdu_len, + uint8_t invoke_id, + BACNET_COV_DATA *data); - /* common for both confirmed and unconfirmed */ - BACNET_STACK_EXPORT - int cov_notify_decode_service_request( - uint8_t * apdu, - unsigned apdu_len, - BACNET_COV_DATA * data); +BACNET_STACK_EXPORT +int ccov_notify_decode_apdu(uint8_t *apdu, + unsigned apdu_len, + uint8_t *invoke_id, + BACNET_COV_DATA *data); - BACNET_STACK_EXPORT - int cov_subscribe_property_decode_service_request( - uint8_t * apdu, - unsigned apdu_len, - BACNET_SUBSCRIBE_COV_DATA * data); +/* common for both confirmed and unconfirmed */ +BACNET_STACK_EXPORT +int cov_notify_decode_service_request( + uint8_t *apdu, unsigned apdu_len, BACNET_COV_DATA *data); - BACNET_STACK_EXPORT - int cov_subscribe_property_encode_apdu( - uint8_t * apdu, - unsigned max_apdu_len, - uint8_t invoke_id, - BACNET_SUBSCRIBE_COV_DATA * data); +BACNET_STACK_EXPORT +int cov_subscribe_property_decode_service_request( + uint8_t *apdu, unsigned apdu_len, BACNET_SUBSCRIBE_COV_DATA *data); - BACNET_STACK_EXPORT - int cov_subscribe_decode_service_request( - uint8_t * apdu, - unsigned apdu_len, - BACNET_SUBSCRIBE_COV_DATA * data); +BACNET_STACK_EXPORT +int cov_subscribe_property_apdu_encode( + uint8_t *apdu, BACNET_SUBSCRIBE_COV_DATA *data); - BACNET_STACK_EXPORT - int cov_subscribe_encode_apdu( - uint8_t * apdu, - unsigned max_apdu_len, - uint8_t invoke_id, - BACNET_SUBSCRIBE_COV_DATA * data); +BACNET_STACK_EXPORT +size_t cov_subscribe_property_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_SUBSCRIBE_COV_DATA *data); - BACNET_STACK_EXPORT - void cov_data_value_list_link( - BACNET_COV_DATA *data, - BACNET_PROPERTY_VALUE *value_list, - size_t count); +BACNET_STACK_EXPORT +int cov_subscribe_property_encode_apdu(uint8_t *apdu, + unsigned max_apdu_len, + uint8_t invoke_id, + BACNET_SUBSCRIBE_COV_DATA *data); - BACNET_STACK_EXPORT - bool cov_value_list_encode_real( - BACNET_PROPERTY_VALUE * value_list, - float value, - bool in_alarm, - bool fault, - bool overridden, - bool out_of_service); - BACNET_STACK_EXPORT - bool cov_value_list_encode_enumerated( - BACNET_PROPERTY_VALUE * value_list, - uint32_t value, - bool in_alarm, - bool fault, - bool overridden, - bool out_of_service); - BACNET_STACK_EXPORT - bool cov_value_list_encode_unsigned( - BACNET_PROPERTY_VALUE * value_list, - uint32_t value, - bool in_alarm, - bool fault, - bool overridden, - bool out_of_service); - BACNET_STACK_EXPORT - bool cov_value_list_encode_character_string( - BACNET_PROPERTY_VALUE * value_list, - BACNET_CHARACTER_STRING * value, - bool in_alarm, - bool fault, - bool overridden, - bool out_of_service); +BACNET_STACK_EXPORT +int cov_subscribe_decode_service_request( + uint8_t *apdu, + unsigned apdu_len, + BACNET_SUBSCRIBE_COV_DATA *data); + +BACNET_STACK_EXPORT +int cov_subscribe_apdu_encode(uint8_t *apdu, + BACNET_SUBSCRIBE_COV_DATA *data); + +BACNET_STACK_EXPORT +size_t cov_subscribe_service_request_encode( + uint8_t *apdu, + size_t apdu_size, + BACNET_SUBSCRIBE_COV_DATA *data); + +BACNET_STACK_EXPORT +int cov_subscribe_encode_apdu(uint8_t *apdu, + unsigned max_apdu_len, + uint8_t invoke_id, + BACNET_SUBSCRIBE_COV_DATA *data); + +BACNET_STACK_EXPORT +void cov_data_value_list_link( + BACNET_COV_DATA *data, BACNET_PROPERTY_VALUE *value_list, size_t count); + +BACNET_STACK_EXPORT +bool cov_value_list_encode_real(BACNET_PROPERTY_VALUE *value_list, + float value, + bool in_alarm, + bool fault, + bool overridden, + bool out_of_service); +BACNET_STACK_EXPORT +bool cov_value_list_encode_enumerated(BACNET_PROPERTY_VALUE *value_list, + uint32_t value, + bool in_alarm, + bool fault, + bool overridden, + bool out_of_service); +BACNET_STACK_EXPORT +bool cov_value_list_encode_unsigned(BACNET_PROPERTY_VALUE *value_list, + uint32_t value, + bool in_alarm, + bool fault, + bool overridden, + bool out_of_service); +BACNET_STACK_EXPORT +bool cov_value_list_encode_character_string(BACNET_PROPERTY_VALUE *value_list, + BACNET_CHARACTER_STRING *value, + bool in_alarm, + bool fault, + bool overridden, + bool out_of_service); #ifdef __cplusplus } diff --git a/src/bacnet/create_object.c b/src/bacnet/create_object.c index 4e2c2fba..60277d1a 100644 --- a/src/bacnet/create_object.c +++ b/src/bacnet/create_object.c @@ -95,6 +95,28 @@ int create_object_encode_service_request( return apdu_len; } +/** + * @brief Encode the CreateObject 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 create_object_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_CREATE_OBJECT_DATA *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = create_object_encode_service_request(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = create_object_encode_service_request(apdu, data); + } + + return apdu_len; +} + /** * @brief Decode the CreateObject service request * @@ -351,7 +373,6 @@ int create_object_error_ack_encode( return len; } -#if !BACNET_SVC_SERVER /** * @brief Decode a CreateObject-Error ACK APDU * @@ -420,4 +441,3 @@ int create_object_error_ack_service_decode( return apdu_len; } -#endif diff --git a/src/bacnet/create_object.h b/src/bacnet/create_object.h index f0a92b97..70c16ef8 100644 --- a/src/bacnet/create_object.h +++ b/src/bacnet/create_object.h @@ -51,6 +51,9 @@ typedef uint32_t (*create_object_function)(uint32_t object_instance); extern "C" { #endif /* __cplusplus */ +BACNET_STACK_EXPORT +size_t create_object_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_CREATE_OBJECT_DATA *data); BACNET_STACK_EXPORT int create_object_encode_service_request( uint8_t *apdu, BACNET_CREATE_OBJECT_DATA *data); diff --git a/src/bacnet/dcc.c b/src/bacnet/dcc.c index 5b40854b..3e1a0215 100644 --- a/src/bacnet/dcc.c +++ b/src/bacnet/dcc.c @@ -160,22 +160,91 @@ bool dcc_set_status_duration( #if BACNET_SVC_DCC_A /** - * Encode service - * + * @brief Encode DeviceCommunicationControl service * @param apdu Pointer to the APDU buffer used for encoding. - * @param invoke_id Invoke-Id * @param timeDuration Optional time duration in minutes. * @param enable_disable Enable/disable communication * @param password Pointer to an optional password. * * @return Bytes encoded or zero on an error. */ -int dcc_encode_apdu(uint8_t *apdu, - uint8_t invoke_id, - uint16_t timeDuration, /* 0=optional */ +int dcc_apdu_encode(uint8_t *apdu, + uint16_t timeDuration, BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable, BACNET_CHARACTER_STRING *password) -{ /* NULL=optional */ +{ + int len = 0; /* length of each encoding */ + int apdu_len = 0; /* total length of the apdu, return value */ + + /* optional timeDuration */ + if (timeDuration) { + len = encode_context_unsigned(apdu, 0, timeDuration); + apdu_len += len; + if (apdu) { + apdu += len; + } + } + /* enable disable */ + len = encode_context_enumerated(apdu, 1, enable_disable); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* optional password */ + if (password) { + if ((password->length >= 1) && (password->length <= 20)) { + len = encode_context_character_string(apdu, 2, password); + apdu_len += len; + } + } + + return apdu_len; +} + +/** + * @brief Encode the COVNotification service request + * @param apdu Pointer to the buffer for encoding into + * @param apdu_size number of bytes available in the buffer + * @param timeDuration Optional time duration in minutes. + * @param enable_disable Enable/disable communication + * @param password Pointer to an optional password. + * @return number of bytes encoded, or zero if unable to encode or too large + */ +size_t dcc_service_request_encode(uint8_t *apdu, + size_t apdu_size, + uint16_t timeDuration, + BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable, + BACNET_CHARACTER_STRING *password) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = dcc_apdu_encode(NULL, timeDuration, enable_disable, password); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = + dcc_apdu_encode(apdu, timeDuration, enable_disable, password); + } + + return apdu_len; +} + +/** + * Encode service + * + * @param apdu Pointer to the APDU buffer used for encoding. + * @param invoke_id Invoke-Id + * @param timeDuration Optional time duration in minutes, 0=optional + * @param enable_disable Enable/disable communication + * @param password Pointer to an optional password, NULL=optional + * @return Bytes encoded or zero on an error. + */ +int dcc_encode_apdu(uint8_t *apdu, + uint8_t invoke_id, + uint16_t timeDuration, + BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable, + BACNET_CHARACTER_STRING *password) +{ int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ @@ -184,24 +253,15 @@ int dcc_encode_apdu(uint8_t *apdu, apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); apdu[2] = invoke_id; apdu[3] = SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL; - apdu_len = 4; - /* optional timeDuration */ - if (timeDuration) { - len = encode_context_unsigned(&apdu[apdu_len], 0, timeDuration); - apdu_len += len; - } - /* enable disable */ - len = encode_context_enumerated(&apdu[apdu_len], 1, enable_disable); - apdu_len += len; - /* optional password */ - if (password) { - if ((password->length >= 1) && (password->length <= 20)) { - len = encode_context_character_string( - &apdu[apdu_len], 2, password); - apdu_len += len; - } - } } + len = 4; + apdu_len += len; + if (apdu) { + apdu += len; + } + len = dcc_apdu_encode( + apdu, timeDuration, enable_disable, password); + apdu_len += len; return apdu_len; } diff --git a/src/bacnet/dcc.h b/src/bacnet/dcc.h index ae9bfc81..a91f8348 100644 --- a/src/bacnet/dcc.h +++ b/src/bacnet/dcc.h @@ -62,16 +62,25 @@ extern "C" { BACNET_COMMUNICATION_ENABLE_DISABLE status, uint16_t minutes); -/* encode service */ + BACNET_STACK_EXPORT + int dcc_apdu_encode(uint8_t *apdu, + uint16_t timeDuration, + BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable, + BACNET_CHARACTER_STRING *password); + BACNET_STACK_EXPORT + size_t dcc_service_request_encode(uint8_t *apdu, + size_t apdu_size, + uint16_t timeDuration, + BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable, + BACNET_CHARACTER_STRING *password); BACNET_STACK_EXPORT int dcc_encode_apdu( uint8_t * apdu, uint8_t invoke_id, - uint16_t timeDuration, /* 0=optional */ + uint16_t timeDuration, BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable, - BACNET_CHARACTER_STRING * password); /* NULL=optional */ + BACNET_CHARACTER_STRING * password); -/* decode the service request only */ BACNET_STACK_EXPORT int dcc_decode_service_request( uint8_t * apdu, diff --git a/src/bacnet/delete_object.c b/src/bacnet/delete_object.c index d666430c..36704e55 100644 --- a/src/bacnet/delete_object.c +++ b/src/bacnet/delete_object.c @@ -44,6 +44,33 @@ int delete_object_encode_service_request( return apdu_len; } +/** + * @brief Encode the DeleteObject service request + * + * DeleteObject-Request ::= SEQUENCE { + * object-identifier BACnetObjectIdentifier + * } + * + * @param apdu Pointer to the buffer for encoded values + * @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 + */ +int delete_object_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_DELETE_OBJECT_DATA *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = delete_object_encode_service_request(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = delete_object_encode_service_request(apdu, data); + } + + return apdu_len; +} + /** * @brief Decode the DeleteObject service request * diff --git a/src/bacnet/delete_object.h b/src/bacnet/delete_object.h index 461a9ef6..4cb997b1 100644 --- a/src/bacnet/delete_object.h +++ b/src/bacnet/delete_object.h @@ -45,6 +45,11 @@ extern "C" { BACNET_STACK_EXPORT int delete_object_encode_service_request( uint8_t *apdu, BACNET_DELETE_OBJECT_DATA *data); + +BACNET_STACK_EXPORT +int delete_object_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_DELETE_OBJECT_DATA *data); + BACNET_STACK_EXPORT int delete_object_decode_service_request( uint8_t *apdu, uint32_t apdu_size, BACNET_DELETE_OBJECT_DATA *data); diff --git a/src/bacnet/event.c b/src/bacnet/event.c index 5d34159b..1188f4fd 100644 --- a/src/bacnet/event.c +++ b/src/bacnet/event.c @@ -91,6 +91,12 @@ static int complex_event_type_values_decode( return len; } +/** + * @brief Encode the unconfirmed COVNotification service request + * @param apdu Pointer to the buffer for encoding into + * @param data Pointer to the service data used for encoding values + * @return number of bytes encoded, or zero if unable to encode + */ int uevent_notify_encode_apdu( uint8_t *apdu, BACNET_EVENT_NOTIFICATION_DATA *data) { @@ -100,20 +106,29 @@ int uevent_notify_encode_apdu( if (apdu) { apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST; apdu[1] = SERVICE_UNCONFIRMED_EVENT_NOTIFICATION; /* service choice */ - apdu_len = 2; - - len += event_notify_encode_service_request(&apdu[apdu_len], data); - - if (len > 0) { - apdu_len += len; - } else { - apdu_len = 0; - } + } + len = 2; + apdu_len += len; + if (apdu) { + apdu += len; + } + len = event_notify_encode_service_request(apdu, data); + if (len > 0) { + apdu_len += len; + } else { + apdu_len = 0; } return apdu_len; } +/** + * @brief Encode the confirmed COVNotification service request + * @param apdu Pointer to the buffer for encoding into + * @param invoke_id ID to invoke for notification + * @param data Pointer to the service data used for encoding values + * @return number of bytes encoded, or zero if unable to encode + */ int cevent_notify_encode_apdu( uint8_t *apdu, uint8_t invoke_id, BACNET_EVENT_NOTIFICATION_DATA *data) { @@ -125,436 +140,599 @@ int cevent_notify_encode_apdu( apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); apdu[2] = invoke_id; apdu[3] = SERVICE_CONFIRMED_EVENT_NOTIFICATION; /* service choice */ - apdu_len = 4; - - len += event_notify_encode_service_request(&apdu[apdu_len], data); - - if (len > 0) { - apdu_len += len; - } else { - apdu_len = 0; - } + } + len = 4; + apdu_len += len; + if (apdu) { + apdu += len; + } + len = event_notify_encode_service_request(apdu, data); + if (len > 0) { + apdu_len += len; + } else { + apdu_len = 0; } return apdu_len; } +/** + * @brief Encode the COVNotification service request + * @param apdu Pointer to the buffer for encoding into + * @param data Pointer to the service data used for encoding values + * @return number of bytes encoded, or zero if unable to encode + */ int event_notify_encode_service_request( uint8_t *apdu, BACNET_EVENT_NOTIFICATION_DATA *data) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ + if (!data) { + return 0; + } + /* tag 0 - processIdentifier */ + len = encode_context_unsigned(apdu, 0, data->processIdentifier); + apdu_len += len; if (apdu) { - /* tag 0 - processIdentifier */ - len = encode_context_unsigned( - &apdu[apdu_len], 0, data->processIdentifier); - apdu_len += len; - /* tag 1 - initiatingObjectIdentifier */ - len = encode_context_object_id(&apdu[apdu_len], 1, - data->initiatingObjectIdentifier.type, + 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; - - /* tag 2 - eventObjectIdentifier */ - len = encode_context_object_id(&apdu[apdu_len], 2, - data->eventObjectIdentifier.type, - data->eventObjectIdentifier.instance); - apdu_len += len; - - /* tag 3 - timeStamp */ - - len = bacapp_encode_context_timestamp( - &apdu[apdu_len], 3, &data->timeStamp); - apdu_len += len; - - /* tag 4 - noticicationClass */ - - len = encode_context_unsigned( - &apdu[apdu_len], 4, data->notificationClass); - apdu_len += len; - - /* tag 5 - priority */ - - len = encode_context_unsigned(&apdu[apdu_len], 5, data->priority); - apdu_len += len; - - /* tag 6 - eventType */ - len = encode_context_enumerated(&apdu[apdu_len], 6, data->eventType); - apdu_len += len; - - /* tag 7 - messageText */ - if (data->messageText) { - len = encode_context_character_string( - &apdu[apdu_len], 7, data->messageText); - apdu_len += len; - } - /* tag 8 - notifyType */ - len = encode_context_enumerated(&apdu[apdu_len], 8, data->notifyType); - apdu_len += len; - - switch (data->notifyType) { - case NOTIFY_ALARM: - case NOTIFY_EVENT: - /* tag 9 - ackRequired */ - - len = encode_context_boolean( - &apdu[apdu_len], 9, data->ackRequired); - apdu_len += len; - - /* tag 10 - fromState */ - len = encode_context_enumerated( - &apdu[apdu_len], 10, data->fromState); - apdu_len += len; - break; - - default: - break; - } - - /* tag 11 - toState */ - len = encode_context_enumerated(&apdu[apdu_len], 11, data->toState); - apdu_len += len; - - switch (data->notifyType) { - case NOTIFY_ALARM: - case NOTIFY_EVENT: - /* tag 12 - event values */ - len = encode_opening_tag(&apdu[apdu_len], 12); - apdu_len += len; - - switch (data->eventType) { - case EVENT_CHANGE_OF_BITSTRING: - len = encode_opening_tag(&apdu[apdu_len], 0); - apdu_len += len; - - len = encode_context_bitstring(&apdu[apdu_len], 0, - &data->notificationParams.changeOfBitstring - .referencedBitString); - apdu_len += len; - - len = encode_context_bitstring(&apdu[apdu_len], 1, - &data->notificationParams.changeOfBitstring - .statusFlags); - apdu_len += len; - - len = encode_closing_tag(&apdu[apdu_len], 0); - apdu_len += len; - break; - - case EVENT_CHANGE_OF_STATE: - len = encode_opening_tag(&apdu[apdu_len], 1); - apdu_len += len; - - len = encode_opening_tag(&apdu[apdu_len], 0); - apdu_len += len; - - len = bacapp_encode_property_state(&apdu[apdu_len], - &data->notificationParams.changeOfState.newState); - apdu_len += len; - - len = encode_closing_tag(&apdu[apdu_len], 0); - apdu_len += len; - - len = encode_context_bitstring(&apdu[apdu_len], 1, - &data->notificationParams.changeOfState - .statusFlags); - apdu_len += len; - - len = encode_closing_tag(&apdu[apdu_len], 1); - apdu_len += len; - break; - - case EVENT_CHANGE_OF_VALUE: - len = encode_opening_tag(&apdu[apdu_len], 2); - apdu_len += len; - - len = encode_opening_tag(&apdu[apdu_len], 0); - apdu_len += len; - - switch (data->notificationParams.changeOfValue.tag) { - case CHANGE_OF_VALUE_REAL: - len = encode_context_real(&apdu[apdu_len], 1, - data->notificationParams.changeOfValue - .newValue.changeValue); - apdu_len += len; - break; - - case CHANGE_OF_VALUE_BITS: - len = - encode_context_bitstring(&apdu[apdu_len], 0, - &data->notificationParams.changeOfValue - .newValue.changedBits); - apdu_len += len; - break; - - default: - return 0; - } - - len = encode_closing_tag(&apdu[apdu_len], 0); - apdu_len += len; - - len = encode_context_bitstring(&apdu[apdu_len], 1, - &data->notificationParams.changeOfValue - .statusFlags); - apdu_len += len; - - len = encode_closing_tag(&apdu[apdu_len], 2); - apdu_len += len; - break; - - case EVENT_COMMAND_FAILURE: - - len = encode_opening_tag(&apdu[apdu_len], 3); - apdu_len += len; - - len = encode_opening_tag(&apdu[apdu_len], 0); - apdu_len += len; - - switch (data->notificationParams.commandFailure.tag) { - case COMMAND_FAILURE_BINARY_PV: - len = encode_application_enumerated( - &apdu[apdu_len], - data->notificationParams.commandFailure - .commandValue.binaryValue); - apdu_len += len; - break; - - case COMMAND_FAILURE_UNSIGNED: - len = - encode_application_unsigned(&apdu[apdu_len], - data->notificationParams.commandFailure - .commandValue.unsignedValue); - apdu_len += len; - break; - - default: - return 0; - } - - len = encode_closing_tag(&apdu[apdu_len], 0); - apdu_len += len; - - len = encode_context_bitstring(&apdu[apdu_len], 1, - &data->notificationParams.commandFailure - .statusFlags); - apdu_len += len; - - len = encode_opening_tag(&apdu[apdu_len], 2); - apdu_len += len; - - switch (data->notificationParams.commandFailure.tag) { - case COMMAND_FAILURE_BINARY_PV: - len = encode_application_enumerated( - &apdu[apdu_len], - data->notificationParams.commandFailure - .feedbackValue.binaryValue); - apdu_len += len; - break; - - case COMMAND_FAILURE_UNSIGNED: - len = - encode_application_unsigned(&apdu[apdu_len], - data->notificationParams.commandFailure - .feedbackValue.unsignedValue); - apdu_len += len; - break; - - default: - return 0; - } - - len = encode_closing_tag(&apdu[apdu_len], 2); - apdu_len += len; - - len = encode_closing_tag(&apdu[apdu_len], 3); - apdu_len += len; - break; - - case EVENT_FLOATING_LIMIT: - len = encode_opening_tag(&apdu[apdu_len], 4); - apdu_len += len; - - len = encode_context_real(&apdu[apdu_len], 0, - data->notificationParams.floatingLimit - .referenceValue); - apdu_len += len; - - len = encode_context_bitstring(&apdu[apdu_len], 1, - &data->notificationParams.floatingLimit - .statusFlags); - apdu_len += len; - - len = encode_context_real(&apdu[apdu_len], 2, - data->notificationParams.floatingLimit - .setPointValue); - apdu_len += len; - - len = encode_context_real(&apdu[apdu_len], 3, - data->notificationParams.floatingLimit.errorLimit); - apdu_len += len; - - len = encode_closing_tag(&apdu[apdu_len], 4); - apdu_len += len; - break; - - case EVENT_OUT_OF_RANGE: - len = encode_opening_tag(&apdu[apdu_len], 5); - apdu_len += len; - - len = encode_context_real(&apdu[apdu_len], 0, - data->notificationParams.outOfRange.exceedingValue); - apdu_len += len; - - len = encode_context_bitstring(&apdu[apdu_len], 1, - &data->notificationParams.outOfRange.statusFlags); - apdu_len += len; - - len = encode_context_real(&apdu[apdu_len], 2, - data->notificationParams.outOfRange.deadband); - apdu_len += len; - - len = encode_context_real(&apdu[apdu_len], 3, - data->notificationParams.outOfRange.exceededLimit); - apdu_len += len; - - len = encode_closing_tag(&apdu[apdu_len], 5); - apdu_len += len; - break; - - case EVENT_CHANGE_OF_LIFE_SAFETY: - len = encode_opening_tag(&apdu[apdu_len], 8); - apdu_len += len; - - len = encode_context_enumerated(&apdu[apdu_len], 0, - data->notificationParams.changeOfLifeSafety - .newState); - apdu_len += len; - - len = encode_context_enumerated(&apdu[apdu_len], 1, - data->notificationParams.changeOfLifeSafety - .newMode); - apdu_len += len; - - len = encode_context_bitstring(&apdu[apdu_len], 2, - &data->notificationParams.changeOfLifeSafety - .statusFlags); - apdu_len += len; - - len = encode_context_enumerated(&apdu[apdu_len], 3, - data->notificationParams.changeOfLifeSafety - .operationExpected); - apdu_len += len; - - len = encode_closing_tag(&apdu[apdu_len], 8); - apdu_len += len; - break; - - case EVENT_BUFFER_READY: - len = encode_opening_tag(&apdu[apdu_len], 10); - apdu_len += len; - - len = bacapp_encode_context_device_obj_property_ref( - &apdu[apdu_len], 0, - &data->notificationParams.bufferReady - .bufferProperty); - apdu_len += len; - - len = encode_context_unsigned(&apdu[apdu_len], 1, - data->notificationParams.bufferReady - .previousNotification); - apdu_len += len; - - len = encode_context_unsigned(&apdu[apdu_len], 2, - data->notificationParams.bufferReady - .currentNotification); - apdu_len += len; - - len = encode_closing_tag(&apdu[apdu_len], 10); - apdu_len += len; - break; - case EVENT_UNSIGNED_RANGE: - len = encode_opening_tag(&apdu[apdu_len], 11); - apdu_len += len; - - len = encode_context_unsigned(&apdu[apdu_len], 0, - data->notificationParams.unsignedRange - .exceedingValue); - apdu_len += len; - - len = encode_context_bitstring(&apdu[apdu_len], 1, - &data->notificationParams.unsignedRange - .statusFlags); - apdu_len += len; - - len = encode_context_unsigned(&apdu[apdu_len], 2, - data->notificationParams.unsignedRange - .exceededLimit); - apdu_len += len; - - len = encode_closing_tag(&apdu[apdu_len], 11); - apdu_len += len; - break; - case EVENT_ACCESS_EVENT: - len = encode_opening_tag(&apdu[apdu_len], 13); - apdu_len += len; - - len = encode_context_enumerated(&apdu[apdu_len], 0, - data->notificationParams.accessEvent.accessEvent); - apdu_len += len; - - len = encode_context_bitstring(&apdu[apdu_len], 1, - &data->notificationParams.accessEvent.statusFlags); - apdu_len += len; - - len = encode_context_unsigned(&apdu[apdu_len], 2, - data->notificationParams.accessEvent - .accessEventTag); - apdu_len += len; - - len = - bacapp_encode_context_timestamp(&apdu[apdu_len], 3, - &data->notificationParams.accessEvent - .accessEventTime); - apdu_len += len; - - len = bacapp_encode_context_device_obj_ref( - &apdu[apdu_len], 4, - &data->notificationParams.accessEvent - .accessCredential); - apdu_len += len; - - if (data->notificationParams.accessEvent - .authenticationFactor.format_type < - AUTHENTICATION_FACTOR_MAX) { - len = bacapp_encode_context_authentication_factor( - &apdu[apdu_len], 5, - &data->notificationParams.accessEvent - .authenticationFactor); - apdu_len += len; - } - - len = encode_closing_tag(&apdu[apdu_len], 13); - apdu_len += len; - break; - case EVENT_EXTENDED: - default: - assert(0); - break; - } - len = encode_closing_tag(&apdu[apdu_len], 12); - apdu_len += len; - break; - case NOTIFY_ACK_NOTIFICATION: - /* FIXME: handle this case */ - default: - break; + if (apdu) { + apdu += len; } } + /* tag 8 - notifyType */ + len = encode_context_enumerated(apdu, 8, data->notifyType); + apdu_len += len; + if (apdu) { + apdu += len; + } + switch (data->notifyType) { + case NOTIFY_ALARM: + case NOTIFY_EVENT: + /* tag 9 - ackRequired */ + len = encode_context_boolean(apdu, 9, data->ackRequired); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* tag 10 - fromState */ + len = encode_context_enumerated(apdu, 10, data->fromState); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + + default: + break; + } + /* tag 11 - toState */ + len = encode_context_enumerated(apdu, 11, data->toState); + apdu_len += len; + if (apdu) { + apdu += len; + } + switch (data->notifyType) { + case NOTIFY_ALARM: + case NOTIFY_EVENT: + /* tag 12 - event values */ + len = encode_opening_tag(apdu, 12); + apdu_len += len; + if (apdu) { + apdu += len; + } + switch (data->eventType) { + case EVENT_CHANGE_OF_BITSTRING: + len = encode_opening_tag(apdu, 0); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_bitstring(apdu, 0, + &data->notificationParams.changeOfBitstring + .referencedBitString); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_bitstring(apdu, 1, + &data->notificationParams.changeOfBitstring + .statusFlags); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, 0); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + case EVENT_CHANGE_OF_STATE: + len = encode_opening_tag(apdu, 1); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_opening_tag(apdu, 0); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = bacapp_encode_property_state( + apdu, &data->notificationParams.changeOfState.newState); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, 0); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_bitstring(apdu, 1, + &data->notificationParams.changeOfState.statusFlags); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, 1); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + case EVENT_CHANGE_OF_VALUE: + len = encode_opening_tag(apdu, 2); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_opening_tag(apdu, 0); + apdu_len += len; + if (apdu) { + apdu += len; + } + switch (data->notificationParams.changeOfValue.tag) { + case CHANGE_OF_VALUE_REAL: + len = encode_context_real(apdu, 1, + data->notificationParams.changeOfValue.newValue + .changeValue); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + case CHANGE_OF_VALUE_BITS: + len = encode_context_bitstring(apdu, 0, + &data->notificationParams.changeOfValue.newValue + .changedBits); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + default: + return 0; + } + len = encode_closing_tag(apdu, 0); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_bitstring(apdu, 1, + &data->notificationParams.changeOfValue.statusFlags); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, 2); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + case EVENT_COMMAND_FAILURE: + len = encode_opening_tag(apdu, 3); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_opening_tag(apdu, 0); + apdu_len += len; + if (apdu) { + apdu += len; + } + switch (data->notificationParams.commandFailure.tag) { + case COMMAND_FAILURE_BINARY_PV: + len = encode_application_enumerated(apdu, + data->notificationParams.commandFailure + .commandValue.binaryValue); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + case COMMAND_FAILURE_UNSIGNED: + len = encode_application_unsigned(apdu, + data->notificationParams.commandFailure + .commandValue.unsignedValue); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + default: + return 0; + } + len = encode_closing_tag(apdu, 0); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_bitstring(apdu, 1, + &data->notificationParams.commandFailure.statusFlags); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_opening_tag(apdu, 2); + apdu_len += len; + if (apdu) { + apdu += len; + } + switch (data->notificationParams.commandFailure.tag) { + case COMMAND_FAILURE_BINARY_PV: + len = encode_application_enumerated(apdu, + data->notificationParams.commandFailure + .feedbackValue.binaryValue); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + case COMMAND_FAILURE_UNSIGNED: + len = encode_application_unsigned(apdu, + data->notificationParams.commandFailure + .feedbackValue.unsignedValue); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + default: + return 0; + } + len = encode_closing_tag(apdu, 2); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, 3); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + case EVENT_FLOATING_LIMIT: + len = encode_opening_tag(apdu, 4); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_real(apdu, 0, + data->notificationParams.floatingLimit.referenceValue); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_bitstring(apdu, 1, + &data->notificationParams.floatingLimit.statusFlags); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_real(apdu, 2, + data->notificationParams.floatingLimit.setPointValue); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_real(apdu, 3, + data->notificationParams.floatingLimit.errorLimit); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, 4); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + case EVENT_OUT_OF_RANGE: + len = encode_opening_tag(apdu, 5); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_real(apdu, 0, + data->notificationParams.outOfRange.exceedingValue); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_bitstring(apdu, 1, + &data->notificationParams.outOfRange.statusFlags); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_real( + apdu, 2, data->notificationParams.outOfRange.deadband); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_real(apdu, 3, + data->notificationParams.outOfRange.exceededLimit); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, 5); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + + case EVENT_CHANGE_OF_LIFE_SAFETY: + len = encode_opening_tag(apdu, 8); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_enumerated(apdu, 0, + data->notificationParams.changeOfLifeSafety.newState); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_enumerated(apdu, 1, + data->notificationParams.changeOfLifeSafety.newMode); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_bitstring(apdu, 2, + &data->notificationParams.changeOfLifeSafety + .statusFlags); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_enumerated(apdu, 3, + data->notificationParams.changeOfLifeSafety + .operationExpected); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, 8); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + + case EVENT_BUFFER_READY: + len = encode_opening_tag(apdu, 10); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = bacapp_encode_context_device_obj_property_ref(apdu, 0, + &data->notificationParams.bufferReady.bufferProperty); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_unsigned(apdu, 1, + data->notificationParams.bufferReady + .previousNotification); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_unsigned(apdu, 2, + data->notificationParams.bufferReady + .currentNotification); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, 10); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + case EVENT_UNSIGNED_RANGE: + len = encode_opening_tag(apdu, 11); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_unsigned(apdu, 0, + data->notificationParams.unsignedRange.exceedingValue); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_bitstring(apdu, 1, + &data->notificationParams.unsignedRange.statusFlags); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_unsigned(apdu, 2, + data->notificationParams.unsignedRange.exceededLimit); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, 11); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + case EVENT_ACCESS_EVENT: + len = encode_opening_tag(apdu, 13); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_enumerated(apdu, 0, + data->notificationParams.accessEvent.accessEvent); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_bitstring(apdu, 1, + &data->notificationParams.accessEvent.statusFlags); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_unsigned(apdu, 2, + data->notificationParams.accessEvent.accessEventTag); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = bacapp_encode_context_timestamp(apdu, 3, + &data->notificationParams.accessEvent.accessEventTime); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = bacapp_encode_context_device_obj_ref(apdu, 4, + &data->notificationParams.accessEvent.accessCredential); + apdu_len += len; + if (apdu) { + apdu += len; + } + if (data->notificationParams.accessEvent + .authenticationFactor.format_type < + AUTHENTICATION_FACTOR_MAX) { + len = + bacapp_encode_context_authentication_factor(apdu, 5, + &data->notificationParams.accessEvent + .authenticationFactor); + apdu_len += len; + if (apdu) { + apdu += len; + } + } + len = encode_closing_tag(apdu, 13); + apdu_len += len; + if (apdu) { + apdu += len; + } + break; + case EVENT_EXTENDED: + default: + assert(0); + break; + } + len = encode_closing_tag(apdu, 12); + apdu_len += len; + break; + case NOTIFY_ACK_NOTIFICATION: + /* FIXME: handle this case */ + default: + break; + } + return apdu_len; } +/** + * @brief Encode the EventNotification service request + * @param apdu Pointer to the buffer for encoding into + * @param apdu_size number of bytes available in the buffer + * @param data Pointer to the service data used for encoding values + * @return number of bytes encoded, or zero if unable to encode or too large + */ +size_t event_notification_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_EVENT_NOTIFICATION_DATA *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = event_notify_encode_service_request(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = event_notify_encode_service_request(apdu, data); + } + + return apdu_len; +} + +/** + * @brief Decode the EventNotification service request only. + * @param apdu Pointer to the buffer. + * @param apdu_len Number of valid bytes in the buffer. + * @param data Pointer to the data to store the decoded values, or NULL + * + * @return Bytes decoded or BACNET_STATUS_ERROR on error. + */ int event_notify_decode_service_request( uint8_t *apdu, unsigned apdu_len, BACNET_EVENT_NOTIFICATION_DATA *data) { diff --git a/src/bacnet/event.h b/src/bacnet/event.h index edda5e19..8d3fcc80 100644 --- a/src/bacnet/event.h +++ b/src/bacnet/event.h @@ -227,6 +227,12 @@ extern "C" { uint8_t * apdu, BACNET_EVENT_NOTIFICATION_DATA * data); + BACNET_STACK_EXPORT + size_t event_notification_service_request_encode( + uint8_t *apdu, + size_t apdu_size, + BACNET_EVENT_NOTIFICATION_DATA *data); + /*************************************************** ** ** Decodes the service data part of Event Notification diff --git a/src/bacnet/getevent.c b/src/bacnet/getevent.c index 5f6856aa..ea2e7a90 100644 --- a/src/bacnet/getevent.c +++ b/src/bacnet/getevent.c @@ -39,6 +39,52 @@ /** @file getevent.c Encode/Decode GetEvent services */ +/** + * @brief Encode APDU for GetEvent-Request service + * @param apdu Pointer to a buffer, or NULL for length + * @param lastReceivedObjectIdentifier Object identifier + * @return Bytes encoded. + */ +int getevent_apdu_encode(uint8_t *apdu, + BACNET_OBJECT_ID *lastReceivedObjectIdentifier) +{ + int len = 0; + int apdu_len = 0; + + /* encode optional parameter */ + if (lastReceivedObjectIdentifier) { + len = encode_context_object_id(apdu, 0, + lastReceivedObjectIdentifier->type, + lastReceivedObjectIdentifier->instance); + apdu_len += len; + } + + return apdu_len; +} + +/** + * @brief Encode the GetEvent-Request service + * @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 getevent_service_request_encode( + uint8_t *apdu, size_t apdu_size, + BACNET_OBJECT_ID *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = getevent_apdu_encode(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = getevent_apdu_encode(apdu, data); + } + + return apdu_len; +} + /** Encode service * * @param apdu APDU buffer to encode to. @@ -49,7 +95,7 @@ */ int getevent_encode_apdu(uint8_t *apdu, uint8_t invoke_id, - BACNET_OBJECT_ID *lastReceivedObjectIdentifier) + BACNET_OBJECT_ID *data) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ @@ -59,15 +105,14 @@ int getevent_encode_apdu(uint8_t *apdu, apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); apdu[2] = invoke_id; apdu[3] = SERVICE_CONFIRMED_GET_EVENT_INFORMATION; - apdu_len = 4; - /* encode optional parameter */ - if (lastReceivedObjectIdentifier) { - len = encode_context_object_id(&apdu[apdu_len], 0, - lastReceivedObjectIdentifier->type, - lastReceivedObjectIdentifier->instance); - apdu_len += len; - } } + len = 4; + apdu_len += len; + if (apdu) { + apdu += len; + } + len = getevent_apdu_encode(apdu, data); + apdu_len += len; return apdu_len; } diff --git a/src/bacnet/getevent.h b/src/bacnet/getevent.h index 69ff86e4..e63d9465 100644 --- a/src/bacnet/getevent.h +++ b/src/bacnet/getevent.h @@ -62,6 +62,11 @@ extern "C" { uint8_t invoke_id, BACNET_OBJECT_ID * lastReceivedObjectIdentifier); + BACNET_STACK_EXPORT + size_t getevent_service_request_encode( + uint8_t *apdu, size_t apdu_size, + BACNET_OBJECT_ID *data); + BACNET_STACK_EXPORT int getevent_decode_service_request( uint8_t * apdu, diff --git a/src/bacnet/list_element.c b/src/bacnet/list_element.c index d8b20b17..8b572b10 100644 --- a/src/bacnet/list_element.c +++ b/src/bacnet/list_element.c @@ -18,7 +18,7 @@ #include "bacnet/list_element.h" /** - * @brief Encode the Add/Remove ListElement service request only + * @brief Encode the Add/Remove ListElement service request APDU * * AddListElement-Request ::= SEQUENCE { * object-identifier [0] BACnetObjectIdentifier, @@ -85,6 +85,28 @@ int list_element_encode_service_request( return apdu_len; } +/** + * @brief Encode the Add/Remove ListElement service request only + * @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 list_element_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_LIST_ELEMENT_DATA *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = list_element_encode_service_request(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = list_element_encode_service_request(apdu, data); + } + + return apdu_len; +} + /** * @brief Decode the Add/Remove ListElement service request only * @param apdu Pointer to the buffer for decoding. @@ -273,7 +295,6 @@ int list_element_error_ack_encode( return apdu_len; } -#if !BACNET_SVC_SERVER /** * @brief Decoding for AddListElement or RemoveListElement Error Ack * AddListElement-Error ::= SEQUENCE { @@ -362,4 +383,3 @@ int list_element_error_ack_decode( return apdu_len; } -#endif diff --git a/src/bacnet/list_element.h b/src/bacnet/list_element.h index bfd059ce..957b8da4 100644 --- a/src/bacnet/list_element.h +++ b/src/bacnet/list_element.h @@ -67,6 +67,9 @@ BACNET_STACK_EXPORT int list_element_encode_service_request( uint8_t *apdu, BACNET_LIST_ELEMENT_DATA *list_element); BACNET_STACK_EXPORT +size_t list_element_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_LIST_ELEMENT_DATA *list_element); +BACNET_STACK_EXPORT int list_element_decode_service_request( uint8_t *apdu, unsigned apdu_len, BACNET_LIST_ELEMENT_DATA *list_element); BACNET_STACK_EXPORT diff --git a/src/bacnet/lso.c b/src/bacnet/lso.c index 44766f71..fe44ab66 100644 --- a/src/bacnet/lso.c +++ b/src/bacnet/lso.c @@ -38,37 +38,98 @@ /** @file lso.c BACnet Life Safety Operation encode/decode */ +/** + * @brief Encode APDU for LifeSafetyOperation-Request + * @param apdu Pointer to the buffer, or NULL for length + * @param data Pointer to the data to encode. + * @return number of bytes encoded, or zero on error. + */ +int life_safety_operation_encode(uint8_t *apdu, BACNET_LSO_DATA *data) +{ + int len = 0; /* length of each encoding */ + int apdu_len = 0; /* total length of the apdu, return value */ + + if (!data) { + return 0; + } + /* tag 0 - requestingProcessId */ + len = encode_context_unsigned(apdu, 0, data->processId); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* tag 1 - requestingSource */ + len = encode_context_character_string( + apdu, 1, &data->requestingSrc); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* Operation */ + len = encode_context_enumerated(apdu, 2, data->operation); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* Object ID */ + if (data->use_target) { + len = encode_context_object_id(apdu, 3, + data->targetObject.type, data->targetObject.instance); + apdu_len += len; + } + + return apdu_len; +} + +/** + * @brief Encode APDU for LifeSafetyOperation-Request + * @param apdu Pointer to the buffer, or NULL for length + * @param data Pointer to the data to encode. + * @return number of bytes encoded, or zero on error. + */ int lso_encode_apdu(uint8_t *apdu, uint8_t invoke_id, BACNET_LSO_DATA *data) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ - if (apdu && data) { + 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_LIFE_SAFETY_OPERATION; - apdu_len = 4; - /* tag 0 - requestingProcessId */ - len = encode_context_unsigned(&apdu[apdu_len], 0, data->processId); + } + len = 4; + apdu_len += len; + if (apdu) { + apdu += len; + } + len = life_safety_operation_encode(apdu, data); + if (len > 0) { apdu_len += len; - /* tag 1 - requestingSource */ - len = encode_context_character_string( - &apdu[apdu_len], 1, &data->requestingSrc); - apdu_len += len; - /* - Operation - */ - len = encode_context_enumerated(&apdu[apdu_len], 2, data->operation); - apdu_len += len; - /* - Object ID - */ - if (data->use_target) { - len = encode_context_object_id(&apdu[apdu_len], 3, - data->targetObject.type, data->targetObject.instance); - apdu_len += len; - } + } else { + apdu_len = len; + } + + return apdu_len; +} + +/** + * @brief Encode the LifeSafetyOperation-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 life_safety_operation_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_LSO_DATA *data) +{ + size_t apdu_len = 0; + + apdu_len = life_safety_operation_encode(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = life_safety_operation_encode(apdu, data); } return apdu_len; diff --git a/src/bacnet/lso.h b/src/bacnet/lso.h index 9f6c33be..bc366514 100644 --- a/src/bacnet/lso.h +++ b/src/bacnet/lso.h @@ -31,27 +31,35 @@ #include "bacnet/bacdef.h" #include "bacnet/bacstr.h" +typedef struct { + uint32_t processId; + BACNET_CHARACTER_STRING requestingSrc; + BACNET_LIFE_SAFETY_OPERATION operation; + BACNET_OBJECT_ID targetObject; + bool use_target:1; +} BACNET_LSO_DATA; + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/* Life Safety Operation Service */ - - typedef struct { - uint32_t processId; - BACNET_CHARACTER_STRING requestingSrc; - BACNET_LIFE_SAFETY_OPERATION operation; - BACNET_OBJECT_ID targetObject; - bool use_target:1; - } BACNET_LSO_DATA; - - BACNET_STACK_EXPORT int lso_encode_apdu( uint8_t * apdu, uint8_t invoke_id, BACNET_LSO_DATA * data); -/* decode the service request only */ + + BACNET_STACK_EXPORT + int life_safety_operation_encode( + uint8_t *apdu, + BACNET_LSO_DATA *data); + + BACNET_STACK_EXPORT + size_t life_safety_operation_request_encode( + uint8_t *apdu, + size_t apdu_size, + BACNET_LSO_DATA *data); + BACNET_STACK_EXPORT int lso_decode_service_request( uint8_t * apdu, diff --git a/src/bacnet/rd.c b/src/bacnet/rd.c index 10563db5..fa15eff7 100644 --- a/src/bacnet/rd.c +++ b/src/bacnet/rd.c @@ -40,9 +40,8 @@ /** @file rd.c Encode/Decode Reinitialize Device APDUs */ #if BACNET_SVC_RD_A - /** - * @brief Encode Reinitialize Device service + * @brief Encode ReinitializeDevice-Request APDU * * ReinitializeDevice-Request ::= SEQUENCE { * reinitialized-state-of-device [0] ENUMERATED { @@ -58,6 +57,62 @@ * password [1] CharacterString (SIZE (1..20)) OPTIONAL * } * + * @param apdu Pointer to the buffer, or NULL for length + * @param state Reinitialization state + * @param password Pointer to the pass phrase. + * @return number of bytes encoded + */ +int reinitialize_device_encode(uint8_t *apdu, + BACNET_REINITIALIZED_STATE state, + BACNET_CHARACTER_STRING *password) +{ + int len = 0; /* length of each encoding */ + int apdu_len = 0; /* total length of the apdu, return value */ + + /* reinitialized-state-of-device [0] ENUMERATED */ + len = encode_context_enumerated(apdu, 0, state); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* password [1] CharacterString (SIZE (1..20)) OPTIONAL */ + if (password) { + if ((password->length >= 1) && (password->length <= 20)) { + len = encode_context_character_string(apdu, 1, password); + apdu_len += len; + } + } + + return apdu_len; +} + +/** + * @brief Encode the COVNotification service request + * @param apdu Pointer to the buffer for encoding into + * @param apdu_size number of bytes available in the buffer + * @param state Reinitialization state + * @param password Pointer to the pass phrase. + * @return number of bytes encoded, or zero if unable to encode or too large + */ +size_t reinitialize_device_request_encode(uint8_t *apdu, + size_t apdu_size, + BACNET_REINITIALIZED_STATE state, + BACNET_CHARACTER_STRING *password) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = reinitialize_device_encode(NULL, state, password); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = reinitialize_device_encode(apdu, state, password); + } + + return apdu_len; +} + +/** + * @brief Encode Reinitialize Device service * @param apdu Pointer to the APDU buffer. * @param invoke_id Invoke-Id * @param state Reinitialization state @@ -84,20 +139,8 @@ int rd_encode_apdu(uint8_t *apdu, if (apdu) { apdu += len; } - len = encode_context_enumerated(apdu, 0, state); + len = reinitialize_device_encode(apdu, state, password); apdu_len += len; - if (apdu) { - apdu += len; - } - /* optional password */ - if (password) { - /* Must be at least 1 character, limited to 20 characters */ - if ((password->length >= 1) && (password->length <= 20)) { - len = encode_context_character_string( - apdu, 1, password); - apdu_len += len; - } - } return apdu_len; } diff --git a/src/bacnet/rd.h b/src/bacnet/rd.h index b3bc7fdf..9b6a7f8f 100644 --- a/src/bacnet/rd.h +++ b/src/bacnet/rd.h @@ -45,7 +45,6 @@ typedef bool( extern "C" { #endif /* __cplusplus */ -/* encode service */ BACNET_STACK_EXPORT int rd_encode_apdu( uint8_t * apdu, @@ -53,6 +52,17 @@ extern "C" { BACNET_REINITIALIZED_STATE state, BACNET_CHARACTER_STRING * password); + BACNET_STACK_EXPORT + int reinitialize_device_encode(uint8_t *apdu, + BACNET_REINITIALIZED_STATE state, + BACNET_CHARACTER_STRING *password); + + BACNET_STACK_EXPORT + size_t reinitialize_device_request_encode( + uint8_t *apdu, size_t apdu_size, + BACNET_REINITIALIZED_STATE state, + BACNET_CHARACTER_STRING *password); + /* decode the service request only */ BACNET_STACK_EXPORT int rd_decode_service_request( diff --git a/src/bacnet/readrange.c b/src/bacnet/readrange.c index 7575189c..67772cb4 100644 --- a/src/bacnet/readrange.c +++ b/src/bacnet/readrange.c @@ -44,11 +44,13 @@ * objectIdentifier [0] BACnetObjectIdentifier, * propertyIdentifier [1] BACnetPropertyIdentifier, * propertyArrayIndex [2] Unsigned OPTIONAL, -- used only with array - * datatype range CHOICE { byPosition [3] SEQUENCE { referenceIndex Unsigned, + * datatype range CHOICE { + * byPosition [3] SEQUENCE { + * referenceIndex Unsigned, * count INTEGER * }, - * -- context tag 4 is deprecated - * -- context tag 5 is deprecated + * -- context tag 4 is deprecated + * -- context tag 5 is deprecated * bySequenceNumber [6] SEQUENCE { * referenceIndex Unsigned, * count INTEGER @@ -56,11 +58,144 @@ * byTime [7] SEQUENCE { * referenceTime BACnetDateTime, * count INTEGER - * } + * } * } OPTIONAL * } */ +/** + * @brief Encode ReadRange-Request APDU + * @param apdu Pointer to the buffer, or NULL for length + * @param data Pointer to the data to encode. + * @return number of bytes encoded, or zero on error. + */ +int read_range_encode(uint8_t *apdu, BACNET_READ_RANGE_DATA *data) +{ + int len = 0; /* length of each encoding */ + int apdu_len = 0; /* total length of the apdu, return value */ + + if (!data) { + return 0; + } + /* objectIdentifier [0] BACnetObjectIdentifier */ + len = encode_context_object_id( + apdu, 0, data->object_type, data->object_instance); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* propertyIdentifier [1] BACnetPropertyIdentifier */ + len = encode_context_enumerated(apdu, 1, data->object_property); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* propertyArrayIndex [2] Unsigned OPTIONAL */ + if (data->array_index != BACNET_ARRAY_ALL) { + len = encode_context_unsigned(apdu, 2, data->array_index); + apdu_len += len; + if (apdu) { + apdu += len; + } + } + switch (data->RequestType) { + case RR_BY_POSITION: + /* byPosition [3] SEQUENCE */ + len = encode_opening_tag(apdu, 3); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_application_unsigned(apdu, data->Range.RefIndex); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_application_signed(apdu, data->Count); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, 3); + apdu_len += len; + break; + case RR_BY_SEQUENCE: + /* bySequenceNumber [6] SEQUENCE */ + len = encode_opening_tag(apdu, 6); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_application_unsigned(apdu, data->Range.RefSeqNum); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_application_signed(apdu, data->Count); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, 6); + apdu_len += len; + break; + case RR_BY_TIME: + /* byTime [7] SEQUENCE */ + len = encode_opening_tag(apdu, 7); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_application_date(apdu, &data->Range.RefTime.date); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_application_time(apdu, &data->Range.RefTime.time); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_application_signed(apdu, data->Count); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, 7); + apdu_len += len; + break; + case RR_READ_ALL: + /* read the whole list - omit the range parameter */ + break; + default: + break; + } + + return apdu_len; +} + +/** + * @brief Encode ReadRange-Request service APDU + * @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 read_range_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_READ_RANGE_DATA *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = read_range_encode(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = read_range_encode(apdu, data); + } + + return apdu_len; +} + /** * Build a ReadRange request packet. * @@ -71,8 +206,9 @@ * @return Bytes encoded. */ int rr_encode_apdu( - uint8_t *apdu, uint8_t invoke_id, BACNET_READ_RANGE_DATA *rrdata) + uint8_t *apdu, uint8_t invoke_id, BACNET_READ_RANGE_DATA *data) { + int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ if (apdu) { @@ -80,61 +216,14 @@ int rr_encode_apdu( apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); apdu[2] = invoke_id; apdu[3] = SERVICE_CONFIRMED_READ_RANGE; /* service choice */ - apdu_len = 4; - - apdu_len += encode_context_object_id( - &apdu[apdu_len], 0, rrdata->object_type, rrdata->object_instance); - apdu_len += encode_context_enumerated( - &apdu[apdu_len], 1, rrdata->object_property); - - /* optional array index */ - - if (rrdata->array_index != BACNET_ARRAY_ALL) { - apdu_len += encode_context_unsigned( - &apdu[apdu_len], 2, rrdata->array_index); - } - - /* Build the appropriate (optional) range parameter based on the request - * type */ - - switch (rrdata->RequestType) { - case RR_BY_POSITION: - apdu_len += encode_opening_tag(&apdu[apdu_len], 3); - apdu_len += encode_application_unsigned( - &apdu[apdu_len], rrdata->Range.RefIndex); - apdu_len += - encode_application_signed(&apdu[apdu_len], rrdata->Count); - apdu_len += encode_closing_tag(&apdu[apdu_len], 3); - break; - - case RR_BY_SEQUENCE: - apdu_len += encode_opening_tag(&apdu[apdu_len], 6); - apdu_len += encode_application_unsigned( - &apdu[apdu_len], rrdata->Range.RefSeqNum); - apdu_len += - encode_application_signed(&apdu[apdu_len], rrdata->Count); - apdu_len += encode_closing_tag(&apdu[apdu_len], 6); - break; - - case RR_BY_TIME: - apdu_len += encode_opening_tag(&apdu[apdu_len], 7); - apdu_len += encode_application_date( - &apdu[apdu_len], &rrdata->Range.RefTime.date); - apdu_len += encode_application_time( - &apdu[apdu_len], &rrdata->Range.RefTime.time); - apdu_len += - encode_application_signed(&apdu[apdu_len], rrdata->Count); - apdu_len += encode_closing_tag(&apdu[apdu_len], 7); - break; - - case RR_READ_ALL: /* to attempt a read of the whole array or list, - omit the range parameter */ - break; - - default: - break; - } } + len = 4; + apdu_len += len; + if (apdu) { + apdu += len; + } + len = read_range_encode(apdu, data); + apdu_len += len; return apdu_len; } @@ -200,12 +289,13 @@ int rr_decode_service_request( explicit checking later */ if (len < apdu_len) { /* - * Note: We pick up the opening tag and then decode the parameter - * types we recognise. We deal with the count and the closing tag in - * each case statement even though it might appear that we could do - * them after the switch statement as common elements. This is so - * that if we receive a tag we don't recognise, we don't try to - * decode it blindly and make a mess of it. + * Note: We pick up the opening tag and then decode the + * parameter types we recognise. We deal with the count and the + * closing tag in each case statement even though it might + * appear that we could do them after the switch statement as + * common elements. This is so that if we receive a tag we don't + * recognise, we don't try to decode it blindly and make a mess + * of it. */ len += decode_tag_number_and_value( &apdu[len], &tag_number, &len_value_type); @@ -313,7 +403,8 @@ int rr_decode_service_request( break; default: /* If we don't recognise the tag then we do nothing - * here and try to return all elements of the array */ + * here and try to return all elements of the array + */ break; } } @@ -331,10 +422,10 @@ int rr_decode_service_request( * propertyArrayIndex [2] Unsigned OPTIONAL , -- used only with * array datatype resultFlags [3] BACnetResultFlags, itemCount [4] * Unsigned, itemData [5] SEQUENCE OF ABSTRACT-SYNTAX.&TYPE, - * firstSequenceNumber [6] Unsigned32 OPTIONAL -- used only if 'Item Count' - * > 0 and the request was either of - * -- type 'By Sequence Number' - * or 'By Time' + * firstSequenceNumber [6] Unsigned32 OPTIONAL -- used only if 'Item + * Count' > 0 and the request was either of + * -- type 'By Sequence + * Number' or 'By Time' * } */ @@ -343,7 +434,8 @@ int rr_decode_service_request( * * @param apdu Pointer to the buffer. * @param invoke_id ID invoked. - * @param rrdata Pointer to the read range data structure used for encoding. + * @param rrdata Pointer to the read range data structure used for + * encoding. * * @return The count of encoded bytes. */ @@ -375,9 +467,9 @@ int rr_ack_encode_apdu( /* Context 4 Item Count */ apdu_len += encode_context_unsigned(&apdu[apdu_len], 4, rrdata->ItemCount); - /* Context 5 Property list - reading the standard it looks like an empty - * list still requires an opening and closing tag as the tagged - * parameter is not optional + /* Context 5 Property list - reading the standard it looks like an + * empty list still requires an opening and closing tag as the + * tagged parameter is not optional */ apdu_len += encode_opening_tag(&apdu[apdu_len], 5); if (rrdata->ItemCount != 0) { @@ -498,9 +590,9 @@ int rr_ack_decode_service_request(uint8_t *apdu, } if (decode_is_opening_tag_number(&apdu[len], 5)) { len++; /* A tag number of 5 is not extended so only one octet - * Setup the start position and length of the data returned - * from the request don't decode the application tag number - * or its data here. */ + * Setup the start position and length of the data + * returned from the request don't decode the application + * tag number or its data here. */ rrdata->application_data = &apdu[len]; start_len = len; while (len < apdu_len) { @@ -510,7 +602,8 @@ int rr_ack_decode_service_request(uint8_t *apdu, len++; /* Step over single byte closing tag */ break; } else { - /* Don't care about tag number, just skipping over anyway */ + /* Don't care about tag number, just skipping over + * anyway */ len += decode_tag_number_and_value( &apdu[len], NULL, &len_value_type); len += len_value_type; /* Skip over data value as well */ @@ -540,5 +633,3 @@ int rr_ack_decode_service_request(uint8_t *apdu, return len; } - -/* FIXME: Currently does not have test framework */ diff --git a/src/bacnet/readrange.h b/src/bacnet/readrange.h index 26ed0be3..64b6a67f 100644 --- a/src/bacnet/readrange.h +++ b/src/bacnet/readrange.h @@ -138,6 +138,16 @@ extern "C" { uint8_t invoke_id, BACNET_READ_RANGE_DATA * rrdata); + BACNET_STACK_EXPORT + int read_range_encode( + uint8_t *apdu, + BACNET_READ_RANGE_DATA *data); + BACNET_STACK_EXPORT + size_t read_range_request_encode( + uint8_t *apdu, + size_t apdu_size, + BACNET_READ_RANGE_DATA *data); + BACNET_STACK_EXPORT int rr_decode_service_request( uint8_t * apdu, diff --git a/src/bacnet/rp.c b/src/bacnet/rp.c index ebef3401..87128338 100644 --- a/src/bacnet/rp.c +++ b/src/bacnet/rp.c @@ -40,6 +40,76 @@ /** @file rp.c Encode/Decode Read Property and RP ACKs */ #if BACNET_SVC_RP_A +/** + * @brief Encode APDU for ReadProperty-Request + * + * ReadProperty-Request ::= SEQUENCE { + * object-identifier [0] BACnetObjectIdentifier, + * property-identifier [1] BACnetPropertyIdentifier, + * property-array-index [2] Unsigned OPTIONAL + * -- used only with array datatype + * -- if omitted with an array the entire array is referenced + * } + * + * @param apdu Pointer to the buffer, or NULL for length + * @param data Pointer to the data to encode. + * @return number of bytes encoded, or zero on error. + */ +int read_property_request_encode(uint8_t *apdu, BACNET_READ_PROPERTY_DATA *data) +{ + int len = 0; /* length of each encoding */ + int apdu_len = 0; /* total length of the apdu, return value */ + + if (!data) { + return 0; + } + /* object-identifier [0] BACnetObjectIdentifier */ + if (data->object_type <= BACNET_MAX_OBJECT) { + len = encode_context_object_id( + apdu, 0, data->object_type, data->object_instance); + apdu_len += len; + if (apdu) { + apdu += len; + } + } + /* property-identifier [1] BACnetPropertyIdentifier */ + if (data->object_property <= MAX_BACNET_PROPERTY_ID) { + len = encode_context_enumerated(apdu, 1, data->object_property); + apdu_len += len; + if (apdu) { + apdu += len; + } + } + /* property-array-index [2] Unsigned OPTIONAL */ + if (data->array_index != BACNET_ARRAY_ALL) { + len = encode_context_unsigned(apdu, 2, data->array_index); + apdu_len += len; + } + + return apdu_len; +} + +/** + * @brief Encode the ReadProperty-Request service + * @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 read_property_request_service_encode( + uint8_t *apdu, size_t apdu_size, BACNET_READ_PROPERTY_DATA *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = read_property_request_encode(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = read_property_request_encode(apdu, data); + } + + return apdu_len; +} /** Encode the service * @@ -50,7 +120,7 @@ * @return Bytes encoded or zero on error. */ int rp_encode_apdu( - uint8_t *apdu, uint8_t invoke_id, BACNET_READ_PROPERTY_DATA *rpdata) + uint8_t *apdu, uint8_t invoke_id, BACNET_READ_PROPERTY_DATA *data) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ @@ -60,29 +130,14 @@ int rp_encode_apdu( apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); apdu[2] = invoke_id; apdu[3] = SERVICE_CONFIRMED_READ_PROPERTY; /* service choice */ - apdu_len = 4; - if (rpdata->object_type <= BACNET_MAX_OBJECT) { - /* check bounds so that we could create malformed - messages for testing */ - len = encode_context_object_id(&apdu[apdu_len], 0, - rpdata->object_type, rpdata->object_instance); - apdu_len += len; - } - /* The value should be in the range of 0 to 4194303. */ - if (rpdata->object_property <= MAX_BACNET_PROPERTY_ID) { - /* check bounds so that we could create malformed - messages for testing */ - len = encode_context_enumerated( - &apdu[apdu_len], 1, rpdata->object_property); - apdu_len += len; - } - /* optional array index */ - if (rpdata->array_index != BACNET_ARRAY_ALL) { - len = encode_context_unsigned( - &apdu[apdu_len], 2, rpdata->array_index); - apdu_len += len; - } } + len = 4; + apdu_len += len; + if (apdu) { + apdu += len; + } + len = read_property_request_encode(apdu, data); + apdu_len += len; return apdu_len; } @@ -158,6 +213,91 @@ int rp_decode_service_request( return (int)len; } +/** + * @brief Encode APDU for ReadProperty-ACK + * + * ReadProperty-ACK ::= SEQUENCE { + * object-identifier [0] BACnetObjectIdentifier, + * property-identifier [1] BACnetPropertyIdentifier, + * property-array-index [2] Unsigned OPTIONAL, + * -- used only with array datatype + * -- if omitted with an array the entire array is referenced + * property-value [3] + * } + * + * @param apdu Pointer to the buffer, or NULL for length + * @param data Pointer to the data to encode. + * @return number of bytes encoded, or zero on error. + */ +int read_property_ack_encode(uint8_t *apdu, BACNET_READ_PROPERTY_DATA *data) +{ + int len = 0; /* length of each encoding */ + int apdu_len = 0; /* total length of the apdu, return value */ + + if (!data) { + return 0; + } + /* object-identifier [0] BACnetObjectIdentifier */ + len = encode_context_object_id( + apdu, 0, data->object_type, data->object_instance); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* property-identifier [1] BACnetPropertyIdentifier */ + len = encode_context_enumerated(apdu, 1, data->object_property); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* property-array-index [2] Unsigned OPTIONAL */ + if (data->array_index != BACNET_ARRAY_ALL) { + len = encode_context_unsigned(apdu, 2, data->array_index); + apdu_len += len; + if (apdu) { + apdu += len; + } + } + /* property-value [3] */ + len = encode_opening_tag(apdu, 3); + apdu_len += len; + if (apdu) { + apdu += len; + } + if (apdu) { + for (len = 0; len < data->application_data_len; len++) { + apdu[len] = data->application_data[len]; + } + apdu += data->application_data_len; + } + apdu_len += data->application_data_len; + len = encode_closing_tag(apdu, 3); + apdu_len += len; + + return apdu_len; +} + +/** + * @brief Encode the COVNotification 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 read_property_ack_service_encode( + uint8_t *apdu, size_t apdu_size, BACNET_READ_PROPERTY_DATA *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = read_property_ack_encode(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = read_property_ack_encode(apdu, data); + } + + return apdu_len; +} /** Alternate method to encode the ack without extra buffer. * @@ -177,24 +317,34 @@ int rp_ack_encode_apdu_init( apdu[0] = PDU_TYPE_COMPLEX_ACK; /* complex ACK service */ apdu[1] = invoke_id; /* original invoke id from request */ apdu[2] = SERVICE_CONFIRMED_READ_PROPERTY; /* service choice */ - apdu_len = 3; - - /* service ack follows */ - len = encode_context_object_id( - &apdu[apdu_len], 0, rpdata->object_type, rpdata->object_instance); - apdu_len += len; - len = encode_context_enumerated( - &apdu[apdu_len], 1, rpdata->object_property); - apdu_len += len; - /* context 2 array index is optional */ - if (rpdata->array_index != BACNET_ARRAY_ALL) { - len = encode_context_unsigned( - &apdu[apdu_len], 2, rpdata->array_index); - apdu_len += len; - } - len = encode_opening_tag(&apdu[apdu_len], 3); - apdu_len += len; } + len = 3; + apdu_len += len; + if (apdu) { + apdu += len; + } + /* service ack follows */ + len = encode_context_object_id( + apdu, 0, rpdata->object_type, rpdata->object_instance); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_enumerated(apdu, 1, rpdata->object_property); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* context 2 array index is optional */ + if (rpdata->array_index != BACNET_ARRAY_ALL) { + len = encode_context_unsigned(apdu, 2, rpdata->array_index); + apdu_len += len; + if (apdu) { + apdu += len; + } + } + len = encode_opening_tag(apdu, 3); + apdu_len += len; return apdu_len; } @@ -234,19 +384,25 @@ int rp_ack_encode_apdu( int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ - if (apdu) { + if (rpdata) { /* Do the initial encoding */ - apdu_len = rp_ack_encode_apdu_init(apdu, invoke_id, rpdata); - /* propertyValue - * double check maximum possible */ + len = rp_ack_encode_apdu_init(apdu, invoke_id, rpdata); + apdu_len += len; + if (apdu) { + apdu += len; + } imax = rpdata->application_data_len; - if (imax > (MAX_APDU - apdu_len - 2)) { - imax = (MAX_APDU - apdu_len - 2); - } for (len = 0; len < imax; len++) { - apdu[apdu_len++] = rpdata->application_data[len]; + if (apdu) { + apdu[len] = rpdata->application_data[len]; + } } - apdu_len += encode_closing_tag(&apdu[apdu_len], 3); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_closing_tag(apdu, 3); + apdu_len += len; } return apdu_len; diff --git a/src/bacnet/rp.h b/src/bacnet/rp.h index 87e63fa7..effed2b7 100644 --- a/src/bacnet/rp.h +++ b/src/bacnet/rp.h @@ -61,7 +61,28 @@ typedef int ( extern "C" { #endif /* __cplusplus */ -/* encode service */ + BACNET_STACK_EXPORT + int read_property_request_encode( + uint8_t *apdu, + BACNET_READ_PROPERTY_DATA *data); + + BACNET_STACK_EXPORT + size_t read_property_request_service_encode( + uint8_t *apdu, + size_t apdu_size, + BACNET_READ_PROPERTY_DATA *data); + + BACNET_STACK_EXPORT + int read_property_ack_encode( + uint8_t *apdu, + BACNET_READ_PROPERTY_DATA *data); + + BACNET_STACK_EXPORT + size_t read_property_ack_service_encode( + uint8_t *apdu, + size_t apdu_size, + BACNET_READ_PROPERTY_DATA *data); + BACNET_STACK_EXPORT int rp_encode_apdu( uint8_t * apdu, diff --git a/src/bacnet/wp.c b/src/bacnet/wp.c index 51e81553..96e89207 100644 --- a/src/bacnet/wp.c +++ b/src/bacnet/wp.c @@ -41,6 +41,104 @@ /** @file wp.c Encode/Decode BACnet Write Property APDUs */ #if BACNET_SVC_WP_A +/** + * @brief Encode the WriteProperty service request + * + * WriteProperty-Request ::= SEQUENCE { + * object-identifier [0] BACnetObjectIdentifier, + * property-identifier [1] BACnetPropertyIdentifier, + * property-array-index [2] Unsigned OPTIONAL, + * -- used only with array datatype + * -- if omitted with an array the entire + * -- array is referenced + * property-value [3] ABSTRACT-SYNTAX.&Type, + * priority [4] Unsigned (1..16) OPTIONAL + * -– used only when property is commandable + * } + * + * @param apdu Pointer to the buffer, or NULL for length + * @param invoke_id ID of service invoked. + * @param data Pointer to the service data used for encoding values + * @return number of bytes encoded, or zero if unable to encode + */ +size_t writeproperty_apdu_encode( + uint8_t *apdu, BACNET_WRITE_PROPERTY_DATA *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + size_t len = 0; /* total length of the apdu, return value */ + + if (!data) { + return 0; + } + len = encode_context_object_id( + apdu, 0, data->object_type, data->object_instance); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_enumerated(apdu, 1, data->object_property); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* optional array index; ALL is -1 which is assumed when missing */ + if (data->array_index != BACNET_ARRAY_ALL) { + len = encode_context_unsigned(apdu, 2, data->array_index); + apdu_len += len; + if (apdu) { + apdu += len; + } + } + /* propertyValue */ + len = encode_opening_tag(apdu, 3); + apdu_len += len; + if (apdu) { + apdu += len; + } + for (len = 0; len < data->application_data_len; len++) { + if (apdu) { + *apdu = data->application_data[len]; + apdu += 1; + } + apdu_len++; + } + len = encode_closing_tag(apdu, 3); + apdu_len += len; + if (apdu) { + apdu += len; + } + /* optional priority - 0 if not set, 1..16 if set */ + if (data->priority != BACNET_NO_PRIORITY) { + len = encode_context_unsigned(apdu, 4, data->priority); + apdu_len += len; + } + + return apdu_len; +} + +/** + * @brief Initialize the APDU for encode service. + * @param apdu Pointer to the buffer, or NULL for length + * @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 writeproperty_service_request_encode( + uint8_t *apdu, size_t apdu_size, BACNET_WRITE_PROPERTY_DATA *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = writeproperty_apdu_encode(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = writeproperty_apdu_encode(apdu, data); + } + + return apdu_len; +} + /** * @brief Initialize the APDU for encode service. * @@ -82,48 +180,8 @@ int wp_encode_apdu( if (apdu) { apdu += len; } - len = encode_context_object_id( - apdu, 0, wpdata->object_type, wpdata->object_instance); + len = writeproperty_apdu_encode(apdu, wpdata); apdu_len += len; - if (apdu) { - apdu += len; - } - len = encode_context_enumerated(apdu, 1, wpdata->object_property); - apdu_len += len; - if (apdu) { - apdu += len; - } - /* optional array index; ALL is -1 which is assumed when missing */ - if (wpdata->array_index != BACNET_ARRAY_ALL) { - len = encode_context_unsigned(apdu, 2, wpdata->array_index); - apdu_len += len; - if (apdu) { - apdu += len; - } - } - /* propertyValue */ - len = encode_opening_tag(apdu, 3); - apdu_len += len; - if (apdu) { - apdu += len; - } - for (len = 0; len < wpdata->application_data_len; len++) { - if (apdu) { - *apdu = wpdata->application_data[len]; - apdu += 1; - } - apdu_len++; - } - len = encode_closing_tag(apdu, 3); - apdu_len += len; - if (apdu) { - apdu += len; - } - /* optional priority - 0 if not set, 1..16 if set */ - if (wpdata->priority != BACNET_NO_PRIORITY) { - len = encode_context_unsigned(apdu, 4, wpdata->priority); - apdu_len += len; - } return apdu_len; } @@ -318,8 +376,9 @@ bool write_property_string_valid(BACNET_WRITE_PROPERTY_DATA *wp_data, wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } - } else if ((len_max > 0) && (characterstring_length( - &value->type.Character_String) > len_max)) { + } else if ((len_max > 0) && + (characterstring_length(&value->type.Character_String) > + len_max)) { if (wp_data) { wp_data->error_class = ERROR_CLASS_RESOURCES; wp_data->error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; @@ -362,8 +421,9 @@ bool write_property_empty_string_valid(BACNET_WRITE_PROPERTY_DATA *wp_data, if (value && (value->tag == BACNET_APPLICATION_TAG_CHARACTER_STRING)) { if (characterstring_encoding(&value->type.Character_String) == CHARACTER_ANSI_X34) { - if ((len_max > 0) && (characterstring_length( - &value->type.Character_String) > len_max)) { + if ((len_max > 0) && + (characterstring_length(&value->type.Character_String) > + len_max)) { if (wp_data) { wp_data->error_class = ERROR_CLASS_RESOURCES; wp_data->error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; diff --git a/src/bacnet/wp.h b/src/bacnet/wp.h index 38c19dc6..e8941a59 100644 --- a/src/bacnet/wp.h +++ b/src/bacnet/wp.h @@ -68,6 +68,15 @@ extern "C" { /* encode service */ BACNET_STACK_EXPORT + size_t writeproperty_apdu_encode( + uint8_t *apdu, + BACNET_WRITE_PROPERTY_DATA *data); + BACNET_STACK_EXPORT + size_t writeproperty_service_request_encode( + uint8_t *apdu, + size_t apdu_size, + BACNET_WRITE_PROPERTY_DATA *data); + BACNET_STACK_EXPORT int wp_encode_apdu( uint8_t * apdu, uint8_t invoke_id, diff --git a/test/bacnet/cov/src/main.c b/test/bacnet/cov/src/main.c index c01059e6..849e278d 100644 --- a/test/bacnet/cov/src/main.c +++ b/test/bacnet/cov/src/main.c @@ -165,13 +165,14 @@ static void testCOVNotifyData(BACNET_COV_DATA *data, BACNET_COV_DATA *test_data) static void testUCOVNotifyData(BACNET_COV_DATA *data) { uint8_t apdu[480] = { 0 }; - int len = 0; - int apdu_len = 0; + int len = 0, null_len = 0, apdu_len = 0; BACNET_COV_DATA test_data = { 0 }; BACNET_PROPERTY_VALUE value_list[5] = { { 0 } }; + null_len = ucov_notify_encode_apdu(NULL, sizeof(apdu), data); len = ucov_notify_encode_apdu(&apdu[0], sizeof(apdu), data); zassert_true(len > 0, NULL); + zassert_equal(len, null_len, NULL); apdu_len = len; cov_data_value_list_link( @@ -184,14 +185,15 @@ static void testUCOVNotifyData(BACNET_COV_DATA *data) static void testCCOVNotifyData(uint8_t invoke_id, BACNET_COV_DATA *data) { uint8_t apdu[480] = { 0 }; - int len = 0; - int apdu_len = 0; + int len = 0, null_len = 0, apdu_len = 0; BACNET_COV_DATA test_data = { 0 }; BACNET_PROPERTY_VALUE value_list[2] = { { 0 } }; uint8_t test_invoke_id = 0; + null_len = ccov_notify_encode_apdu(NULL, sizeof(apdu), invoke_id, data); len = ccov_notify_encode_apdu(&apdu[0], sizeof(apdu), invoke_id, data); zassert_not_equal(len, 0, NULL); + zassert_equal(len, null_len, NULL); apdu_len = len; cov_data_value_list_link(&test_data, &value_list[0], 2); diff --git a/test/bacnet/dcc/src/main.c b/test/bacnet/dcc/src/main.c index 3fcac70b..bd46f7e1 100644 --- a/test/bacnet/dcc/src/main.c +++ b/test/bacnet/dcc/src/main.c @@ -20,60 +20,74 @@ * @brief Test */ static int dcc_decode_apdu(uint8_t *apdu, - unsigned apdu_len, + unsigned apdu_size, uint8_t *invoke_id, uint16_t *timeDuration, BACNET_COMMUNICATION_ENABLE_DISABLE *enable_disable, BACNET_CHARACTER_STRING *password) { int len = 0; - unsigned offset = 0; + unsigned apdu_len = 0; - if (!apdu) - return -1; - /* optional checking - most likely was already done prior to this call */ - if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) - return -1; - /* apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); */ - *invoke_id = apdu[2]; /* invoke id - filled in by net layer */ - if (apdu[3] != SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL) - return -1; - offset = 4; - - if (apdu_len > offset) { - len = dcc_decode_service_request(&apdu[offset], apdu_len - offset, + if (!apdu) { + return BACNET_STATUS_ERROR; + } + if (apdu_size > 4) { + if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) { + return BACNET_STATUS_ERROR; + } + /* apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); */ + *invoke_id = apdu[2]; /* invoke id - filled in by net layer */ + if (apdu[3] != SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL) { + return BACNET_STATUS_ERROR; + } + apdu_len = 4; + } else { + return BACNET_STATUS_ERROR; + } + if (apdu_size > apdu_len) { + len = dcc_decode_service_request(&apdu[apdu_len], apdu_size - apdu_len, timeDuration, enable_disable, password); + if (len > 0) { + apdu_len += len; + } else { + apdu_len = len; + } } - return len; + return apdu_len; } -static void test_DeviceCommunicationControlData( - uint8_t invoke_id, +static void test_DeviceCommunicationControlData(uint8_t invoke_id, uint16_t timeDuration, BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable, BACNET_CHARACTER_STRING *password) { uint8_t apdu[480] = { 0 }; - int len = 0; - int apdu_len = 0; + int apdu_size = 0, null_len = 0, test_len = 0; uint8_t test_invoke_id = 0; uint16_t test_timeDuration = 0; BACNET_COMMUNICATION_ENABLE_DISABLE test_enable_disable; BACNET_CHARACTER_STRING test_password; - len = dcc_encode_apdu( + null_len = dcc_encode_apdu( + NULL, invoke_id, timeDuration, enable_disable, password); + apdu_size = dcc_encode_apdu( &apdu[0], invoke_id, timeDuration, enable_disable, password); - zassert_not_equal(len, 0, NULL); - apdu_len = len; + zassert_equal(apdu_size, null_len, NULL); + zassert_not_equal(apdu_size, 0, NULL); - len = dcc_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, + test_len = dcc_decode_apdu(&apdu[0], apdu_size, &test_invoke_id, &test_timeDuration, &test_enable_disable, &test_password); - zassert_not_equal(len, -1, NULL); + zassert_not_equal(test_len, -1, NULL); zassert_equal(test_invoke_id, invoke_id, NULL); zassert_equal(test_timeDuration, timeDuration, NULL); zassert_equal(test_enable_disable, enable_disable, NULL); zassert_true(characterstring_same(&test_password, password), NULL); + test_len = dcc_decode_apdu(apdu, 4, &test_invoke_id, + &test_timeDuration, &test_enable_disable, &test_password); + zassert_true(test_len < 0, "apdu_size=%d test_len=%d", + apdu_size, test_len); } #if defined(CONFIG_ZTEST_NEW_API) @@ -149,16 +163,14 @@ static void test_DeviceCommunicationControlMalformedData(void) * @} */ - #if defined(CONFIG_ZTEST_NEW_API) ZTEST_SUITE(dcc_tests, NULL, NULL, NULL, NULL, NULL); #else void test_main(void) { ztest_test_suite(dcc_tests, - ztest_unit_test(test_DeviceCommunicationControl), - ztest_unit_test(test_DeviceCommunicationControlMalformedData) - ); + ztest_unit_test(test_DeviceCommunicationControl), + ztest_unit_test(test_DeviceCommunicationControlMalformedData)); ztest_run_test_suite(dcc_tests); } diff --git a/test/bacnet/event/src/main.c b/test/bacnet/event/src/main.c index 95b5ee92..e7a95eb8 100644 --- a/test/bacnet/event/src/main.c +++ b/test/bacnet/event/src/main.c @@ -25,17 +25,14 @@ static BACNET_EVENT_NOTIFICATION_DATA data2; static void verifyBaseEventState(void) { zassert_equal(data.processIdentifier, data2.processIdentifier, NULL); - zassert_equal( - data.initiatingObjectIdentifier.instance, - data2.initiatingObjectIdentifier.instance, NULL); - zassert_equal( - data.initiatingObjectIdentifier.type, - data2.initiatingObjectIdentifier.type, NULL); - zassert_equal( - data.eventObjectIdentifier.instance, - data2.eventObjectIdentifier.instance, NULL); - zassert_equal( - data.eventObjectIdentifier.type, data2.eventObjectIdentifier.type, NULL); + zassert_equal(data.initiatingObjectIdentifier.instance, + data2.initiatingObjectIdentifier.instance, NULL); + zassert_equal(data.initiatingObjectIdentifier.type, + data2.initiatingObjectIdentifier.type, NULL); + zassert_equal(data.eventObjectIdentifier.instance, + data2.eventObjectIdentifier.instance, NULL); + zassert_equal(data.eventObjectIdentifier.type, + data2.eventObjectIdentifier.type, NULL); zassert_equal(data.notificationClass, data2.notificationClass, NULL); zassert_equal(data.priority, data2.priority, NULL); zassert_equal(data.notifyType, data2.notifyType, NULL); @@ -44,8 +41,10 @@ static void verifyBaseEventState(void) zassert_equal(data.toState, data2.toState, NULL); if (data.messageText != NULL && data2.messageText != NULL) { - zassert_equal(data.messageText->encoding, data2.messageText->encoding, NULL); - zassert_equal(data.messageText->length, data2.messageText->length, NULL); + zassert_equal( + data.messageText->encoding, data2.messageText->encoding, NULL); + zassert_equal( + data.messageText->length, data2.messageText->length, NULL); zassert_equal( strcmp(data.messageText->value, data2.messageText->value), 0, NULL); } @@ -54,52 +53,39 @@ static void verifyBaseEventState(void) switch (data.timeStamp.tag) { case TIME_STAMP_SEQUENCE: - zassert_equal( - data.timeStamp.value.sequenceNum, - data2.timeStamp.value.sequenceNum, NULL); + zassert_equal(data.timeStamp.value.sequenceNum, + data2.timeStamp.value.sequenceNum, NULL); break; case TIME_STAMP_DATETIME: - zassert_equal( - data.timeStamp.value.dateTime.time.hour, - data2.timeStamp.value.dateTime.time.hour, NULL); - zassert_equal( - data.timeStamp.value.dateTime.time.min, - data2.timeStamp.value.dateTime.time.min, NULL); - zassert_equal( - data.timeStamp.value.dateTime.time.sec, - data2.timeStamp.value.dateTime.time.sec, NULL); - zassert_equal( - data.timeStamp.value.dateTime.time.hundredths, - data2.timeStamp.value.dateTime.time.hundredths, NULL); + zassert_equal(data.timeStamp.value.dateTime.time.hour, + data2.timeStamp.value.dateTime.time.hour, NULL); + zassert_equal(data.timeStamp.value.dateTime.time.min, + data2.timeStamp.value.dateTime.time.min, NULL); + zassert_equal(data.timeStamp.value.dateTime.time.sec, + data2.timeStamp.value.dateTime.time.sec, NULL); + zassert_equal(data.timeStamp.value.dateTime.time.hundredths, + data2.timeStamp.value.dateTime.time.hundredths, NULL); - zassert_equal( - data.timeStamp.value.dateTime.date.day, - data2.timeStamp.value.dateTime.date.day, NULL); - zassert_equal( - data.timeStamp.value.dateTime.date.month, - data2.timeStamp.value.dateTime.date.month, NULL); - zassert_equal( - data.timeStamp.value.dateTime.date.wday, - data2.timeStamp.value.dateTime.date.wday, NULL); - zassert_equal( - data.timeStamp.value.dateTime.date.year, - data2.timeStamp.value.dateTime.date.year, NULL); + zassert_equal(data.timeStamp.value.dateTime.date.day, + data2.timeStamp.value.dateTime.date.day, NULL); + zassert_equal(data.timeStamp.value.dateTime.date.month, + data2.timeStamp.value.dateTime.date.month, NULL); + zassert_equal(data.timeStamp.value.dateTime.date.wday, + data2.timeStamp.value.dateTime.date.wday, NULL); + zassert_equal(data.timeStamp.value.dateTime.date.year, + data2.timeStamp.value.dateTime.date.year, NULL); break; case TIME_STAMP_TIME: - zassert_equal( - data.timeStamp.value.time.hour, - data2.timeStamp.value.time.hour, NULL); - zassert_equal( - data.timeStamp.value.time.min, - data2.timeStamp.value.time.min, NULL); - zassert_equal( - data.timeStamp.value.time.sec, - data2.timeStamp.value.time.sec, NULL); - zassert_equal( - data.timeStamp.value.time.hundredths, - data2.timeStamp.value.time.hundredths, NULL); + zassert_equal(data.timeStamp.value.time.hour, + data2.timeStamp.value.time.hour, NULL); + zassert_equal(data.timeStamp.value.time.min, + data2.timeStamp.value.time.min, NULL); + zassert_equal(data.timeStamp.value.time.sec, + data2.timeStamp.value.time.sec, NULL); + zassert_equal(data.timeStamp.value.time.hundredths, + data2.timeStamp.value.time.hundredths, NULL); break; default: @@ -118,8 +104,7 @@ static void testEventEventState(void) #endif { uint8_t buffer[MAX_APDU]; - int inLen; - int outLen; + int apdu_len, test_len, null_len; BACNET_CHARACTER_STRING messageText; BACNET_CHARACTER_STRING messageText2; characterstring_init_ansi( @@ -156,31 +141,25 @@ static void testEventEventState(void) bitstring_set_bit(&data.notificationParams.changeOfState.statusFlags, STATUS_FLAG_OUT_OF_SERVICE, false); - inLen = event_notify_encode_service_request(&buffer[0], &data); - - outLen = event_notify_decode_service_request(&buffer[0], inLen, &data2); - - zassert_equal(inLen, outLen, NULL); + null_len = event_notify_encode_service_request(NULL, &data); + apdu_len = event_notify_encode_service_request(&buffer[0], &data); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); + test_len = + event_notify_decode_service_request(&buffer[0], apdu_len, &data2); + zassert_equal( + apdu_len, test_len, "apdu_len=%d test_len=%d", apdu_len, test_len); verifyBaseEventState(); - zassert_equal( - data.notificationParams.changeOfState.newState.tag, - data2.notificationParams.changeOfState.newState.tag, NULL); - zassert_equal( - data.notificationParams.changeOfState.newState.state.units, - data2.notificationParams.changeOfState.newState.state.units, NULL); + zassert_equal(data.notificationParams.changeOfState.newState.tag, + data2.notificationParams.changeOfState.newState.tag, NULL); + zassert_equal(data.notificationParams.changeOfState.newState.state.units, + data2.notificationParams.changeOfState.newState.state.units, NULL); zassert_true( bitstring_same(&data.notificationParams.changeOfState.statusFlags, - &data2.notificationParams.changeOfState.statusFlags), NULL); - - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ + &data2.notificationParams.changeOfState.statusFlags), + NULL); /* ** Same, but timestamp of @@ -197,29 +176,22 @@ static void testEventEventState(void) data.timeStamp.value.dateTime.date.year = 1945; memset(buffer, 0, MAX_APDU); - inLen = event_notify_encode_service_request(&buffer[0], &data); + null_len = event_notify_encode_service_request(NULL, &data); + apdu_len = event_notify_encode_service_request(&buffer[0], &data); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); memset(&data2, 0, sizeof(data2)); data2.messageText = &messageText2; - outLen = event_notify_decode_service_request(&buffer[0], inLen, &data2); + test_len = + event_notify_decode_service_request(&buffer[0], apdu_len, &data2); - zassert_equal(inLen, outLen, NULL); + zassert_equal(apdu_len, test_len, NULL); verifyBaseEventState(); - zassert_equal( - data.notificationParams.changeOfState.newState.tag, - data2.notificationParams.changeOfState.newState.tag, NULL); - zassert_equal( - data.notificationParams.changeOfState.newState.state.units, - data2.notificationParams.changeOfState.newState.state.units, NULL); - - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - + zassert_equal(data.notificationParams.changeOfState.newState.tag, + data2.notificationParams.changeOfState.newState.tag, NULL); + zassert_equal(data.notificationParams.changeOfState.newState.state.units, + data2.notificationParams.changeOfState.newState.state.units, NULL); /* ** Event Type = EVENT_CHANGE_OF_BITSTRING */ @@ -255,35 +227,33 @@ static void testEventEventState(void) STATUS_FLAG_OUT_OF_SERVICE, false); memset(buffer, 0, MAX_APDU); - inLen = event_notify_encode_service_request(&buffer[0], &data); + null_len = event_notify_encode_service_request(NULL, &data); + apdu_len = event_notify_encode_service_request(&buffer[0], &data); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); memset(&data2, 0, sizeof(data2)); data2.messageText = &messageText2; - outLen = event_notify_decode_service_request(&buffer[0], inLen, &data2); + test_len = + event_notify_decode_service_request(&buffer[0], apdu_len, &data2); - zassert_equal(inLen, outLen, NULL); + zassert_equal(apdu_len, test_len, NULL); verifyBaseEventState(); zassert_true( bitstring_same( &data.notificationParams.changeOfBitstring.referencedBitString, - &data2.notificationParams.changeOfBitstring.referencedBitString), NULL); + &data2.notificationParams.changeOfBitstring.referencedBitString), + NULL); zassert_true( bitstring_same(&data.notificationParams.changeOfBitstring.statusFlags, - &data2.notificationParams.changeOfBitstring.statusFlags), NULL); + &data2.notificationParams.changeOfBitstring.statusFlags), + NULL); - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ /* ** Event Type = EVENT_CHANGE_OF_VALUE - float value */ - data.eventType = EVENT_CHANGE_OF_VALUE; data.notificationParams.changeOfValue.tag = CHANGE_OF_VALUE_REAL; data.notificationParams.changeOfValue.newValue.changeValue = 1.23f; @@ -300,33 +270,35 @@ static void testEventEventState(void) STATUS_FLAG_OUT_OF_SERVICE, false); memset(buffer, 0, MAX_APDU); - inLen = event_notify_encode_service_request(&buffer[0], &data); + null_len = event_notify_encode_service_request(NULL, &data); + apdu_len = event_notify_encode_service_request(&buffer[0], &data); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); memset(&data2, 0, sizeof(data2)); data2.messageText = &messageText2; - outLen = event_notify_decode_service_request(&buffer[0], inLen, &data2); + test_len = + event_notify_decode_service_request(&buffer[0], apdu_len, &data2); - zassert_equal(inLen, outLen, NULL); + zassert_equal(apdu_len, test_len, NULL); verifyBaseEventState(); zassert_true( bitstring_same(&data.notificationParams.changeOfValue.statusFlags, - &data2.notificationParams.changeOfValue.statusFlags), NULL); + &data2.notificationParams.changeOfValue.statusFlags), + NULL); - zassert_equal( - data.notificationParams.changeOfValue.tag, - data2.notificationParams.changeOfValue.tag, NULL); + zassert_equal(data.notificationParams.changeOfValue.tag, + data2.notificationParams.changeOfValue.tag, NULL); - zassert_equal( - data.notificationParams.changeOfValue.newValue.changeValue, - data2.notificationParams.changeOfValue.newValue.changeValue, NULL); + zassert_equal(data.notificationParams.changeOfValue.newValue.changeValue, + data2.notificationParams.changeOfValue.newValue.changeValue, NULL); /* ** Event Type = EVENT_CHANGE_OF_VALUE - bitstring value */ data.notificationParams.changeOfValue.tag = CHANGE_OF_VALUE_BITS; - bitstring_init(&data.notificationParams.changeOfValue.newValue.changedBits); bitstring_set_bit( &data.notificationParams.changeOfValue.newValue.changedBits, 0, true); @@ -336,42 +308,34 @@ static void testEventEventState(void) &data.notificationParams.changeOfValue.newValue.changedBits, 2, false); bitstring_set_bit( &data.notificationParams.changeOfValue.newValue.changedBits, 3, false); - memset(buffer, 0, MAX_APDU); - inLen = event_notify_encode_service_request(&buffer[0], &data); - + null_len = event_notify_encode_service_request(NULL, &data); + apdu_len = event_notify_encode_service_request(&buffer[0], &data); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); memset(&data2, 0, sizeof(data2)); data2.messageText = &messageText2; - outLen = event_notify_decode_service_request(&buffer[0], inLen, &data2); + test_len = + event_notify_decode_service_request(&buffer[0], apdu_len, &data2); + zassert_equal(apdu_len, test_len, NULL); - zassert_equal(inLen, outLen, NULL); verifyBaseEventState(); - zassert_true( bitstring_same(&data.notificationParams.changeOfValue.statusFlags, - &data2.notificationParams.changeOfValue.statusFlags), NULL); - - zassert_equal( - data.notificationParams.changeOfValue.tag, - data2.notificationParams.changeOfValue.tag, NULL); - + &data2.notificationParams.changeOfValue.statusFlags), + NULL); + zassert_equal(data.notificationParams.changeOfValue.tag, + data2.notificationParams.changeOfValue.tag, NULL); zassert_true( bitstring_same( &data.notificationParams.changeOfValue.newValue.changedBits, - &data2.notificationParams.changeOfValue.newValue.changedBits), NULL); + &data2.notificationParams.changeOfValue.newValue.changedBits), + NULL); - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ /* ** Event Type = EVENT_COMMAND_FAILURE */ - /* ** commandValue = enumerated */ @@ -381,9 +345,7 @@ static void testEventEventState(void) BINARY_INACTIVE; data.notificationParams.commandFailure.feedbackValue.binaryValue = BINARY_ACTIVE; - bitstring_init(&data.notificationParams.commandFailure.statusFlags); - bitstring_set_bit(&data.notificationParams.commandFailure.statusFlags, STATUS_FLAG_IN_ALARM, true); bitstring_set_bit(&data.notificationParams.commandFailure.statusFlags, @@ -392,21 +354,23 @@ static void testEventEventState(void) STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&data.notificationParams.commandFailure.statusFlags, STATUS_FLAG_OUT_OF_SERVICE, false); - memset(buffer, 0, MAX_APDU); - inLen = event_notify_encode_service_request(&buffer[0], &data); - + null_len = event_notify_encode_service_request(NULL, &data); + apdu_len = event_notify_encode_service_request(&buffer[0], &data); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); memset(&data2, 0, sizeof(data2)); data2.messageText = &messageText2; - outLen = event_notify_decode_service_request(&buffer[0], inLen, &data2); + test_len = + event_notify_decode_service_request(&buffer[0], apdu_len, &data2); + zassert_equal( + apdu_len, test_len, "apdu_len=%d test_len=%d", apdu_len, test_len); - zassert_equal(inLen, outLen, NULL); verifyBaseEventState(); zassert_equal( data.notificationParams.commandFailure.commandValue.binaryValue, - data2.notificationParams.commandFailure.commandValue.binaryValue, - NULL); + data2.notificationParams.commandFailure.commandValue.binaryValue, NULL); zassert_equal( data.notificationParams.commandFailure.feedbackValue.binaryValue, @@ -415,7 +379,8 @@ static void testEventEventState(void) zassert_true( bitstring_same(&data.notificationParams.commandFailure.statusFlags, - &data2.notificationParams.commandFailure.statusFlags), NULL); + &data2.notificationParams.commandFailure.statusFlags), + NULL); /* ** commandValue = unsigned @@ -437,13 +402,17 @@ static void testEventEventState(void) STATUS_FLAG_OUT_OF_SERVICE, false); memset(buffer, 0, MAX_APDU); - inLen = event_notify_encode_service_request(&buffer[0], &data); + null_len = event_notify_encode_service_request(NULL, &data); + apdu_len = event_notify_encode_service_request(&buffer[0], &data); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); memset(&data2, 0, sizeof(data2)); data2.messageText = &messageText2; - outLen = event_notify_decode_service_request(&buffer[0], inLen, &data2); + test_len = + event_notify_decode_service_request(&buffer[0], apdu_len, &data2); - zassert_equal(inLen, outLen, NULL); + zassert_equal(apdu_len, test_len, NULL); verifyBaseEventState(); zassert_equal( @@ -458,15 +427,9 @@ static void testEventEventState(void) zassert_true( bitstring_same(&data.notificationParams.commandFailure.statusFlags, - &data2.notificationParams.commandFailure.statusFlags), NULL); + &data2.notificationParams.commandFailure.statusFlags), + NULL); - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ /* ** Event Type = EVENT_FLOATING_LIMIT */ @@ -487,37 +450,31 @@ static void testEventEventState(void) STATUS_FLAG_OUT_OF_SERVICE, false); memset(buffer, 0, MAX_APDU); - inLen = event_notify_encode_service_request(&buffer[0], &data); - + null_len = event_notify_encode_service_request(NULL, &data); + apdu_len = event_notify_encode_service_request(&buffer[0], &data); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); memset(&data2, 0, sizeof(data2)); data2.messageText = &messageText2; - outLen = event_notify_decode_service_request(&buffer[0], inLen, &data2); - - zassert_equal(inLen, outLen, NULL); + test_len = + event_notify_decode_service_request(&buffer[0], apdu_len, &data2); + zassert_equal( + apdu_len, test_len, "apdu_len=%d test_len=%d", apdu_len, test_len); verifyBaseEventState(); - zassert_equal( - data.notificationParams.floatingLimit.referenceValue, - data2.notificationParams.floatingLimit.referenceValue, NULL); + zassert_equal(data.notificationParams.floatingLimit.referenceValue, + data2.notificationParams.floatingLimit.referenceValue, NULL); - zassert_equal( - data.notificationParams.floatingLimit.setPointValue, - data2.notificationParams.floatingLimit.setPointValue, NULL); + zassert_equal(data.notificationParams.floatingLimit.setPointValue, + data2.notificationParams.floatingLimit.setPointValue, NULL); - zassert_equal( - data.notificationParams.floatingLimit.errorLimit, - data2.notificationParams.floatingLimit.errorLimit, NULL); + zassert_equal(data.notificationParams.floatingLimit.errorLimit, + data2.notificationParams.floatingLimit.errorLimit, NULL); zassert_true( bitstring_same(&data.notificationParams.floatingLimit.statusFlags, - &data2.notificationParams.floatingLimit.statusFlags), NULL); + &data2.notificationParams.floatingLimit.statusFlags), + NULL); - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ /* ** Event Type = EVENT_OUT_OF_RANGE */ @@ -538,37 +495,31 @@ static void testEventEventState(void) STATUS_FLAG_OUT_OF_SERVICE, false); memset(buffer, 0, MAX_APDU); - inLen = event_notify_encode_service_request(&buffer[0], &data); + null_len = event_notify_encode_service_request(NULL, &data); + apdu_len = event_notify_encode_service_request(&buffer[0], &data); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); memset(&data2, 0, sizeof(data2)); data2.messageText = &messageText2; - outLen = event_notify_decode_service_request(&buffer[0], inLen, &data2); + test_len = + event_notify_decode_service_request(&buffer[0], apdu_len, &data2); - zassert_equal(inLen, outLen, NULL); + zassert_equal(apdu_len, test_len, NULL); verifyBaseEventState(); - zassert_equal( - data.notificationParams.outOfRange.deadband, - data2.notificationParams.outOfRange.deadband, NULL); + zassert_equal(data.notificationParams.outOfRange.deadband, + data2.notificationParams.outOfRange.deadband, NULL); - zassert_equal( - data.notificationParams.outOfRange.exceededLimit, - data2.notificationParams.outOfRange.exceededLimit, NULL); + zassert_equal(data.notificationParams.outOfRange.exceededLimit, + data2.notificationParams.outOfRange.exceededLimit, NULL); - zassert_equal( - data.notificationParams.outOfRange.exceedingValue, - data2.notificationParams.outOfRange.exceedingValue, NULL); - zassert_true( - bitstring_same(&data.notificationParams.outOfRange.statusFlags, - &data2.notificationParams.outOfRange.statusFlags), NULL); + zassert_equal(data.notificationParams.outOfRange.exceedingValue, + data2.notificationParams.outOfRange.exceedingValue, NULL); + zassert_true(bitstring_same(&data.notificationParams.outOfRange.statusFlags, + &data2.notificationParams.outOfRange.statusFlags), + NULL); - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ /* ** Event Type = EVENT_CHANGE_OF_LIFE_SAFETY */ @@ -591,38 +542,33 @@ static void testEventEventState(void) STATUS_FLAG_OUT_OF_SERVICE, false); memset(buffer, 0, MAX_APDU); - inLen = event_notify_encode_service_request(&buffer[0], &data); + null_len = event_notify_encode_service_request(NULL, &data); + apdu_len = event_notify_encode_service_request(&buffer[0], &data); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); memset(&data2, 0, sizeof(data2)); data2.messageText = &messageText2; - outLen = event_notify_decode_service_request(&buffer[0], inLen, &data2); + test_len = + event_notify_decode_service_request(&buffer[0], apdu_len, &data2); - zassert_equal(inLen, outLen, NULL); + zassert_equal(apdu_len, test_len, NULL); verifyBaseEventState(); - zassert_equal( - data.notificationParams.changeOfLifeSafety.newMode, - data2.notificationParams.changeOfLifeSafety.newMode, NULL); + zassert_equal(data.notificationParams.changeOfLifeSafety.newMode, + data2.notificationParams.changeOfLifeSafety.newMode, NULL); - zassert_equal( - data.notificationParams.changeOfLifeSafety.newState, - data2.notificationParams.changeOfLifeSafety.newState, NULL); + zassert_equal(data.notificationParams.changeOfLifeSafety.newState, + data2.notificationParams.changeOfLifeSafety.newState, NULL); - zassert_equal( - data.notificationParams.changeOfLifeSafety.operationExpected, - data2.notificationParams.changeOfLifeSafety.operationExpected, NULL); + zassert_equal(data.notificationParams.changeOfLifeSafety.operationExpected, + data2.notificationParams.changeOfLifeSafety.operationExpected, NULL); zassert_true( bitstring_same(&data.notificationParams.changeOfLifeSafety.statusFlags, - &data2.notificationParams.changeOfLifeSafety.statusFlags), NULL); + &data2.notificationParams.changeOfLifeSafety.statusFlags), + NULL); - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ /* ** Event Type = EVENT_UNSIGNED_RANGE */ @@ -642,34 +588,30 @@ static void testEventEventState(void) STATUS_FLAG_OUT_OF_SERVICE, false); memset(buffer, 0, MAX_APDU); - inLen = event_notify_encode_service_request(&buffer[0], &data); + null_len = event_notify_encode_service_request(NULL, &data); + apdu_len = event_notify_encode_service_request(&buffer[0], &data); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); memset(&data2, 0, sizeof(data2)); data2.messageText = &messageText2; - outLen = event_notify_decode_service_request(&buffer[0], inLen, &data2); + test_len = + event_notify_decode_service_request(&buffer[0], apdu_len, &data2); - zassert_equal(inLen, outLen, NULL); + zassert_equal(apdu_len, test_len, NULL); verifyBaseEventState(); - zassert_equal( - data.notificationParams.unsignedRange.exceedingValue, - data2.notificationParams.unsignedRange.exceedingValue, NULL); + zassert_equal(data.notificationParams.unsignedRange.exceedingValue, + data2.notificationParams.unsignedRange.exceedingValue, NULL); - zassert_equal( - data.notificationParams.unsignedRange.exceededLimit, - data2.notificationParams.unsignedRange.exceededLimit, NULL); + zassert_equal(data.notificationParams.unsignedRange.exceededLimit, + data2.notificationParams.unsignedRange.exceededLimit, NULL); zassert_true( bitstring_same(&data.notificationParams.unsignedRange.statusFlags, - &data2.notificationParams.unsignedRange.statusFlags), NULL); + &data2.notificationParams.unsignedRange.statusFlags), + NULL); - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ /* ** Event Type = EVENT_BUFFER_READY */ @@ -689,62 +631,57 @@ static void testEventEventState(void) data.notificationParams.bufferReady.bufferProperty.arrayIndex = 0; memset(buffer, 0, MAX_APDU); - inLen = event_notify_encode_service_request(&buffer[0], &data); + null_len = event_notify_encode_service_request(NULL, &data); + apdu_len = event_notify_encode_service_request(&buffer[0], &data); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); memset(&data2, 0, sizeof(data2)); data2.messageText = &messageText2; - outLen = event_notify_decode_service_request(&buffer[0], inLen, &data2); + test_len = + event_notify_decode_service_request(&buffer[0], apdu_len, &data2); - zassert_equal(inLen, outLen, NULL); + zassert_equal(apdu_len, test_len, NULL); verifyBaseEventState(); - zassert_equal( - data.notificationParams.bufferReady.previousNotification, - data2.notificationParams.bufferReady.previousNotification, NULL); + zassert_equal(data.notificationParams.bufferReady.previousNotification, + data2.notificationParams.bufferReady.previousNotification, NULL); - zassert_equal( - data.notificationParams.bufferReady.currentNotification, - data2.notificationParams.bufferReady.currentNotification, NULL); + zassert_equal(data.notificationParams.bufferReady.currentNotification, + data2.notificationParams.bufferReady.currentNotification, NULL); - zassert_equal( - data.notificationParams.bufferReady.bufferProperty.deviceIdentifier - .type, - data2.notificationParams.bufferReady.bufferProperty.deviceIdentifier - .type, NULL); + zassert_equal(data.notificationParams.bufferReady.bufferProperty + .deviceIdentifier.type, + data2.notificationParams.bufferReady.bufferProperty.deviceIdentifier + .type, + NULL); - zassert_equal( - data.notificationParams.bufferReady.bufferProperty.deviceIdentifier - .instance, - data2.notificationParams.bufferReady.bufferProperty.deviceIdentifier - .instance, NULL); + zassert_equal(data.notificationParams.bufferReady.bufferProperty + .deviceIdentifier.instance, + data2.notificationParams.bufferReady.bufferProperty.deviceIdentifier + .instance, + NULL); - zassert_equal( - data.notificationParams.bufferReady.bufferProperty.objectIdentifier - .instance, - data2.notificationParams.bufferReady.bufferProperty.objectIdentifier - .instance, NULL); + zassert_equal(data.notificationParams.bufferReady.bufferProperty + .objectIdentifier.instance, + data2.notificationParams.bufferReady.bufferProperty.objectIdentifier + .instance, + NULL); - zassert_equal( - data.notificationParams.bufferReady.bufferProperty.objectIdentifier - .type, - data2.notificationParams.bufferReady.bufferProperty.objectIdentifier - .type, NULL); + zassert_equal(data.notificationParams.bufferReady.bufferProperty + .objectIdentifier.type, + data2.notificationParams.bufferReady.bufferProperty.objectIdentifier + .type, + NULL); zassert_equal( data.notificationParams.bufferReady.bufferProperty.propertyIdentifier, - data2.notificationParams.bufferReady.bufferProperty - .propertyIdentifier, NULL); + data2.notificationParams.bufferReady.bufferProperty.propertyIdentifier, + NULL); + + zassert_equal(data.notificationParams.bufferReady.bufferProperty.arrayIndex, + data2.notificationParams.bufferReady.bufferProperty.arrayIndex, NULL); - zassert_equal( - data.notificationParams.bufferReady.bufferProperty.arrayIndex, - data2.notificationParams.bufferReady.bufferProperty.arrayIndex, NULL); - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ - /**********************************************************************************/ /* ** Event Type = EVENT_ACCESS_EVENT */ @@ -757,15 +694,16 @@ static void testEventEventState(void) data.notificationParams.accessEvent.accessEventTime.tag = TIME_STAMP_SEQUENCE; data.notificationParams.accessEvent.accessEventTime.value.sequenceNum = 17; - data.notificationParams.accessEvent.accessCredential. - deviceIdentifier.instance = 1234; - data.notificationParams.accessEvent.accessCredential. - deviceIdentifier.type = OBJECT_DEVICE; - data.notificationParams.accessEvent.accessCredential. - objectIdentifier.instance = 17; - data.notificationParams.accessEvent.accessCredential. - objectIdentifier.type = OBJECT_ACCESS_POINT; - data.notificationParams.accessEvent.authenticationFactor.format_type = AUTHENTICATION_FACTOR_MAX; // omit authenticationFactor + data.notificationParams.accessEvent.accessCredential.deviceIdentifier + .instance = 1234; + data.notificationParams.accessEvent.accessCredential.deviceIdentifier.type = + OBJECT_DEVICE; + data.notificationParams.accessEvent.accessCredential.objectIdentifier + .instance = 17; + data.notificationParams.accessEvent.accessCredential.objectIdentifier.type = + OBJECT_ACCESS_POINT; + data.notificationParams.accessEvent.authenticationFactor.format_type = + AUTHENTICATION_FACTOR_MAX; // omit authenticationFactor bitstring_init(&data.notificationParams.accessEvent.statusFlags); bitstring_set_bit(&data.notificationParams.accessEvent.statusFlags, @@ -778,60 +716,61 @@ static void testEventEventState(void) STATUS_FLAG_OUT_OF_SERVICE, false); memset(buffer, 0, MAX_APDU); - inLen = event_notify_encode_service_request(&buffer[0], &data); + null_len = event_notify_encode_service_request(NULL, &data); + apdu_len = event_notify_encode_service_request(&buffer[0], &data); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); memset(&data2, 0, sizeof(data2)); data2.messageText = &messageText2; - outLen = event_notify_decode_service_request(&buffer[0], inLen, &data2); + test_len = + event_notify_decode_service_request(&buffer[0], apdu_len, &data2); - zassert_equal(inLen, outLen, NULL); + zassert_equal(apdu_len, test_len, NULL); verifyBaseEventState(); - zassert_equal( - data.notificationParams.accessEvent.accessEvent, + zassert_equal(data.notificationParams.accessEvent.accessEvent, data2.notificationParams.accessEvent.accessEvent, NULL); zassert_true( bitstring_same(&data.notificationParams.accessEvent.statusFlags, - &data2.notificationParams.accessEvent.statusFlags), NULL); + &data2.notificationParams.accessEvent.statusFlags), + NULL); - zassert_equal( - data.notificationParams.accessEvent.accessEventTag, + zassert_equal(data.notificationParams.accessEvent.accessEventTag, data2.notificationParams.accessEvent.accessEventTag, NULL); - zassert_equal( - data.notificationParams.accessEvent.accessEventTime.tag, + zassert_equal(data.notificationParams.accessEvent.accessEventTime.tag, data2.notificationParams.accessEvent.accessEventTime.tag, NULL); zassert_equal( - data.notificationParams.accessEvent.accessEventTime. - value.sequenceNum, - data2.notificationParams.accessEvent.accessEventTime. - value.sequenceNum, NULL); + data.notificationParams.accessEvent.accessEventTime.value.sequenceNum, + data2.notificationParams.accessEvent.accessEventTime.value.sequenceNum, + NULL); - zassert_equal( - data.notificationParams.accessEvent.accessCredential. - deviceIdentifier.instance, - data2.notificationParams.accessEvent.accessCredential. - deviceIdentifier.instance, NULL); + zassert_equal(data.notificationParams.accessEvent.accessCredential + .deviceIdentifier.instance, + data2.notificationParams.accessEvent.accessCredential.deviceIdentifier + .instance, + NULL); - zassert_equal( - data.notificationParams.accessEvent.accessCredential. - deviceIdentifier.type, - data2.notificationParams.accessEvent.accessCredential. - deviceIdentifier.type, NULL); + zassert_equal(data.notificationParams.accessEvent.accessCredential + .deviceIdentifier.type, + data2.notificationParams.accessEvent.accessCredential.deviceIdentifier + .type, + NULL); - zassert_equal( - data.notificationParams.accessEvent.accessCredential. - objectIdentifier.instance, - data2.notificationParams.accessEvent.accessCredential. - objectIdentifier.instance, NULL); + zassert_equal(data.notificationParams.accessEvent.accessCredential + .objectIdentifier.instance, + data2.notificationParams.accessEvent.accessCredential.objectIdentifier + .instance, + NULL); - zassert_equal( - data.notificationParams.accessEvent.accessCredential. - objectIdentifier.type, - data2.notificationParams.accessEvent.accessCredential. - objectIdentifier.type, NULL); + zassert_equal(data.notificationParams.accessEvent.accessCredential + .objectIdentifier.type, + data2.notificationParams.accessEvent.accessCredential.objectIdentifier + .type, + NULL); // OPTIONAL authenticationFactor included data.eventType = EVENT_ACCESS_EVENT; @@ -841,22 +780,22 @@ static void testEventEventState(void) data.notificationParams.accessEvent.accessEventTime.tag = TIME_STAMP_SEQUENCE; data.notificationParams.accessEvent.accessEventTime.value.sequenceNum = 17; - data.notificationParams.accessEvent.accessCredential. - deviceIdentifier.instance = 1234; - data.notificationParams.accessEvent.accessCredential. - deviceIdentifier.type = OBJECT_DEVICE; - data.notificationParams.accessEvent.accessCredential. - objectIdentifier.instance = 17; - data.notificationParams.accessEvent.accessCredential. - objectIdentifier.type = OBJECT_ACCESS_POINT; + data.notificationParams.accessEvent.accessCredential.deviceIdentifier + .instance = 1234; + data.notificationParams.accessEvent.accessCredential.deviceIdentifier.type = + OBJECT_DEVICE; + data.notificationParams.accessEvent.accessCredential.objectIdentifier + .instance = 17; + data.notificationParams.accessEvent.accessCredential.objectIdentifier.type = + OBJECT_ACCESS_POINT; data.notificationParams.accessEvent.authenticationFactor.format_type = AUTHENTICATION_FACTOR_SIMPLE_NUMBER16; - data.notificationParams.accessEvent.authenticationFactor.format_class = - 215; + data.notificationParams.accessEvent.authenticationFactor.format_class = 215; uint8_t octetstringValue[2] = { 0x00, 0x10 }; - octetstring_init(&data.notificationParams.accessEvent. - authenticationFactor.value, octetstringValue, 2); + octetstring_init( + &data.notificationParams.accessEvent.authenticationFactor.value, + octetstringValue, 2); bitstring_init(&data.notificationParams.accessEvent.statusFlags); bitstring_set_bit(&data.notificationParams.accessEvent.statusFlags, @@ -869,60 +808,61 @@ static void testEventEventState(void) STATUS_FLAG_OUT_OF_SERVICE, false); memset(buffer, 0, MAX_APDU); - inLen = event_notify_encode_service_request(&buffer[0], &data); + null_len = event_notify_encode_service_request(NULL, &data); + apdu_len = event_notify_encode_service_request(&buffer[0], &data); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); memset(&data2, 0, sizeof(data2)); data2.messageText = &messageText2; - outLen = event_notify_decode_service_request(&buffer[0], inLen, &data2); + test_len = + event_notify_decode_service_request(&buffer[0], apdu_len, &data2); - zassert_equal(inLen, outLen, NULL); + zassert_equal(apdu_len, test_len, NULL); verifyBaseEventState(); - zassert_equal( - data.notificationParams.accessEvent.accessEvent, + zassert_equal(data.notificationParams.accessEvent.accessEvent, data2.notificationParams.accessEvent.accessEvent, NULL); zassert_true( bitstring_same(&data.notificationParams.accessEvent.statusFlags, - &data2.notificationParams.accessEvent.statusFlags), NULL); + &data2.notificationParams.accessEvent.statusFlags), + NULL); - zassert_equal( - data.notificationParams.accessEvent.accessEventTag, + zassert_equal(data.notificationParams.accessEvent.accessEventTag, data2.notificationParams.accessEvent.accessEventTag, NULL); - zassert_equal( - data.notificationParams.accessEvent.accessEventTime.tag, + zassert_equal(data.notificationParams.accessEvent.accessEventTime.tag, data2.notificationParams.accessEvent.accessEventTime.tag, NULL); zassert_equal( - data.notificationParams.accessEvent.accessEventTime. - value.sequenceNum, - data2.notificationParams.accessEvent.accessEventTime. - value.sequenceNum, NULL); + data.notificationParams.accessEvent.accessEventTime.value.sequenceNum, + data2.notificationParams.accessEvent.accessEventTime.value.sequenceNum, + NULL); - zassert_equal( - data.notificationParams.accessEvent.accessCredential. - deviceIdentifier.instance, - data2.notificationParams.accessEvent.accessCredential. - deviceIdentifier.instance, NULL); + zassert_equal(data.notificationParams.accessEvent.accessCredential + .deviceIdentifier.instance, + data2.notificationParams.accessEvent.accessCredential.deviceIdentifier + .instance, + NULL); - zassert_equal( - data.notificationParams.accessEvent.accessCredential. - deviceIdentifier.type, - data2.notificationParams.accessEvent.accessCredential. - deviceIdentifier.type, NULL); + zassert_equal(data.notificationParams.accessEvent.accessCredential + .deviceIdentifier.type, + data2.notificationParams.accessEvent.accessCredential.deviceIdentifier + .type, + NULL); - zassert_equal( - data.notificationParams.accessEvent.accessCredential. - objectIdentifier.instance, - data2.notificationParams.accessEvent.accessCredential. - objectIdentifier.instance, NULL); + zassert_equal(data.notificationParams.accessEvent.accessCredential + .objectIdentifier.instance, + data2.notificationParams.accessEvent.accessCredential.objectIdentifier + .instance, + NULL); - zassert_equal( - data.notificationParams.accessEvent.accessCredential. - objectIdentifier.type, - data2.notificationParams.accessEvent.accessCredential. - objectIdentifier.type, NULL); + zassert_equal(data.notificationParams.accessEvent.accessCredential + .objectIdentifier.type, + data2.notificationParams.accessEvent.accessCredential.objectIdentifier + .type, + NULL); zassert_equal( data.notificationParams.accessEvent.authenticationFactor.format_type, @@ -930,30 +870,26 @@ static void testEventEventState(void) NULL); zassert_equal( - data.notificationParams.accessEvent. - authenticationFactor.format_class, - data2.notificationParams.accessEvent. - authenticationFactor.format_class, NULL); + data.notificationParams.accessEvent.authenticationFactor.format_class, + data2.notificationParams.accessEvent.authenticationFactor.format_class, + NULL); zassert_true( - octetstring_value_same(&data.notificationParams. - accessEvent.authenticationFactor.value, + octetstring_value_same( + &data.notificationParams.accessEvent.authenticationFactor.value, &data2.notificationParams.accessEvent.authenticationFactor.value), - NULL); + NULL); } /** * @} */ - #if defined(CONFIG_ZTEST_NEW_API) ZTEST_SUITE(event_tests, NULL, NULL, NULL, NULL, NULL); #else void test_main(void) { - ztest_test_suite(event_tests, - ztest_unit_test(testEventEventState) - ); + ztest_test_suite(event_tests, ztest_unit_test(testEventEventState)); ztest_run_test_suite(event_tests); } diff --git a/test/bacnet/getevent/src/main.c b/test/bacnet/getevent/src/main.c index 11e66060..2aa62de8 100644 --- a/test/bacnet/getevent/src/main.c +++ b/test/bacnet/getevent/src/main.c @@ -20,30 +20,39 @@ * @brief Test */ static int getevent_decode_apdu(uint8_t *apdu, - unsigned apdu_len, + unsigned apdu_size, uint8_t *invoke_id, BACNET_OBJECT_ID *lastReceivedObjectIdentifier) { int len = 0; - unsigned offset = 0; + unsigned apdu_len = 0; - if (!apdu) - return -1; - /* optional checking - most likely was already done prior to this call */ - if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) - return -1; - /* apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); */ - *invoke_id = apdu[2]; /* invoke id - filled in by net layer */ - if (apdu[3] != SERVICE_CONFIRMED_GET_EVENT_INFORMATION) - return -1; - offset = 4; - - if (apdu_len > offset) { - len = getevent_decode_service_request( - &apdu[offset], apdu_len - offset, lastReceivedObjectIdentifier); + if (!apdu) { + return BACNET_STATUS_ERROR; + } + if (apdu_size > 4) { + if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) { + return BACNET_STATUS_ERROR; + } + /* apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); */ + *invoke_id = apdu[2]; /* invoke id - filled in by net layer */ + if (apdu[3] != SERVICE_CONFIRMED_GET_EVENT_INFORMATION) { + return BACNET_STATUS_ERROR; + } + apdu_len = 4; } - return len; + if (apdu_size > apdu_len) { + len = getevent_decode_service_request( + &apdu[apdu_len], apdu_size - apdu_len, lastReceivedObjectIdentifier); + if (len > 0) { + apdu_len += len; + } else { + apdu_len = len; + } + } + + return apdu_len; } static int getevent_ack_decode_apdu(uint8_t *apdu, @@ -150,8 +159,7 @@ static void testGetEventInformation(void) #endif { uint8_t apdu[480] = { 0 }; - int len = 0; - int apdu_len = 0; + int apdu_len, test_len, null_len; uint8_t invoke_id = 128; uint8_t test_invoke_id = 0; BACNET_OBJECT_ID lastReceivedObjectIdentifier; @@ -159,14 +167,18 @@ static void testGetEventInformation(void) lastReceivedObjectIdentifier.type = OBJECT_BINARY_INPUT; lastReceivedObjectIdentifier.instance = 12345; - len = getevent_encode_apdu( + null_len = getevent_encode_apdu( + NULL, invoke_id, &lastReceivedObjectIdentifier); + apdu_len = getevent_encode_apdu( &apdu[0], invoke_id, &lastReceivedObjectIdentifier); - zassert_not_equal(len, 0, NULL); - apdu_len = len; + zassert_equal(apdu_len, null_len, NULL); + zassert_not_equal(apdu_len, 0, NULL); - len = getevent_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, + test_len = getevent_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_lastReceivedObjectIdentifier); - zassert_not_equal(len, -1, NULL); + zassert_equal( + apdu_len, test_len, "apdu_len=%d test_len=%d", apdu_len, test_len); + zassert_not_equal(test_len, -1, NULL); zassert_equal(test_invoke_id, invoke_id, NULL); zassert_equal( test_lastReceivedObjectIdentifier.type, diff --git a/test/bacnet/list_element/src/main.c b/test/bacnet/list_element/src/main.c index f9e7a314..d7bd8c7d 100644 --- a/test/bacnet/list_element/src/main.c +++ b/test/bacnet/list_element/src/main.c @@ -27,9 +27,17 @@ static void test_ListElement(void) list_element.application_data = NULL; list_element.application_data_len = 0; + /* NULL test - number of bytes which would have been written to the APDU */ null_len = list_element_encode_service_request(NULL, &list_element); apdu_len = list_element_encode_service_request(apdu, &list_element); zassert_equal(apdu_len, null_len, NULL); + apdu_len = + list_element_service_request_encode(apdu, null_len, &list_element); + zassert_equal(apdu_len, null_len, NULL); + /* negative test - too short */ + null_len = list_element_service_request_encode(NULL, 0, &list_element); + zassert_equal(0, null_len, NULL); + /* decoder test */ test_len = list_element_decode_service_request(apdu, apdu_len, &test_list_element); zassert_equal(apdu_len, test_len, NULL); diff --git a/test/bacnet/lso/src/main.c b/test/bacnet/lso/src/main.c index 7f52d6f7..cc5b37a5 100644 --- a/test/bacnet/lso/src/main.c +++ b/test/bacnet/lso/src/main.c @@ -25,13 +25,12 @@ ZTEST(lso_tests, testLSO) static void testLSO(void) #endif { - uint8_t apdu[1000]; - int len; + uint8_t apdu[1000] = { 0 }; + uint8_t invoke_id = 100; + int apdu_len = 0, null_len = 0, test_len = 0; - BACNET_LSO_DATA data; - BACNET_LSO_DATA rxdata; - - memset(&rxdata, 0, sizeof(rxdata)); + BACNET_LSO_DATA data = { 0 }; + BACNET_LSO_DATA test_data = { 0 }; characterstring_init_ansi(&data.requestingSrc, "foobar"); data.operation = LIFE_SAFETY_OP_RESET; @@ -39,19 +38,22 @@ static void testLSO(void) data.use_target = true; data.targetObject.instance = 0x1000; data.targetObject.type = OBJECT_BINARY_INPUT; - - len = lso_encode_apdu(apdu, 100, &data); - - lso_decode_service_request(&apdu[4], len, &rxdata); - - zassert_equal(data.operation, rxdata.operation, NULL); - zassert_equal(data.processId, rxdata.processId, NULL); - zassert_equal(data.use_target, rxdata.use_target, NULL); - zassert_equal(data.targetObject.instance, rxdata.targetObject.instance, NULL); - zassert_equal(data.targetObject.type, rxdata.targetObject.type, NULL); + /* encode/decode */ + null_len = lso_encode_apdu(NULL, invoke_id, &data); + apdu_len = lso_encode_apdu(apdu, invoke_id, &data); zassert_equal( - memcmp(data.requestingSrc.value, rxdata.requestingSrc.value, - rxdata.requestingSrc.length), 0, NULL); + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); + test_len = lso_decode_service_request(&apdu[4], apdu_len, &test_data); + zassert_true(test_len > 0, "test_len=%d", test_len); + /* check the values decoded */ + zassert_equal(data.operation, test_data.operation, NULL); + zassert_equal(data.processId, test_data.processId, NULL); + zassert_equal(data.use_target, test_data.use_target, NULL); + zassert_equal(data.targetObject.instance, test_data.targetObject.instance, NULL); + zassert_equal(data.targetObject.type, test_data.targetObject.type, NULL); + zassert_equal( + memcmp(data.requestingSrc.value, test_data.requestingSrc.value, + test_data.requestingSrc.length), 0, NULL); } /** * @} diff --git a/test/bacnet/rd/src/main.c b/test/bacnet/rd/src/main.c index 29a68d8d..25054bbd 100644 --- a/test/bacnet/rd/src/main.c +++ b/test/bacnet/rd/src/main.c @@ -30,21 +30,21 @@ static int rd_decode_apdu(uint8_t *apdu, int apdu_len = 0; if (!apdu) { - return -1; + return BACNET_STATUS_ERROR; } if (apdu_size <= 4) { - return -1; + return BACNET_STATUS_ERROR; } /* optional checking - most likely was already done prior to this call */ if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) { - return -1; + return BACNET_STATUS_ERROR; } /* apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); */ if (invoke_id) { *invoke_id = apdu[2]; /* invoke id - filled in by net layer */ } if (apdu[3] != SERVICE_CONFIRMED_REINITIALIZE_DEVICE) { - return -1; + return BACNET_STATUS_ERROR; } apdu_len = 4; if (apdu_len < apdu_size) { diff --git a/test/bacnet/rp/src/main.c b/test/bacnet/rp/src/main.c index 2b9dc944..cb51db1a 100644 --- a/test/bacnet/rp/src/main.c +++ b/test/bacnet/rp/src/main.c @@ -21,55 +21,77 @@ * @brief Test */ static int rp_decode_apdu(uint8_t *apdu, - unsigned apdu_len, + unsigned apdu_size, uint8_t *invoke_id, BACNET_READ_PROPERTY_DATA *rpdata) { int len = 0; - unsigned offset = 0; + unsigned apdu_len = 0; - if (!apdu) - return -1; + if (!apdu) { + return BACNET_STATUS_ERROR; + } + if (apdu_size <= 4) { + return BACNET_STATUS_ERROR; + } /* optional checking - most likely was already done prior to this call */ - if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) - return -1; + if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) { + return BACNET_STATUS_ERROR; + } /* apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); */ *invoke_id = apdu[2]; /* invoke id - filled in by net layer */ - if (apdu[3] != SERVICE_CONFIRMED_READ_PROPERTY) - return -1; - offset = 4; + if (apdu[3] != SERVICE_CONFIRMED_READ_PROPERTY) { + return BACNET_STATUS_ERROR; + } + apdu_len = 4; - if (apdu_len > offset) { - len = - rp_decode_service_request(&apdu[offset], apdu_len - offset, rpdata); + if (apdu_size > apdu_len) { + len = rp_decode_service_request( + &apdu[apdu_len], apdu_size - apdu_len, rpdata); + if (len > 0) { + apdu_len += len; + } else { + apdu_len = len; + } } - return len; + return apdu_len; } static int rp_ack_decode_apdu(uint8_t *apdu, - int apdu_len, /* total length of the apdu */ + int apdu_size, uint8_t *invoke_id, BACNET_READ_PROPERTY_DATA *rpdata) { int len = 0; - int offset = 0; + int apdu_len = 0; - if (!apdu) - return -1; + if (!apdu) { + return BACNET_STATUS_ERROR; + } + if (apdu_size <= 3) { + return BACNET_STATUS_ERROR; + } /* optional checking - most likely was already done prior to this call */ - if (apdu[0] != PDU_TYPE_COMPLEX_ACK) - return -1; + if (apdu[0] != PDU_TYPE_COMPLEX_ACK) { + return BACNET_STATUS_ERROR; + } *invoke_id = apdu[1]; - if (apdu[2] != SERVICE_CONFIRMED_READ_PROPERTY) - return -1; - offset = 3; - if (apdu_len > offset) { + if (apdu[2] != SERVICE_CONFIRMED_READ_PROPERTY) { + return BACNET_STATUS_ERROR; + } + apdu_len = 3; + if (apdu_size > apdu_len) { len = rp_ack_decode_service_request( - &apdu[offset], apdu_len - offset, rpdata); + &apdu[apdu_len], apdu_size - apdu_len, rpdata); + if (len > 0) { + apdu_len += len; + } else { + apdu_len = len; + } } - return len; + return apdu_len; } #if defined(CONFIG_ZTEST_NEW_API) @@ -80,12 +102,11 @@ static void testReadPropertyAck(void) { uint8_t apdu[480] = { 0 }; uint8_t apdu2[480] = { 0 }; - int len = 0; - int apdu_len = 0; + int apdu_len = 0, test_len = 0, null_len = 0; uint8_t invoke_id = 1; uint8_t test_invoke_id = 0; - BACNET_READ_PROPERTY_DATA rpdata; - BACNET_READ_PROPERTY_DATA test_data; + BACNET_READ_PROPERTY_DATA rpdata = { 0 }; + BACNET_READ_PROPERTY_DATA test_data = { 0 }; BACNET_OBJECT_TYPE object_type = OBJECT_DEVICE; uint32_t object_instance = 0; BACNET_OBJECT_TYPE object = 0; @@ -99,13 +120,16 @@ static void testReadPropertyAck(void) &apdu2[0], rpdata.object_type, rpdata.object_instance); rpdata.application_data = &apdu2[0]; - len = rp_ack_encode_apdu(&apdu[0], invoke_id, &rpdata); - zassert_not_equal(len, 0, NULL); - zassert_not_equal(len, -1, NULL); - apdu_len = len; - len = rp_ack_decode_apdu(&apdu[0], apdu_len, /* total length of the apdu */ - &test_invoke_id, &test_data); - zassert_not_equal(len, -1, NULL); + null_len = rp_ack_encode_apdu(NULL, invoke_id, &rpdata); + apdu_len = rp_ack_encode_apdu(&apdu[0], invoke_id, &rpdata); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); + zassert_not_equal(apdu_len, 0, NULL); + zassert_not_equal(apdu_len, BACNET_STATUS_ERROR, NULL); + test_len = + rp_ack_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data); + zassert_equal(apdu_len, test_len, NULL); + zassert_not_equal(test_len, -1, NULL); zassert_equal(test_invoke_id, invoke_id, NULL); zassert_equal(test_data.object_type, rpdata.object_type, NULL); @@ -117,11 +141,22 @@ static void testReadPropertyAck(void) /* since object property == object_id, decode the application data using the appropriate decode function */ - len = + test_len = decode_object_id(test_data.application_data, &object, &object_instance); object_type = object; zassert_equal(object_type, rpdata.object_type, NULL); zassert_equal(object_instance, rpdata.object_instance, NULL); + while (apdu_len) { + apdu_len--; + if ((apdu_len <= 15) && (apdu_len >= 11)) { + /* boundary of optional parameters, so becomes valid */ + continue; + } + test_len = + rp_ack_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data); + zassert_true( + test_len < 0, "test_len=%d apdu_len=%d", test_len, apdu_len); + } } #if defined(CONFIG_ZTEST_NEW_API) @@ -131,8 +166,7 @@ static void testReadProperty(void) #endif { uint8_t apdu[480] = { 0 }; - int len = 0; - int apdu_len = 0; + int apdu_len = 0, test_len = 0, null_len = 0; uint8_t invoke_id = 128; uint8_t test_invoke_id = 0; BACNET_READ_PROPERTY_DATA rpdata; @@ -142,16 +176,27 @@ static void testReadProperty(void) rpdata.object_instance = 1; rpdata.object_property = PROP_OBJECT_IDENTIFIER; rpdata.array_index = BACNET_ARRAY_ALL; - len = rp_encode_apdu(&apdu[0], invoke_id, &rpdata); - zassert_not_equal(len, 0, NULL); - apdu_len = len; + null_len = rp_encode_apdu(NULL, invoke_id, &rpdata); + apdu_len = rp_encode_apdu(&apdu[0], invoke_id, &rpdata); + zassert_equal( + apdu_len, null_len, "apdu_len=%d null_len=%d", apdu_len, null_len); + zassert_not_equal(apdu_len, 0, NULL); - len = rp_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data); - zassert_not_equal(len, -1, NULL); + test_len = rp_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data); + zassert_equal( + apdu_len, test_len, "apdu_len=%d test_len=%d", apdu_len, test_len); + zassert_not_equal(test_len, -1, NULL); zassert_equal(test_data.object_type, rpdata.object_type, NULL); zassert_equal(test_data.object_instance, rpdata.object_instance, NULL); zassert_equal(test_data.object_property, rpdata.object_property, NULL); zassert_equal(test_data.array_index, rpdata.array_index, NULL); + while (apdu_len) { + apdu_len--; + test_len = + rp_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data); + zassert_true( + test_len < 0, "test_len=%d apdu_len=%d", test_len, apdu_len); + } return; } @@ -159,16 +204,13 @@ static void testReadProperty(void) * @} */ - #if defined(CONFIG_ZTEST_NEW_API) ZTEST_SUITE(rp_tests, NULL, NULL, NULL, NULL, NULL); #else void test_main(void) { - ztest_test_suite(rp_tests, - ztest_unit_test(testReadProperty), - ztest_unit_test(testReadPropertyAck) - ); + ztest_test_suite(rp_tests, ztest_unit_test(testReadProperty), + ztest_unit_test(testReadPropertyAck)); ztest_run_test_suite(rp_tests); }