Device_Set_System_Status() now does some range checking (also has local flag to allow internal and external sources have different levels of control.
Simplified write property code using new validation helper functions in h_wp.c. Added location, description and model name to the writable properties.
This commit is contained in:
@@ -133,15 +133,24 @@ void Device_Property_Lists(
|
|||||||
properties that are writable or that may change.
|
properties that are writable or that may change.
|
||||||
The properties that are constant can be hard coded
|
The properties that are constant can be hard coded
|
||||||
into the read-property encoding. */
|
into the read-property encoding. */
|
||||||
|
|
||||||
|
/* String Lengths - excluding any nul terminator */
|
||||||
|
|
||||||
|
#define MAX_DEV_NAME_LEN 32
|
||||||
|
#define MAX_DEV_LOC_LEN 64
|
||||||
|
#define MAX_DEV_MOD_LEN 32
|
||||||
|
#define MAX_DEV_VER_LEN 16
|
||||||
|
#define MAX_DEV_DESC_LEN 64
|
||||||
|
|
||||||
static uint32_t Object_Instance_Number = 260001;
|
static uint32_t Object_Instance_Number = 260001;
|
||||||
static char My_Object_Name[16] = "SimpleServer";
|
static char My_Object_Name[MAX_DEV_NAME_LEN + 1] = "SimpleServer";
|
||||||
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
||||||
static char *Vendor_Name = BACNET_VENDOR_NAME;
|
static char *Vendor_Name = BACNET_VENDOR_NAME;
|
||||||
static uint16_t Vendor_Identifier = BACNET_VENDOR_ID;
|
static uint16_t Vendor_Identifier = BACNET_VENDOR_ID;
|
||||||
static char Model_Name[16] = "GNU";
|
static char Model_Name[MAX_DEV_MOD_LEN + 1] = "GNU";
|
||||||
static char Application_Software_Version[16] = "1.0";
|
static char Application_Software_Version[MAX_DEV_VER_LEN + 1] = "1.0";
|
||||||
static char Location[16] = "USA";
|
static char Location[MAX_DEV_LOC_LEN + 1] = "USA";
|
||||||
static char Description[16] = "server";
|
static char Description[MAX_DEV_DESC_LEN + 1] = "server";
|
||||||
/* static uint8_t Protocol_Version = 1; - constant, not settable */
|
/* static uint8_t Protocol_Version = 1; - constant, not settable */
|
||||||
/* static uint8_t Protocol_Revision = 4; - constant, not settable */
|
/* static uint8_t Protocol_Revision = 4; - constant, not settable */
|
||||||
/* Protocol_Services_Supported - dynamically generated */
|
/* Protocol_Services_Supported - dynamically generated */
|
||||||
@@ -216,7 +225,9 @@ bool Device_Set_Object_Name(
|
|||||||
const char *name,
|
const char *name,
|
||||||
size_t length)
|
size_t length)
|
||||||
{
|
{
|
||||||
bool status = false; /*return value */
|
bool status; /*return value */
|
||||||
|
|
||||||
|
status = false;
|
||||||
|
|
||||||
/* FIXME: All the object names in a device must be unique.
|
/* FIXME: All the object names in a device must be unique.
|
||||||
Disallow setting the Device Object Name to any objects in
|
Disallow setting the Device Object Name to any objects in
|
||||||
@@ -238,11 +249,71 @@ BACNET_DEVICE_STATUS Device_System_Status(
|
|||||||
return System_Status;
|
return System_Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device_Set_System_Status(
|
int Device_Set_System_Status(
|
||||||
BACNET_DEVICE_STATUS status)
|
BACNET_DEVICE_STATUS status,
|
||||||
|
bool local)
|
||||||
{
|
{
|
||||||
/* FIXME: bounds check? */
|
int result; /*return value - 0 = ok, -1 = bad value, -2 = not allowed */
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
/* We limit the options available depending on whether the source is
|
||||||
|
* internal or external. */
|
||||||
|
if(local) {
|
||||||
|
switch(status) {
|
||||||
|
case STATUS_OPERATIONAL:
|
||||||
|
case STATUS_OPERATIONAL_READ_ONLY:
|
||||||
|
case STATUS_DOWNLOAD_REQUIRED:
|
||||||
|
case STATUS_DOWNLOAD_IN_PROGRESS:
|
||||||
|
case STATUS_NON_OPERATIONAL:
|
||||||
|
System_Status = status;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Don't support backup at present so don't allow setting */
|
||||||
|
case STATUS_BACKUP_IN_PROGRESS:
|
||||||
|
result = -2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch(status) {
|
||||||
|
/* Allow these for the moment as a way to easily alter
|
||||||
|
* overall device operation. The lack of password protection
|
||||||
|
* or other authentication makes allowing writes to this
|
||||||
|
* property a risky facility to provide.
|
||||||
|
*/
|
||||||
|
case STATUS_OPERATIONAL:
|
||||||
|
case STATUS_OPERATIONAL_READ_ONLY:
|
||||||
|
case STATUS_NON_OPERATIONAL:
|
||||||
|
System_Status = status;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Don't allow outsider set this - it should probably
|
||||||
|
* be set if the device config is incomplete or
|
||||||
|
* corrupted or perhaps after some sort of operator
|
||||||
|
* wipe operation.
|
||||||
|
*/
|
||||||
|
case STATUS_DOWNLOAD_REQUIRED:
|
||||||
|
/* Don't allow outsider set this - it should be set
|
||||||
|
* internally at the start of a multi packet download
|
||||||
|
* perhaps indirectly via PT or WF to a config file.
|
||||||
|
*/
|
||||||
|
case STATUS_DOWNLOAD_IN_PROGRESS:
|
||||||
|
/* Don't support backup at present so don't allow setting */
|
||||||
|
case STATUS_BACKUP_IN_PROGRESS:
|
||||||
|
result = -2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
System_Status = status;
|
System_Status = status;
|
||||||
|
|
||||||
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *Device_Vendor_Name(
|
const char *Device_Vendor_Name(
|
||||||
@@ -811,6 +882,7 @@ bool Device_Write_Property(
|
|||||||
bool status = false; /* return value */
|
bool status = false; /* return value */
|
||||||
int len = 0;
|
int len = 0;
|
||||||
BACNET_APPLICATION_DATA_VALUE value;
|
BACNET_APPLICATION_DATA_VALUE value;
|
||||||
|
int temp;
|
||||||
|
|
||||||
if (!Device_Valid_Object_Instance_Number(wp_data->object_instance)) {
|
if (!Device_Valid_Object_Instance_Number(wp_data->object_instance)) {
|
||||||
*error_class = ERROR_CLASS_OBJECT;
|
*error_class = ERROR_CLASS_OBJECT;
|
||||||
@@ -825,92 +897,70 @@ bool Device_Write_Property(
|
|||||||
/* FIXME: len == 0: unable to decode? */
|
/* FIXME: len == 0: unable to decode? */
|
||||||
switch (wp_data->object_property) {
|
switch (wp_data->object_property) {
|
||||||
case PROP_OBJECT_IDENTIFIER:
|
case PROP_OBJECT_IDENTIFIER:
|
||||||
if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) {
|
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_OBJECT_ID, error_class, error_code) == true) {
|
||||||
if ((value.type.Object_Id.type == OBJECT_DEVICE) &&
|
if ((value.type.Object_Id.type == OBJECT_DEVICE) &&
|
||||||
(Device_Set_Object_Instance_Number(value.type.
|
(Device_Set_Object_Instance_Number(value.type.Object_Id.instance))) {
|
||||||
Object_Id.instance))) {
|
|
||||||
/* FIXME: we could send an I-Am broadcast to let the world know */
|
/* FIXME: we could send an I-Am broadcast to let the world know */
|
||||||
status = true;
|
status = true;
|
||||||
} else {
|
} else {
|
||||||
*error_class = ERROR_CLASS_PROPERTY;
|
*error_class = ERROR_CLASS_PROPERTY;
|
||||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
*error_class = ERROR_CLASS_PROPERTY;
|
|
||||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PROP_NUMBER_OF_APDU_RETRIES:
|
case PROP_NUMBER_OF_APDU_RETRIES:
|
||||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code)) == true) {
|
||||||
/* FIXME: bounds check? */
|
/* FIXME: bounds check? */
|
||||||
apdu_retries_set((uint8_t) value.type.Unsigned_Int);
|
apdu_retries_set((uint8_t) value.type.Unsigned_Int);
|
||||||
status = true;
|
|
||||||
} else {
|
|
||||||
*error_class = ERROR_CLASS_PROPERTY;
|
|
||||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PROP_APDU_TIMEOUT:
|
case PROP_APDU_TIMEOUT:
|
||||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code)) == true) {
|
||||||
/* FIXME: bounds check? */
|
/* FIXME: bounds check? */
|
||||||
apdu_timeout_set((uint16_t) value.type.Unsigned_Int);
|
apdu_timeout_set((uint16_t) value.type.Unsigned_Int);
|
||||||
status = true;
|
|
||||||
} else {
|
|
||||||
*error_class = ERROR_CLASS_PROPERTY;
|
|
||||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PROP_VENDOR_IDENTIFIER:
|
case PROP_VENDOR_IDENTIFIER:
|
||||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
if((status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code)) == true) {
|
||||||
/* FIXME: bounds check? */
|
/* FIXME: bounds check? */
|
||||||
Device_Set_Vendor_Identifier((uint16_t) value.
|
Device_Set_Vendor_Identifier((uint16_t) value.type.Unsigned_Int);
|
||||||
type.Unsigned_Int);
|
|
||||||
status = true;
|
|
||||||
} else {
|
|
||||||
*error_class = ERROR_CLASS_PROPERTY;
|
|
||||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PROP_SYSTEM_STATUS:
|
case PROP_SYSTEM_STATUS:
|
||||||
if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) {
|
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED, error_class, error_code) == true) {
|
||||||
/* FIXME: bounds check? */
|
temp = Device_Set_System_Status((BACNET_DEVICE_STATUS) value.type.Enumerated, false);
|
||||||
Device_Set_System_Status((BACNET_DEVICE_STATUS) value.
|
if(temp == 0)
|
||||||
type.Enumerated);
|
status = true;
|
||||||
status = true;
|
else {
|
||||||
} else {
|
|
||||||
*error_class = ERROR_CLASS_PROPERTY;
|
|
||||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PROP_OBJECT_NAME:
|
|
||||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
|
||||||
if (characterstring_encoding(&value.type.Character_String) == CHARACTER_ANSI_X34) {
|
|
||||||
if(characterstring_length(&value.type.Character_String) == 0) {
|
|
||||||
*error_class = ERROR_CLASS_PROPERTY;
|
|
||||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
|
||||||
} else {
|
|
||||||
status =
|
|
||||||
Device_Set_Object_Name(characterstring_value
|
|
||||||
(&value.type.Character_String),
|
|
||||||
characterstring_length(&value.type.Character_String));
|
|
||||||
|
|
||||||
if (!status) {
|
|
||||||
*error_class = ERROR_CLASS_RESOURCES;
|
|
||||||
*error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*error_class = ERROR_CLASS_PROPERTY;
|
*error_class = ERROR_CLASS_PROPERTY;
|
||||||
*error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
*error_code = temp == -1 ? ERROR_CODE_VALUE_OUT_OF_RANGE : ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
*error_class = ERROR_CLASS_PROPERTY;
|
|
||||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_OBJECT_NAME:
|
||||||
|
if((status = WPValidateString(&value, MAX_DEV_LOC_LEN, false, error_class, error_code)) == true)
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
Device_Set_Model_Name(characterstring_value(&value.type.Character_String), characterstring_length(&value.type.Character_String));
|
||||||
|
break;
|
||||||
|
|
||||||
#if defined(BACDL_MSTP)
|
#if defined(BACDL_MSTP)
|
||||||
case PROP_MAX_INFO_FRAMES:
|
case PROP_MAX_INFO_FRAMES:
|
||||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code) == true) {
|
||||||
if (value.type.Unsigned_Int <= 255) {
|
if (value.type.Unsigned_Int <= 255) {
|
||||||
dlmstp_set_max_info_frames((uint8_t) value.
|
dlmstp_set_max_info_frames((uint8_t) value.
|
||||||
type.Unsigned_Int);
|
type.Unsigned_Int);
|
||||||
@@ -919,13 +969,10 @@ bool Device_Write_Property(
|
|||||||
*error_class = ERROR_CLASS_PROPERTY;
|
*error_class = ERROR_CLASS_PROPERTY;
|
||||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
*error_class = ERROR_CLASS_PROPERTY;
|
|
||||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PROP_MAX_MASTER:
|
case PROP_MAX_MASTER:
|
||||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
if(WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT, error_class, error_code) == true) {
|
||||||
if ((value.type.Unsigned_Int > 0) &&
|
if ((value.type.Unsigned_Int > 0) &&
|
||||||
(value.type.Unsigned_Int <= 127)) {
|
(value.type.Unsigned_Int <= 127)) {
|
||||||
dlmstp_set_max_master((uint8_t) value.type.Unsigned_Int);
|
dlmstp_set_max_master((uint8_t) value.type.Unsigned_Int);
|
||||||
@@ -934,9 +981,6 @@ bool Device_Write_Property(
|
|||||||
*error_class = ERROR_CLASS_PROPERTY;
|
*error_class = ERROR_CLASS_PROPERTY;
|
||||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
*error_class = ERROR_CLASS_PROPERTY;
|
|
||||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@@ -1025,7 +1069,7 @@ void testDevice(
|
|||||||
ct_test(pTest, status == false);
|
ct_test(pTest, status == false);
|
||||||
|
|
||||||
|
|
||||||
Device_Set_System_Status(STATUS_NON_OPERATIONAL);
|
Device_Set_System_Status(STATUS_NON_OPERATIONAL, true);
|
||||||
ct_test(pTest, Device_System_Status() == STATUS_NON_OPERATIONAL);
|
ct_test(pTest, Device_System_Status() == STATUS_NON_OPERATIONAL);
|
||||||
|
|
||||||
ct_test(pTest, Device_Vendor_Identifier() == BACNET_VENDOR_ID);
|
ct_test(pTest, Device_Vendor_Identifier() == BACNET_VENDOR_ID);
|
||||||
|
|||||||
@@ -86,8 +86,9 @@ extern "C" {
|
|||||||
|
|
||||||
BACNET_DEVICE_STATUS Device_System_Status(
|
BACNET_DEVICE_STATUS Device_System_Status(
|
||||||
void);
|
void);
|
||||||
void Device_Set_System_Status(
|
int Device_Set_System_Status(
|
||||||
BACNET_DEVICE_STATUS status);
|
BACNET_DEVICE_STATUS status,
|
||||||
|
bool local);
|
||||||
|
|
||||||
const char *Device_Vendor_Name(
|
const char *Device_Vendor_Name(
|
||||||
void);
|
void);
|
||||||
|
|||||||
Reference in New Issue
Block a user