Refactored RP, WP, RPM to reduce coupling with objects for Linux and Win32 ports.

This commit is contained in:
skarg
2010-02-10 16:27:31 +00:00
parent a7de276acc
commit f0863c0238
69 changed files with 2734 additions and 1710 deletions
+36 -32
View File
@@ -142,29 +142,30 @@ char *Analog_Input_Name(
/* return apdu length, or -1 on error */
/* assumption - object has already exists */
int Analog_Input_Encode_Property_APDU(
uint8_t * apdu,
uint32_t object_instance,
BACNET_PROPERTY_ID property,
int32_t array_index,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
int Analog_Input_Read_Property(
BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
uint8_t *apdu = NULL;
(void) array_index;
switch (property) {
if ((rpdata == NULL) ||
(rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT,
object_instance);
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string,
Analog_Input_Name(object_instance));
Analog_Input_Name(rpdata->object_instance));
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
@@ -175,7 +176,7 @@ int Analog_Input_Encode_Property_APDU(
case PROP_PRESENT_VALUE:
apdu_len =
encode_application_real(&apdu[0],
Analog_Input_Present_Value(object_instance));
Analog_Input_Present_Value(rpdata->object_instance));
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
@@ -196,26 +197,28 @@ int Analog_Input_Encode_Property_APDU(
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
break;
case 9997:
apdu_len = encode_application_real(&apdu[0], (float) 90.510);
/* test case for real encoding-decoding unsigned value correctly */
apdu_len = encode_application_real(&apdu[0], 90.510F);
break;
case 9998:
/* test case for unsigned encoding-decoding unsigned value correctly */
apdu_len = encode_application_unsigned(&apdu[0], 90);
break;
/* test case for signed encoding-decoding negative value correctly */
case 9999:
/* test case for signed encoding-decoding negative value correctly */
apdu_len = encode_application_signed(&apdu[0], -200);
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(array_index != BACNET_ARRAY_ALL)) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = -1;
}
@@ -239,24 +242,25 @@ void testAnalogInput(
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_OUTPUT;
uint32_t decoded_instance = 0;
uint32_t instance = 123;
BACNET_ERROR_CLASS error_class;
BACNET_ERROR_CODE error_code;
uint16_t decoded_type = 0;
BACNET_READ_PROPERTY_DATA rpdata;
/* FIXME: we should do a lot more testing here... */
len =
Analog_Input_Encode_Property_APDU(&apdu[0], instance,
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
ct_test(pTest, len >= 0);
Analog_Input_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_ANALOG_INPUT;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Analog_Input_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len =
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == OBJECT_ANALOG_INPUT);
ct_test(pTest, decoded_instance == instance);
decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
+74 -69
View File
@@ -37,8 +37,6 @@
#include "ao.h"
#include "handlers.h"
#define MAX_ANALOG_OUTPUTS 4
/* we choose to have a NULL level in our system represented by */
/* a particular value. When the priorities are not in use, they */
/* will be relinquished (i.e. set to the NULL level). */
@@ -265,13 +263,8 @@ char *Analog_Output_Name(
}
/* return apdu len, or -1 on error */
int Analog_Output_Encode_Property_APDU(
uint8_t * apdu,
uint32_t object_instance,
BACNET_PROPERTY_ID property,
int32_t array_index,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
int Analog_Output_Read_Property(
BACNET_READ_PROPERTY_DATA *rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
@@ -281,17 +274,24 @@ int Analog_Output_Encode_Property_APDU(
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
switch (property) {
if ((rpdata == NULL) ||
(rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_ANALOG_OUTPUT,
object_instance);
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string,
Analog_Output_Name(object_instance));
Analog_Output_Name(rpdata->object_instance));
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
@@ -300,7 +300,7 @@ int Analog_Output_Encode_Property_APDU(
encode_application_enumerated(&apdu[0], OBJECT_ANALOG_OUTPUT);
break;
case PROP_PRESENT_VALUE:
real_value = Analog_Output_Present_Value(object_instance);
real_value = Analog_Output_Present_Value(rpdata->object_instance);
apdu_len = encode_application_real(&apdu[0], real_value);
break;
case PROP_STATUS_FLAGS:
@@ -316,7 +316,7 @@ int Analog_Output_Encode_Property_APDU(
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
break;
case PROP_OUT_OF_SERVICE:
object_index = Analog_Output_Instance_To_Index(object_instance);
object_index = Analog_Output_Instance_To_Index(rpdata->object_instance);
state = Analog_Output_Out_Of_Service[object_index];
apdu_len = encode_application_boolean(&apdu[0], state);
break;
@@ -325,14 +325,14 @@ int Analog_Output_Encode_Property_APDU(
break;
case PROP_PRIORITY_ARRAY:
/* Array element zero is the number of elements in the array */
if (array_index == 0)
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 (array_index == BACNET_ARRAY_ALL) {
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
object_index =
Analog_Output_Instance_To_Index(object_instance);
Analog_Output_Instance_To_Index(rpdata->object_instance);
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
/* FIXME: check if we have room before adding it to APDU */
if (Analog_Output_Level[object_index][i] == AO_LEVEL_NULL)
@@ -347,28 +347,28 @@ int Analog_Output_Encode_Property_APDU(
if ((apdu_len + len) < MAX_APDU)
apdu_len += len;
else {
*error_class = ERROR_CLASS_SERVICES;
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = -1;
break;
}
}
} else {
object_index =
Analog_Output_Instance_To_Index(object_instance);
if (array_index <= BACNET_MAX_PRIORITY) {
if (Analog_Output_Level[object_index][array_index - 1] ==
Analog_Output_Instance_To_Index(rpdata->object_instance);
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
if (Analog_Output_Level[object_index][rpdata->array_index - 1] ==
AO_LEVEL_NULL)
apdu_len = encode_application_null(&apdu[0]);
else {
real_value =
Analog_Output_Level[object_index][array_index - 1];
Analog_Output_Level[object_index][rpdata->array_index - 1];
apdu_len =
encode_application_real(&apdu[0], real_value);
}
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = -1;
}
}
@@ -378,17 +378,17 @@ int Analog_Output_Encode_Property_APDU(
apdu_len = encode_application_real(&apdu[0], real_value);
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(property != PROP_PRIORITY_ARRAY) &&
(array_index != BACNET_ARRAY_ALL)) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
(rpdata->object_property != PROP_PRIORITY_ARRAY) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = -1;
}
@@ -397,9 +397,7 @@ int Analog_Output_Encode_Property_APDU(
/* returns true if successful */
bool Analog_Output_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
@@ -407,11 +405,6 @@ bool Analog_Output_Write_Property(
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
if (!Analog_Output_Valid_Instance(wp_data->object_instance)) {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
return false;
}
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
@@ -431,27 +424,37 @@ bool Analog_Output_Write_Property(
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
} else if (!status) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
} else if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL, error_class, error_code) == true) {
level = AO_LEVEL_NULL;
object_index =
Analog_Output_Instance_To_Index(wp_data->object_instance);
status =
Analog_Output_Present_Value_Relinquish
(wp_data->object_instance, wp_data->priority);
if (!status) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
} else {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_NULL,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
level = AO_LEVEL_NULL;
object_index =
Analog_Output_Instance_To_Index(wp_data->object_instance);
status =
Analog_Output_Present_Value_Relinquish
(wp_data->object_instance, wp_data->priority);
if (!status) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
}
break;
case PROP_OUT_OF_SERVICE:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
object_index =
Analog_Output_Instance_To_Index(wp_data->object_instance);
Analog_Output_Out_Of_Service[object_index] =
@@ -459,8 +462,8 @@ bool Analog_Output_Write_Property(
}
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
@@ -480,23 +483,25 @@ void testAnalogOutput(
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_OUTPUT;
uint32_t decoded_instance = 0;
uint32_t instance = 123;
BACNET_ERROR_CLASS error_class;
BACNET_ERROR_CODE error_code;
uint16_t decoded_type = 0;
BACNET_READ_PROPERTY_DATA rpdata;
len =
Analog_Output_Encode_Property_APDU(&apdu[0], instance,
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
Analog_Output_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_ANALOG_OUTPUT;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Analog_Output_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len =
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == OBJECT_ANALOG_OUTPUT);
ct_test(pTest, decoded_instance == instance);
decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
+84 -92
View File
@@ -52,9 +52,6 @@ static uint8_t Analog_Value_Level[MAX_ANALOG_VALUES][BACNET_MAX_PRIORITY];
/* without changing the physical output */
static bool Analog_Value_Out_Of_Service[MAX_ANALOG_VALUES];
/* we need to have our arrays initialized before answering any calls */
static bool Analog_Value_Initialized = false;
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Analog_Value_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
@@ -99,14 +96,10 @@ void Analog_Value_Init(
{
unsigned i, j;
if (!Analog_Value_Initialized) {
Analog_Value_Initialized = true;
/* initialize all the analog output priority arrays to NULL */
for (i = 0; i < MAX_ANALOG_VALUES; i++) {
for (j = 0; j < BACNET_MAX_PRIORITY; j++) {
Analog_Value_Level[i][j] = ANALOG_LEVEL_NULL;
}
/* initialize all the analog output priority arrays to NULL */
for (i = 0; i < MAX_ANALOG_VALUES; i++) {
for (j = 0; j < BACNET_MAX_PRIORITY; j++) {
Analog_Value_Level[i][j] = ANALOG_LEVEL_NULL;
}
}
@@ -119,7 +112,6 @@ void Analog_Value_Init(
bool Analog_Value_Valid_Instance(
uint32_t object_instance)
{
Analog_Value_Init();
if (object_instance < MAX_ANALOG_VALUES)
return true;
@@ -131,7 +123,6 @@ bool Analog_Value_Valid_Instance(
unsigned Analog_Value_Count(
void)
{
Analog_Value_Init();
return MAX_ANALOG_VALUES;
}
@@ -141,7 +132,6 @@ unsigned Analog_Value_Count(
uint32_t Analog_Value_Index_To_Instance(
unsigned index)
{
Analog_Value_Init();
return index;
}
@@ -153,7 +143,6 @@ unsigned Analog_Value_Instance_To_Index(
{
unsigned index = MAX_ANALOG_VALUES;
Analog_Value_Init();
if (object_instance < MAX_ANALOG_VALUES)
index = object_instance;
@@ -168,7 +157,6 @@ bool Analog_Value_Present_Value_Set(
unsigned index = 0;
bool status = false;
Analog_Value_Init();
index = Analog_Value_Instance_To_Index(object_instance);
if (index < MAX_ANALOG_VALUES) {
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
@@ -195,7 +183,6 @@ float Analog_Value_Present_Value(
unsigned index = 0;
unsigned i = 0;
Analog_Value_Init();
index = Analog_Value_Instance_To_Index(object_instance);
if (index < MAX_ANALOG_VALUES) {
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
@@ -224,13 +211,8 @@ char *Analog_Value_Name(
}
/* return apdu len, or -1 on error */
int Analog_Value_Encode_Property_APDU(
uint8_t * apdu,
uint32_t object_instance,
BACNET_PROPERTY_ID property,
int32_t array_index,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
int Analog_Value_Read_Property(
BACNET_READ_PROPERTY_DATA *rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
@@ -240,18 +222,24 @@ int Analog_Value_Encode_Property_APDU(
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
Analog_Value_Init();
switch (property) {
if ((rpdata == NULL) ||
(rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
object_instance);
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string,
Analog_Value_Name(object_instance));
Analog_Value_Name(rpdata->object_instance));
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
@@ -260,7 +248,7 @@ int Analog_Value_Encode_Property_APDU(
encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE);
break;
case PROP_PRESENT_VALUE:
real_value = Analog_Value_Present_Value(object_instance);
real_value = Analog_Value_Present_Value(rpdata->object_instance);
apdu_len = encode_application_real(&apdu[0], real_value);
break;
case PROP_STATUS_FLAGS:
@@ -276,7 +264,7 @@ int Analog_Value_Encode_Property_APDU(
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
break;
case PROP_OUT_OF_SERVICE:
object_index = Analog_Value_Instance_To_Index(object_instance);
object_index = Analog_Value_Instance_To_Index(rpdata->object_instance);
state = Analog_Value_Out_Of_Service[object_index];
apdu_len = encode_application_boolean(&apdu[0], state);
break;
@@ -285,13 +273,13 @@ int Analog_Value_Encode_Property_APDU(
break;
case PROP_PRIORITY_ARRAY:
/* Array element zero is the number of elements in the array */
if (array_index == 0)
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 (array_index == BACNET_ARRAY_ALL) {
object_index = Analog_Value_Instance_To_Index(object_instance);
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
object_index = Analog_Value_Instance_To_Index(rpdata->object_instance);
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
/* FIXME: check if we have room before adding it to APDU */
if (Analog_Value_Level[object_index][i] ==
@@ -307,27 +295,27 @@ int Analog_Value_Encode_Property_APDU(
if ((apdu_len + len) < MAX_APDU)
apdu_len += len;
else {
*error_class = ERROR_CLASS_SERVICES;
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = -1;
break;
}
}
} else {
object_index = Analog_Value_Instance_To_Index(object_instance);
if (array_index <= BACNET_MAX_PRIORITY) {
if (Analog_Value_Level[object_index][array_index - 1] ==
object_index = Analog_Value_Instance_To_Index(rpdata->object_instance);
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
if (Analog_Value_Level[object_index][rpdata->array_index - 1] ==
ANALOG_LEVEL_NULL)
apdu_len = encode_application_null(&apdu[0]);
else {
real_value =
Analog_Value_Level[object_index][array_index - 1];
Analog_Value_Level[object_index][rpdata->array_index - 1];
apdu_len =
encode_application_real(&apdu[0], real_value);
}
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = -1;
}
}
@@ -337,17 +325,17 @@ int Analog_Value_Encode_Property_APDU(
apdu_len = encode_application_real(&apdu[0], real_value);
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(property != PROP_PRIORITY_ARRAY) &&
(array_index != BACNET_ARRAY_ALL)) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
(rpdata->object_property != PROP_PRIORITY_ARRAY) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = -1;
}
@@ -356,9 +344,7 @@ int Analog_Value_Encode_Property_APDU(
/* returns true if successful */
bool Analog_Value_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
@@ -367,12 +353,6 @@ bool Analog_Value_Write_Property(
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
Analog_Value_Init();
if (!Analog_Value_Valid_Instance(wp_data->object_instance)) {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
return false;
}
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
@@ -392,43 +372,53 @@ bool Analog_Value_Write_Property(
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
} else if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL, error_class, error_code) == true) {
level = ANALOG_LEVEL_NULL;
object_index =
Analog_Value_Instance_To_Index(wp_data->object_instance);
priority = wp_data->priority;
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
priority--;
Analog_Value_Level[object_index][priority] = level;
/* Note: you could set the physical output here to the next
highest priority, or to the relinquish default if no
priorities are set.
However, if Out of Service is TRUE, then don't set the
physical output. This comment may apply to the
main loop (i.e. check out of service before changing output) */
status = true;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
} else {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_NULL,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
level = ANALOG_LEVEL_NULL;
object_index =
Analog_Value_Instance_To_Index(wp_data->object_instance);
priority = wp_data->priority;
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
priority--;
Analog_Value_Level[object_index][priority] = level;
/* Note: you could set the physical output here to the next
highest priority, or to the relinquish default if no
priorities are set.
However, if Out of Service is TRUE, then don't set the
physical output. This comment may apply to the
main loop (i.e. check out of service before changing output) */
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
}
break;
case PROP_OUT_OF_SERVICE:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
object_index =
Analog_Value_Instance_To_Index(wp_data->object_instance);
Analog_Value_Out_Of_Service[object_index] = value.type.Boolean;
}
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
@@ -444,27 +434,29 @@ bool Analog_Value_Write_Property(
void testAnalog_Value(
Test * pTest)
{
BACNET_READ_PROPERTY_DATA rpdata;
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_VALUE;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
uint32_t instance = 123;
BACNET_ERROR_CLASS error_class;
BACNET_ERROR_CODE error_code;
len =
Analog_Value_Encode_Property_APDU(&apdu[0], instance,
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
Analog_Value_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_ANALOG_VALUE;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Analog_Value_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len =
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == OBJECT_ANALOG_VALUE);
ct_test(pTest, decoded_instance == instance);
decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
+33 -26
View File
@@ -39,6 +39,8 @@
#include "device.h"
#include "arf.h"
#include "awf.h"
#include "rp.h"
#include "wp.h"
typedef struct {
uint32_t instance;
@@ -181,29 +183,30 @@ static unsigned bacfile_file_size(
}
/* return the number of bytes used, or -1 on error */
int bacfile_encode_property_apdu(
uint8_t * apdu,
uint32_t object_instance,
BACNET_PROPERTY_ID property,
int32_t array_index,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
int bacfile_read_property(
BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
char text_string[32] = { "" };
BACNET_CHARACTER_STRING char_string;
BACNET_DATE bdate;
BACNET_TIME btime;
uint8_t *apdu = NULL;
(void) array_index;
switch (property) {
if ((rpdata == NULL) ||
(rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_FILE,
object_instance);
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
sprintf(text_string, "FILE %lu", (unsigned long)object_instance);
sprintf(text_string, "FILE %lu", (unsigned long)rpdata->object_instance);
characterstring_init_ansi(&char_string, text_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
@@ -213,7 +216,7 @@ int bacfile_encode_property_apdu(
break;
case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string,
bacfile_name(object_instance));
bacfile_name(rpdata->object_instance));
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
@@ -225,7 +228,7 @@ int bacfile_encode_property_apdu(
case PROP_FILE_SIZE:
apdu_len =
encode_application_unsigned(&apdu[0],
bacfile_file_size(object_instance));
bacfile_file_size(rpdata->object_instance));
break;
case PROP_MODIFICATION_DATE:
/* FIXME: get the actual value instead of April Fool's Day */
@@ -261,8 +264,8 @@ int bacfile_encode_property_apdu(
encode_application_enumerated(&apdu[0], FILE_STREAM_ACCESS);
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1;
break;
}
@@ -272,17 +275,15 @@ int bacfile_encode_property_apdu(
/* returns true if successful */
bool bacfile_write_property(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
if (!bacfile_valid_instance(wp_data->object_instance)) {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
wp_data->error_class = ERROR_CLASS_OBJECT;
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
return false;
}
@@ -300,7 +301,11 @@ bool bacfile_write_property(
property shall be logical TRUE only if no changes have been
made to the file data by internal processes or through File
Access Services since the last time the object was archived. */
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
if (value.type.Boolean) {
/* FIXME: do something to wp_data->object_instance */
} else {
@@ -312,22 +317,24 @@ bool bacfile_write_property(
/* If the file size can be changed by writing to the file,
and File_Access_Method is STREAM_ACCESS, then this property
shall be writable. */
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
/* FIXME: do something with value.type.Unsigned
to wp_data->object_instance */
}
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
return status;
}
uint32_t bacfile_instance(
char *filename)
{
+58 -52
View File
@@ -31,13 +31,14 @@
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "rp.h"
#include "wp.h"
#include "cov.h"
#include "config.h" /* the custom stuff */
#include "bi.h"
#include "handlers.h"
#define MAX_BINARY_INPUTS 5
/* stores the current value */
static BACNET_BINARY_PV Present_Value[MAX_BINARY_INPUTS];
/* out of service decouples physical input from Present_Value */
@@ -148,7 +149,7 @@ unsigned Binary_Input_Instance_To_Index(
return index;
}
static BACNET_BINARY_PV Binary_Input_Present_Value(
BACNET_BINARY_PV Binary_Input_Present_Value(
uint32_t object_instance)
{
BACNET_BINARY_PV value = BINARY_INACTIVE;
@@ -240,11 +241,12 @@ bool Binary_Input_Encode_Value_List(
return true;
}
static void Binary_Input_Present_Value_Set(
bool Binary_Input_Present_Value_Set(
uint32_t object_instance,
BACNET_BINARY_PV value)
{
unsigned index = 0;
bool status = false;
index = Binary_Input_Instance_To_Index(object_instance);
if (index < MAX_BINARY_INPUTS) {
@@ -252,9 +254,10 @@ static void Binary_Input_Present_Value_Set(
Change_Of_Value[index] = true;
}
Present_Value[index] = value;
status = true;
}
return;
return status;
}
static void Binary_Input_Out_Of_Service_Set(
@@ -289,31 +292,32 @@ char *Binary_Input_Name(
/* return apdu length, or -1 on error */
/* assumption - object already exists, and has been bounds checked */
int Binary_Input_Encode_Property_APDU(
uint8_t * apdu,
uint32_t object_instance,
BACNET_PROPERTY_ID property,
int32_t array_index,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
int Binary_Input_Read_Property(
BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
BACNET_POLARITY polarity = POLARITY_NORMAL;
uint8_t *apdu = NULL;
(void) array_index;
switch (property) {
if ((rpdata == NULL) ||
(rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_BINARY_INPUT,
object_instance);
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
/* note: object name must be unique in our device */
characterstring_init_ansi(&char_string,
Binary_Input_Name(object_instance));
Binary_Input_Name(rpdata->object_instance));
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
@@ -325,7 +329,7 @@ int Binary_Input_Encode_Property_APDU(
/* note: you need to look up the actual value */
apdu_len =
encode_application_enumerated(&apdu[0],
Binary_Input_Present_Value(object_instance));
Binary_Input_Present_Value(rpdata->object_instance));
break;
case PROP_STATUS_FLAGS:
/* note: see the details in the standard on how to use these */
@@ -333,7 +337,7 @@ int Binary_Input_Encode_Property_APDU(
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
if (Binary_Input_Out_Of_Service(object_instance)) {
if (Binary_Input_Out_Of_Service(rpdata->object_instance)) {
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
true);
} else {
@@ -350,22 +354,22 @@ int Binary_Input_Encode_Property_APDU(
case PROP_OUT_OF_SERVICE:
apdu_len =
encode_application_boolean(&apdu[0],
Binary_Input_Out_Of_Service(object_instance));
Binary_Input_Out_Of_Service(rpdata->object_instance));
break;
case PROP_POLARITY:
apdu_len = encode_application_enumerated(&apdu[0], polarity);
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(array_index != BACNET_ARRAY_ALL)) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = -1;
}
@@ -374,19 +378,12 @@ int Binary_Input_Encode_Property_APDU(
/* returns true if successful */
bool Binary_Input_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
if (!Binary_Input_Valid_Instance(wp_data->object_instance)) {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
return false;
}
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
@@ -395,26 +392,34 @@ bool Binary_Input_Write_Property(
/* FIXME: len == 0: unable to decode? */
switch (wp_data->object_property) {
case PROP_PRESENT_VALUE:
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED, error_class, error_code) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_ENUMERATED,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
if (value.type.Enumerated <= MAX_BINARY_PV) {
Binary_Input_Present_Value_Set(wp_data->object_instance,
(BACNET_BINARY_PV) value.type.Enumerated);
status = true;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
break;
case PROP_OUT_OF_SERVICE:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
Binary_Input_Out_Of_Service_Set(wp_data->object_instance,
value.type.Boolean);
}
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
@@ -429,28 +434,29 @@ bool Binary_Input_Write_Property(
void testBinaryInput(
Test * pTest)
{
BACNET_READ_PROPERTY_DATA rpdata;
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_BINARY_OUTPUT;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
uint32_t instance = 123;
BACNET_ERROR_CLASS error_class;
BACNET_ERROR_CODE error_code;
/* FIXME: we should do a lot more testing here... */
len =
Binary_Input_Encode_Property_APDU(&apdu[0], instance,
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
ct_test(pTest, len >= 0);
Binary_Input_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_BINARY_INPUT;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Binary_Input_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len =
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == OBJECT_BINARY_INPUT);
ct_test(pTest, decoded_instance == instance);
decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
+4
View File
@@ -12,6 +12,10 @@ SRCS = bi.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(SRC_DIR)/datetime.c \
$(TEST_DIR)/ctest.c
TARGET = binary_input
+82 -78
View File
@@ -33,11 +33,11 @@
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "rp.h"
#include "wp.h"
#include "bo.h"
#include "handlers.h"
#define MAX_BINARY_OUTPUTS 6
/* When all the priorities are level null, the present value returns */
/* the Relinquish Default value */
#define RELINQUISH_DEFAULT BINARY_INACTIVE
@@ -159,7 +159,6 @@ static BACNET_BINARY_PV Binary_Output_Present_Value(
unsigned index = 0;
unsigned i = 0;
Binary_Output_Init();
index = Binary_Output_Instance_To_Index(object_instance);
if (index < MAX_BINARY_OUTPUTS) {
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
@@ -188,13 +187,8 @@ char *Binary_Output_Name(
}
/* return apdu len, or -1 on error */
int Binary_Output_Encode_Property_APDU(
uint8_t * apdu,
uint32_t object_instance,
BACNET_PROPERTY_ID property,
int32_t array_index,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
int Binary_Output_Read_Property(
BACNET_READ_PROPERTY_DATA *rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
@@ -205,20 +199,26 @@ int Binary_Output_Encode_Property_APDU(
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
Binary_Output_Init();
switch (property) {
if ((rpdata == NULL) ||
(rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_BINARY_OUTPUT,
object_instance);
rpdata->object_instance);
break;
/* note: Name and Description don't have to be the same.
You could make Description writable and different */
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string,
Binary_Output_Name(object_instance));
Binary_Output_Name(rpdata->object_instance));
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
@@ -227,7 +227,7 @@ int Binary_Output_Encode_Property_APDU(
encode_application_enumerated(&apdu[0], OBJECT_BINARY_OUTPUT);
break;
case PROP_PRESENT_VALUE:
present_value = Binary_Output_Present_Value(object_instance);
present_value = Binary_Output_Present_Value(rpdata->object_instance);
apdu_len = encode_application_enumerated(&apdu[0], present_value);
break;
case PROP_STATUS_FLAGS:
@@ -245,7 +245,7 @@ int Binary_Output_Encode_Property_APDU(
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
break;
case PROP_OUT_OF_SERVICE:
object_index = Binary_Output_Instance_To_Index(object_instance);
object_index = Binary_Output_Instance_To_Index(rpdata->object_instance);
state = Binary_Output_Out_Of_Service[object_index];
apdu_len = encode_application_boolean(&apdu[0], state);
break;
@@ -254,14 +254,14 @@ int Binary_Output_Encode_Property_APDU(
break;
case PROP_PRIORITY_ARRAY:
/* Array element zero is the number of elements in the array */
if (array_index == 0)
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 (array_index == BACNET_ARRAY_ALL) {
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
object_index =
Binary_Output_Instance_To_Index(object_instance);
Binary_Output_Instance_To_Index(rpdata->object_instance);
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
/* FIXME: check if we have room before adding it to APDU */
if (Binary_Output_Level[object_index][i] == BINARY_NULL)
@@ -276,29 +276,29 @@ int Binary_Output_Encode_Property_APDU(
if ((apdu_len + len) < MAX_APDU)
apdu_len += len;
else {
*error_class = ERROR_CLASS_SERVICES;
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = -1;
break;
}
}
} else {
object_index =
Binary_Output_Instance_To_Index(object_instance);
if (array_index <= BACNET_MAX_PRIORITY) {
if (Binary_Output_Level[object_index][array_index - 1] ==
Binary_Output_Instance_To_Index(rpdata->object_instance);
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
if (Binary_Output_Level[object_index][rpdata->array_index - 1] ==
BINARY_NULL)
apdu_len = encode_application_null(&apdu[apdu_len]);
else {
present_value =
Binary_Output_Level[object_index][array_index - 1];
Binary_Output_Level[object_index][rpdata->array_index - 1];
apdu_len =
encode_application_enumerated(&apdu[apdu_len],
present_value);
}
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = -1;
}
}
@@ -319,17 +319,17 @@ int Binary_Output_Encode_Property_APDU(
encode_application_character_string(&apdu[0], &char_string);
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(property != PROP_PRIORITY_ARRAY) &&
(array_index != BACNET_ARRAY_ALL)) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
(rpdata->object_property != PROP_PRIORITY_ARRAY) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = -1;
}
@@ -338,9 +338,7 @@ int Binary_Output_Encode_Property_APDU(
/* returns true if successful */
bool Binary_Output_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
@@ -349,12 +347,6 @@ bool Binary_Output_Write_Property(
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
Binary_Output_Init();
if (!Binary_Output_Valid_Instance(wp_data->object_instance)) {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
return false;
}
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
@@ -387,35 +379,45 @@ bool Binary_Output_Write_Property(
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
} else if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL, error_class, error_code) == true) {
level = BINARY_NULL;
object_index =
Binary_Output_Instance_To_Index(wp_data->object_instance);
priority = wp_data->priority;
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
priority--;
Binary_Output_Level[object_index][priority] = level;
/* Note: you could set the physical output here to the next
highest priority, or to the relinquish default if no
priorities are set.
However, if Out of Service is TRUE, then don't set the
physical output. This comment may apply to the
main loop (i.e. check out of service before changing output) */
status = true;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
} else {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_NULL,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
level = BINARY_NULL;
object_index =
Binary_Output_Instance_To_Index(wp_data->object_instance);
priority = wp_data->priority;
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
priority--;
Binary_Output_Level[object_index][priority] = level;
/* Note: you could set the physical output here to the next
highest priority, or to the relinquish default if no
priorities are set.
However, if Out of Service is TRUE, then don't set the
physical output. This comment may apply to the
main loop (i.e. check out of service before changing output) */
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
}
break;
case PROP_OUT_OF_SERVICE:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
object_index =
Binary_Output_Instance_To_Index(wp_data->object_instance);
Binary_Output_Out_Of_Service[object_index] =
@@ -423,8 +425,8 @@ bool Binary_Output_Write_Property(
}
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
@@ -444,23 +446,25 @@ void testBinaryOutput(
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_BINARY_OUTPUT;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
uint32_t instance = 123;
BACNET_ERROR_CLASS error_class;
BACNET_ERROR_CODE error_code;
BACNET_READ_PROPERTY_DATA rpdata;
len =
Binary_Output_Encode_Property_APDU(&apdu[0], instance,
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
Binary_Output_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_BINARY_OUTPUT;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Binary_Output_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len =
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == OBJECT_BINARY_OUTPUT);
ct_test(pTest, decoded_instance == instance);
decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
+82 -78
View File
@@ -34,10 +34,10 @@
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "rp.h"
#include "bv.h"
#include "handlers.h"
#define MAX_BINARY_VALUES 2
/* When all the priorities are level null, the present value returns */
/* the Relinquish Default value */
#define RELINQUISH_DEFAULT BINARY_INACTIVE
@@ -156,7 +156,6 @@ static BACNET_BINARY_PV Binary_Value_Present_Value(
unsigned index = 0;
unsigned i = 0;
Binary_Value_Init();
index = Binary_Value_Instance_To_Index(object_instance);
if (index < MAX_BINARY_VALUES) {
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
@@ -185,13 +184,8 @@ char *Binary_Value_Name(
}
/* return apdu len, or -1 on error */
int Binary_Value_Encode_Property_APDU(
uint8_t * apdu,
uint32_t object_instance,
BACNET_PROPERTY_ID property,
int32_t array_index,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
int Binary_Value_Read_Property(
BACNET_READ_PROPERTY_DATA *rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
@@ -201,20 +195,26 @@ int Binary_Value_Encode_Property_APDU(
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
Binary_Value_Init();
switch (property) {
if ((rpdata == NULL) ||
(rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE,
object_instance);
rpdata->object_instance);
break;
/* note: Name and Description don't have to be the same.
You could make Description writable and different */
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string,
Binary_Value_Name(object_instance));
Binary_Value_Name(rpdata->object_instance));
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
@@ -223,7 +223,7 @@ int Binary_Value_Encode_Property_APDU(
encode_application_enumerated(&apdu[0], OBJECT_BINARY_VALUE);
break;
case PROP_PRESENT_VALUE:
present_value = Binary_Value_Present_Value(object_instance);
present_value = Binary_Value_Present_Value(rpdata->object_instance);
apdu_len = encode_application_enumerated(&apdu[0], present_value);
break;
case PROP_STATUS_FLAGS:
@@ -241,19 +241,19 @@ int Binary_Value_Encode_Property_APDU(
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
break;
case PROP_OUT_OF_SERVICE:
object_index = Binary_Value_Instance_To_Index(object_instance);
object_index = Binary_Value_Instance_To_Index(rpdata->object_instance);
state = Binary_Value_Out_Of_Service[object_index];
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 (array_index == 0)
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 (array_index == BACNET_ARRAY_ALL) {
object_index = Binary_Value_Instance_To_Index(object_instance);
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
object_index = Binary_Value_Instance_To_Index(rpdata->object_instance);
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
/* FIXME: check if we have room before adding it to APDU */
if (Binary_Value_Level[object_index][i] == BINARY_NULL)
@@ -268,28 +268,28 @@ int Binary_Value_Encode_Property_APDU(
if ((apdu_len + len) < MAX_APDU)
apdu_len += len;
else {
*error_class = ERROR_CLASS_SERVICES;
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = -1;
break;
}
}
} else {
object_index = Binary_Value_Instance_To_Index(object_instance);
if (array_index <= BACNET_MAX_PRIORITY) {
if (Binary_Value_Level[object_index][array_index] ==
object_index = Binary_Value_Instance_To_Index(rpdata->object_instance);
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
if (Binary_Value_Level[object_index][rpdata->array_index] ==
BINARY_NULL)
apdu_len = encode_application_null(&apdu[apdu_len]);
else {
present_value =
Binary_Value_Level[object_index][array_index];
Binary_Value_Level[object_index][rpdata->array_index];
apdu_len =
encode_application_enumerated(&apdu[apdu_len],
present_value);
}
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = -1;
}
}
@@ -300,17 +300,17 @@ int Binary_Value_Encode_Property_APDU(
apdu_len = encode_application_enumerated(&apdu[0], present_value);
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(property != PROP_PRIORITY_ARRAY) &&
(array_index != BACNET_ARRAY_ALL)) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
(rpdata->object_property != PROP_PRIORITY_ARRAY) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = -1;
}
@@ -319,9 +319,7 @@ int Binary_Value_Encode_Property_APDU(
/* returns true if successful */
bool Binary_Value_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
@@ -330,12 +328,6 @@ bool Binary_Value_Write_Property(
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
Binary_Value_Init();
if (!Binary_Value_Valid_Instance(wp_data->object_instance)) {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
return false;
}
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
@@ -368,42 +360,52 @@ bool Binary_Value_Write_Property(
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
} else if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL, error_class, error_code) == true) {
level = BINARY_NULL;
object_index =
Binary_Value_Instance_To_Index(wp_data->object_instance);
priority = wp_data->priority;
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
priority--;
Binary_Value_Level[object_index][priority] = level;
/* Note: you could set the physical output here to the next
highest priority, or to the relinquish default if no
priorities are set.
However, if Out of Service is TRUE, then don't set the
physical output. This comment may apply to the
main loop (i.e. check out of service before changing output) */
status = true;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
} else {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_NULL,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
level = BINARY_NULL;
object_index =
Binary_Value_Instance_To_Index(wp_data->object_instance);
priority = wp_data->priority;
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
priority--;
Binary_Value_Level[object_index][priority] = level;
/* Note: you could set the physical output here to the next
highest priority, or to the relinquish default if no
priorities are set.
However, if Out of Service is TRUE, then don't set the
physical output. This comment may apply to the
main loop (i.e. check out of service before changing output) */
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
}
break;
case PROP_OUT_OF_SERVICE:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
object_index = Binary_Value_Instance_To_Index(wp_data->object_instance);
Binary_Value_Out_Of_Service[object_index] = value.type.Boolean;
}
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
@@ -423,23 +425,25 @@ void testBinary_Value(
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_BINARY_VALUE;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
uint32_t instance = 123;
BACNET_ERROR_CLASS error_class;
BACNET_ERROR_CODE error_code;
BACNET_READ_PROPERTY_DATA rpdata;
len =
Binary_Value_Encode_Property_APDU(&apdu[0], instance,
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
Binary_Value_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_BINARY_VALUE;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Binary_Value_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len =
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == OBJECT_BINARY_VALUE);
ct_test(pTest, decoded_instance == instance);
decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
+494 -126
View File
@@ -34,11 +34,24 @@
#include "config.h" /* the custom stuff */
#include "apdu.h"
#include "wp.h" /* write property handling */
#include "rp.h" /* read property handling */
#include "version.h"
#include "device.h" /* me */
#include "handlers.h"
#include "datalink.h"
#include "address.h"
/* include the objects */
#include "device.h"
#include "ai.h"
#include "ao.h"
#include "av.h"
#include "bi.h"
#include "bo.h"
#include "bv.h"
#include "lc.h"
#include "lsp.h"
#include "mso.h"
#include "trendlog.h"
#if defined(BACFILE)
#include "bacfile.h" /* object list dependency */
#endif
@@ -51,22 +64,279 @@
long int timezone;
#endif
static object_count_function Object_Count[MAX_BACNET_OBJECT_TYPE];
static object_index_to_instance_function
Object_Index_To_Instance[MAX_BACNET_OBJECT_TYPE];
static object_name_function Object_Name[MAX_BACNET_OBJECT_TYPE];
void Device_Object_Function_Set(
BACNET_OBJECT_TYPE object_type,
object_count_function count_function,
object_index_to_instance_function index_function,
object_name_function name_function)
static struct object_functions {
BACNET_OBJECT_TYPE Object_Type;
object_init_function Object_Init;
object_count_function Object_Count;
object_index_to_instance_function Object_Index_To_Instance;
object_valid_instance_function Object_Valid_Instance;
object_name_function Object_Name;
read_property_function Object_Read_Property;
write_property_function Object_Write_Property;
rpm_property_lists_function Object_RPM_List;
} Object_Table[] =
{
if (object_type < MAX_BACNET_OBJECT_TYPE) {
Object_Count[object_type] = count_function;
Object_Index_To_Instance[object_type] = index_function;
Object_Name[object_type] = name_function;
{OBJECT_DEVICE,
NULL,
Device_Count,
Device_Index_To_Instance,
Device_Valid_Object_Instance_Number,
Device_Name,
Device_Read_Property,
Device_Write_Property,
Device_Property_Lists},
{OBJECT_ANALOG_INPUT,
Analog_Input_Init,
Analog_Input_Count,
Analog_Input_Index_To_Instance,
Analog_Input_Valid_Instance,
Analog_Input_Name,
Analog_Input_Read_Property,
NULL,
Analog_Input_Property_Lists},
{OBJECT_ANALOG_OUTPUT,
Analog_Output_Init,
Analog_Output_Count,
Analog_Output_Index_To_Instance,
Analog_Output_Valid_Instance,
Analog_Output_Name,
Analog_Output_Read_Property,
Analog_Output_Write_Property,
Analog_Output_Property_Lists},
{OBJECT_ANALOG_VALUE,
Analog_Value_Init,
Analog_Value_Count,
Analog_Value_Index_To_Instance,
Analog_Value_Valid_Instance,
Analog_Value_Name,
Analog_Value_Read_Property,
Analog_Value_Write_Property,
Analog_Value_Property_Lists},
{OBJECT_BINARY_INPUT,
Binary_Input_Init,
Binary_Input_Count,
Binary_Input_Index_To_Instance,
Binary_Input_Valid_Instance,
Binary_Input_Name,
Binary_Input_Read_Property,
NULL,
Binary_Input_Property_Lists},
{OBJECT_BINARY_OUTPUT,
Binary_Output_Init,
Binary_Output_Count,
Binary_Output_Index_To_Instance,
Binary_Output_Valid_Instance,
Binary_Output_Name,
Binary_Output_Read_Property,
Binary_Output_Write_Property,
Binary_Output_Property_Lists},
{OBJECT_BINARY_VALUE,
Binary_Value_Init,
Binary_Value_Count,
Binary_Value_Index_To_Instance,
Binary_Value_Valid_Instance,
Binary_Value_Name,
Binary_Value_Read_Property,
Binary_Value_Write_Property,
Binary_Value_Property_Lists},
{OBJECT_LIFE_SAFETY_POINT,
Life_Safety_Point_Init,
Life_Safety_Point_Count,
Life_Safety_Point_Index_To_Instance,
Life_Safety_Point_Valid_Instance,
Life_Safety_Point_Name,
Life_Safety_Point_Read_Property,
Life_Safety_Point_Write_Property,
Life_Safety_Point_Property_Lists},
{OBJECT_LOAD_CONTROL,
Load_Control_Init,
Load_Control_Count,
Load_Control_Index_To_Instance,
Load_Control_Valid_Instance,
Load_Control_Name,
Load_Control_Read_Property,
Load_Control_Write_Property,
Load_Control_Property_Lists},
{OBJECT_MULTI_STATE_OUTPUT,
Multistate_Output_Init,
Multistate_Output_Count,
Multistate_Output_Index_To_Instance,
Multistate_Output_Valid_Instance,
Multistate_Output_Name,
Multistate_Output_Read_Property,
Multistate_Output_Write_Property,
Multistate_Output_Property_Lists},
{OBJECT_TRENDLOG,
Trend_Log_Init,
Trend_Log_Count,
Trend_Log_Index_To_Instance,
Trend_Log_Valid_Instance,
Trend_Log_Name,
Trend_Log_Read_Property,
Trend_Log_Write_Property,
Trend_Log_Property_Lists},
#if defined(BACFILE)
{OBJECT_FILE,
bacfile_init,
bacfile_count,
bacfile_index_to_instance,
bacfile_valid_instance,
bacfile_name,
bacfile_read_property,
bacfile_write_property,
BACfile_Property_Lists},
#endif
{-1, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
};
/* Encodes the property APDU and returns the length,
or sets the error, and returns -1 */
int Device_Objects_Read_Property(
BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = -1;
unsigned index = 0;
struct object_functions *pObject = NULL;
bool found = false;
/* initialize the default return values */
rpdata->error_class = ERROR_CLASS_OBJECT;
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
pObject = &Object_Table[0];
while (pObject->Object_Type != -1) {
/* handle each object type */
if (pObject->Object_Type == rpdata->object_type) {
found = true;
if (pObject->Object_Valid_Instance &&
pObject->Object_Valid_Instance(rpdata->object_instance)) {
if (pObject->Object_Read_Property) {
apdu_len = pObject->Object_Read_Property(rpdata);
}
} else {
rpdata->error_class = ERROR_CLASS_OBJECT;
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
}
break;
}
index++;
pObject = &Object_Table[index];
}
if (!found) {
rpdata->error_class = ERROR_CLASS_OBJECT;
rpdata->error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE;
}
return apdu_len;
}
bool Device_Objects_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
int apdu_len = -1;
unsigned index = 0;
struct object_functions *pObject = NULL;
bool found = false;
/* initialize the default return values */
wp_data->error_class = ERROR_CLASS_OBJECT;
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
pObject = &Object_Table[0];
while (pObject->Object_Type != -1) {
/* handle each object type */
if (pObject->Object_Type == wp_data->object_type) {
found = true;
if (pObject->Object_Valid_Instance &&
pObject->Object_Valid_Instance(wp_data->object_instance)) {
if (pObject->Object_Write_Property) {
apdu_len = pObject->Object_Write_Property(wp_data);
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
}
} else {
wp_data->error_class = ERROR_CLASS_OBJECT;
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
}
break;
}
index++;
pObject = &Object_Table[index];
}
if (!found) {
wp_data->error_class = ERROR_CLASS_OBJECT;
wp_data->error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE;
}
return apdu_len;
}
static unsigned property_list_count(
const int *pList)
{
unsigned property_count = 0;
if (pList) {
while (*pList != -1) {
property_count++;
pList++;
}
}
return property_count;
}
/* for a given object type, returns the special property list */
static void Device_Objects_Property_List(
BACNET_OBJECT_TYPE object_type,
struct special_property_list_t *pPropertyList)
{
rpm_property_lists_function object_property_list = NULL;
unsigned index = 0;
struct object_functions *pObject = NULL;
bool found = false;
pPropertyList->Required.pList = NULL;
pPropertyList->Optional.pList = NULL;
pPropertyList->Proprietary.pList = NULL;
pObject = &Object_Table[0];
while (pObject->Object_Type != -1) {
/* handle each object type */
if (pObject->Object_Type == object_type) {
found = true;
object_property_list = pObject->Object_RPM_List;
break;
}
index++;
pObject = &Object_Table[index];
}
if (found && object_property_list) {
object_property_list(
&pPropertyList->Required.pList,
&pPropertyList->Optional.pList,
&pPropertyList->Proprietary.pList);
}
/* fill the count */
if (pPropertyList->Required.pList) {
pPropertyList->Required.count =
property_list_count(pPropertyList->Required.pList);
} else {
pPropertyList->Required.count = 0;
}
if (pPropertyList->Optional.pList) {
pPropertyList->Optional.count =
property_list_count(pPropertyList->Optional.pList);
} else {
pPropertyList->Optional.count = 0;
}
if (pPropertyList->Proprietary.pList) {
pPropertyList->Proprietary.count =
property_list_count(pPropertyList->Proprietary.pList);
} else {
pPropertyList->Proprietary.count = 0;
}
return;
}
/* These three arrays are used by the ReadPropertyMultiple handler */
@@ -184,6 +454,17 @@ static uint32_t Database_Revision = 0;
/* Slave_Address_Binding */
/* Profile_Name */
unsigned Device_Count(void)
{
return 1;
}
uint32_t Device_Index_To_Instance(
unsigned index)
{
return Object_Instance_Number;
}
/* methods to manipulate the data */
uint32_t Device_Object_Instance_Number(
void)
@@ -215,6 +496,16 @@ bool Device_Valid_Object_Instance_Number(
(object_id == BACNET_MAX_INSTANCE));
}
char *Device_Name(
uint32_t object_instance)
{
if (object_instance == Object_Instance_Number) {
return My_Object_Name;
}
return NULL;
}
const char *Device_Object_Name(
void)
{
@@ -469,13 +760,18 @@ void Device_Inc_Database_Revision(
unsigned Device_Object_List_Count(
void)
{
unsigned count = 1; /* 1 for the device object */
unsigned i = 0; /* loop counter */
unsigned count = 0; /* number of objects */
unsigned index = 0; /* loop counter */
struct object_functions *pObject = NULL;
for (i = 0; i < MAX_BACNET_OBJECT_TYPE; i++) {
if (Object_Count[i]) {
count += Object_Count[i] ();
/* initialize the default return values */
pObject = &Object_Table[0];
while (pObject->Object_Type != -1) {
if (pObject->Object_Count) {
count += pObject->Object_Count();
}
index++;
pObject = &Object_Table[index];
}
return count;
@@ -487,38 +783,32 @@ bool Device_Object_List_Identifier(
uint32_t * instance)
{
bool status = false;
unsigned object_index = 0;
unsigned count = 0;
unsigned i = 0; /* loop counter */
unsigned object_index = 0;
unsigned index = 0; /* loop counter */
struct object_functions *pObject = NULL;
/* array index zero is length - so invalid */
if (array_index == 0) {
return status;
}
/* device object */
if (array_index == 1) {
*object_type = OBJECT_DEVICE;
*instance = Object_Instance_Number;
status = true;
}
if (!status) {
/* array index starts at 1, and if we are this far,
we are not the device object, so array_index must
be at least 2. */
object_index = array_index - 2;
/* look through the objects to find the right index */
for (i = 0; i < MAX_BACNET_OBJECT_TYPE; i++) {
if (Object_Count[i] && Object_Index_To_Instance[i]) {
object_index -= count;
count = Object_Count[i] ();
if (object_index < count) {
*object_type = i;
*instance = Object_Index_To_Instance[i] (object_index);
status = true;
break;
}
object_index = array_index - 1;
/* initialize the default return values */
pObject = &Object_Table[0];
while (pObject->Object_Type != -1) {
if (pObject->Object_Count &&
pObject->Object_Index_To_Instance) {
object_index -= count;
count = pObject->Object_Count();
if (object_index < count) {
*object_type = pObject->Object_Type;
*instance = pObject->Object_Index_To_Instance(object_index);
status = true;
break;
}
}
index++;
pObject = &Object_Table[index];
}
return status;
@@ -563,20 +853,20 @@ char *Device_Valid_Object_Id(
uint32_t object_instance)
{
char *name = NULL; /* return value */
object_name_function name_function = NULL;
unsigned index = 0; /* loop counter */
struct object_functions *pObject = NULL;
if (object_type < MAX_BACNET_OBJECT_TYPE) {
name_function = Object_Name[object_type];
}
if (name_function) {
name = name_function(object_instance);
} else {
if ((object_type == OBJECT_DEVICE) &&
(object_instance == Object_Instance_Number)) {
name = My_Object_Name;
pObject = &Object_Table[0];
while (pObject->Object_Type != -1) {
if ((pObject->Object_Type == object_type) &&
(pObject->Object_Name)) {
name = pObject->Object_Name(object_instance);
break;
}
index++;
pObject = &Object_Table[index];
}
return name;
}
@@ -647,13 +937,8 @@ int tm_isdst Daylight Savings flag.
/* return the length of the apdu encoded or -1 for error or
-2 for abort message */
int Device_Encode_Property_APDU(
uint8_t * apdu,
uint32_t object_instance,
BACNET_PROPERTY_ID property,
int32_t array_index,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
int Device_Read_Property(
BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
int len = 0; /* apdu len intermediate value */
@@ -663,9 +948,17 @@ int Device_Encode_Property_APDU(
int object_type = 0;
uint32_t instance = 0;
unsigned count = 0;
uint8_t *apdu = NULL;
struct object_functions *pObject = NULL;
bool found = false;
object_instance = object_instance;
switch (property) {
if ((rpdata == NULL) ||
(rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_DEVICE,
@@ -763,28 +1056,38 @@ int Device_Encode_Property_APDU(
not a list of objects that this device can access */
bitstring_init(&bit_string);
for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) {
if ((i == OBJECT_DEVICE) || Object_Count[i]) {
bitstring_set_bit(&bit_string, i, true);
} else {
/* initialize all the object types to not-supported */
bitstring_set_bit(&bit_string, (uint8_t) i, false);
/* initialize all the object types to not-supported */
bitstring_set_bit(&bit_string, (uint8_t) i, false);
}
/* set the object types with objects to supported */
i = 0;
pObject = &Object_Table[i];
while (pObject->Object_Type != -1) {
if ((pObject->Object_Count) &&
(pObject->Object_Count() > 0)) {
bitstring_set_bit(&bit_string, pObject->Object_Type, true);
}
i++;
pObject = &Object_Table[i];
}
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_OBJECT_LIST:
count = Device_Object_List_Count();
/* Array element zero is the number of objects in the list */
if (array_index == 0)
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 (array_index == BACNET_ARRAY_ALL) {
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) {
if (Device_Object_List_Identifier(i, &object_type,
&instance)) {
found = Device_Object_List_Identifier(
i,
&object_type,
&instance);
if (found) {
len =
encode_application_object_id(&apdu[apdu_len],
object_type, instance);
@@ -798,21 +1101,24 @@ int Device_Encode_Property_APDU(
}
} else {
/* error: internal error? */
*error_class = ERROR_CLASS_SERVICES;
*error_code = ERROR_CODE_OTHER;
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_OTHER;
apdu_len = -1;
break;
}
}
} else {
if (Device_Object_List_Identifier(array_index, &object_type,
&instance))
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 {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = -1;
}
}
@@ -855,17 +1161,17 @@ int Device_Encode_Property_APDU(
apdu_len = handler_cov_encode_subscriptions(&apdu[0], MAX_APDU);
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(property != PROP_OBJECT_LIST) &&
(array_index != BACNET_ARRAY_ALL)) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
(rpdata->object_property != PROP_OBJECT_LIST) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = -1;
}
@@ -874,20 +1180,13 @@ int Device_Encode_Property_APDU(
/* returns true if successful */
bool Device_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
int temp;
if (!Device_Valid_Object_Instance_Number(wp_data->object_instance)) {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
return false;
}
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
@@ -896,96 +1195,149 @@ bool Device_Write_Property(
/* FIXME: len == 0: unable to decode? */
switch (wp_data->object_property) {
case PROP_OBJECT_IDENTIFIER:
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_OBJECT_ID, error_class, error_code) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_OBJECT_ID,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
if ((value.type.Object_Id.type == OBJECT_DEVICE) &&
(Device_Set_Object_Instance_Number(value.type.Object_Id.instance))) {
/* FIXME: we could send an I-Am broadcast to let the world know */
status = true;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
break;
case PROP_NUMBER_OF_APDU_RETRIES:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
/* FIXME: bounds check? */
apdu_retries_set((uint8_t) value.type.Unsigned_Int);
}
break;
case PROP_APDU_TIMEOUT:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
/* FIXME: bounds check? */
apdu_timeout_set((uint16_t) value.type.Unsigned_Int);
}
break;
case PROP_VENDOR_IDENTIFIER:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
/* FIXME: bounds check? */
Device_Set_Vendor_Identifier((uint16_t) value.type.Unsigned_Int);
Device_Set_Vendor_Identifier((uint16_t) value.
type.Unsigned_Int);
}
break;
case PROP_SYSTEM_STATUS:
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED, error_class, error_code) == true) {
temp = Device_Set_System_Status((BACNET_DEVICE_STATUS) value.type.Enumerated, false);
if(temp == 0)
status = true;
else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = temp == -1 ? ERROR_CODE_VALUE_OUT_OF_RANGE : ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_ENUMERATED,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
temp = Device_Set_System_Status((BACNET_DEVICE_STATUS)
value.type.Enumerated, false);
if (temp != 0) {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
if (temp == -1) {
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
} else {
wp_data->error_code = ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
}
}
}
break;
case PROP_OBJECT_NAME:
if((status = WPValidateString(&value, MAX_DEV_LOC_LEN, false, error_class, error_code)) == true)
status = WPValidateString(&value,
MAX_DEV_LOC_LEN,
false,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
Device_Set_Object_Name(characterstring_value(&value.type.Character_String), characterstring_length(&value.type.Character_String));
}
break;
case PROP_LOCATION:
if((status = WPValidateString(&value, MAX_DEV_LOC_LEN, true, error_class, error_code)) == true)
status = WPValidateString(&value,
MAX_DEV_LOC_LEN,
true,
&wp_data->error_class, &wp_data->error_code);
if (status) {
Device_Set_Location(characterstring_value(&value.type.Character_String), characterstring_length(&value.type.Character_String));
}
break;
case PROP_DESCRIPTION:
if((status = WPValidateString(&value, MAX_DEV_DESC_LEN, true, error_class, error_code)) == true)
status = WPValidateString(&value,
MAX_DEV_DESC_LEN,
true,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
Device_Set_Description(characterstring_value(&value.type.Character_String), characterstring_length(&value.type.Character_String));
}
break;
case PROP_MODEL_NAME:
if((status = WPValidateString(&value, MAX_DEV_MOD_LEN, true, error_class, error_code)) == true)
status = WPValidateString(&value,
MAX_DEV_MOD_LEN,
true,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
Device_Set_Model_Name(characterstring_value(&value.type.Character_String), characterstring_length(&value.type.Character_String));
}
break;
#if defined(BACDL_MSTP)
case PROP_MAX_INFO_FRAMES:
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
if (value.type.Unsigned_Int <= 255) {
dlmstp_set_max_info_frames((uint8_t) value.
type.Unsigned_Int);
status = true;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
break;
case PROP_MAX_MASTER:
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
if ((value.type.Unsigned_Int > 0) &&
(value.type.Unsigned_Int <= 127)) {
dlmstp_set_max_master((uint8_t) value.type.Unsigned_Int);
status = true;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
break;
#endif
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
@@ -995,6 +1347,22 @@ bool Device_Write_Property(
void Device_Init(
void)
{
unsigned index = 0; /* loop counter */
struct object_functions *pObject = NULL;
handler_read_property_function_set(Device_Objects_Read_Property);
handler_rpm_function_set(Device_Objects_Read_Property);
handler_rpm_list_set(Device_Objects_Property_List);
handler_write_property_function_set(Device_Objects_Write_Property);
pObject = &Object_Table[0];
while (pObject->Object_Type != -1) {
if (pObject->Object_Init) {
pObject->Object_Init();
}
index++;
pObject = &Object_Table[index];
}
}
bool DeviceGetRRInfo(
+124 -109
View File
@@ -136,9 +136,6 @@ static float Shed_Level_Values[MAX_SHED_LEVELS] = {
};
/* we need to have our arrays initialized before answering any calls */
static bool Load_Control_Initialized = false;
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Load_Control_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
@@ -189,29 +186,26 @@ void Load_Control_Init(
{
unsigned i, j;
if (!Load_Control_Initialized) {
Load_Control_Initialized = true;
for (i = 0; i < MAX_LOAD_CONTROLS; i++) {
/* FIXME: load saved data? */
Present_Value[i] = BACNET_SHED_INACTIVE;
Requested_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL;
Requested_Shed_Level[i].value.level = 0;
datetime_wildcard_set(&Start_Time[i]);
datetime_wildcard_set(&End_Time[i]);
datetime_wildcard_set(&Current_Time);
Shed_Duration[i] = 0;
Duty_Window[i] = 0;
Load_Control_Enable[i] = true;
Full_Duty_Baseline[i] = 1.500; /* kilowatts */
Expected_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL;
Expected_Shed_Level[i].value.level = 0;
Actual_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL;
Actual_Shed_Level[i].value.level = 0;
Load_Control_Request_Written[i] = false;
Start_Time_Property_Written[i] = false;
for (j = 0; j < MAX_SHED_LEVELS; j++) {
Shed_Levels[i][j] = j + 1;
}
for (i = 0; i < MAX_LOAD_CONTROLS; i++) {
/* FIXME: load saved data? */
Present_Value[i] = BACNET_SHED_INACTIVE;
Requested_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL;
Requested_Shed_Level[i].value.level = 0;
datetime_wildcard_set(&Start_Time[i]);
datetime_wildcard_set(&End_Time[i]);
datetime_wildcard_set(&Current_Time);
Shed_Duration[i] = 0;
Duty_Window[i] = 0;
Load_Control_Enable[i] = true;
Full_Duty_Baseline[i] = 1.500; /* kilowatts */
Expected_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL;
Expected_Shed_Level[i].value.level = 0;
Actual_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL;
Actual_Shed_Level[i].value.level = 0;
Load_Control_Request_Written[i] = false;
Start_Time_Property_Written[i] = false;
for (j = 0; j < MAX_SHED_LEVELS; j++) {
Shed_Levels[i][j] = j + 1;
}
}
@@ -224,7 +218,6 @@ void Load_Control_Init(
bool Load_Control_Valid_Instance(
uint32_t object_instance)
{
Load_Control_Init();
if (object_instance < MAX_LOAD_CONTROLS)
return true;
@@ -236,7 +229,6 @@ bool Load_Control_Valid_Instance(
unsigned Load_Control_Count(
void)
{
Load_Control_Init();
return MAX_LOAD_CONTROLS;
}
@@ -246,7 +238,6 @@ unsigned Load_Control_Count(
uint32_t Load_Control_Index_To_Instance(
unsigned index)
{
Load_Control_Init();
return index;
}
@@ -258,7 +249,6 @@ unsigned Load_Control_Instance_To_Index(
{
unsigned index = MAX_LOAD_CONTROLS;
Load_Control_Init();
if (object_instance < MAX_LOAD_CONTROLS)
index = object_instance;
@@ -271,7 +261,6 @@ static BACNET_SHED_STATE Load_Control_Present_Value(
BACNET_SHED_STATE value = BACNET_SHED_INACTIVE;
unsigned index = 0;
Load_Control_Init();
index = Load_Control_Instance_To_Index(object_instance);
if (index < MAX_LOAD_CONTROLS) {
value = Present_Value[index];
@@ -666,7 +655,6 @@ void Load_Control_State_Machine_Handler(
unsigned i = 0;
static bool initialized = false;
Load_Control_Init();
if (!initialized) {
initialized = true;
for (i = 0; i < MAX_LOAD_CONTROLS; i++) {
@@ -689,13 +677,8 @@ void Load_Control_State_Machine_Handler(
}
/* return apdu len, or -1 on error */
int Load_Control_Encode_Property_APDU(
uint8_t * apdu,
uint32_t object_instance,
BACNET_PROPERTY_ID property,
int32_t array_index,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
int Load_Control_Read_Property(
BACNET_READ_PROPERTY_DATA *rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
@@ -705,19 +688,25 @@ int Load_Control_Encode_Property_APDU(
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
Load_Control_Init();
object_index = Load_Control_Instance_To_Index(object_instance);
switch (property) {
if ((rpdata == NULL) ||
(rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index = Load_Control_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_LOAD_CONTROL,
object_instance);
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string,
Load_Control_Name(object_instance));
Load_Control_Name(rpdata->object_instance));
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
@@ -726,7 +715,7 @@ int Load_Control_Encode_Property_APDU(
encode_application_enumerated(&apdu[0], OBJECT_LOAD_CONTROL);
break;
case PROP_PRESENT_VALUE:
enumeration = Load_Control_Present_Value(object_instance);
enumeration = Load_Control_Present_Value(rpdata->object_instance);
apdu_len = encode_application_enumerated(&apdu[0], enumeration);
break;
case PROP_STATUS_FLAGS:
@@ -841,12 +830,12 @@ int Load_Control_Encode_Property_APDU(
break;
case PROP_SHED_LEVELS:
/* Array element zero is the number of elements in the array */
if (array_index == 0)
if (rpdata->array_index == 0)
apdu_len =
encode_application_unsigned(&apdu[0], MAX_SHED_LEVELS);
/* if no index was specified, then try to encode the entire list */
/* into one packet. */
else if (array_index == BACNET_ARRAY_ALL) {
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
apdu_len = 0;
for (i = 0; i < MAX_SHED_LEVELS; i++) {
/* FIXME: check if we have room before adding it to APDU */
@@ -857,32 +846,32 @@ int Load_Control_Encode_Property_APDU(
if ((apdu_len + len) < MAX_APDU)
apdu_len += len;
else {
*error_class = ERROR_CLASS_SERVICES;
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = -1;
break;
}
}
} else {
if (array_index <= MAX_SHED_LEVELS) {
if (rpdata->array_index <= MAX_SHED_LEVELS) {
apdu_len =
encode_application_unsigned(&apdu[0],
Shed_Levels[object_index][array_index - 1]);
Shed_Levels[object_index][rpdata->array_index - 1]);
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = -1;
}
}
break;
case PROP_SHED_LEVEL_DESCRIPTIONS:
/* Array element zero is the number of elements in the array */
if (array_index == 0)
if (rpdata->array_index == 0)
apdu_len =
encode_application_unsigned(&apdu[0], MAX_SHED_LEVELS);
/* if no index was specified, then try to encode the entire list */
/* into one packet. */
else if (array_index == BACNET_ARRAY_ALL) {
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
apdu_len = 0;
for (i = 0; i < MAX_SHED_LEVELS; i++) {
/* FIXME: check if we have room before adding it to APDU */
@@ -895,39 +884,39 @@ int Load_Control_Encode_Property_APDU(
if ((apdu_len + len) < MAX_APDU)
apdu_len += len;
else {
*error_class = ERROR_CLASS_SERVICES;
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = -1;
break;
}
}
} else {
if (array_index <= MAX_SHED_LEVELS) {
if (rpdata->array_index <= MAX_SHED_LEVELS) {
characterstring_init_ansi(&char_string,
Shed_Level_Descriptions[array_index - 1]);
Shed_Level_Descriptions[rpdata->array_index - 1]);
apdu_len =
encode_application_character_string(&apdu[0],
&char_string);
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = -1;
}
}
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(property != PROP_SHED_LEVEL_DESCRIPTIONS) &&
(property != PROP_SHED_LEVELS) &&
(array_index != BACNET_ARRAY_ALL)) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
(rpdata->object_property != PROP_SHED_LEVEL_DESCRIPTIONS) &&
(rpdata->object_property != PROP_SHED_LEVELS) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = -1;
}
@@ -936,9 +925,7 @@ int Load_Control_Encode_Property_APDU(
/* returns true if successful */
bool Load_Control_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
@@ -946,12 +933,6 @@ bool Load_Control_Write_Property(
BACNET_APPLICATION_DATA_VALUE value;
BACNET_DATE TempDate; /* build here in case of error in time half of datetime */
Load_Control_Init();
if (!Load_Control_Valid_Instance(wp_data->object_instance)) {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
return false;
}
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
@@ -988,8 +969,8 @@ bool Load_Control_Write_Property(
status = true;
} else {
/* error! */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
}
if (status) {
Load_Control_Request_Written[object_index] = true;
@@ -997,65 +978,96 @@ bool Load_Control_Write_Property(
break;
case PROP_START_TIME:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_DATE, error_class, error_code)) == false)
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_DATE,
&wp_data->error_class,
&wp_data->error_code);
if (!status) {
/* don't continue if we don't have a valid date */
break;
}
/* Hold the date until we are sure the time is also there */
TempDate = value.type.Date;
len = bacapp_decode_application_data(wp_data->application_data + len,
wp_data->application_data_len - len, &value);
if (len && ((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_TIME, error_class, error_code)) == true)) {
/* Write time and date and set written flag */
Start_Time[object_index].date = TempDate;
Start_Time[object_index].time = value.type.Time;
Start_Time_Property_Written[object_index] = true;
if (len) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_TIME,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
/* Write time and date and set written flag */
Start_Time[object_index].date = TempDate;
Start_Time[object_index].time = value.type.Time;
Start_Time_Property_Written[object_index] = true;
}
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
break;
case PROP_SHED_DURATION:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
Shed_Duration[object_index] = value.type.Unsigned_Int;
Load_Control_Request_Written[object_index] = true;
}
break;
case PROP_DUTY_WINDOW:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
Duty_Window[object_index] = value.type.Unsigned_Int;
Load_Control_Request_Written[object_index] = true;
}
break;
case PROP_SHED_LEVELS:
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
/* re-write the size of the array? */
if (wp_data->array_index == 0) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
status = false;
} else if (wp_data->array_index == BACNET_ARRAY_ALL) {
/* FIXME: write entire array */
status = true;
} else if (wp_data->array_index <= MAX_SHED_LEVELS) {
Shed_Levels[object_index][wp_data->array_index - 1] =
value.type.Unsigned_Int;
status = true;
} else {
/* FIXME: Something's missing from here so I'll just put in
* a place holder error here for the moment*/
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_OTHER;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_OTHER;
status = false;
}
}
break;
case PROP_ENABLE:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code)) == true)
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
Load_Control_Enable[object_index] = value.type.Boolean;
}
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
@@ -1456,22 +1468,25 @@ void testLoadControl(
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_LOAD_CONTROL;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
uint32_t instance = 123;
BACNET_ERROR_CLASS error_class;
BACNET_ERROR_CODE error_code;
BACNET_READ_PROPERTY_DATA rpdata;
len =
Load_Control_Encode_Property_APDU(&apdu[0], instance,
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
Load_Control_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_LOAD_CONTROL;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Load_Control_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len =
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == OBJECT_LOAD_CONTROL);
ct_test(pTest, decoded_instance == instance);
decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
+96 -104
View File
@@ -38,8 +38,13 @@
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "rp.h"
#include "wp.h"
<<<<<<< .mine
#include "lo.h"
=======
#include "handlers.h"
>>>>>>> .r1574
#define MAX_LIGHTING_OUTPUTS 5
@@ -79,8 +84,6 @@ static bool Lighting_Output_Out_Of_Service[MAX_LIGHTING_OUTPUTS];
/* the lighting command is what we are doing */
static uint8_t Lighting_Command_Priority = 16;
static BACNET_LIGHTING_COMMAND Lighting_Command[MAX_LIGHTING_OUTPUTS];
/* we need to have our arrays initialized before answering any calls */
static bool Lighting_Output_Initialized = false;
int Lighting_Output_Encode_Lighting_Command(
uint8_t * apdu,
@@ -136,13 +139,8 @@ int Lighting_Output_Decode_Lighting_Command(
{
int len = 0;
int apdu_len = 0;
int tag_len = 0;
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
int type = 0; /* for decoding */
int property = 0; /* for decoding */
uint32_t unsigned_value = 0;
int i = 0; /* loop counter */
float real_value = 0.0;
/* check for value pointers */
@@ -183,20 +181,16 @@ void Lighting_Output_Init(
{
unsigned i, j;
if (!Lighting_Output_Initialized) {
Lighting_Output_Initialized = true;
/* initialize all the analog output priority arrays to NULL */
for (i = 0; i < MAX_LIGHTING_OUTPUTS; i++) {
for (j = 0; j < BACNET_MAX_PRIORITY; j++) {
Lighting_Output_Level[i][j] = LIGHTING_LEVEL_NULL;
}
Lighting_Command[i].operation = BACNET_LIGHTS_STOP;
Lighting_Output_Out_Of_Service[i] = false;
Lighting_Output_Progress[i] = LIGHTING_RELINQUISH_DEFAULT;
Lighting_Output_Min_Present_Value[i] = 0;
Lighting_Output_Max_Present_Value[i] = 100;
/* initialize all the analog output priority arrays to NULL */
for (i = 0; i < MAX_LIGHTING_OUTPUTS; i++) {
for (j = 0; j < BACNET_MAX_PRIORITY; j++) {
Lighting_Output_Level[i][j] = LIGHTING_LEVEL_NULL;
}
Lighting_Command[i].operation = BACNET_LIGHTS_STOP;
Lighting_Output_Out_Of_Service[i] = false;
Lighting_Output_Progress[i] = LIGHTING_RELINQUISH_DEFAULT;
Lighting_Output_Min_Present_Value[i] = 0;
Lighting_Output_Max_Present_Value[i] = 100;
}
return;
@@ -208,7 +202,6 @@ void Lighting_Output_Init(
bool Lighting_Output_Valid_Instance(
uint32_t object_instance)
{
Lighting_Output_Init();
if (object_instance < MAX_LIGHTING_OUTPUTS)
return true;
@@ -220,7 +213,6 @@ bool Lighting_Output_Valid_Instance(
unsigned Lighting_Output_Count(
void)
{
Lighting_Output_Init();
return MAX_LIGHTING_OUTPUTS;
}
@@ -230,7 +222,6 @@ unsigned Lighting_Output_Count(
uint32_t Lighting_Output_Index_To_Instance(
unsigned index)
{
Lighting_Output_Init();
return index;
}
@@ -242,7 +233,6 @@ unsigned Lighting_Output_Instance_To_Index(
{
unsigned index = MAX_LIGHTING_OUTPUTS;
Lighting_Output_Init();
if (object_instance < MAX_LIGHTING_OUTPUTS)
index = object_instance;
@@ -256,7 +246,6 @@ float Lighting_Output_Present_Value(
unsigned index = 0;
unsigned i = 0;
Lighting_Output_Init();
index = Lighting_Output_Instance_To_Index(object_instance);
if (index < MAX_LIGHTING_OUTPUTS) {
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
@@ -277,7 +266,6 @@ unsigned Lighting_Output_Present_Value_Priority(
unsigned i = 0; /* loop counter */
unsigned priority = 0; /* return value */
Lighting_Output_Init();
index = Lighting_Output_Instance_To_Index(object_instance);
if (index < MAX_LIGHTING_OUTPUTS) {
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
@@ -349,7 +337,6 @@ float Lighting_Output_Progress_Value(
float value = LIGHTING_RELINQUISH_DEFAULT;
unsigned index = 0;
Lighting_Output_Init();
index = Lighting_Output_Instance_To_Index(object_instance);
if (index < MAX_LIGHTING_OUTPUTS) {
value = Lighting_Output_Progress[index];
@@ -373,13 +360,8 @@ char *Lighting_Output_Name(
}
/* return apdu len, or -1 on error */
int Lighting_Output_Encode_Property_APDU(
uint8_t * apdu,
uint32_t object_instance,
BACNET_PROPERTY_ID property,
int32_t array_index,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
int Lighting_Output_Read_Property(
BACNET_READ_PROPERTY_DATA *rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
@@ -389,20 +371,26 @@ int Lighting_Output_Encode_Property_APDU(
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
Lighting_Output_Init();
switch (property) {
if ((rpdata == NULL) ||
(rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_LIGHTING_OUTPUT,
object_instance);
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
/* object name must be unique in this device. */
/* FIXME: description could be writable and different than object name */
characterstring_init_ansi(&char_string,
Lighting_Output_Name(object_instance));
Lighting_Output_Name(rpdata->object_instance));
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
@@ -412,17 +400,17 @@ int Lighting_Output_Encode_Property_APDU(
OBJECT_LIGHTING_OUTPUT);
break;
case PROP_PRESENT_VALUE:
real_value = Lighting_Output_Present_Value(object_instance);
real_value = Lighting_Output_Present_Value(rpdata->object_instance);
apdu_len = encode_application_real(&apdu[0], real_value);
break;
case PROP_PROGRESS_VALUE:
real_value = Lighting_Output_Progress_Value(object_instance);
real_value = Lighting_Output_Progress_Value(rpdata->object_instance);
apdu_len = encode_application_real(&apdu[0], real_value);
break;
case PROP_LIGHTING_COMMAND:
apdu_len =
Lighting_Output_Encode_Lighting_Command(&apdu[0],
&Lighting_Command[object_instance]);
&Lighting_Command[rpdata->object_instance]);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
@@ -437,7 +425,7 @@ int Lighting_Output_Encode_Property_APDU(
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
break;
case PROP_OUT_OF_SERVICE:
object_index = Lighting_Output_Instance_To_Index(object_instance);
object_index = Lighting_Output_Instance_To_Index(rpdata->object_instance);
state = Lighting_Output_Out_Of_Service[object_index];
apdu_len = encode_application_boolean(&apdu[0], state);
break;
@@ -446,14 +434,14 @@ int Lighting_Output_Encode_Property_APDU(
break;
case PROP_PRIORITY_ARRAY:
/* Array element zero is the number of elements in the array */
if (array_index == 0)
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 (array_index == BACNET_ARRAY_ALL) {
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
object_index =
Lighting_Output_Instance_To_Index(object_instance);
Lighting_Output_Instance_To_Index(rpdata->object_instance);
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
/* FIXME: check if we have room before adding it to APDU */
if (Lighting_Output_Level[object_index][i] ==
@@ -469,29 +457,29 @@ int Lighting_Output_Encode_Property_APDU(
if ((apdu_len + len) < MAX_APDU)
apdu_len += len;
else {
*error_class = ERROR_CLASS_SERVICES;
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = -1;
break;
}
}
} else {
object_index =
Lighting_Output_Instance_To_Index(object_instance);
if (array_index <= BACNET_MAX_PRIORITY) {
if (Lighting_Output_Level[object_index][array_index - 1] ==
Lighting_Output_Instance_To_Index(rpdata->object_instance);
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
if (Lighting_Output_Level[object_index][rpdata->array_index - 1] ==
LIGHTING_LEVEL_NULL)
apdu_len = encode_application_null(&apdu[0]);
else {
real_value =
Lighting_Output_Level[object_index][array_index -
Lighting_Output_Level[object_index][rpdata->array_index -
1];
apdu_len =
encode_application_real(&apdu[0], real_value);
}
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = -1;
}
}
@@ -502,17 +490,17 @@ int Lighting_Output_Encode_Property_APDU(
apdu_len = encode_application_real(&apdu[0], real_value);
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(property != PROP_PRIORITY_ARRAY) &&
(array_index != BACNET_ARRAY_ALL)) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
(rpdata->object_property != PROP_PRIORITY_ARRAY) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = -1;
}
@@ -521,9 +509,7 @@ int Lighting_Output_Encode_Property_APDU(
/* returns true if successful */
bool Lighting_Output_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
@@ -531,12 +517,6 @@ bool Lighting_Output_Write_Property(
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
Lighting_Output_Init();
if (!Lighting_Output_Valid_Instance(wp_data->object_instance)) {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
return false;
}
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
@@ -556,30 +536,36 @@ bool Lighting_Output_Write_Property(
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
} else if (!status) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
} else if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL, error_class, error_code) == true) {
level = LIGHTING_LEVEL_NULL;
object_index =
Lighting_Output_Instance_To_Index
(wp_data->object_instance);
status =
Lighting_Output_Present_Value_Relinquish
(wp_data->object_instance, wp_data->priority);
if (wp_data->priority == 6) {
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. - Note Lighting_Output_Present_Value_Relinquish()
will have returned false because of this */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
} else if (!status) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
} else {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_NULL,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
level = LIGHTING_LEVEL_NULL;
object_index =
Lighting_Output_Instance_To_Index
(wp_data->object_instance);
status =
Lighting_Output_Present_Value_Relinquish
(wp_data->object_instance, wp_data->priority);
if (wp_data->priority == 6) {
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. - Note Lighting_Output_Present_Value_Relinquish()
will have returned false because of this */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
} else if (!status) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
}
break;
@@ -590,7 +576,11 @@ bool Lighting_Output_Write_Property(
&Lighting_Command[wp_data->object_instance]);
break;
case PROP_OUT_OF_SERVICE:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
object_index =
Lighting_Output_Instance_To_Index
(wp_data->object_instance);
@@ -599,8 +589,8 @@ bool Lighting_Output_Write_Property(
}
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
@@ -620,23 +610,25 @@ void testLightingOutput(
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_LIGHTING_OUTPUT;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
uint32_t instance = 123;
BACNET_ERROR_CLASS error_class;
BACNET_ERROR_CODE error_code;
BACNET_READ_PROPERTY_DATA rpdata;
len =
Lighting_Output_Encode_Property_APDU(&apdu[0], instance,
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
Lighting_Output_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_LIGHTING_OUTPUT;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Lighting_Output_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len =
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == OBJECT_LIGHTING_OUTPUT);
ct_test(pTest, decoded_instance == instance);
decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
+53 -55
View File
@@ -33,11 +33,11 @@
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "rp.h"
#include "wp.h"
#include "lsp.h"
#include "handlers.h"
#define MAX_LIFE_SAFETY_POINTS 7
/* Here are our stored levels.*/
static BACNET_LIFE_SAFETY_MODE Life_Safety_Point_Mode[MAX_LIFE_SAFETY_POINTS];
static BACNET_LIFE_SAFETY_STATE
@@ -118,7 +118,6 @@ void Life_Safety_Point_Init(
bool Life_Safety_Point_Valid_Instance(
uint32_t object_instance)
{
Life_Safety_Point_Init();
if (object_instance < MAX_LIFE_SAFETY_POINTS)
return true;
@@ -130,7 +129,6 @@ bool Life_Safety_Point_Valid_Instance(
unsigned Life_Safety_Point_Count(
void)
{
Life_Safety_Point_Init();
return MAX_LIFE_SAFETY_POINTS;
}
@@ -140,7 +138,6 @@ unsigned Life_Safety_Point_Count(
uint32_t Life_Safety_Point_Index_To_Instance(
unsigned index)
{
Life_Safety_Point_Init();
return index;
}
@@ -152,7 +149,6 @@ unsigned Life_Safety_Point_Instance_To_Index(
{
unsigned index = MAX_LIFE_SAFETY_POINTS;
Life_Safety_Point_Init();
if (object_instance < MAX_LIFE_SAFETY_POINTS)
index = object_instance;
@@ -165,7 +161,6 @@ static BACNET_LIFE_SAFETY_STATE Life_Safety_Point_Present_Value(
BACNET_LIFE_SAFETY_STATE present_value = LIFE_SAFETY_STATE_QUIET;
unsigned index = 0;
Life_Safety_Point_Init();
index = Life_Safety_Point_Instance_To_Index(object_instance);
if (index < MAX_LIFE_SAFETY_POINTS)
present_value = Life_Safety_Point_State[index];
@@ -188,13 +183,8 @@ char *Life_Safety_Point_Name(
}
/* return apdu len, or -1 on error */
int Life_Safety_Point_Encode_Property_APDU(
uint8_t * apdu,
uint32_t object_instance,
BACNET_PROPERTY_ID property,
int32_t array_index,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
int Life_Safety_Point_Read_Property(
BACNET_READ_PROPERTY_DATA *rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
@@ -207,18 +197,24 @@ int Life_Safety_Point_Encode_Property_APDU(
unsigned object_index = 0;
bool state = false;
BACNET_RELIABILITY reliability = RELIABILITY_NO_FAULT_DETECTED;
uint8_t *apdu = NULL;
Life_Safety_Point_Init();
switch (property) {
if ((rpdata == NULL) ||
(rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0],
OBJECT_LIFE_SAFETY_POINT, object_instance);
OBJECT_LIFE_SAFETY_POINT, rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string,
Life_Safety_Point_Name(object_instance));
Life_Safety_Point_Name(rpdata->object_instance));
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
@@ -228,7 +224,7 @@ int Life_Safety_Point_Encode_Property_APDU(
OBJECT_LIFE_SAFETY_POINT);
break;
case PROP_PRESENT_VALUE:
present_value = Life_Safety_Point_Present_Value(object_instance);
present_value = Life_Safety_Point_Present_Value(rpdata->object_instance);
apdu_len = encode_application_enumerated(&apdu[0], present_value);
break;
case PROP_STATUS_FLAGS:
@@ -245,7 +241,7 @@ int Life_Safety_Point_Encode_Property_APDU(
break;
case PROP_OUT_OF_SERVICE:
object_index =
Life_Safety_Point_Instance_To_Index(object_instance);
Life_Safety_Point_Instance_To_Index(rpdata->object_instance);
state = Life_Safety_Point_Out_Of_Service[object_index];
apdu_len = encode_application_boolean(&apdu[0], state);
break;
@@ -256,7 +252,7 @@ int Life_Safety_Point_Encode_Property_APDU(
break;
case PROP_MODE:
object_index =
Life_Safety_Point_Instance_To_Index(object_instance);
Life_Safety_Point_Instance_To_Index(rpdata->object_instance);
mode = Life_Safety_Point_Mode[object_index];
apdu_len = encode_application_enumerated(&apdu[0], mode);
break;
@@ -269,27 +265,27 @@ int Life_Safety_Point_Encode_Property_APDU(
break;
case PROP_SILENCED:
object_index =
Life_Safety_Point_Instance_To_Index(object_instance);
Life_Safety_Point_Instance_To_Index(rpdata->object_instance);
silenced_state = Life_Safety_Point_Silenced_State[object_index];
apdu_len = encode_application_enumerated(&apdu[0], silenced_state);
break;
case PROP_OPERATION_EXPECTED:
object_index =
Life_Safety_Point_Instance_To_Index(object_instance);
Life_Safety_Point_Instance_To_Index(rpdata->object_instance);
operation = Life_Safety_Point_Operation[object_index];
apdu_len = encode_application_enumerated(&apdu[0], operation);
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(array_index != BACNET_ARRAY_ALL)) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = -1;
}
@@ -298,21 +294,13 @@ int Life_Safety_Point_Encode_Property_APDU(
/* returns true if successful */
bool Life_Safety_Point_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
Life_Safety_Point_Init();
if (!Life_Safety_Point_Valid_Instance(wp_data->object_instance)) {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
return false;
}
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
@@ -321,22 +309,30 @@ bool Life_Safety_Point_Write_Property(
/* FIXME: len == 0: unable to decode? */
switch (wp_data->object_property) {
case PROP_MODE:
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED, error_class, error_code) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_ENUMERATED,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
if (value.type.Enumerated <= MAX_LIFE_SAFETY_MODE) {
object_index =
Life_Safety_Point_Instance_To_Index
(wp_data->object_instance);
Life_Safety_Point_Mode[object_index] =
value.type.Enumerated;
status = true;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
break;
case PROP_OUT_OF_SERVICE:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
object_index =
Life_Safety_Point_Instance_To_Index
(wp_data->object_instance);
@@ -345,8 +341,8 @@ bool Life_Safety_Point_Write_Property(
}
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
@@ -366,23 +362,25 @@ void testLifeSafetyPoint(
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_LIFE_SAFETY_POINT;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
uint32_t instance = 123;
BACNET_ERROR_CLASS error_class;
BACNET_ERROR_CODE error_code;
BACNET_READ_PROPERTY_DATA rpdata;
len =
Life_Safety_Point_Encode_Property_APDU(&apdu[0], instance,
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
Life_Safety_Point_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_LIFE_SAFETY_POINT;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Life_Safety_Point_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len =
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == OBJECT_LIFE_SAFETY_POINT);
ct_test(pTest, decoded_instance == instance);
decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
+70 -67
View File
@@ -33,13 +33,11 @@
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "rp.h"
#include "wp.h"
#include "ms-input.h"
#include "handlers.h"
#ifndef MAX_MULTISTATE_INPUTS
#define MAX_MULTISTATE_INPUTS 1
#endif
/* how many states? 0-253 is 254 states */
#ifndef MULTISTATE_NUMBER_OF_STATES
#define MULTISTATE_NUMBER_OF_STATES (254)
@@ -314,13 +312,8 @@ bool Multistate_Input_State_Text_Set(
/* return apdu len, or -1 on error */
int Multistate_Input_Encode_Property_APDU(
uint8_t * apdu,
uint32_t object_instance,
BACNET_PROPERTY_ID property,
int32_t array_index,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
int Multistate_Input_Read_Property(
BACNET_READ_PROPERTY_DATA *rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
@@ -330,24 +323,31 @@ int Multistate_Input_Encode_Property_APDU(
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
switch (property) {
if ((rpdata == NULL) ||
(rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0],
OBJECT_MULTI_STATE_INPUT, object_instance);
OBJECT_MULTI_STATE_INPUT, rpdata->object_instance);
break;
/* note: Name and Description don't have to be the same.
You could make Description writable and different */
case PROP_OBJECT_NAME:
characterstring_init_ansi(&char_string,
Multistate_Input_Name(object_instance));
Multistate_Input_Name(rpdata->object_instance));
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string,
Multistate_Input_Description(object_instance));
Multistate_Input_Description(rpdata->object_instance));
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
@@ -357,7 +357,7 @@ int Multistate_Input_Encode_Property_APDU(
OBJECT_MULTI_STATE_INPUT);
break;
case PROP_PRESENT_VALUE:
present_value = Multistate_Input_Present_Value(object_instance);
present_value = Multistate_Input_Present_Value(rpdata->object_instance);
apdu_len = encode_application_unsigned(&apdu[0], present_value);
break;
case PROP_STATUS_FLAGS:
@@ -375,7 +375,7 @@ int Multistate_Input_Encode_Property_APDU(
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
break;
case PROP_OUT_OF_SERVICE:
object_index = Multistate_Input_Instance_To_Index(object_instance);
object_index = Multistate_Input_Instance_To_Index(rpdata->object_instance);
state = Out_Of_Service[object_index];
apdu_len = encode_application_boolean(&apdu[0], state);
break;
@@ -385,19 +385,19 @@ int Multistate_Input_Encode_Property_APDU(
MULTISTATE_NUMBER_OF_STATES);
break;
case PROP_STATE_TEXT:
if (array_index == 0) {
if (rpdata->array_index == 0) {
/* Array element zero is the number of elements in the array */
apdu_len =
encode_application_unsigned(&apdu[0],
MULTISTATE_NUMBER_OF_STATES);
} else if (array_index == BACNET_ARRAY_ALL) {
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
/* if no index was specified, then try to encode the entire list */
/* into one packet. */
object_index =
Multistate_Input_Instance_To_Index(object_instance);
Multistate_Input_Instance_To_Index(rpdata->object_instance);
for (i = 0; i < MULTISTATE_NUMBER_OF_STATES; i++) {
characterstring_init_ansi(&char_string,
Multistate_Input_State_Text(object_instance, i));
Multistate_Input_State_Text(rpdata->object_instance, i));
/* FIXME: this might go beyond MAX_APDU length! */
len =
encode_application_character_string(&apdu[apdu_len],
@@ -406,42 +406,41 @@ int Multistate_Input_Encode_Property_APDU(
if ((apdu_len + len) < MAX_APDU) {
apdu_len += len;
} else {
*error_class = ERROR_CLASS_SERVICES;
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = -1;
break;
}
}
} else {
object_index =
Multistate_Input_Instance_To_Index(object_instance);
if (array_index <= MULTISTATE_NUMBER_OF_STATES) {
array_index--;
Multistate_Input_Instance_To_Index(rpdata->object_instance);
if (rpdata->array_index <= MULTISTATE_NUMBER_OF_STATES) {
characterstring_init_ansi(&char_string,
Multistate_Input_State_Text(object_instance,
array_index));
Multistate_Input_State_Text(rpdata->object_instance,
rpdata->array_index-1));
apdu_len =
encode_application_character_string(&apdu[0],
&char_string);
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = -1;
}
}
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(property != PROP_STATE_TEXT) &&
(array_index != BACNET_ARRAY_ALL)) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
(rpdata->object_property != PROP_STATE_TEXT) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = -1;
}
@@ -450,21 +449,13 @@ int Multistate_Input_Encode_Property_APDU(
/* returns true if successful */
bool Multistate_Input_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
Multistate_Input_Init();
if (!Multistate_Input_Valid_Instance(wp_data->object_instance)) {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
return false;
}
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
@@ -473,23 +464,32 @@ bool Multistate_Input_Write_Property(
/* FIXME: len == 0: unable to decode? */
switch (wp_data->object_property) {
case PROP_PRESENT_VALUE:
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
if (Out_Of_Service[object_index]) {
if (Multistate_Input_Present_Value_Set(wp_data->
object_instance, value.type.Unsigned_Int)) {
status = true;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
status = Multistate_Input_Present_Value_Set(
wp_data->object_instance,
value.type.Unsigned_Int);
if (!status) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
}
}
break;
case PROP_OUT_OF_SERVICE:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
object_index =
Multistate_Input_Instance_To_Index
(wp_data->object_instance);
@@ -497,8 +497,8 @@ bool Multistate_Input_Write_Property(
}
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
@@ -518,22 +518,25 @@ void testMultistateInput(
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_MULTI_STATE_INPUT;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
uint32_t instance = 123;
BACNET_ERROR_CLASS error_class;
BACNET_ERROR_CODE error_code;
BACNET_READ_PROPERTY_DATA rpdata;
len =
Multistate_Input_Encode_Property_APDU(&apdu[0], instance,
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
Multistate_Input_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_MULTI_STATE_INPUT;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Multistate_Input_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len =
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == OBJECT_MULTI_STATE_INPUT);
ct_test(pTest, decoded_instance == instance);
decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
+40
View File
@@ -0,0 +1,40 @@
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_MULTISTATE_INPUT
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = ms-input.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = multistate_input
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
+84 -80
View File
@@ -33,11 +33,11 @@
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "rp.h"
#include "wp.h"
#include "mso.h"
#include "handlers.h"
#define MAX_MULTISTATE_OUTPUTS 4
/* When all the priorities are level null, the present value returns */
/* the Relinquish Default value */
#define MULTISTATE_RELINQUISH_DEFAULT 0
@@ -162,7 +162,6 @@ static uint32_t Multistate_Output_Present_Value(
unsigned index = 0;
unsigned i = 0;
Multistate_Output_Init();
index = Multistate_Output_Instance_To_Index(object_instance);
if (index < MAX_MULTISTATE_OUTPUTS) {
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
@@ -191,13 +190,8 @@ char *Multistate_Output_Name(
}
/* return apdu len, or -1 on error */
int Multistate_Output_Encode_Property_APDU(
uint8_t * apdu,
uint32_t object_instance,
BACNET_PROPERTY_ID property,
int32_t array_index,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
int Multistate_Output_Read_Property(
BACNET_READ_PROPERTY_DATA *rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
@@ -207,20 +201,26 @@ int Multistate_Output_Encode_Property_APDU(
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
Multistate_Output_Init();
switch (property) {
if ((rpdata == NULL) ||
(rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0],
OBJECT_MULTI_STATE_OUTPUT, object_instance);
OBJECT_MULTI_STATE_OUTPUT, rpdata->object_instance);
break;
/* note: Name and Description don't have to be the same.
You could make Description writable and different */
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string,
Multistate_Output_Name(object_instance));
Multistate_Output_Name(rpdata->object_instance));
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
@@ -230,7 +230,7 @@ int Multistate_Output_Encode_Property_APDU(
OBJECT_MULTI_STATE_OUTPUT);
break;
case PROP_PRESENT_VALUE:
present_value = Multistate_Output_Present_Value(object_instance);
present_value = Multistate_Output_Present_Value(rpdata->object_instance);
apdu_len = encode_application_unsigned(&apdu[0], present_value);
break;
case PROP_STATUS_FLAGS:
@@ -249,20 +249,20 @@ int Multistate_Output_Encode_Property_APDU(
break;
case PROP_OUT_OF_SERVICE:
object_index =
Multistate_Output_Instance_To_Index(object_instance);
Multistate_Output_Instance_To_Index(rpdata->object_instance);
state = Multistate_Output_Out_Of_Service[object_index];
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 (array_index == 0)
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 (array_index == BACNET_ARRAY_ALL) {
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
object_index =
Multistate_Output_Instance_To_Index(object_instance);
Multistate_Output_Instance_To_Index(rpdata->object_instance);
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
/* FIXME: check if we have room before adding it to APDU */
if (Multistate_Output_Level[object_index][i] ==
@@ -279,30 +279,30 @@ int Multistate_Output_Encode_Property_APDU(
if ((apdu_len + len) < MAX_APDU)
apdu_len += len;
else {
*error_class = ERROR_CLASS_SERVICES;
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = -1;
break;
}
}
} else {
object_index =
Multistate_Output_Instance_To_Index(object_instance);
if (array_index <= BACNET_MAX_PRIORITY) {
if (Multistate_Output_Level[object_index][array_index -
Multistate_Output_Instance_To_Index(rpdata->object_instance);
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
if (Multistate_Output_Level[object_index][rpdata->array_index -
1] == MULTISTATE_NULL)
apdu_len = encode_application_null(&apdu[0]);
else {
present_value =
Multistate_Output_Level[object_index][array_index -
Multistate_Output_Level[object_index][rpdata->array_index -
1];
apdu_len =
encode_application_unsigned(&apdu[0],
present_value);
}
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = -1;
}
}
@@ -319,17 +319,17 @@ int Multistate_Output_Encode_Property_APDU(
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(property != PROP_PRIORITY_ARRAY) &&
(array_index != BACNET_ARRAY_ALL)) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
(rpdata->object_property != PROP_PRIORITY_ARRAY) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = -1;
}
@@ -338,9 +338,7 @@ int Multistate_Output_Encode_Property_APDU(
/* returns true if successful */
bool Multistate_Output_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
@@ -349,12 +347,6 @@ bool Multistate_Output_Write_Property(
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
Multistate_Output_Init();
if (!Multistate_Output_Valid_Instance(wp_data->object_instance)) {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
return false;
}
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
@@ -388,37 +380,47 @@ bool Multistate_Output_Write_Property(
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
} else if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL, error_class, error_code) == true) {
level = MULTISTATE_NULL;
object_index =
Multistate_Output_Instance_To_Index
(wp_data->object_instance);
priority = wp_data->priority;
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
priority--;
Multistate_Output_Level[object_index][priority] =
(uint8_t) level;
/* Note: you could set the physical output here to the next
highest priority, or to the relinquish default if no
priorities are set.
However, if Out of Service is TRUE, then don't set the
physical output. This comment may apply to the
main loop (i.e. check out of service before changing output) */
status = true;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
} else {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_NULL,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
level = MULTISTATE_NULL;
object_index =
Multistate_Output_Instance_To_Index
(wp_data->object_instance);
priority = wp_data->priority;
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
priority--;
Multistate_Output_Level[object_index][priority] =
(uint8_t) level;
/* Note: you could set the physical output here to the next
highest priority, or to the relinquish default if no
priorities are set.
However, if Out of Service is TRUE, then don't set the
physical output. This comment may apply to the
main loop (i.e. check out of service before changing output) */
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
}
break;
case PROP_OUT_OF_SERVICE:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
object_index =
Multistate_Output_Instance_To_Index
(wp_data->object_instance);
@@ -427,8 +429,8 @@ bool Multistate_Output_Write_Property(
}
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
@@ -448,23 +450,25 @@ void testMultistateOutput(
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_MULTI_STATE_OUTPUT;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
uint32_t instance = 123;
BACNET_ERROR_CLASS error_class;
BACNET_ERROR_CODE error_code;
BACNET_READ_PROPERTY_DATA rpdata;
len =
Multistate_Output_Encode_Property_APDU(&apdu[0], instance,
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
Multistate_Output_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_MULTI_STATE_OUTPUT;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Multistate_Output_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len =
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == OBJECT_MULTI_STATE_OUTPUT);
ct_test(pTest, decoded_instance == instance);
decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
+181 -92
View File
@@ -44,8 +44,6 @@
#include "bacfile.h" /* object list dependency */
#endif
#define MAX_TREND_LOGS 8
/* Error code for Trend Log storage */
typedef struct tl_error {
@@ -347,36 +345,33 @@ char *Trend_Log_Name(
/* return the length of the apdu encoded or -1 for error or
-2 for abort message */
int Trend_Log_Encode_Property_APDU(
uint8_t * apdu,
uint32_t object_instance,
BACNET_PROPERTY_ID property,
int32_t array_index,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
int Trend_Log_Read_Property(
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;
unsigned i = 0;
int object_type = 0;
uint32_t instance = 0;
unsigned count = 0;
TL_LOG_INFO *CurrentLog;
uint8_t *apdu = NULL;
CurrentLog = &LogInfo[Trend_Log_Instance_To_Index(object_instance)]; /* Pin down which log to look at */
switch (property) {
if ((rpdata == NULL) ||
(rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
CurrentLog = &LogInfo[Trend_Log_Instance_To_Index(rpdata->object_instance)]; /* Pin down which log to look at */
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_TRENDLOG,
object_instance);
rpdata->object_instance);
break;
case PROP_DESCRIPTION:
case PROP_OBJECT_NAME:
characterstring_init_ansi(&char_string, Trend_Log_Name(object_instance));
characterstring_init_ansi(&char_string, Trend_Log_Name(rpdata->object_instance));
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
@@ -399,8 +394,8 @@ int Trend_Log_Encode_Property_APDU(
case PROP_LOG_BUFFER:
/* You can only read the buffer via the ReadRange service */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_READ_ACCESS_DENIED;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_READ_ACCESS_DENIED;
apdu_len = -1;
break;
@@ -482,17 +477,17 @@ int Trend_Log_Encode_Property_APDU(
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(property != PROP_EVENT_TIME_STAMPS) &&
(array_index != BACNET_ARRAY_ALL)) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
(rpdata->object_property != PROP_EVENT_TIME_STAMPS) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = -1;
}
@@ -501,9 +496,7 @@ int Trend_Log_Encode_Property_APDU(
/* returns true if successful */
bool Trend_Log_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
@@ -514,14 +507,8 @@ bool Trend_Log_Write_Property(
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE TempSource;
bool bEffectiveEnable;
if (!Trend_Log_Valid_Instance(wp_data->object_instance)) {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
return false;
}
CurrentLog = &LogInfo[Trend_Log_Instance_To_Index(wp_data->object_instance)]; /* Pin down which log to look at */
/* Pin down which log to look at */
CurrentLog = &LogInfo[Trend_Log_Instance_To_Index(wp_data->object_instance)];
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
@@ -531,14 +518,19 @@ bool Trend_Log_Write_Property(
switch (wp_data->object_property) {
case PROP_ENABLE:
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
/* Section 12.25.5 can't enable a full log with stop when full set */
if((CurrentLog->bEnable == false) &&
(CurrentLog->bStopWhenFull == true) &&
(CurrentLog->ulRecordCount == TL_MAX_ENTRIES) &&
(value.type.Boolean == true)) {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_LOG_BUFFER_FULL;
status = false;
wp_data->error_class = ERROR_CLASS_OBJECT;
wp_data->error_code = ERROR_CODE_LOG_BUFFER_FULL;
break;
}
@@ -549,24 +541,30 @@ bool Trend_Log_Write_Property(
/* To do: what actions do we need to take on writing ? */
if(value.type.Boolean == false) {
if(bEffectiveEnable == true) {
/* Only insert record if we really were enabled i.e. times and enable flags */
TL_Insert_Status_Rec(wp_data->object_instance, LOG_STATUS_LOG_DISABLED, true);
/* Only insert record if we really were
enabled i.e. times and enable flags */
TL_Insert_Status_Rec(wp_data->object_instance,
LOG_STATUS_LOG_DISABLED, true);
}
} else {
if(TL_Is_Enabled(wp_data->object_instance)) {
/* Have really gone from disabled to enabled as
* enable flag and times were correct
*/
TL_Insert_Status_Rec(wp_data->object_instance, LOG_STATUS_LOG_DISABLED, false);
TL_Insert_Status_Rec(wp_data->object_instance,
LOG_STATUS_LOG_DISABLED, false);
}
}
}
status = true;
}
break;
case PROP_STOP_WHEN_FULL:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
/* Only trigger this on a change of state */
if(CurrentLog->bStopWhenFull != value.type.Boolean) {
CurrentLog->bStopWhenFull = value.type.Boolean;
@@ -579,7 +577,8 @@ bool Trend_Log_Write_Property(
* disable the log and record the fact - see 135-2008 12.25.12
*/
CurrentLog->bEnable = false;
TL_Insert_Status_Rec(wp_data->object_instance, LOG_STATUS_LOG_DISABLED, true);
TL_Insert_Status_Rec(wp_data->object_instance,
LOG_STATUS_LOG_DISABLED, true);
}
}
}
@@ -590,12 +589,16 @@ bool Trend_Log_Write_Property(
* we would probably erase the current log, resize, re-initalise
* and carry on - however write is not allowed if enable is true.
*/
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
case PROP_RECORD_COUNT:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code)) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
if(value.type.Unsigned_Int == 0) {
/* Time to clear down the log */
CurrentLog->ulRecordCount = 0;
@@ -608,9 +611,12 @@ bool Trend_Log_Write_Property(
case PROP_LOGGING_TYPE:
/* logic
* triggered and polled options.
*/
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED, error_class, error_code) == true) {
*/
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_ENUMERATED,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
if(value.type.Enumerated != LOGGING_TYPE_COV) {
CurrentLog->LoggingType = value.type.Enumerated;
if(value.type.Enumerated == LOGGING_TYPE_POLLED) {
@@ -623,26 +629,37 @@ bool Trend_Log_Write_Property(
/* As per 12.25.27 0 the interval if triggered logging selected */
CurrentLog->ulLogInterval = 0;
}
status = true;
} else {
/* We don't currently support COV */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
}
}
break;
case PROP_START_TIME:
/* Copy the date part to safe place */
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_DATE, error_class, error_code) == false)
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_DATE,
&wp_data->error_class,
&wp_data->error_code);
if (!status) {
break;
}
TempDate = value.type.Date;
/* Then decode the time part */
/* Then decode the time part */
len = bacapp_decode_application_data(wp_data->application_data + len,
wp_data->application_data_len - len, &value);
if (len && ((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_TIME, error_class, error_code)) == true)) {
if (len) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_TIME,
&wp_data->error_class,
&wp_data->error_code);
if (!status) {
break;
}
/* First record the current enable state of the log */
bEffectiveEnable = TL_Is_Enabled(wp_data->object_instance);
CurrentLog->StartTime.date = TempDate; /* Safe to copy the date now */
@@ -673,15 +690,26 @@ bool Trend_Log_Write_Property(
case PROP_STOP_TIME:
/* Copy the date part to safe place */
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_DATE, error_class, error_code) == false)
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_DATE,
&wp_data->error_class,
&wp_data->error_code);
if (!status) {
break;
}
TempDate = value.type.Date;
/* Then decode the time part */
len = bacapp_decode_application_data(wp_data->application_data + len,
wp_data->application_data_len - len, &value);
if (len && ((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_TIME, error_class, error_code)) == true)) {
if (len) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_TIME,
&wp_data->error_class,
&wp_data->error_code);
if (!status) {
break;
}
/* First record the current enable state of the log */
bEffectiveEnable = TL_Is_Enabled(wp_data->object_instance);
CurrentLog->StopTime.date = TempDate; /* Safe to copy the date now */
@@ -718,8 +746,8 @@ bool Trend_Log_Write_Property(
len = bacapp_decode_context_data(wp_data->application_data, wp_data->application_data_len, &value, PROP_LOG_DEVICE_OBJECT_PROPERTY);
if((len == 0) || (value.context_tag != 0) || ((wp_data->application_data_len - len) == 0)) {
/* Bad decode, wrong tag or following required parameter missing */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_OTHER;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_OTHER;
break;
}
@@ -730,8 +758,8 @@ bool Trend_Log_Write_Property(
len = bacapp_decode_context_data(&wp_data->application_data[iOffset], wp_data->application_data_len, &value, PROP_LOG_DEVICE_OBJECT_PROPERTY);
if((len == 0) || (value.context_tag != 1)) {
/* Bad decode or wrong tag */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_OTHER;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_OTHER;
break;
}
@@ -744,8 +772,8 @@ bool Trend_Log_Write_Property(
len = bacapp_decode_context_data(&wp_data->application_data[iOffset], wp_data->application_data_len, &value, PROP_LOG_DEVICE_OBJECT_PROPERTY);
if((len == 0) || ((value.context_tag != 2) && (value.context_tag != 3))) {
/* Bad decode or wrong tag */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_OTHER;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_OTHER;
break;
}
@@ -759,8 +787,8 @@ bool Trend_Log_Write_Property(
len = bacapp_decode_context_data(&wp_data->application_data[iOffset], wp_data->application_data_len, &value, PROP_LOG_DEVICE_OBJECT_PROPERTY);
if((len == 0) || (value.context_tag != 3)) {
/* Bad decode or wrong tag */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_OTHER;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_OTHER;
break;
}
}
@@ -772,8 +800,8 @@ bool Trend_Log_Write_Property(
if((TempSource.deviceIndentifier.instance != Device_Object_Instance_Number()) ||
(TempSource.deviceIndentifier.type != OBJECT_DEVICE)) {
/* Not our ID so can't handle it at the moment */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
break;
}
}
@@ -795,58 +823,74 @@ bool Trend_Log_Write_Property(
case PROP_LOG_INTERVAL:
if(CurrentLog->LoggingType == LOGGING_TYPE_TRIGGERED) {
/* Read only if triggered log so flag error and bail out */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code) == true) {
if((CurrentLog->LoggingType == LOGGING_TYPE_POLLED) && (value.type.Unsigned_Int == 0)) {
/* We don't support COV at the moment so don't allow switching
* to it by clearing interval whilst in polling mode */
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
if((CurrentLog->LoggingType == LOGGING_TYPE_POLLED) &&
(value.type.Unsigned_Int == 0)) {
/* We don't support COV at the moment so don't allow switching
* to it by clearing interval whilst in polling mode */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
status = false;
} else {
/* We only log to 1 sec accuracy so must divide by 100 before passing it on */
CurrentLog->ulLogInterval = value.type.Unsigned_Int / 100;
status = true;
}
}
break;
case PROP_ALIGN_INTERVALS:
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code)) == true)
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
CurrentLog->bAlignIntervals = value.type.Boolean;
}
break;
case PROP_INTERVAL_OFFSET:
/* We only log to 1 sec accuracy so must divide by 100 before passing it on */
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code)) == true)
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
CurrentLog->ulIntervalOffset = value.type.Unsigned_Int / 100;
}
break;
case PROP_TRIGGER:
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN, error_class, error_code) == true) {
status = WPValidateArgType(&value,
BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class,
&wp_data->error_code);
if (status) {
/* We will not allow triggered operation if polling with aligning
* to the clock as that will produce non aligned readings which
* goes against the reason for selscting this mode
*/
if((CurrentLog->LoggingType == LOGGING_TYPE_POLLED) &&
(CurrentLog->bAlignIntervals == true)) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_NOT_CONFIGURED_FOR_TRIGGERED_LOGGING;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_NOT_CONFIGURED_FOR_TRIGGERED_LOGGING;
status = false;
} else {
CurrentLog->bTrigger = value.type.Boolean;
status = true;
}
}
break;
default:
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
@@ -1546,6 +1590,51 @@ int TL_encode_entry(uint8_t *apdu, int iLog, int iEntry)
return(iLen);
}
static int local_read_property(
uint8_t * value,
uint8_t * status,
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *Source,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
{
int len = 0;
BACNET_READ_PROPERTY_DATA rpdata;
if (value != NULL) {
/* configure our storage */
rpdata.application_data = value;
rpdata.application_data_len = MAX_APDU;
rpdata.object_type = Source->objectIdentifier.type;
rpdata.object_instance = Source->objectIdentifier.instance;
rpdata.object_property = Source->propertyIdentifier;
rpdata.array_index = Source->arrayIndex;
/* Try to fetch the required property */
len = Device_Objects_Read_Property(&rpdata);
if (len < 0) {
*error_class = rpdata.error_class;
*error_code = rpdata.error_code;
}
}
if((len >= 0) && (status != NULL)){
/* Fetch the status flags if required */
rpdata.application_data = status;
rpdata.application_data_len = MAX_APDU;
rpdata.object_property = PROP_STATUS_FLAGS;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Device_Objects_Read_Property(&rpdata);
if (len < 0) {
*error_class = rpdata.error_class;
*error_code = rpdata.error_code;
}
} else {
*error_class = rpdata.error_class;
*error_code = rpdata.error_code;
}
return(len);
}
/****************************************************************************
* Attempt to fetch the logged property and store it in the Trend Log *
****************************************************************************/