Change Life-Safety-Point object to use Create/Delete-Object (#555)

* Change Life-Safety-Point object to use Create/Delete-Object
This commit is contained in:
Steve Karg
2024-01-12 16:01:50 -06:00
committed by GitHub
parent ebc47571ba
commit c6dcab8f0a
9 changed files with 669 additions and 133 deletions
+15 -3
View File
@@ -79,9 +79,21 @@ if(BACNET_STACK_DEPRECATED_DISABLE)
add_definitions(-DBACNET_STACK_DEPRECATED_DISABLE)
endif()
set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
if (CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "AppleClang" OR CMAKE_C_COMPILER_ID MATCHES "GNU")
add_compile_options(-Wall -Wextra -pedantic)
add_compile_options(-Wfloat-equal -Wconversion -Wparentheses)
add_compile_options(-Wunused-value -Wreturn-type -Wswitch-default)
add_compile_options(-Wuninitialized -Winit-self)
add_compile_options(-Wno-sign-conversion -Wno-conversion)
add_compile_options(-Wno-sign-compare -Wno-long-long)
add_compile_options(-Wno-implicit-fallthrough -Wno-attributes)
add_compile_options(-Wunused-variable -Wunused-function)
add_compile_options(-Wunused-parameter)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "AppleClang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
add_compile_options(-Wall -Wextra -pedantic -g -O3)
endif()
#
# library
+1 -1
View File
@@ -207,7 +207,7 @@ static object_functions_t My_Object_Table[] = {
NULL /* ReadRangeInfo */, NULL /* Iterator */, NULL /* Value_Lists */,
NULL /* COV */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */, NULL /* Remove_List_Element */,
NULL /* Create */, NULL /* Delete */, NULL /* Timer */ },
Life_Safety_Point_Create, Life_Safety_Point_Delete, NULL /* Timer */ },
{ OBJECT_LOAD_CONTROL, Load_Control_Init, Load_Control_Count,
Load_Control_Index_To_Instance, Load_Control_Valid_Instance,
Load_Control_Object_Name, Load_Control_Read_Property,
+477 -105
View File
@@ -28,6 +28,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "bacnet/bacdef.h"
#include "bacnet/bacdcode.h"
#include "bacnet/bacenum.h"
@@ -37,22 +38,23 @@
#include "bacnet/wp.h"
#include "bacnet/basic/object/lsp.h"
#include "bacnet/basic/services.h"
#include "bacnet/basic/sys/keylist.h"
#include "bacnet/proplist.h"
#ifndef MAX_LIFE_SAFETY_POINTS
#define MAX_LIFE_SAFETY_POINTS 7
#endif
/* Here are our stored levels.*/
static BACNET_LIFE_SAFETY_MODE Life_Safety_Point_Mode[MAX_LIFE_SAFETY_POINTS];
static BACNET_LIFE_SAFETY_STATE Life_Safety_Point_State[MAX_LIFE_SAFETY_POINTS];
static BACNET_SILENCED_STATE
Life_Safety_Point_Silenced_State[MAX_LIFE_SAFETY_POINTS];
static BACNET_LIFE_SAFETY_OPERATION
Life_Safety_Point_Operation[MAX_LIFE_SAFETY_POINTS];
/* Writable out-of-service allows others to play with our Present Value */
/* without changing the physical output */
static bool Life_Safety_Point_Out_Of_Service[MAX_LIFE_SAFETY_POINTS];
struct object_data {
bool Out_Of_Service : 1;
BACNET_LIFE_SAFETY_STATE Present_Value;
BACNET_LIFE_SAFETY_STATE Tracking_Value;
BACNET_LIFE_SAFETY_MODE Mode;
BACNET_SILENCED_STATE Silenced;
BACNET_LIFE_SAFETY_OPERATION Operation_Expected;
uint8_t Reliability;
const char *Object_Name;
};
/* Key List for storing the object data sorted by instance number */
static OS_Keylist Object_List;
/* common object type */
static const BACNET_OBJECT_TYPE Object_Type = OBJECT_LIFE_SAFETY_POINT;
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Life_Safety_Point_Properties_Required[] = {
@@ -62,8 +64,7 @@ static const int Life_Safety_Point_Properties_Required[] = {
PROP_ACCEPTED_MODES, PROP_SILENCED, PROP_OPERATION_EXPECTED, -1
};
static const int Life_Safety_Point_Properties_Optional[] = { PROP_DESCRIPTION,
-1 };
static const int Life_Safety_Point_Properties_Optional[] = { -1 };
static const int Life_Safety_Point_Properties_Proprietary[] = { -1 };
@@ -94,97 +95,341 @@ void Life_Safety_Point_Property_Lists(
return;
}
void Life_Safety_Point_Init(void)
{
static bool initialized = false;
unsigned i;
if (!initialized) {
initialized = true;
/* initialize all the analog output priority arrays to NULL */
for (i = 0; i < MAX_LIFE_SAFETY_POINTS; i++) {
Life_Safety_Point_Mode[i] = LIFE_SAFETY_MODE_DEFAULT;
Life_Safety_Point_State[i] = LIFE_SAFETY_STATE_QUIET;
Life_Safety_Point_Silenced_State[i] = SILENCED_STATE_UNSILENCED;
Life_Safety_Point_Operation[i] = LIFE_SAFETY_OP_NONE;
}
}
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
/**
* @brief Determines if a given object instance is valid
* @param object_instance - object-instance number of the object
* @return true if the instance is valid, and false if not
*/
bool Life_Safety_Point_Valid_Instance(uint32_t object_instance)
{
if (object_instance < MAX_LIFE_SAFETY_POINTS) {
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
return true;
}
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
/**
* @brief Determines the number of objects
* @return Number of objects
*/
unsigned Life_Safety_Point_Count(void)
{
return MAX_LIFE_SAFETY_POINTS;
return Keylist_Count(Object_List);
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
/**
* @brief Determines if a given object instance is valid
* @param object_instance - object-instance number of the object
* @return true if the instance is BACNET_SILENCED_STATE Silenced;
* @brief Determines the object instance-number for a given 0..N index
* where N is Life_Safety_Point_Count().
* @param index - 0..N value
* @return object instance-number for the given index
*/
uint32_t Life_Safety_Point_Index_To_Instance(unsigned index)
{
return index;
return Keylist_Key(Object_List, index);
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
/**
* @brief For a given object instance-number, determines a 0..N index
* of where N is Life_Safety_Point_Count().
* @param object_instance - object-instance number of the object
* @return index for the given instance-number
*/
unsigned Life_Safety_Point_Instance_To_Index(uint32_t object_instance)
{
unsigned index = MAX_LIFE_SAFETY_POINTS;
if (object_instance < MAX_LIFE_SAFETY_POINTS) {
index = object_instance;
return Keylist_Index(Object_List, object_instance);
}
return index;
}
static BACNET_LIFE_SAFETY_STATE Life_Safety_Point_Present_Value(
/**
* @brief For a given object instance-number, determines the present-value
* @param object_instance - object-instance number of the object
* @return present-value of the object
*/
BACNET_LIFE_SAFETY_STATE Life_Safety_Point_Present_Value(
uint32_t object_instance)
{
BACNET_LIFE_SAFETY_STATE present_value = LIFE_SAFETY_STATE_QUIET;
unsigned index = 0;
BACNET_LIFE_SAFETY_STATE value = LIFE_SAFETY_STATE_QUIET;
struct object_data *pObject;
index = Life_Safety_Point_Instance_To_Index(object_instance);
if (index < MAX_LIFE_SAFETY_POINTS) {
present_value = Life_Safety_Point_State[index];
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
value = pObject->Present_Value;
}
return present_value;
return value;
}
/* note: the object name must be unique within this device */
bool Life_Safety_Point_Object_Name(
uint32_t object_instance, BACNET_CHARACTER_STRING *object_name)
/**
* @brief For a given object instance-number, sets the present-value
* @param object_instance - object-instance number of the object
* @param value - floating point analog output relinquish-default value
* @return true if values are within range and relinquish-default value is set.
*/
bool Life_Safety_Point_Present_Value_Set(
uint32_t object_instance, BACNET_LIFE_SAFETY_STATE value)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
struct object_data *pObject;
if (object_instance < MAX_LIFE_SAFETY_POINTS) {
sprintf(text_string, "LS POINT %u", object_instance);
status = characterstring_init_ansi(object_name, text_string);
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
pObject->Present_Value = value;
status = true;
}
return status;
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
/**
* For a given object instance-number, loads the object-name into
* a characterstring. Note that the object name must be unique
* within this device.
*
* @param object_instance - object-instance number of the object
* @param object_name - holds the object-name retrieved
*
* @return true if object-name was retrieved
*/
bool Life_Safety_Point_Object_Name(
uint32_t object_instance, BACNET_CHARACTER_STRING *object_name)
{
bool status = false;
struct object_data *pObject;
char name_text[32];
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (pObject->Object_Name) {
status =
characterstring_init_ansi(object_name, pObject->Object_Name);
} else {
snprintf(name_text, sizeof(name_text), "LIFE-SAFETY-POINT-%u",
object_instance);
status = characterstring_init_ansi(object_name, name_text);
}
}
return status;
}
/**
* @brief For a given object instance-number, gets the property value
* @param object_instance - object-instance number of the object
* @return property value
*/
BACNET_SILENCED_STATE Life_Safety_Point_Silenced(uint32_t object_instance)
{
BACNET_SILENCED_STATE value = SILENCED_STATE_UNSILENCED;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
value = pObject->Silenced;
}
return value;
}
/**
* @brief For a given object instance-number, sets the property value
* @param object_instance - object-instance number of the object
* @param value - enumerated value
* @return true if values are within range and property is set.
*/
bool Life_Safety_Point_Silenced_Set(
uint32_t object_instance, BACNET_SILENCED_STATE value)
{
struct object_data *pObject;
bool status = false;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (value <= SILENCED_STATE_PROPRIETARY_MAX) {
pObject->Silenced = value;
status = true;
}
}
return status;
}
/**
* @brief For a given object instance-number, gets the property value
* @param object_instance - object-instance number of the object
* @return property value
*/
BACNET_LIFE_SAFETY_MODE Life_Safety_Point_Mode(uint32_t object_instance)
{
BACNET_LIFE_SAFETY_MODE value = LIFE_SAFETY_MODE_OFF;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
value = pObject->Mode;
}
return value;
}
/**
* @brief For a given object instance-number, sets the property value
* @param object_instance - object-instance number of the object
* @param value - enumerated value
* @return true if values are within range and property is set.
*/
bool Life_Safety_Point_Mode_Set(
uint32_t object_instance, BACNET_LIFE_SAFETY_MODE value)
{
struct object_data *pObject;
bool status = false;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (value <= LIFE_SAFETY_MODE_PROPRIETARY_MAX) {
pObject->Mode = value;
status = true;
}
}
return status;
}
/**
* @brief For a given object instance-number, gets the property value
* @param object_instance - object-instance number of the object
* @return property value
*/
BACNET_LIFE_SAFETY_OPERATION Life_Safety_Point_Operation_Expected(
uint32_t object_instance)
{
BACNET_LIFE_SAFETY_OPERATION value = LIFE_SAFETY_OP_NONE;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
value = pObject->Operation_Expected;
}
return value;
}
/**
* @brief For a given object instance-number, sets the property value
* @param object_instance - object-instance number of the object
* @param value - enumerated value
* @return true if values are within range and property is set.
*/
bool Life_Safety_Point_Operation_Expected_Set(
uint32_t object_instance, BACNET_LIFE_SAFETY_OPERATION value)
{
struct object_data *pObject;
bool status = false;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (value <= LIFE_SAFETY_OP_PROPRIETARY_MAX) {
pObject->Operation_Expected = value;
status = true;
}
}
return status;
}
/**
* @brief For a given object instance-number, returns the out-of-service
* status flag
* @param object_instance - object-instance number of the object
* @return out-of-service status flag
*/
bool Life_Safety_Point_Out_Of_Service(uint32_t object_instance)
{
bool value = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
value = pObject->Out_Of_Service;
}
return value;
}
/**
* @brief For a given object instance-number, sets the out-of-service status
* flag
* @param object_instance - object-instance number of the object
* @param value - boolean out-of-service value
* @return true if the out-of-service status flag was set
*/
void Life_Safety_Point_Out_Of_Service_Set(uint32_t object_instance, bool value)
{
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (pObject->Out_Of_Service != value) {
pObject->Out_Of_Service = value;
}
}
}
/**
* @brief For a given object instance-number, gets the reliability.
* @param object_instance - object-instance number of the object
* @return reliability value
*/
BACNET_RELIABILITY Life_Safety_Point_Reliability(uint32_t object_instance)
{
BACNET_RELIABILITY reliability = RELIABILITY_NO_FAULT_DETECTED;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
reliability = (BACNET_RELIABILITY)pObject->Reliability;
}
return reliability;
}
/**
* @brief For a given object instance-number, sets the reliability
* @param object_instance - object-instance number of the object
* @param value - reliability enumerated value
* @return true if values are within range and property is set.
*/
bool Life_Safety_Point_Reliability_Set(
uint32_t object_instance, BACNET_RELIABILITY value)
{
struct object_data *pObject;
bool status = false;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (value <= 255) {
pObject->Reliability = value;
status = true;
}
}
return status;
}
/**
* @brief ReadProperty handler for this object. For the given ReadProperty
* data, the application_data is loaded or the error flags are set.
* @param rpdata - BACNET_READ_PROPERTY_DATA data, including
* requested data and space for the reply, or error response.
* @return number of APDU bytes in the response, or
* BACNET_STATUS_ERROR on error.
*/
int Life_Safety_Point_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
{
int len = 0;
@@ -195,7 +440,6 @@ int Life_Safety_Point_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
BACNET_LIFE_SAFETY_MODE mode = LIFE_SAFETY_MODE_DEFAULT;
BACNET_SILENCED_STATE silenced_state = SILENCED_STATE_UNSILENCED;
BACNET_LIFE_SAFETY_OPERATION operation = LIFE_SAFETY_OP_NONE;
unsigned object_index = 0;
bool state = false;
BACNET_RELIABILITY reliability = RELIABILITY_NO_FAULT_DETECTED;
uint8_t *apdu = NULL;
@@ -208,18 +452,16 @@ int Life_Safety_Point_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len = encode_application_object_id(
&apdu[0], OBJECT_LIFE_SAFETY_POINT, rpdata->object_instance);
&apdu[0], Object_Type, rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
Life_Safety_Point_Object_Name(
rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len = encode_application_enumerated(
&apdu[0], OBJECT_LIFE_SAFETY_POINT);
apdu_len = encode_application_enumerated(&apdu[0], Object_Type);
break;
case PROP_PRESENT_VALUE:
present_value =
@@ -235,9 +477,20 @@ int Life_Safety_Point_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
if (Life_Safety_Point_Reliability(rpdata->object_instance) ==
RELIABILITY_NO_FAULT_DETECTED) {
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
} else {
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, true);
}
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
if (Life_Safety_Point_Out_Of_Service(rpdata->object_instance)) {
bitstring_set_bit(
&bit_string, STATUS_FLAG_OUT_OF_SERVICE, true);
} else {
bitstring_set_bit(
&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
}
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_EVENT_STATE:
@@ -245,20 +498,16 @@ int Life_Safety_Point_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
break;
case PROP_OUT_OF_SERVICE:
object_index =
Life_Safety_Point_Instance_To_Index(rpdata->object_instance);
state = Life_Safety_Point_Out_Of_Service[object_index];
state = Life_Safety_Point_Out_Of_Service(rpdata->object_instance);
apdu_len = encode_application_boolean(&apdu[0], state);
break;
case PROP_RELIABILITY:
/* see standard for details about this property */
reliability = RELIABILITY_NO_FAULT_DETECTED;
reliability =
Life_Safety_Point_Reliability(rpdata->object_instance);
apdu_len = encode_application_enumerated(&apdu[0], reliability);
break;
case PROP_MODE:
object_index =
Life_Safety_Point_Instance_To_Index(rpdata->object_instance);
mode = Life_Safety_Point_Mode[object_index];
mode = Life_Safety_Point_Mode(rpdata->object_instance);
apdu_len = encode_application_enumerated(&apdu[0], mode);
break;
case PROP_ACCEPTED_MODES:
@@ -269,15 +518,12 @@ int Life_Safety_Point_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
}
break;
case PROP_SILENCED:
object_index =
Life_Safety_Point_Instance_To_Index(rpdata->object_instance);
silenced_state = Life_Safety_Point_Silenced_State[object_index];
silenced_state =
Life_Safety_Point_Silenced(rpdata->object_instance);
apdu_len = encode_application_enumerated(&apdu[0], silenced_state);
break;
case PROP_OPERATION_EXPECTED:
object_index =
Life_Safety_Point_Instance_To_Index(rpdata->object_instance);
operation = Life_Safety_Point_Operation[object_index];
operation = Life_Safety_Point_Operation_Expected(rpdata->object_instance);
apdu_len = encode_application_enumerated(&apdu[0], operation);
break;
default:
@@ -300,7 +546,6 @@ int Life_Safety_Point_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
bool Life_Safety_Point_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
@@ -326,10 +571,23 @@ bool Life_Safety_Point_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
wp_data, &value, BACNET_APPLICATION_TAG_ENUMERATED);
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] =
(BACNET_LIFE_SAFETY_MODE)value.type.Enumerated;
Life_Safety_Point_Mode_Set(wp_data->object_instance,
(BACNET_LIFE_SAFETY_MODE)value.type.Enumerated);
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
break;
case PROP_PRESENT_VALUE:
status = write_property_type_valid(
wp_data, &value, BACNET_APPLICATION_TAG_ENUMERATED);
if (status) {
if (value.type.Enumerated <= UINT16_MAX) {
Life_Safety_Point_Present_Value_Set(
wp_data->object_instance,
(BACNET_LIFE_SAFETY_STATE)value.type.Enumerated);
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
@@ -341,25 +599,48 @@ bool Life_Safety_Point_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
status = write_property_type_valid(
wp_data, &value, BACNET_APPLICATION_TAG_BOOLEAN);
if (status) {
object_index = Life_Safety_Point_Instance_To_Index(
wp_data->object_instance);
Life_Safety_Point_Out_Of_Service[object_index] =
value.type.Boolean;
Life_Safety_Point_Out_Of_Service_Set(
wp_data->object_instance, value.type.Boolean);
}
break;
case PROP_SILENCED:
status = write_property_type_valid(
wp_data, &value, BACNET_APPLICATION_TAG_ENUMERATED);
if (status) {
if (value.type.Enumerated <= UINT16_MAX) {
Life_Safety_Point_Silenced_Set(wp_data->object_instance,
(BACNET_SILENCED_STATE)value.type.Enumerated);
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
break;
case PROP_OPERATION_EXPECTED:
status = write_property_type_valid(
wp_data, &value, BACNET_APPLICATION_TAG_ENUMERATED);
if (status) {
if (value.type.Enumerated <= UINT16_MAX) {
Life_Safety_Point_Operation_Expected_Set(
wp_data->object_instance,
(BACNET_LIFE_SAFETY_OPERATION)value.type.Enumerated);
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
case PROP_OBJECT_TYPE:
case PROP_PRESENT_VALUE:
case PROP_TRACKING_VALUE:
case PROP_STATUS_FLAGS:
case PROP_EVENT_STATE:
case PROP_RELIABILITY:
case PROP_ACCEPTED_MODES:
case PROP_SILENCED:
case PROP_OPERATION_EXPECTED:
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
@@ -371,3 +652,94 @@ bool Life_Safety_Point_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
return status;
}
/**
* @brief Creates an object and initialize its properties to defaults
* @param object_instance - object-instance number of the object
* @return the object-instance that was created, or BACNET_MAX_INSTANCE
*/
uint32_t Life_Safety_Point_Create(uint32_t object_instance)
{
struct object_data *pObject = NULL;
int index = 0;
if (object_instance > BACNET_MAX_INSTANCE) {
return BACNET_MAX_INSTANCE;
} else if (object_instance == BACNET_MAX_INSTANCE) {
/* wildcard instance */
/* the Object_Identifier property of the newly created object
shall be initialized to a value that is unique within the
responding BACnet-user device. The method used to generate
the object identifier is a local matter.*/
object_instance = Keylist_Next_Empty_Key(Object_List, 1);
}
pObject = Keylist_Data(Object_List, object_instance);
if (!pObject) {
pObject = calloc(1, sizeof(struct object_data));
if (pObject) {
pObject->Object_Name = NULL;
pObject->Reliability = RELIABILITY_NO_FAULT_DETECTED;
pObject->Mode = LIFE_SAFETY_MODE_DEFAULT;
pObject->Present_Value = LIFE_SAFETY_STATE_QUIET;
pObject->Silenced = SILENCED_STATE_UNSILENCED;
pObject->Operation_Expected = LIFE_SAFETY_OP_NONE;
pObject->Out_Of_Service = false;
/* add to list */
index = Keylist_Data_Add(Object_List, object_instance, pObject);
if (index < 0) {
free(pObject);
return BACNET_MAX_INSTANCE;
}
} else {
return BACNET_MAX_INSTANCE;
}
}
return object_instance;
}
/**
* @brief Deletes an object and its property
* @param object_instance - object-instance number of the object
* @return true if the object-instance was deleted
*/
bool Life_Safety_Point_Delete(uint32_t object_instance)
{
bool status = false;
struct object_data *pObject = NULL;
pObject = Keylist_Data_Delete(Object_List, object_instance);
if (pObject) {
free(pObject);
status = true;
}
return status;
}
/**
* @brief Deletes all the objects and their property data
*/
void Life_Safety_Point_Cleanup(void)
{
struct object_data *pObject;
if (Object_List) {
do {
pObject = Keylist_Data_Pop(Object_List);
if (pObject) {
free(pObject);
}
} while (pObject);
Keylist_Delete(Object_List);
Object_List = NULL;
}
}
/**
* @brief Initializes the object data
*/
void Life_Safety_Point_Init(void)
{
Object_List = Keylist_Create();
}
+64 -2
View File
@@ -54,13 +54,61 @@ extern "C" {
BACNET_STACK_EXPORT
unsigned Life_Safety_Point_Instance_To_Index(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Life_Safety_Point_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
BACNET_STACK_EXPORT
void Life_Safety_Point_Init(
void);
bool Life_Safety_Point_Name_Set(
uint32_t object_instance,
char *new_name);
BACNET_STACK_EXPORT
BACNET_LIFE_SAFETY_STATE Life_Safety_Point_Present_Value(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Life_Safety_Point_Present_Value_Set(
uint32_t object_instance,
BACNET_LIFE_SAFETY_STATE present_value);
BACNET_STACK_EXPORT
BACNET_SILENCED_STATE Life_Safety_Point_Silenced(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Life_Safety_Point_Silenced_Set(
uint32_t object_instance,
BACNET_SILENCED_STATE value);
BACNET_STACK_EXPORT
BACNET_LIFE_SAFETY_MODE Life_Safety_Point_Mode(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Life_Safety_Point_Mode_Set(
uint32_t object_instance,
BACNET_LIFE_SAFETY_MODE value);
BACNET_STACK_EXPORT
BACNET_LIFE_SAFETY_OPERATION Life_Safety_Point_Operation_Expected(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Life_Safety_Point_Operation_Expected_Set(
uint32_t object_instance,
BACNET_LIFE_SAFETY_OPERATION value);
BACNET_STACK_EXPORT
bool Life_Safety_Point_Out_Of_Service(
uint32_t instance);
BACNET_STACK_EXPORT
void Life_Safety_Point_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag);
BACNET_STACK_EXPORT
BACNET_RELIABILITY Life_Safety_Point_Reliability(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Life_Safety_Point_Reliability_Set(
uint32_t object_instance, BACNET_RELIABILITY value);
BACNET_STACK_EXPORT
int Life_Safety_Point_Read_Property(
@@ -70,6 +118,20 @@ extern "C" {
bool Life_Safety_Point_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
BACNET_STACK_EXPORT
uint32_t Life_Safety_Point_Create(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Life_Safety_Point_Delete(
uint32_t object_instance);
BACNET_STACK_EXPORT
void Life_Safety_Point_Cleanup(
void);
BACNET_STACK_EXPORT
void Life_Safety_Point_Init(
void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
+11 -6
View File
@@ -4,9 +4,6 @@ cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
# set the project name
project(Unit_Tests)
# add definitions
add_definitions(-fprofile-arcs -ftest-coverage)
option(BACNET_STACK_DEPRECATED_DISABLE "Disable deprecation compile warnings" ON)
if(BACNET_STACK_DEPRECATED_DISABLE)
@@ -14,11 +11,19 @@ if(BACNET_STACK_DEPRECATED_DISABLE)
endif()
# Set the compiler options
if (NOT MSVC)
add_compile_options(-Wall -g -O0 -W -fprofile-arcs -ftest-coverage)
if (CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "GNU")
add_definitions(-fprofile-arcs -ftest-coverage)
add_compile_options(-g -O0 -W -fprofile-arcs -ftest-coverage)
add_compile_options(-Wall -Wextra -pedantic)
add_compile_options(-Wfloat-equal -Wconversion -Wparentheses)
add_compile_options(-Wunused-value -Wreturn-type -Wswitch-default)
add_compile_options(-Wuninitialized -Winit-self)
add_compile_options(-Wno-sign-conversion -Wno-conversion)
add_compile_options(-Wno-sign-compare -Wno-long-long)
add_compile_options(-Wno-implicit-fallthrough -Wno-attributes)
# ignore some warnings that occur during unit testing
add_compile_options(-Wno-unused-variable -Wno-unused-function)
add_compile_options(-Wno-sign-compare -Wno-unused-parameter)
add_compile_options(-Wno-unused-parameter)
add_link_options(-fprofile-arcs -ftest-coverage)
endif()
+2 -2
View File
@@ -7,7 +7,6 @@ project(test_${basename}
VERSION 1.0.0
LANGUAGES C)
string(REGEX REPLACE
"/test/bacnet/[a-zA-Z_/-]*$"
"/src"
@@ -45,8 +44,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/bacstr.c
${SRC_DIR}/bacnet/bactext.c
${SRC_DIR}/bacnet/basic/sys/bigend.c
${SRC_DIR}/bacnet/datetime.c
${SRC_DIR}/bacnet/basic/sys/days.c
${SRC_DIR}/bacnet/basic/sys/keylist.c
${SRC_DIR}/bacnet/datetime.c
${SRC_DIR}/bacnet/indtext.c
${SRC_DIR}/bacnet/hostnport.c
${SRC_DIR}/bacnet/lighting.c
+95 -12
View File
@@ -9,6 +9,7 @@
*/
#include <zephyr/ztest.h>
#include <bacnet/bactext.h>
#include <bacnet/basic/object/lsp.h>
/**
@@ -25,26 +26,108 @@ ZTEST(lsp_tests, testLifeSafetyPoint)
static void testLifeSafetyPoint(void)
#endif
{
BACNET_OBJECT_TYPE object_type = OBJECT_LIFE_SAFETY_POINT;
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0, test_len = 0;
BACNET_OBJECT_TYPE decoded_type = 0;
uint32_t decoded_instance = 0;
BACNET_READ_PROPERTY_DATA rpdata;
int len = 0;
int test_len = 0;
BACNET_READ_PROPERTY_DATA rpdata = { 0 };
BACNET_APPLICATION_DATA_VALUE value = { 0 };
const int *pRequired = NULL;
const int *pOptional = NULL;
const int *pProprietary = NULL;
const uint32_t instance = 123;
BACNET_WRITE_PROPERTY_DATA wpdata = { 0 };
bool status = false;
unsigned index;
Life_Safety_Point_Init();
Life_Safety_Point_Create(instance);
status = Life_Safety_Point_Valid_Instance(instance);
zassert_true(status, NULL);
index = Life_Safety_Point_Instance_To_Index(instance);
zassert_equal(index, 0, NULL);
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_LIFE_SAFETY_POINT;
rpdata.object_instance = 1;
rpdata.object_type = object_type;
rpdata.object_instance = instance;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
Life_Safety_Point_Property_Lists(&pRequired, &pOptional, &pProprietary);
while ((*pRequired) >= 0) {
rpdata.object_property = *pRequired;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Life_Safety_Point_Read_Property(&rpdata);
zassert_not_equal(len, 0, NULL);
test_len = bacnet_object_id_application_decode(
apdu, len, &decoded_type, &decoded_instance);
zassert_not_equal(test_len, BACNET_STATUS_ERROR, NULL);
zassert_equal(decoded_type, rpdata.object_type, NULL);
zassert_equal(decoded_instance, rpdata.object_instance, NULL);
zassert_not_equal(len, BACNET_STATUS_ERROR,
"property '%s': failed to ReadProperty!\n",
bactext_property_name(rpdata.object_property));
if (len >= 0) {
test_len = bacapp_decode_known_property(rpdata.application_data,
len, &value, rpdata.object_type, rpdata.object_property);
if (len != test_len) {
printf("property '%s': failed to decode!\n",
bactext_property_name(rpdata.object_property));
} else {
zassert_equal(len, test_len, NULL);
}
/* check WriteProperty properties */
wpdata.object_type = rpdata.object_type;
wpdata.object_instance = rpdata.object_instance;
wpdata.object_property = rpdata.object_property;
wpdata.array_index = rpdata.array_index;
memcpy(&wpdata.application_data, rpdata.application_data, MAX_APDU);
wpdata.application_data_len = len;
wpdata.error_code = ERROR_CODE_SUCCESS;
status = Life_Safety_Point_Write_Property(&wpdata);
if (!status) {
/* verify WriteProperty property is known */
zassert_not_equal(wpdata.error_code,
ERROR_CODE_UNKNOWN_PROPERTY,
"property '%s': WriteProperty Unknown!\n",
bactext_property_name(rpdata.object_property));
}
}
pRequired++;
}
while ((*pOptional) != -1) {
rpdata.object_property = *pOptional;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Life_Safety_Point_Read_Property(&rpdata);
zassert_not_equal(len, BACNET_STATUS_ERROR,
"property '%s': failed to ReadProperty!\n",
bactext_property_name(rpdata.object_property));
if (len > 0) {
test_len = bacapp_decode_application_data(rpdata.application_data,
(uint8_t)rpdata.application_data_len, &value);
zassert_equal(len, test_len, "property '%s': failed to decode!\n",
bactext_property_name(rpdata.object_property));
/* check WriteProperty properties */
wpdata.object_type = rpdata.object_type;
wpdata.object_instance = rpdata.object_instance;
wpdata.object_property = rpdata.object_property;
wpdata.array_index = rpdata.array_index;
memcpy(&wpdata.application_data, rpdata.application_data, MAX_APDU);
wpdata.application_data_len = len;
wpdata.error_code = ERROR_CODE_SUCCESS;
status = Life_Safety_Point_Write_Property(&wpdata);
if (!status) {
/* verify WriteProperty property is known */
zassert_not_equal(wpdata.error_code,
ERROR_CODE_UNKNOWN_PROPERTY,
"property '%s': WriteProperty Unknown!\n",
bactext_property_name(rpdata.object_property));
}
}
pOptional++;
}
rpdata.object_property = PROP_ALL;
len = Life_Safety_Point_Read_Property(&rpdata);
zassert_equal(len, BACNET_STATUS_ERROR, NULL);
wpdata.object_property = PROP_ALL;
status = Life_Safety_Point_Write_Property(&wpdata);
zassert_false(status, NULL);
status = Life_Safety_Point_Delete(instance);
zassert_true(status, NULL);
return;
}
+1
View File
@@ -251,6 +251,7 @@ static void handle_signal(int sig)
PRINT(" at %s function\n", phase_str[phase]);
longjmp(test_fail, 1);
case TEST_PHASE_FRAMEWORK:
default:
PRINT("\n");
longjmp(stack_fail, 1);
}
@@ -42,6 +42,7 @@ if(BOARD STREQUAL unit_testing)
${BACNET_SRC}/datetime.c
${BACNET_SRC}/timestamp.c
${BACNET_SRC}/basic/sys/days.c
${BACNET_SRC}/basic/sys/keylist.c
${BACNET_SRC}/bacdevobjpropref.c
${BACNET_SRC}/bactext.c
${BACNET_SRC}/indtext.c