Bugfix/bacnet array encoding overflows (#414)

* Add common BACnetARRAY encode function to fix Device object list buffer overflow. Refactor device, analog-output, access-door and binary-output objects to use common BACnetARRAY encoder.

* Fix non-POSIX builds (win32).

* Cleanup some ports/stm32 build warnings
---------

Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
Steve Karg
2023-04-13 20:43:54 -05:00
committed by GitHub
parent 064c6f7f1c
commit e517df0d47
23 changed files with 872 additions and 834 deletions
+39 -46
View File
@@ -694,6 +694,39 @@ bool Device_Object_List_Identifier(
return status;
}
/**
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
int Device_Object_List_Element_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
BACNET_OBJECT_TYPE object_type;
uint32_t instance;
bool found;
if (object_instance == Device_Object_Instance_Number()) {
/* single element is zero based, add 1 for BACnetARRAY which is one
* based */
array_index++;
found =
Device_Object_List_Identifier(array_index, &object_type, &instance);
if (found) {
apdu_len =
encode_application_object_id(apdu, object_type, instance);
}
}
return apdu_len;
}
/** Determine if we have an object with the given object_name.
* If the object_type and object_instance pointers are not null,
* and the lookup succeeds, they will be given the resulting values.
@@ -858,16 +891,12 @@ bool Device_Daylight_Savings_Status(void)
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
int len = 0; /* apdu len intermediate value */
BACNET_BIT_STRING bit_string = { 0 };
BACNET_CHARACTER_STRING char_string = { 0 };
uint32_t i = 0;
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t instance = 0;
uint32_t count = 0;
uint8_t *apdu = NULL;
struct object_functions *pObject = NULL;
bool found = false;
uint16_t apdu_max = 0;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
@@ -981,52 +1010,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
break;
case PROP_OBJECT_LIST:
count = Device_Object_List_Count();
/* Array element zero is the number of objects in the list */
if (rpdata->array_index == 0) {
apdu_len = encode_application_unsigned(&apdu[0], count);
/* if no index was specified, then try to encode the entire list
*/
/* into one packet. Note that more than likely you will have */
/* to return an error if the number of encoded objects exceeds
*/
/* your maximum APDU size. */
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) {
found = Device_Object_List_Identifier(
i, &object_type, &instance);
if (found) {
len = encode_application_object_id(
&apdu[apdu_len], object_type, instance);
apdu_len += len;
/* assume next one is the same size as this one */
/* can we all fit into the APDU? Don't check for last
* entry */
if ((i != count) && (apdu_len + len) >= apdu_max) {
/* Abort response */
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index,
Device_Object_List_Element_Encode,
count, apdu, apdu_max);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
} else {
/* error: internal error? */
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_OTHER;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
} else {
found = Device_Object_List_Identifier(
rpdata->array_index, &object_type, &instance);
if (found) {
apdu_len = encode_application_object_id(
&apdu[0], object_type, instance);
} else {
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_MAX_APDU_LENGTH_ACCEPTED:
+41 -40
View File
@@ -512,6 +512,39 @@ bool Device_Object_List_Identifier(
return status;
}
/**
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
int Device_Object_List_Element_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
BACNET_OBJECT_TYPE object_type;
uint32_t instance;
bool found;
if (object_instance == Device_Object_Instance_Number()) {
/* single element is zero based, add 1 for BACnetARRAY which is one
* based */
array_index++;
found =
Device_Object_List_Identifier(array_index, &object_type, &instance);
if (found) {
apdu_len =
encode_application_object_id(apdu, object_type, instance);
}
}
return apdu_len;
}
bool Device_Valid_Object_Name(BACNET_CHARACTER_STRING *object_name1,
BACNET_OBJECT_TYPE *object_type,
uint32_t *object_instance)
@@ -580,14 +613,12 @@ bool Device_Object_Name_Copy(BACNET_OBJECT_TYPE object_type,
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
int len = 0; /* apdu len intermediate value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
uint32_t i = 0;
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t instance = 0;
uint32_t count = 0;
uint8_t *apdu = NULL;
int apdu_max = 0;
struct my_object_functions *pObject = NULL;
if ((rpdata->application_data == NULL) ||
@@ -595,6 +626,7 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
return 0;
}
apdu = rpdata->application_data;
apdu_max = rpdata->application_data_len;
switch ((int)rpdata->object_property) {
case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, "BACnet Demo");
@@ -672,47 +704,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
break;
case PROP_OBJECT_LIST:
count = Device_Object_List_Count();
/* Array element zero is the number of objects in the list */
if (rpdata->array_index == 0)
apdu_len = encode_application_unsigned(&apdu[0], count);
/* if no index was specified, then try to encode the entire list */
/* into one packet. Note that more than likely you will have */
/* to return an error if the number of encoded objects exceeds */
/* your maximum APDU size. */
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) {
if (Device_Object_List_Identifier(
i, &object_type, &instance)) {
len = encode_application_object_id(
&apdu[apdu_len], object_type, instance);
apdu_len += len;
/* assume next one is the same size as this one */
/* can we all fit into the APDU? */
if ((apdu_len + len) >= MAX_APDU) {
/* Abort response */
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index,
Device_Object_List_Element_Encode,
count, apdu, apdu_max);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
} else {
/* error: internal error? */
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_OTHER;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
} else {
if (Device_Object_List_Identifier(
rpdata->array_index, &object_type, &instance))
apdu_len = encode_application_object_id(
&apdu[0], object_type, instance);
else {
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_MAX_APDU_LENGTH_ACCEPTED:
+41 -32
View File
@@ -154,20 +154,52 @@ bool Device_Object_List_Identifier(
return status;
}
/**
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
int Device_Object_List_Element_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
BACNET_OBJECT_TYPE object_type;
uint32_t instance;
bool found;
if (object_instance == Device_Object_Instance_Number()) {
/* single element is zero based, add 1 for BACnetARRAY which is one
* based */
array_index++;
found =
Device_Object_List_Identifier(array_index, &object_type, &instance);
if (found) {
apdu_len =
encode_application_object_id(apdu, object_type, instance);
}
}
return apdu_len;
}
/* return the length of the apdu encoded or -1 for error */
int Device_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
{
uint8_t *apdu;
int apdu_len = 0; /* return value */
int len = 0; /* apdu len intermediate value */
int apdu_max = 0;
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
uint32_t i = 0;
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t instance = 0;
uint32_t count = 0;
apdu = rpdata->application_data;
apdu_max = rpdata->application_data_len;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len = encode_application_object_id(
@@ -243,39 +275,16 @@ int Device_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
break;
case PROP_OBJECT_LIST:
count = Device_Object_List_Count();
/* Array element zero is the number of objects in the list */
if (rpdata->array_index == 0)
apdu_len = encode_application_unsigned(&apdu[0], count);
/* if no index was specified, then try to encode the entire list */
/* into one packet. Note that more than likely you will have */
/* to return an error if the number of encoded objects exceeds */
/* your maximum APDU size. */
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) {
Device_Object_List_Identifier(i, &object_type, &instance);
len = encode_application_object_id(
&apdu[apdu_len], object_type, instance);
apdu_len += len;
/* assume next one is the same size as this one */
/* can we all fit into the APDU? */
if ((apdu_len + len) >= MAX_APDU) {
/* Abort response */
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index,
Device_Object_List_Element_Encode,
count, apdu, apdu_max);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (Device_Object_List_Identifier(
rpdata->array_index, &object_type, &instance))
apdu_len = encode_application_object_id(
&apdu[0], object_type, instance);
else {
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_MAX_APDU_LENGTH_ACCEPTED:
+41 -40
View File
@@ -487,6 +487,39 @@ bool Device_Object_List_Identifier(
return status;
}
/**
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
int Device_Object_List_Element_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
BACNET_OBJECT_TYPE object_type;
uint32_t instance;
bool found;
if (object_instance == Device_Object_Instance_Number()) {
/* single element is zero based, add 1 for BACnetARRAY which is one
* based */
array_index++;
found =
Device_Object_List_Identifier(array_index, &object_type, &instance);
if (found) {
apdu_len =
encode_application_object_id(apdu, object_type, instance);
}
}
return apdu_len;
}
bool Device_Valid_Object_Name(BACNET_CHARACTER_STRING *object_name1,
BACNET_OBJECT_TYPE *object_type,
uint32_t *object_instance)
@@ -555,14 +588,12 @@ bool Device_Object_Name_Copy(BACNET_OBJECT_TYPE object_type,
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
int len = 0; /* apdu len intermediate value */
BACNET_BIT_STRING bit_string = { 0 };
BACNET_CHARACTER_STRING char_string = { 0 };
uint32_t i = 0;
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t instance = 0;
uint32_t count = 0;
uint8_t *apdu = NULL;
int apdu_max = 0;
struct my_object_functions *pObject = NULL;
if ((rpdata->application_data == NULL) ||
@@ -570,6 +601,7 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
return 0;
}
apdu = rpdata->application_data;
apdu_max = rpdata->application_data_len;
switch ((int)rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len = encode_application_object_id(
@@ -662,47 +694,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
break;
case PROP_OBJECT_LIST:
count = Device_Object_List_Count();
/* Array element zero is the number of objects in the list */
if (rpdata->array_index == 0)
apdu_len = encode_application_unsigned(&apdu[0], count);
/* if no index was specified, then try to encode the entire list */
/* into one packet. Note that more than likely you will have */
/* to return an error if the number of encoded objects exceeds */
/* your maximum APDU size. */
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) {
if (Device_Object_List_Identifier(
i, &object_type, &instance)) {
len = encode_application_object_id(
&apdu[apdu_len], object_type, instance);
apdu_len += len;
/* assume next one is the same size as this one */
/* can we all fit into the APDU? */
if ((apdu_len + len) >= MAX_APDU) {
/* Abort response */
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index,
Device_Object_List_Element_Encode,
count, apdu, apdu_max);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
} else {
/* error: internal error? */
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_OTHER;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
} else {
if (Device_Object_List_Identifier(
rpdata->array_index, &object_type, &instance))
apdu_len = encode_application_object_id(
&apdu[0], object_type, instance);
else {
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_MAX_APDU_LENGTH_ACCEPTED:
+40 -39
View File
@@ -269,23 +269,54 @@ bool Device_Object_List_Identifier(
return status;
}
/**
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
int Device_Object_List_Element_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
BACNET_OBJECT_TYPE object_type;
uint32_t instance;
bool found;
if (object_instance == Device_Object_Instance_Number()) {
/* single element is zero based, add 1 for BACnetARRAY which is one
* based */
array_index++;
found =
Device_Object_List_Identifier(array_index, &object_type, &instance);
if (found) {
apdu_len =
encode_application_object_id(apdu, object_type, instance);
}
}
return apdu_len;
}
/* returns true if successful */
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
{
static char string_buffer[28];
static BACNET_CHARACTER_STRING char_string;
int apdu_len = 0; /* return value */
int len = 0; /* apdu len intermediate value */
BACNET_BIT_STRING bit_string;
uint32_t i = 0;
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t instance = 0;
uint32_t count = 0;
BACNET_TIME local_time;
BACNET_DATE local_date;
uint8_t year = 0;
int16_t TimeZone = 0;
uint8_t *apdu = NULL;
int apdu_max = 0;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
@@ -387,46 +418,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
break;
case PROP_OBJECT_LIST:
count = Device_Object_List_Count();
/* Array element zero is the number of objects in the list */
if (rpdata->array_index == 0)
apdu_len = encode_application_unsigned(&apdu[0], count);
/* if no index was specified, then try to encode the entire list */
/* into one packet. Note that more than likely you will have */
/* to return an error if the number of encoded objects exceeds */
/* your maximum APDU size. */
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) {
if (Device_Object_List_Identifier(
i, &object_type, &instance)) {
len = encode_application_object_id(
&apdu[apdu_len], object_type, instance);
apdu_len += len;
/* assume next one is the same size as this one */
/* can we all fit into the APDU? */
if ((apdu_len + len) >= MAX_APDU) {
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index,
Device_Object_List_Element_Encode,
count, apdu, apdu_max);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
} else {
/* error: internal error? */
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_OTHER;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
} else {
if (Device_Object_List_Identifier(
rpdata->array_index, &object_type, &instance))
apdu_len = encode_application_object_id(
&apdu[0], object_type, instance);
else {
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_MAX_APDU_LENGTH_ACCEPTED:
+41 -39
View File
@@ -247,16 +247,46 @@ bool Device_Object_List_Identifier(
return status;
}
/**
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
int Device_Object_List_Element_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
BACNET_OBJECT_TYPE object_type;
uint32_t instance;
bool found;
if (object_instance == Device_Object_Instance_Number()) {
/* single element is zero based, add 1 for BACnetARRAY which is one
* based */
array_index++;
found =
Device_Object_List_Identifier(array_index, &object_type, &instance);
if (found) {
apdu_len =
encode_application_object_id(apdu, object_type, instance);
}
}
return apdu_len;
}
/* returns true if successful */
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
int len = 0; /* apdu len intermediate value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
uint32_t i = 0;
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t instance = 0;
uint32_t count = 0;
BACNET_TIME local_time;
BACNET_DATE local_date;
@@ -264,12 +294,14 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
char string_buffer[28];
int16_t TimeZone = 0;
uint8_t *apdu = NULL;
int apdu_max = 0;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
apdu_max = rpdata->application_data_len;
/* FIXME: change the hardcoded names to suit your application */
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
@@ -365,46 +397,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
break;
case PROP_OBJECT_LIST:
count = Device_Object_List_Count();
/* Array element zero is the number of objects in the list */
if (rpdata->array_index == 0)
apdu_len = encode_application_unsigned(&apdu[0], count);
/* if no index was specified, then try to encode the entire list */
/* into one packet. Note that more than likely you will have */
/* to return an error if the number of encoded objects exceeds */
/* your maximum APDU size. */
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) {
if (Device_Object_List_Identifier(
i, &object_type, &instance)) {
len = encode_application_object_id(
&apdu[apdu_len], object_type, instance);
apdu_len += len;
/* assume next one is the same size as this one */
/* can we all fit into the APDU? */
if ((apdu_len + len) >= MAX_APDU) {
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index,
Device_Object_List_Element_Encode,
count, apdu, apdu_max);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
} else {
/* error: internal error? */
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_OTHER;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
} else {
if (Device_Object_List_Identifier(
rpdata->array_index, &object_type, &instance))
apdu_len = encode_application_object_id(
&apdu[0], object_type, instance);
else {
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_MAX_APDU_LENGTH_ACCEPTED:
+41 -42
View File
@@ -509,6 +509,39 @@ bool Device_Object_List_Identifier(
return status;
}
/**
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
int Device_Object_List_Element_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
BACNET_OBJECT_TYPE object_type;
uint32_t instance;
bool found;
if (object_instance == Device_Object_Instance_Number()) {
/* single element is zero based, add 1 for BACnetARRAY which is one
* based */
array_index++;
found =
Device_Object_List_Identifier(array_index, &object_type, &instance);
if (found) {
apdu_len =
encode_application_object_id(apdu, object_type, instance);
}
}
return apdu_len;
}
/** Determine if we have an object with the given object_name.
* If the object_type and object_instance pointers are not null,
* and the lookup succeeds, they will be given the resulting values.
@@ -569,22 +602,20 @@ char *Device_Valid_Object_Id(
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
int len = 0; /* apdu len intermediate value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
uint32_t i = 0;
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t instance = 0;
uint32_t count = 0;
uint8_t *apdu = NULL;
int apdu_max = 0;
struct my_object_functions *pObject = NULL;
bool found = false;
if ((rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
apdu_max = rpdata->application_data_len;
switch (rpdata->object_property) {
case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, Description);
@@ -664,48 +695,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
break;
case PROP_OBJECT_LIST:
count = Device_Object_List_Count();
/* Array element zero is the number of objects in the list */
if (rpdata->array_index == 0)
apdu_len = encode_application_unsigned(&apdu[0], count);
/* if no index was specified, then try to encode the entire list */
/* into one packet. Note that more than likely you will have */
/* to return an error if the number of encoded objects exceeds */
/* your maximum APDU size. */
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) {
if (Device_Object_List_Identifier(
i, &object_type, &instance)) {
len = encode_application_object_id(
&apdu[apdu_len], object_type, instance);
apdu_len += len;
/* assume next one is the same size as this one */
/* can we all fit into the APDU? */
if ((apdu_len + len) >= MAX_APDU) {
/* Abort response */
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index,
Device_Object_List_Element_Encode,
count, apdu, apdu_max);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
} else {
/* error: internal error? */
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_OTHER;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
} else {
found = Device_Object_List_Identifier(
rpdata->array_index, &object_type, &instance);
if (found) {
apdu_len = encode_application_object_id(
&apdu[0], object_type, instance);
} else {
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_MAX_APDU_LENGTH_ACCEPTED:
+9 -7
View File
@@ -158,13 +158,14 @@ CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing
CFLAGS += -fno-builtin
# place uninitialized global variables in the data section of the object file.
CFLAGS += -fno-common
WARNING_ALL := -Wall
# enable all relevant warnings that find bugs
WARNING_ALL := -Wall -Wextra -Wall -Wfloat-equal -Wconversion -Wparentheses
WARNING_ALL += -pedantic -Wunused-parameter -Wunused-variable -Wreturn-type
WARNING_ALL += -Wunused-function -Wreturn-type -Wunused-value
WARNING_ALL += -Wswitch-default -Wuninitialized -Winit-self
WARNING_ALL += -Wno-sign-conversion -Wno-conversion -Wno-sign-compare
WARNING_ALL += -Wno-long-long
#WARNING_ALL += -pedantic -Wextra -Wfloat-equal -Wconversion -Wparentheses
#WARNING_ALL += -Wunused-parameter -Wunused-variable -Wreturn-type
#WARNING_ALL += -Wunused-function -Wreturn-type -Wunused-value
#WARNING_ALL += -Wswitch-default -Wuninitialized -Winit-self
#WARNING_ALL += -Wno-sign-conversion -Wno-conversion -Wno-sign-compare
#WARNING_ALL += -Wno-long-long
#WARNING_ALL += -Wredundant-decls
#WARNING_ALL += -Werror
CFLAGS += $(WARNING_ALL)
@@ -174,7 +175,8 @@ CFLAGS += -Wno-missing-braces
CFLAGS += -Wno-missing-prototypes
# don't warn about array subscript being char
CFLAGS += -Wno-char-subscripts
# FIXME later
CFLAGS += -Wno-unused-parameter
# -Wa,<options> Pass comma-separated <options> on to the assembler
AFLAGS = -Wa,-ahls,-mapcs-32,-adhlns=$(<:.s=.lst)
+48 -52
View File
@@ -59,8 +59,7 @@ static struct my_object_functions {
read_property_function Object_Read_Property;
write_property_function Object_Write_Property;
rpm_property_lists_function Object_RPM_List;
} Object_Table[] = {
{ OBJECT_DEVICE, NULL, /* don't init - recursive! */
} Object_Table[] = { { OBJECT_DEVICE, NULL, /* don't init - recursive! */
Device_Count, Device_Index_To_Instance,
Device_Valid_Object_Instance_Number,
Device_Object_Name, Device_Read_Property_Local,
@@ -75,7 +74,8 @@ static struct my_object_functions {
Network_Port_Object_Name, Network_Port_Read_Property,
Network_Port_Write_Property, Network_Port_Property_Lists },
#endif
{ MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL } };
{ MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL } };
/* note: you really only need to define variables for
properties that are writable or that may change.
@@ -185,13 +185,9 @@ static int Read_Property_Common(
#if (BACNET_PROTOCOL_REVISION >= 14)
case PROP_PROPERTY_LIST:
Device_Objects_Property_List(
rpdata->object_type,
rpdata->object_instance,
&property_list);
apdu_len = property_list_encode(
rpdata,
property_list.Required.pList,
property_list.Optional.pList,
rpdata->object_type, rpdata->object_instance, &property_list);
apdu_len = property_list_encode(rpdata,
property_list.Required.pList, property_list.Optional.pList,
property_list.Proprietary.pList);
break;
#endif
@@ -346,8 +342,7 @@ bool Device_Set_Object_Name(BACNET_CHARACTER_STRING *object_name)
return status;
}
bool Device_Reinitialize(
BACNET_REINITIALIZE_DEVICE_DATA * rd_data)
bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
{
bool status = false;
@@ -453,6 +448,7 @@ int Device_Set_System_Status(BACNET_DEVICE_STATUS status, bool local)
/*return value - 0 = ok, -1 = bad value, -2 = not allowed */
int result = -1;
(void)local;
if (status < MAX_DEVICE_STATUS) {
System_Status = status;
result = 0;
@@ -532,6 +528,39 @@ bool Device_Object_List_Identifier(
return status;
}
/**
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
int Device_Object_List_Element_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
BACNET_OBJECT_TYPE object_type;
uint32_t instance;
bool found;
if (object_instance == Device_Object_Instance_Number()) {
/* single element is zero based, add 1 for BACnetARRAY which is one
* based */
array_index++;
found =
Device_Object_List_Identifier(array_index, &object_type, &instance);
if (found) {
apdu_len =
encode_application_object_id(apdu, object_type, instance);
}
}
return apdu_len;
}
bool Device_Valid_Object_Name(BACNET_CHARACTER_STRING *object_name1,
BACNET_OBJECT_TYPE *object_type,
uint32_t *object_instance)
@@ -600,14 +629,12 @@ bool Device_Object_Name_Copy(BACNET_OBJECT_TYPE object_type,
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
int len = 0; /* apdu len intermediate value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
uint32_t i = 0;
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t instance = 0;
uint32_t count = 0;
uint8_t *apdu = NULL;
int apdu_max = 0;
struct my_object_functions *pObject = NULL;
if ((rpdata->application_data == NULL) ||
@@ -615,6 +642,7 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
return 0;
}
apdu = rpdata->application_data;
apdu_max = rpdata->application_data_len;
switch ((int)rpdata->object_property) {
case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, "BACnet Development Kit");
@@ -692,47 +720,15 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
break;
case PROP_OBJECT_LIST:
count = Device_Object_List_Count();
/* Array element zero is the number of objects in the list */
if (rpdata->array_index == 0)
apdu_len = encode_application_unsigned(&apdu[0], count);
/* if no index was specified, then try to encode the entire list */
/* into one packet. Note that more than likely you will have */
/* to return an error if the number of encoded objects exceeds */
/* your maximum APDU size. */
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) {
if (Device_Object_List_Identifier(
i, &object_type, &instance)) {
len = encode_application_object_id(
&apdu[apdu_len], object_type, instance);
apdu_len += len;
/* assume next one is the same size as this one */
/* can we all fit into the APDU? */
if ((apdu_len + len) >= MAX_APDU) {
/* Abort response */
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index, Device_Object_List_Element_Encode, count,
apdu, apdu_max);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
} else {
/* error: internal error? */
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_OTHER;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
} else {
if (Device_Object_List_Identifier(
rpdata->array_index, &object_type, &instance))
apdu_len = encode_application_object_id(
&apdu[0], object_type, instance);
else {
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_MAX_APDU_LENGTH_ACCEPTED:
+51 -9
View File
@@ -254,54 +254,96 @@ static bool dlmstp_compare_data_expecting_reply(uint8_t *request_pdu,
};
struct DER_compare_t request;
struct DER_compare_t reply;
bool request_segmented = false;
bool reply_segmented = false;
/* decode the request data */
request.address.mac[0] = src_address;
request.address.mac_len = 1;
offset = npdu_decode(
&request_pdu[0], NULL, &request.address, &request.npdu_data);
offset = bacnet_npdu_decode(request_pdu, request_pdu_len, NULL,
&request.address, &request.npdu_data);
if (request.npdu_data.network_layer_message) {
return false;
}
if (offset >= request_pdu_len) {
return false;
}
request.pdu_type = request_pdu[offset] & 0xF0;
if (request.pdu_type != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) {
return false;
}
if (request_pdu[offset] & BIT(3)) {
request_segmented = true;
}
if ((offset + 2) >= request_pdu_len) {
return false;
}
request.invoke_id = request_pdu[offset + 2];
/* segmented message? */
if (request_pdu[offset] & BIT(3))
if (request_segmented) {
if ((offset + 5) >= request_pdu_len) {
return false;
}
request.service_choice = request_pdu[offset + 5];
else
} else {
if ((offset + 3) >= request_pdu_len) {
return false;
}
request.service_choice = request_pdu[offset + 3];
}
/* decode the reply data */
reply.address.mac[0] = dest_address;
reply.address.mac_len = 1;
offset = npdu_decode(&reply_pdu[0], &reply.address, NULL, &reply.npdu_data);
offset = bacnet_npdu_decode(
reply_pdu, reply_pdu_len, &reply.address, NULL, &reply.npdu_data);
if (reply.npdu_data.network_layer_message) {
return false;
}
if (offset >= request_pdu_len) {
return false;
}
reply.pdu_type = reply_pdu[offset] & 0xF0;
if (reply_pdu[offset] & BIT(3)) {
reply_segmented = true;
}
/* reply could be a lot of things:
confirmed, simple ack, abort, reject, error */
reply.pdu_type = reply_pdu[offset] & 0xF0;
switch (reply.pdu_type) {
case PDU_TYPE_SIMPLE_ACK:
if ((offset + 2) >= request_pdu_len) {
return false;
}
reply.invoke_id = reply_pdu[offset + 1];
reply.service_choice = reply_pdu[offset + 2];
break;
case PDU_TYPE_COMPLEX_ACK:
reply.invoke_id = reply_pdu[offset + 1];
/* segmented message? */
if (reply_pdu[offset] & BIT(3))
if (reply_segmented) {
if ((offset + 4) >= request_pdu_len) {
return false;
}
reply.invoke_id = reply_pdu[offset + 1];
reply.service_choice = reply_pdu[offset + 4];
else
} else {
if ((offset + 2) >= request_pdu_len) {
return false;
}
reply.invoke_id = reply_pdu[offset + 1];
reply.service_choice = reply_pdu[offset + 2];
}
break;
case PDU_TYPE_ERROR:
if ((offset + 2) >= request_pdu_len) {
return false;
}
reply.invoke_id = reply_pdu[offset + 1];
reply.service_choice = reply_pdu[offset + 2];
break;
case PDU_TYPE_REJECT:
case PDU_TYPE_ABORT:
if ((offset + 1) >= request_pdu_len) {
return false;
}
reply.invoke_id = reply_pdu[offset + 1];
break;
default:
+2
View File
@@ -370,6 +370,8 @@ bool Network_Port_Link_Speed_Set(uint32_t object_instance, float value)
Object_List[0].Changes_Pending = true;
status = true;
break;
default:
break;
}
return status;
+44 -43
View File
@@ -56,8 +56,7 @@ static struct my_object_functions {
read_property_function Object_Read_Property;
write_property_function Object_Write_Property;
rpm_property_lists_function Object_RPM_List;
} Object_Table[] = {
{ OBJECT_DEVICE, NULL, /* don't init - recursive! */
} Object_Table[] = { { OBJECT_DEVICE, NULL, /* don't init - recursive! */
Device_Count, Device_Index_To_Instance,
Device_Valid_Object_Instance_Number,
Device_Object_Name, Device_Read_Property_Local,
@@ -68,7 +67,8 @@ static struct my_object_functions {
Network_Port_Object_Name, Network_Port_Read_Property,
Network_Port_Write_Property, Network_Port_Property_Lists },
#endif
{ MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL } };
{ MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL } };
/* note: you really only need to define variables for
properties that are writable or that may change.
@@ -442,6 +442,7 @@ int Device_Set_System_Status(BACNET_DEVICE_STATUS status, bool local)
/*return value - 0 = ok, -1 = bad value, -2 = not allowed */
int result = -1;
(void)local;
if (status < MAX_DEVICE_STATUS) {
System_Status = status;
result = 0;
@@ -521,6 +522,39 @@ bool Device_Object_List_Identifier(
return status;
}
/**
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
int Device_Object_List_Element_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
BACNET_OBJECT_TYPE object_type;
uint32_t instance;
bool found;
if (object_instance == Device_Object_Instance_Number()) {
/* single element is zero based, add 1 for BACnetARRAY which is one
* based */
array_index++;
found =
Device_Object_List_Identifier(array_index, &object_type, &instance);
if (found) {
apdu_len =
encode_application_object_id(apdu, object_type, instance);
}
}
return apdu_len;
}
bool Device_Valid_Object_Name(BACNET_CHARACTER_STRING *object_name1,
BACNET_OBJECT_TYPE *object_type,
uint32_t *object_instance)
@@ -589,14 +623,12 @@ bool Device_Object_Name_Copy(BACNET_OBJECT_TYPE object_type,
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
int len = 0; /* apdu len intermediate value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
uint32_t i = 0;
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t instance = 0;
uint32_t count = 0;
uint8_t *apdu = NULL;
int apdu_max = 0;
struct my_object_functions *pObject = NULL;
if ((rpdata->application_data == NULL) ||
@@ -604,6 +636,7 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
return 0;
}
apdu = rpdata->application_data;
apdu_max = rpdata->application_data_len;
switch ((int)rpdata->object_property) {
case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, "BACnet Development Kit");
@@ -681,47 +714,15 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
break;
case PROP_OBJECT_LIST:
count = Device_Object_List_Count();
/* Array element zero is the number of objects in the list */
if (rpdata->array_index == 0)
apdu_len = encode_application_unsigned(&apdu[0], count);
/* if no index was specified, then try to encode the entire list */
/* into one packet. Note that more than likely you will have */
/* to return an error if the number of encoded objects exceeds */
/* your maximum APDU size. */
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) {
if (Device_Object_List_Identifier(
i, &object_type, &instance)) {
len = encode_application_object_id(
&apdu[apdu_len], object_type, instance);
apdu_len += len;
/* assume next one is the same size as this one */
/* can we all fit into the APDU? */
if ((apdu_len + len) >= MAX_APDU) {
/* Abort response */
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index, Device_Object_List_Element_Encode, count,
apdu, apdu_max);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
} else {
/* error: internal error? */
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_OTHER;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
} else {
if (Device_Object_List_Identifier(
rpdata->array_index, &object_type, &instance))
apdu_len = encode_application_object_id(
&apdu[0], object_type, instance);
else {
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_MAX_APDU_LENGTH_ACCEPTED:
+41 -40
View File
@@ -509,6 +509,39 @@ bool Device_Object_List_Identifier(
return status;
}
/**
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
int Device_Object_List_Element_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
BACNET_OBJECT_TYPE object_type;
uint32_t instance;
bool found;
if (object_instance == Device_Object_Instance_Number()) {
/* single element is zero based, add 1 for BACnetARRAY which is one
* based */
array_index++;
found =
Device_Object_List_Identifier(array_index, &object_type, &instance);
if (found) {
apdu_len =
encode_application_object_id(apdu, object_type, instance);
}
}
return apdu_len;
}
bool Device_Valid_Object_Name(BACNET_CHARACTER_STRING *object_name1,
BACNET_OBJECT_TYPE *object_type,
uint32_t *object_instance)
@@ -577,14 +610,12 @@ bool Device_Object_Name_Copy(BACNET_OBJECT_TYPE object_type,
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
int len = 0; /* apdu len intermediate value */
BACNET_BIT_STRING bit_string = { 0 };
BACNET_CHARACTER_STRING char_string = { 0 };
uint32_t i = 0;
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t instance = 0;
uint32_t count = 0;
uint8_t *apdu = NULL;
int apdu_len = 0;
struct my_object_functions *pObject = NULL;
if ((rpdata->application_data == NULL) ||
@@ -592,6 +623,7 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
return 0;
}
apdu = rpdata->application_data;
apdu_max = rpdata->application_data_len;
switch ((int)rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len = encode_application_object_id(
@@ -684,47 +716,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
break;
case PROP_OBJECT_LIST:
count = Device_Object_List_Count();
/* Array element zero is the number of objects in the list */
if (rpdata->array_index == 0)
apdu_len = encode_application_unsigned(&apdu[0], count);
/* if no index was specified, then try to encode the entire list */
/* into one packet. Note that more than likely you will have */
/* to return an error if the number of encoded objects exceeds */
/* your maximum APDU size. */
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) {
if (Device_Object_List_Identifier(
i, &object_type, &instance)) {
len = encode_application_object_id(
&apdu[apdu_len], object_type, instance);
apdu_len += len;
/* assume next one is the same size as this one */
/* can we all fit into the APDU? */
if ((apdu_len + len) >= MAX_APDU) {
/* Abort response */
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index,
Device_Object_List_Element_Encode,
count, apdu, apdu_max);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
} else {
/* error: internal error? */
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_OTHER;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
} else {
if (Device_Object_List_Identifier(
rpdata->array_index, &object_type, &instance))
apdu_len = encode_application_object_id(
&apdu[0], object_type, instance);
else {
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_MAX_APDU_LENGTH_ACCEPTED:
+70
View File
@@ -3084,3 +3084,73 @@ int decode_context_bacnet_address(
}
return len;
}
/**
* @brief Encode a BACnetARRAY property value
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 for the array size
* 1 to n for individual array members
* BACNET_ARRAY_ALL for the full array to be read.
* @param encoder [in] function to encode one property array element
* @param array_size [in] number of elements in the array
* @param apdu [out] Buffer in which the APDU contents are built.
* @param max_apdu [in] Max length of the APDU buffer.
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for an invalid array index
* BACNET_STATUS_ABORT for abort message.
*/
int bacnet_array_encode(uint32_t object_instance,
BACNET_ARRAY_INDEX array_index,
bacnet_array_property_element_encode_function encoder,
BACNET_UNSIGNED_INTEGER array_size,
uint8_t *apdu,
int max_apdu)
{
int apdu_len = 0, len = 0;
BACNET_ARRAY_INDEX index;
if (array_index == 0) {
/* Array element zero is the number of objects in the list */
len = encode_application_unsigned(NULL, array_size);
if (len > max_apdu) {
apdu_len = BACNET_STATUS_ABORT;
} else {
len = encode_application_unsigned(NULL, array_size);
apdu_len = len;
}
} else if (array_index == BACNET_ARRAY_ALL) {
/* if no index was specified, then try to encode the entire list */
/* into one packet. */
for (index = 0; index < array_size; index++) {
len += encoder(object_instance, index, NULL);
}
if (len > max_apdu) {
/* encoded size is larger than APDU size */
apdu_len = BACNET_STATUS_ABORT;
} else {
for (index = 1; index < array_size; index++) {
len = encoder(object_instance, index, apdu);
if (apdu) {
apdu += len;
}
apdu_len += len;
}
}
} else if (array_index <= array_size) {
/* index was specified; encode a single array element */
index = array_index - 1;
len = encoder(object_instance, index, NULL);
if (len > max_apdu) {
apdu_len = BACNET_STATUS_ABORT;
} else {
len = encoder(object_instance, index, apdu);
apdu_len = len;
}
} else {
/* array_index was specified out of range */
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
+22
View File
@@ -35,6 +35,19 @@
#include "bacnet/bacreal.h"
#include "bacnet/bits.h"
/**
* @brief Encode a BACnetARRAY property element; a function template
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
typedef int (*bacnet_array_property_element_encode_function)(
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu);
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
@@ -615,6 +628,15 @@ extern "C" {
uint8_t tag_number,
BACNET_ADDRESS * destination);
BACNET_STACK_EXPORT
int bacnet_array_encode(
uint32_t object_instance,
BACNET_ARRAY_INDEX array_index,
bacnet_array_property_element_encode_function encoder,
BACNET_UNSIGNED_INTEGER array_size,
uint8_t *apdu,
int max_apdu);
/* from clause 20.2.1.2 Tag Number */
/* true if extended tag numbering is used */
#define IS_EXTENDED_TAG_NUMBER(x) (((x) & 0xF0) == 0xF0)
+36 -38
View File
@@ -243,6 +243,35 @@ BACNET_DOOR_VALUE Access_Door_Relinquish_Default(uint32_t object_instance)
return status;
}
/**
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
static int Access_Door_Priority_Array_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
unsigned object_index = 0;
object_index = Access_Door_Instance_To_Index(object_instance);
if (object_index < MAX_ACCESS_DOORS) {
if (ad_descr[object_index].value_active[array_index]) {
apdu_len = encode_application_null(apdu);
} else {
apdu_len = encode_application_enumerated(
apdu, ad_descr[object_index].priority_array[array_index]);
}
}
return apdu_len;
}
/* note: the object name must be unique within this device */
bool Access_Door_Object_Name(
uint32_t object_instance, BACNET_CHARACTER_STRING *object_name)
@@ -284,20 +313,20 @@ void Access_Door_Out_Of_Service_Set(uint32_t instance, bool oos_flag)
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Access_Door_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
int apdu_size = 0;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
apdu_size = rpdata->application_data_len;
object_index = Access_Door_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
@@ -339,46 +368,15 @@ int Access_Door_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
apdu_len = encode_application_boolean(&apdu[0], state);
break;
case PROP_PRIORITY_ARRAY:
/* Array element zero is the number of elements in the array */
if (rpdata->array_index == 0) {
apdu_len =
encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY);
/* if no index was specified, then try to encode the entire list
*/
/* into one packet. */
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
/* FIXME: check if we have room before adding it to APDU */
if (ad_descr[object_index].value_active[i]) {
len = encode_application_null(&apdu[apdu_len]);
} else {
len = encode_application_enumerated(&apdu[apdu_len],
ad_descr[object_index].priority_array[i]);
}
/* add it if we have room */
if ((apdu_len + len) < MAX_APDU) {
apdu_len += len;
} else {
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index, Access_Door_Priority_Array_Encode,
BACNET_MAX_PRIORITY, apdu, apdu_size);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
if (ad_descr[object_index].value_active[i]) {
apdu_len = encode_application_null(&apdu[0]);
} else {
apdu_len =
encode_application_enumerated(&apdu[apdu_len],
ad_descr[object_index].priority_array[i]);
}
} else {
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_RELINQUISH_DEFAULT:
+45 -99
View File
@@ -202,8 +202,7 @@ float Analog_Output_Present_Value(uint32_t object_instance)
* @param object_instance - object-instance number of the object
* @return active priority 1..16, or 0 if no priority is active
*/
unsigned Analog_Output_Present_Value_Priority(
uint32_t object_instance)
unsigned Analog_Output_Present_Value_Priority(uint32_t object_instance)
{
unsigned p = 0; /* loop counter */
unsigned priority = 0; /* return value */
@@ -223,55 +222,33 @@ unsigned Analog_Output_Present_Value_Priority(
}
/**
* @brief For a given object instance-number and priority 1..16, determines the
* priority-array value
* @param object_instance - object-instance number of the object
* @param priority - priority-array index value 1..16
*
* @return priority-array value of the object
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
static float Analog_Output_Priority_Array(
uint32_t object_instance, unsigned priority)
static int Analog_Output_Priority_Array_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX index, uint8_t *apdu)
{
float value = 0.0;
int apdu_len = BACNET_STATUS_ERROR;
struct object_data *pObject;
float real_value;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if ((priority >= BACNET_MIN_PRIORITY) &&
(priority <= BACNET_MAX_PRIORITY)) {
value = pObject->Priority_Array[priority - 1];
if (pObject && (index < BACNET_MAX_PRIORITY)) {
if (pObject->Relinquished[index]) {
apdu_len = encode_application_null(apdu);
} else {
real_value = pObject->Priority_Array[index];
apdu_len = encode_application_real(apdu, real_value);
}
}
return value;
}
/**
* @brief For a given object instance-number and priority 1..16, determines
* if the priority-array slot is NULL
* @param object_instance - object-instance number of the object
* @param priority - priority-array index value 1..16
* @return true if the priority array slot is NULL
*/
static bool Analog_Output_Priority_Array_Null(
uint32_t object_instance, unsigned priority)
{
bool null_value = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if ((priority >= BACNET_MIN_PRIORITY) &&
(priority <= BACNET_MAX_PRIORITY)) {
if (pObject->Relinquished[priority - 1]) {
null_value = true;
}
}
}
return null_value;
return apdu_len;
}
/**
@@ -408,8 +385,9 @@ bool Analog_Output_Present_Value_Relinquish(
* @param error_code - BACnet Error code
* @return true if values are within range and present-value is set.
*/
static bool Analog_Output_Present_Value_Write(
uint32_t object_instance, float value, uint8_t priority,
static bool Analog_Output_Present_Value_Write(uint32_t object_instance,
float value,
uint8_t priority,
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code)
{
@@ -424,7 +402,8 @@ static bool Analog_Output_Present_Value_Write(
(value >= 0.0) && (value <= 100.0)) {
if (priority != 6) {
old_value = Analog_Output_Present_Value(object_instance);
Analog_Output_Present_Value_Set(object_instance, value, priority);
Analog_Output_Present_Value_Set(
object_instance, value, priority);
if (pObject->Out_Of_Service) {
/* The physical point that the object represents
is not in service. This means that changes to the
@@ -463,7 +442,8 @@ static bool Analog_Output_Present_Value_Write(
* @return true if values are within range and write is requested
*/
static bool Analog_Output_Present_Value_Relinquish_Write(
uint32_t object_instance, uint8_t priority,
uint32_t object_instance,
uint8_t priority,
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code)
{
@@ -477,7 +457,8 @@ static bool Analog_Output_Present_Value_Relinquish_Write(
if ((priority >= 1) && (priority <= BACNET_MAX_PRIORITY)) {
if (priority != 6) {
old_value = Analog_Output_Present_Value(object_instance);
Analog_Output_Present_Value_Relinquish(object_instance, priority);
Analog_Output_Present_Value_Relinquish(
object_instance, priority);
if (pObject->Out_Of_Service) {
/* The physical point that the object represents
is not in service. This means that changes to the
@@ -526,8 +507,8 @@ bool Analog_Output_Object_Name(
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (pObject->Object_Name) {
status = characterstring_init_ansi(object_name,
pObject->Object_Name);
status =
characterstring_init_ansi(object_name, pObject->Object_Name);
} else {
snprintf(name_text, sizeof(name_text), "ANALOG OUTPUT %u",
object_instance);
@@ -992,8 +973,8 @@ void Analog_Output_COV_Increment_Set(uint32_t object_instance, float value)
*/
int Analog_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
int apdu_size = 0;
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
uint8_t *apdu = NULL;
@@ -1008,6 +989,7 @@ int Analog_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
}
apdu = rpdata->application_data;
apdu_size = rpdata->application_data_len;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len = encode_application_object_id(
@@ -1019,8 +1001,7 @@ int Analog_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], Object_Type);
apdu_len = encode_application_enumerated(&apdu[0], Object_Type);
break;
case PROP_PRESENT_VALUE:
real_value = Analog_Output_Present_Value(rpdata->object_instance);
@@ -1062,49 +1043,15 @@ int Analog_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
apdu_len = encode_application_enumerated(&apdu[0], units);
break;
case PROP_PRIORITY_ARRAY:
if (rpdata->array_index == 0) {
/* Array element zero = the number of elements in the array */
apdu_len =
encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY);
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
/* no index was specified; try to encode the entire list */
for (i = 1; i <= BACNET_MAX_PRIORITY; i++) {
if (Analog_Output_Priority_Array_Null(
rpdata->object_instance, i)) {
len = encode_application_null(&apdu[apdu_len]);
} else {
real_value = Analog_Output_Priority_Array(
rpdata->object_instance, i);
len = encode_application_real(
&apdu[apdu_len], real_value);
}
/* add it if we have room */
if ((apdu_len + len) < MAX_APDU) {
apdu_len += len;
} else {
/* Abort response */
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index, Analog_Output_Priority_Array_Encode,
BACNET_MAX_PRIORITY, apdu, apdu_size);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
if (Analog_Output_Priority_Array_Null(
rpdata->object_instance, rpdata->array_index)) {
apdu_len = encode_application_null(&apdu[apdu_len]);
} else {
real_value = Analog_Output_Priority_Array(
rpdata->object_instance, rpdata->array_index);
apdu_len = encode_application_real(
&apdu[apdu_len], real_value);
}
} else {
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_RELINQUISH_DEFAULT:
@@ -1183,16 +1130,16 @@ bool Analog_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
}
switch (wp_data->object_property) {
case PROP_PRESENT_VALUE:
status = write_property_type_valid(wp_data, &value,
BACNET_APPLICATION_TAG_REAL);
status = write_property_type_valid(
wp_data, &value, BACNET_APPLICATION_TAG_REAL);
if (status) {
status =
Analog_Output_Present_Value_Write(wp_data->object_instance,
value.type.Real, wp_data->priority,
&wp_data->error_class, &wp_data->error_code);
} else {
status = write_property_type_valid(wp_data, &value,
BACNET_APPLICATION_TAG_NULL);
status = write_property_type_valid(
wp_data, &value, BACNET_APPLICATION_TAG_NULL);
if (status) {
status = Analog_Output_Present_Value_Relinquish_Write(
wp_data->object_instance, wp_data->priority,
@@ -1201,8 +1148,8 @@ bool Analog_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
}
break;
case PROP_OUT_OF_SERVICE:
status = write_property_type_valid(wp_data, &value,
BACNET_APPLICATION_TAG_BOOLEAN);
status = write_property_type_valid(
wp_data, &value, BACNET_APPLICATION_TAG_BOOLEAN);
if (status) {
Analog_Output_Out_Of_Service_Set(
wp_data->object_instance, value.type.Boolean);
@@ -1236,7 +1183,6 @@ bool Analog_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
return status;
}
/**
* @brief Sets a callback used when present-value is written from BACnet
* @param cb - callback used to provide indications
+17 -3
View File
@@ -98,6 +98,20 @@ void BACfile_Property_Lists(
return;
}
/**
* @brief duplicate a string (replacement for POSIX strdup)
* @param s - string to duplicate
* @return a pointer to a new string on success, or a null pointer
*/
static char *bacfile_strdup(const char *s) {
size_t size = strlen(s) + 1;
char *p = malloc(size);
if (p != NULL) {
memcpy(p, s, size);
}
return p;
}
/**
* @brief For a given object instance-number, returns the pathname
* @param object_instance - object-instance number of the object
@@ -130,7 +144,7 @@ void bacfile_pathname_set(uint32_t object_instance, const char *pathname)
if (pObject->Pathname) {
free(pObject->Pathname);
}
pObject->Pathname = strdup(pathname);
pObject->Pathname = bacfile_strdup(pathname);
}
}
@@ -409,10 +423,10 @@ void bacfile_file_type_set(
if (pObject->File_Type) {
if (strcmp(pObject->File_Type, mime_type) != 0) {
free(pObject->File_Type);
pObject->File_Type = strdup(mime_type);
pObject->File_Type = bacfile_strdup(mime_type);
}
} else {
pObject->File_Type = strdup(mime_type);
pObject->File_Type = bacfile_strdup(mime_type);
}
}
}
+47 -105
View File
@@ -211,61 +211,35 @@ BACNET_BINARY_PV Binary_Output_Present_Value(uint32_t object_instance)
}
/**
* For a given object instance-number, determines the value at a
* given priority.
*
* @param object_instance - object-instance number of the object
* @param priority - priority 1..16
*
* @return priority-array element of the object
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
static BACNET_BINARY_PV Binary_Output_Priority_Array_Value(
uint32_t object_instance, unsigned priority)
static int Binary_Output_Priority_Array_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
struct object_data *pObject;
BACNET_BINARY_PV value = BINARY_INACTIVE;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
priority--;
if (BIT_CHECK(pObject->Priority_Array, priority)) {
if (pObject && (index < BACNET_MAX_PRIORITY)) {
if (BIT_CHECK(pObject->Priority_Active_Bits, index)) {
if (BIT_CHECK(pObject->Priority_Array, index)) {
value = BINARY_ACTIVE;
}
apdu_len = encode_application_enumerated(apdu, value);
} else {
value = BINARY_INACTIVE;
}
apdu_len = encode_application_null(apdu);
}
}
return value;
}
/**
* For a given object instance-number, determines if the given priority
* is active or NULL.
*
* @param object_instance - object-instance number of the object
* @param priority - priority 1..16
*
* @return true if the priority slot is active
*/
static bool Binary_Output_Priority_Active(
uint32_t object_instance, unsigned priority)
{
bool status = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
priority--;
if (BIT_CHECK(pObject->Priority_Active_Bits, priority)) {
status = true;
}
}
}
return status;
return apdu_len;
}
/**
@@ -369,8 +343,9 @@ bool Binary_Output_Present_Value_Relinquish(
* @param error_code - BACnet Error code
* @return true if values are within range and present-value is set.
*/
static bool Binary_Output_Present_Value_Write(
uint32_t object_instance, BACNET_BINARY_PV value, uint8_t priority,
static bool Binary_Output_Present_Value_Write(uint32_t object_instance,
BACNET_BINARY_PV value,
uint8_t priority,
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code)
{
@@ -382,11 +357,11 @@ static bool Binary_Output_Present_Value_Write(
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if ((priority >= 1) && (priority <= BACNET_MAX_PRIORITY) &&
(value >= 0.0) && (value <= 100.0)) {
(value <= MAX_BINARY_PV)) {
if (priority != 6) {
old_value = Binary_Output_Present_Value(object_instance);
Binary_Output_Present_Value_Set(object_instance, value,
priority);
Binary_Output_Present_Value_Set(
object_instance, value, priority);
if (pObject->Out_Of_Service) {
/* The physical point that the object represents
is not in service. This means that changes to the
@@ -425,7 +400,8 @@ static bool Binary_Output_Present_Value_Write(
* @return true if values are within range and write is requested
*/
static bool Binary_Output_Present_Value_Relinquish_Write(
uint32_t object_instance, uint8_t priority,
uint32_t object_instance,
uint8_t priority,
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code)
{
@@ -439,7 +415,8 @@ static bool Binary_Output_Present_Value_Relinquish_Write(
if ((priority >= 1) && (priority <= BACNET_MAX_PRIORITY)) {
if (priority != 6) {
old_value = Binary_Output_Present_Value(object_instance);
Binary_Output_Present_Value_Relinquish(object_instance, priority);
Binary_Output_Present_Value_Relinquish(
object_instance, priority);
if (pObject->Out_Of_Service) {
/* The physical point that the object represents
is not in service. This means that changes to the
@@ -530,8 +507,8 @@ bool Binary_Output_Object_Name(
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (pObject->Object_Name) {
status = characterstring_init_ansi(object_name,
pObject->Object_Name);
status =
characterstring_init_ansi(object_name, pObject->Object_Name);
} else {
snprintf(name_text, sizeof(name_text), "BINARY OUTPUT %u",
object_instance);
@@ -973,7 +950,6 @@ bool Binary_Output_Encode_Value_List(
*/
int Binary_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
@@ -982,12 +958,14 @@ int Binary_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
int apdu_size = 0;
if ((rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
apdu_size = rpdata->application_data_len;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len = encode_application_object_id(
@@ -999,8 +977,7 @@ int Binary_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], Object_Type);
apdu_len = encode_application_enumerated(&apdu[0], Object_Type);
break;
case PROP_PRESENT_VALUE:
present_value =
@@ -1035,50 +1012,15 @@ int Binary_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
apdu_len = encode_application_enumerated(&apdu[0], polarity);
break;
case PROP_PRIORITY_ARRAY:
/* Array element zero is the number of elements in the array */
if (rpdata->array_index == 0) {
apdu_len =
encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY);
/* if no index was specified, then try to encode the entire list
*/
/* into one packet. */
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= BACNET_MAX_PRIORITY; i++) {
if (Binary_Output_Priority_Active(
rpdata->object_instance, i)) {
present_value = Binary_Output_Priority_Array_Value(
rpdata->object_instance, i);
len = encode_application_enumerated(
&apdu[apdu_len], present_value);
} else {
len = encode_application_null(&apdu[apdu_len]);
}
/* add it if we have room */
if ((apdu_len + len) < MAX_APDU) {
apdu_len += len;
} else {
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
} else {
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
if (Binary_Output_Priority_Active(
rpdata->object_instance, rpdata->array_index)) {
present_value = Binary_Output_Priority_Array_Value(
rpdata->object_instance, rpdata->array_index);
apdu_len = encode_application_enumerated(
&apdu[0], present_value);
} else {
apdu_len = encode_application_null(&apdu[0]);
}
} else {
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index, Binary_Output_Priority_Array_Encode,
BACNET_MAX_PRIORITY, apdu, apdu_size);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_RELINQUISH_DEFAULT:
@@ -1165,16 +1107,16 @@ bool Binary_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
}
switch (wp_data->object_property) {
case PROP_PRESENT_VALUE:
status = write_property_type_valid(wp_data, &value,
BACNET_APPLICATION_TAG_ENUMERATED);
status = write_property_type_valid(
wp_data, &value, BACNET_APPLICATION_TAG_ENUMERATED);
if (status) {
status =
Binary_Output_Present_Value_Write(wp_data->object_instance,
value.type.Enumerated, wp_data->priority,
&wp_data->error_class, &wp_data->error_code);
} else {
status = write_property_type_valid(wp_data, &value,
BACNET_APPLICATION_TAG_NULL);
status = write_property_type_valid(
wp_data, &value, BACNET_APPLICATION_TAG_NULL);
if (status) {
status = Binary_Output_Present_Value_Relinquish_Write(
wp_data->object_instance, wp_data->priority,
@@ -1183,8 +1125,8 @@ bool Binary_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
}
break;
case PROP_OUT_OF_SERVICE:
status = write_property_type_valid(wp_data, &value,
BACNET_APPLICATION_TAG_BOOLEAN);
status = write_property_type_valid(
wp_data, &value, BACNET_APPLICATION_TAG_BOOLEAN);
if (status) {
Binary_Output_Out_Of_Service_Set(
wp_data->object_instance, value.type.Boolean);
+41 -46
View File
@@ -599,6 +599,39 @@ bool Device_Object_List_Identifier(
return status;
}
/**
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
int Device_Object_List_Element_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
BACNET_OBJECT_TYPE object_type;
uint32_t instance;
bool found;
if (object_instance == Device_Object_Instance_Number()) {
/* single element is zero based, add 1 for BACnetARRAY which is one
* based */
array_index++;
found =
Device_Object_List_Identifier(array_index, &object_type, &instance);
if (found) {
apdu_len =
encode_application_object_id(apdu, object_type, instance);
}
}
return apdu_len;
}
/** Determine if we have an object with the given object_name.
* If the object_type and object_instance pointers are not null,
* and the lookup succeeds, they will be given the resulting values.
@@ -788,22 +821,20 @@ uint32_t Device_Interval_Offset(void)
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
int len = 0; /* apdu len intermediate value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
uint32_t i = 0;
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t instance = 0;
uint32_t count = 0;
uint8_t *apdu = NULL;
int apdu_size = 0;
struct object_functions *pObject = NULL;
bool found = false;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
apdu_size = rpdata->application_data_len;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len = encode_application_object_id(
@@ -892,52 +923,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
break;
case PROP_OBJECT_LIST:
count = Device_Object_List_Count();
/* Array element zero is the number of objects in the list */
if (rpdata->array_index == 0) {
apdu_len = encode_application_unsigned(&apdu[0], count);
/* if no index was specified, then try to encode the entire list
*/
/* into one packet. Note that more than likely you will have */
/* to return an error if the number of encoded objects exceeds
*/
/* your maximum APDU size. */
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) {
found = Device_Object_List_Identifier(
i, &object_type, &instance);
if (found) {
len = encode_application_object_id(
&apdu[apdu_len], object_type, instance);
apdu_len += len;
/* assume next one is the same size as this one */
/* can we all fit into the APDU? Don't check for last
* entry */
if ((i != count) && (apdu_len + len) >= MAX_APDU) {
/* Abort response */
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index,
Device_Object_List_Element_Encode,
count, apdu, apdu_size);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
} else {
/* error: internal error? */
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_OTHER;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
} else {
found = Device_Object_List_Identifier(
rpdata->array_index, &object_type, &instance);
if (found) {
apdu_len = encode_application_object_id(
&apdu[0], object_type, instance);
} else {
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_MAX_APDU_LENGTH_ACCEPTED:
+39 -46
View File
@@ -892,6 +892,39 @@ bool Device_Object_List_Identifier(
return status;
}
/**
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet network port object instance number
* @param array_index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
int Device_Object_List_Element_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
BACNET_OBJECT_TYPE object_type;
uint32_t instance;
bool found;
if (object_instance == Device_Object_Instance_Number()) {
/* single element is zero based, add 1 for BACnetARRAY which is one
* based */
array_index++;
found =
Device_Object_List_Identifier(array_index, &object_type, &instance);
if (found) {
apdu_len =
encode_application_object_id(apdu, object_type, instance);
}
}
return apdu_len;
}
/** Determine if we have an object with the given object_name.
* If the object_type and object_instance pointers are not null,
* and the lookup succeeds, they will be given the resulting values.
@@ -1086,16 +1119,12 @@ uint32_t Device_Interval_Offset(void)
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
int len = 0; /* apdu len intermediate value */
BACNET_BIT_STRING bit_string = { 0 };
BACNET_CHARACTER_STRING char_string = { 0 };
uint32_t i = 0;
BACNET_OBJECT_TYPE object_type = OBJECT_NONE;
uint32_t instance = 0;
uint32_t count = 0;
uint8_t *apdu = NULL;
struct object_functions *pObject = NULL;
bool found = false;
uint16_t apdu_max = 0;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
@@ -1210,52 +1239,16 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
break;
case PROP_OBJECT_LIST:
count = Device_Object_List_Count();
/* Array element zero is the number of objects in the list */
if (rpdata->array_index == 0) {
apdu_len = encode_application_unsigned(&apdu[0], count);
/* if no index was specified, then try to encode the entire list
*/
/* into one packet. Note that more than likely you will have */
/* to return an error if the number of encoded objects exceeds
*/
/* your maximum APDU size. */
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) {
found = Device_Object_List_Identifier(
i, &object_type, &instance);
if (found) {
len = encode_application_object_id(
&apdu[apdu_len], object_type, instance);
apdu_len += len;
/* assume next one is the same size as this one */
/* can we all fit into the APDU? Don't check for last
* entry */
if ((i != count) && (apdu_len + len) >= apdu_max) {
/* Abort response */
apdu_len = bacnet_array_encode(rpdata->object_instance,
rpdata->array_index,
Device_Object_List_Element_Encode,
count, apdu, apdu_max);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
} else {
/* error: internal error? */
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_OTHER;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
} else {
found = Device_Object_List_Identifier(
rpdata->array_index, &object_type, &instance);
if (found) {
apdu_len = encode_application_object_id(
&apdu[0], object_type, instance);
} else {
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_MAX_APDU_LENGTH_ACCEPTED:
+6
View File
@@ -298,6 +298,7 @@ extern "C" {
BACNET_STACK_EXPORT
bool Device_Valid_Object_Instance_Number(
uint32_t object_id);
BACNET_STACK_EXPORT
unsigned Device_Object_List_Count(
void);
@@ -306,6 +307,11 @@ extern "C" {
uint32_t array_index,
BACNET_OBJECT_TYPE *object_type,
uint32_t * instance);
BACNET_STACK_EXPORT
int Device_Object_List_Element_Encode(
uint32_t object_instance,
BACNET_ARRAY_INDEX array_index,
uint8_t *apdu);
BACNET_STACK_EXPORT
unsigned Device_Count(
+3 -1
View File
@@ -39,7 +39,9 @@
# include <strings.h>
# endif
#if defined(__GNUC__)
#if defined(__MINGW32__)
#define BACNET_STACK_FALLTHROUGH() /* fall through */
#elif defined(__GNUC__)
#define BACNET_STACK_FALLTHROUGH() __attribute__ ((fallthrough))
#else
#define BACNET_STACK_FALLTHROUGH() /* fall through */