From 46d686a8abdb41832a581be29e776023b18b4f13 Mon Sep 17 00:00:00 2001 From: Sebastian Weyer <50481737+DocSepp@users.noreply.github.com> Date: Mon, 5 Feb 2024 18:32:02 +0100 Subject: [PATCH] Add missing object functions to analog inputs and values (#568) * ai.c: add possibility to set a custom object name The Name_Set function is already declared in the header but not implemented. With this implementation, one can set a custom object name from a server application. Signed-off-by: Sebastian Weyer * av.c: add possibility to set a custom object name The Name_Set function is already declared in the header but not implemented. With this implementation, one can set a custom object name from a server application. Signed-off-by: Sebastian Weyer * ai.c: implement function to set custom description For now the hard-coded behaviour was to return the object name whenever a client requested the value for the description. Therefore implement the functions Description and Description_Set already declared in the header and add a Description property to the data structure used. We also need to properly implement PROP_DESCRIPTION in the Read_Property function. This way we can set and read a custom decsription from a server application and send the appropriate response to a read-property request asking for PROP_DESCRIPTION. Signed-off-by: Sebastian Weyer * av.c: implement function to set custom description For now the hard-coded behaviour was to return the object name whenever a client requested the value for the description. Therefore implement the functions Description and Description_Set already declared in the header and add a Description property to the data structure used. We also need to properly implement PROP_DESCRIPTION in the Read_Property function. This way we can set and read a custom decsription from a server application and send the appropriate response to a read-property request asking for PROP_DESCRIPTION. Signed-off-by: Sebastian Weyer * ai.c: implement function to set custom units Implement the object functions related to Units already declared in the header. By default Analog Inputs will have the Unit UNITS_PERCENT. Add functionality to be able to set and read custom units from a server application. Signed-off-by: Sebastian Weyer * av.c: implement function to set custom units Implement the object functions related to Units already declared in the header. By default Analog Values will have the Unit UNITS_NO_UNIT. Add functionality to be able to set and read custom units from a server application. Signed-off-by: Sebastian Weyer --------- Signed-off-by: Sebastian Weyer Co-authored-by: Sebastian Weyer --- src/bacnet/basic/object/ai.c | 125 +++++++++++++++++++++++++++++++++-- src/bacnet/basic/object/ai.h | 2 + src/bacnet/basic/object/av.c | 112 +++++++++++++++++++++++++++++-- src/bacnet/basic/object/av.h | 2 + 4 files changed, 229 insertions(+), 12 deletions(-) diff --git a/src/bacnet/basic/object/ai.c b/src/bacnet/basic/object/ai.c index 41b5ad16..eb416deb 100644 --- a/src/bacnet/basic/object/ai.c +++ b/src/bacnet/basic/object/ai.c @@ -97,6 +97,7 @@ void Analog_Input_Init(void) AI_Descr[i].Prior_Value = 0.0f; AI_Descr[i].COV_Increment = 1.0f; AI_Descr[i].Changed = false; + AI_Descr[i].Object_Name = NULL; #if defined(INTRINSIC_REPORTING) AI_Descr[i].Event_State = EVENT_STATE_NORMAL; /* notification class not connected */ @@ -209,17 +210,49 @@ void Analog_Input_Present_Value_Set(uint32_t object_instance, float value) } } +/** + * For a given object instance-number, return the name. + * + * Note: the object name must be unique within this device + * + * @param object_instance - object-instance number of the object + * @param object_name - object name/string pointer + * + * @return true/false + */ bool Analog_Input_Object_Name( uint32_t object_instance, BACNET_CHARACTER_STRING *object_name) { - static char text_string[32] = ""; /* okay for single thread */ - unsigned int index; + static char text_string[32] = ""; bool status = false; - index = Analog_Input_Instance_To_Index(object_instance); - if (index < MAX_ANALOG_INPUTS) { - sprintf(text_string, "ANALOG INPUT %lu", (unsigned long)index); - status = characterstring_init_ansi(object_name, text_string); + if (object_instance < MAX_ANALOG_INPUTS) { + if (AI_Descr[object_instance].Object_Name) { + status = characterstring_init_ansi(object_name, AI_Descr[object_instance].Object_Name); + } else { + snprintf(text_string, sizeof(text_string), "ANALOG INPUT %u", + object_instance); + status = characterstring_init_ansi(object_name, text_string); + } + } + + return status; +} + +/** + * For a given object instance-number, sets the object-name + * + * @param object_instance - object-instance number of the object + * @param new_name - holds the object-name to be set + * + * @return true if object-name was set + */ +bool Analog_Input_Name_Set(uint32_t object_instance, char *new_name) +{ + bool status = false; + if (object_instance < MAX_ANALOG_INPUTS) { + status = true; + AI_Descr[object_instance].Object_Name = new_name; } return status; @@ -247,6 +280,40 @@ unsigned Analog_Input_Event_State(uint32_t object_instance) return state; } +/** + * @brief For a given object instance-number, returns the description + * @param object_instance - object-instance number of the object + * @return description text or NULL if not found + */ +char *Analog_Input_Description(uint32_t object_instance) +{ + char *name = NULL; + + if (object_instance < MAX_ANALOG_INPUTS) { + name = AI_Descr[object_instance].Description; + } + + return name; +} + +/** + * @brief For a given object instance-number, sets the description + * @param object_instance - object-instance number of the object + * @param new_name - holds the description to be set + * @return true if object-name was set + */ +bool Analog_Input_Description_Set(uint32_t object_instance, char *new_name) +{ + bool status = false; /* return value */ + + if (object_instance < MAX_ANALOG_INPUTS && new_name) { + status = true; + AI_Descr[object_instance].Description = new_name; + } + + return status; +} + bool Analog_Input_Change_Of_Value(uint32_t object_instance) { unsigned index = 0; @@ -327,6 +394,44 @@ void Analog_Input_COV_Increment_Set(uint32_t object_instance, float value) } } +/** + * For a given object instance-number, returns the units property value + * + * @param object_instance - object-instance number of the object + * + * @return units property value + */ +uint16_t Analog_Input_Units(uint32_t object_instance) +{ + uint16_t units = UNITS_NO_UNITS; + + if (object_instance < MAX_ANALOG_INPUTS) { + units = AI_Descr[object_instance].Units; + } + + return units; +} + +/** + * For a given object instance-number, sets the units property value + * + * @param object_instance - object-instance number of the object + * @param units - units property value + * + * @return true if the units property value was set + */ +bool Analog_Input_Units_Set(uint32_t object_instance, uint16_t units) +{ + bool status = false; + + if (object_instance < MAX_ANALOG_INPUTS) { + AI_Descr[object_instance].Units = units; + status = true; + } + + return status; +} + bool Analog_Input_Out_Of_Service(uint32_t object_instance) { unsigned index = 0; @@ -396,12 +501,18 @@ int Analog_Input_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_NAME: - case PROP_DESCRIPTION: Analog_Input_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; + case PROP_DESCRIPTION: + characterstring_init_ansi(&char_string, + Analog_Input_Description(rpdata->object_instance)); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_ANALOG_INPUT); diff --git a/src/bacnet/basic/object/ai.h b/src/bacnet/basic/object/ai.h index 14127930..7cb01e39 100644 --- a/src/bacnet/basic/object/ai.h +++ b/src/bacnet/basic/object/ai.h @@ -52,6 +52,8 @@ extern "C" { float Prior_Value; float COV_Increment; bool Changed; + char* Object_Name; + char* Description; #if defined(INTRINSIC_REPORTING) uint32_t Time_Delay; uint32_t Notification_Class; diff --git a/src/bacnet/basic/object/av.c b/src/bacnet/basic/object/av.c index c1592c38..327db5e4 100644 --- a/src/bacnet/basic/object/av.c +++ b/src/bacnet/basic/object/av.c @@ -104,6 +104,7 @@ void Analog_Value_Init(void) AV_Descr[i].Prior_Value = 0.0f; AV_Descr[i].COV_Increment = 1.0f; AV_Descr[i].Changed = false; + AV_Descr[i].Object_Name = NULL; #if defined(INTRINSIC_REPORTING) AV_Descr[i].Event_State = EVENT_STATE_NORMAL; /* notification class not connected */ @@ -280,13 +281,36 @@ float Analog_Value_Present_Value(uint32_t object_instance) bool Analog_Value_Object_Name( uint32_t object_instance, BACNET_CHARACTER_STRING *object_name) { - static char text_string[32] = ""; /* okay for single thread */ + static char text_string[32] = ""; bool status = false; if (object_instance < MAX_ANALOG_VALUES) { - sprintf( - text_string, "ANALOG VALUE %lu", (unsigned long)object_instance); - status = characterstring_init_ansi(object_name, text_string); + if (AV_Descr[object_instance].Object_Name) { + status = characterstring_init_ansi(object_name, AV_Descr[object_instance].Object_Name); + } else { + snprintf(text_string, sizeof(text_string), "ANALOG VALUE %u", + object_instance); + status = characterstring_init_ansi(object_name, text_string); + } + } + + return status; +} + +/** + * For a given object instance-number, sets the object-name + * + * @param object_instance - object-instance number of the object + * @param new_name - holds the object-name to be set + * + * @return true if object-name was set + */ +bool Analog_Value_Name_Set(uint32_t object_instance, char *new_name) +{ + bool status = false; + if (object_instance < MAX_ANALOG_VALUES) { + status = true; + AV_Descr[object_instance].Object_Name = new_name; } return status; @@ -314,6 +338,40 @@ unsigned Analog_Value_Event_State(uint32_t object_instance) return state; } +/** + * @brief For a given object instance-number, returns the description + * @param object_instance - object-instance number of the object + * @return description text or NULL if not found + */ +char *Analog_Value_Description(uint32_t object_instance) +{ + char *name = NULL; + + if (object_instance < MAX_ANALOG_VALUES) { + name = AV_Descr[object_instance].Description; + } + + return name; +} + +/** + * @brief For a given object instance-number, sets the description + * @param object_instance - object-instance number of the object + * @param new_name - holds the description to be set + * @return true if object-name was set + */ +bool Analog_Value_Description_Set(uint32_t object_instance, char *new_name) +{ + bool status = false; /* return value */ + + if (object_instance < MAX_ANALOG_VALUES && new_name) { + status = true; + AV_Descr[object_instance].Description = new_name; + } + + return status; +} + /** * For a given object instance-number, determines if the COV flag * has been triggered. @@ -431,6 +489,44 @@ void Analog_Value_COV_Increment_Set(uint32_t object_instance, float value) } } +/** + * For a given object instance-number, returns the units property value + * + * @param object_instance - object-instance number of the object + * + * @return units property value + */ +uint16_t Analog_Value_Units(uint32_t object_instance) +{ + uint16_t units = UNITS_NO_UNITS; + + if (object_instance < MAX_ANALOG_VALUES) { + units = AV_Descr[object_instance].Units; + } + + return units; +} + +/** + * For a given object instance-number, sets the units property value + * + * @param object_instance - object-instance number of the object + * @param units - units property value + * + * @return true if the units property value was set + */ +bool Analog_Value_Units_Set(uint32_t object_instance, uint16_t units) +{ + bool status = false; + + if (object_instance < MAX_ANALOG_VALUES) { + AV_Descr[object_instance].Units = units; + status = true; + } + + return status; +} + bool Analog_Value_Out_Of_Service(uint32_t object_instance) { unsigned index = 0; @@ -506,7 +602,6 @@ int Analog_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) break; case PROP_OBJECT_NAME: - case PROP_DESCRIPTION: if (Analog_Value_Object_Name( rpdata->object_instance, &char_string)) { apdu_len = @@ -514,6 +609,13 @@ int Analog_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) } break; + case PROP_DESCRIPTION: + characterstring_init_ansi(&char_string, + Analog_Value_Description(rpdata->object_instance)); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE); diff --git a/src/bacnet/basic/object/av.h b/src/bacnet/basic/object/av.h index 39981586..c4a63823 100644 --- a/src/bacnet/basic/object/av.h +++ b/src/bacnet/basic/object/av.h @@ -52,6 +52,8 @@ extern "C" { float Prior_Value; float COV_Increment; bool Changed; + char* Object_Name; + char* Description; #if defined(INTRINSIC_REPORTING) uint32_t Time_Delay; uint32_t Notification_Class;