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:
@@ -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 {
|
||||
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 {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
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;
|
||||
} else if (apdu_len == BACNET_STATUS_ERROR) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
}
|
||||
break;
|
||||
case PROP_RELINQUISH_DEFAULT:
|
||||
|
||||
+49
-103
@@ -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 */
|
||||
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 {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
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;
|
||||
} else if (apdu_len == BACNET_STATUS_ERROR) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
}
|
||||
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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+49
-107
@@ -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;
|
||||
} else {
|
||||
value = BINARY_INACTIVE;
|
||||
}
|
||||
apdu_len = encode_application_enumerated(apdu, value);
|
||||
} else {
|
||||
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 {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -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 */
|
||||
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 {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
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;
|
||||
} else if (apdu_len == BACNET_STATUS_ERROR) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
}
|
||||
break;
|
||||
case PROP_MAX_APDU_LENGTH_ACCEPTED:
|
||||
|
||||
@@ -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 */
|
||||
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 {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
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;
|
||||
} else if (apdu_len == BACNET_STATUS_ERROR) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
}
|
||||
break;
|
||||
case PROP_MAX_APDU_LENGTH_ACCEPTED:
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user