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 <skarg@users.sourceforge.net>
This commit is contained in:
Steve Karg
2024-01-05 08:59:45 -06:00
committed by GitHub
parent 5ca14e5320
commit bb081d28da
39 changed files with 2614 additions and 1514 deletions
+22
View File
@@ -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.
+5
View File
@@ -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
+43 -10
View File
@@ -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)
{
+22
View File
@@ -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.
+6
View File
@@ -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,
+22 -17
View File
@@ -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;
}
}
+10
View File
@@ -46,6 +46,16 @@
# include <strings.h>
# 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__)
+301 -168
View File
@@ -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;
+125 -125
View File
@@ -1,26 +1,26 @@
/**************************************************************************
*
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
*
* 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 <skarg@users.sourceforge.net>
*
* 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
}
+22 -2
View File
@@ -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
+3
View File
@@ -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);
+84 -24
View File
@@ -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;
}
+13 -4
View File
@@ -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,
+27
View File
@@ -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
*
+5
View File
@@ -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);
+598 -420
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -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
+54 -9
View File
@@ -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;
}
+5
View File
@@ -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,
+23 -3
View File
@@ -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
+3
View File
@@ -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
+82 -21
View File
@@ -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;
+20 -12
View File
@@ -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,
+58 -15
View File
@@ -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;
}
+11 -1
View File
@@ -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(
+171 -80
View File
@@ -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 */
+10
View File
@@ -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,
+205 -49
View File
@@ -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;
+22 -1
View File
@@ -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,
+105 -45
View File
@@ -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;
+9
View File
@@ -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,
+6 -4
View File
@@ -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);
+41 -29
View File
@@ -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);
}
File diff suppressed because it is too large Load Diff
+36 -24
View File
@@ -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,
+8
View File
@@ -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);
+20 -18
View File
@@ -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);
}
/**
* @}
+4 -4
View File
@@ -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) {
+91 -49
View File
@@ -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);
}