From 1b3912c5ca13b4ca8b0b9ecf60e853282ae86adf Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Wed, 4 Jun 2025 15:53:26 -0500 Subject: [PATCH] Added more writable properties to Analog, Binary, and Multistate Output objects. (#1012) --- CHANGELOG.md | 2 ++ src/bacnet/basic/object/ao.c | 42 ++++++++++++++++++++++ src/bacnet/basic/object/bo.c | 16 +++++++++ src/bacnet/basic/object/mso.c | 67 +++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8c7a293..4b07595b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ The git repositories are hosted at the following sites: ### Added +* Added more writable properties to Analog, Binary, and Multistate Output + objects. (#1012) * Added missing API defined in header into ports/win32/dlmstp.c module, added a PDU queue and refactored receive thread, and refactored MS/TP timing parameters. (#1003) diff --git a/src/bacnet/basic/object/ao.c b/src/bacnet/basic/object/ao.c index 86d06b99..5c22bfbc 100644 --- a/src/bacnet/basic/object/ao.c +++ b/src/bacnet/basic/object/ao.c @@ -1145,6 +1145,48 @@ bool Analog_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) wp_data->object_instance, value.type.Boolean); } break; + case PROP_UNITS: + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_ENUMERATED); + if (status) { + status = Analog_Output_Units_Set( + wp_data->object_instance, value.type.Enumerated); + if (!status) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } + break; + case PROP_COV_INCREMENT: + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_REAL); + if (status) { + if (value.type.Real >= 0.0f) { + Analog_Output_COV_Increment_Set( + wp_data->object_instance, value.type.Real); + } else { + status = false; + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } + break; + case PROP_MIN_PRES_VALUE: + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_REAL); + if (status) { + Analog_Output_Min_Pres_Value_Set( + wp_data->object_instance, value.type.Real); + } + break; + case PROP_MAX_PRES_VALUE: + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_REAL); + if (status) { + Analog_Output_Max_Pres_Value_Set( + wp_data->object_instance, value.type.Real); + } + break; default: if (property_lists_member( Properties_Required, Properties_Optional, diff --git a/src/bacnet/basic/object/bo.c b/src/bacnet/basic/object/bo.c index 33752ccb..5faa43e0 100644 --- a/src/bacnet/basic/object/bo.c +++ b/src/bacnet/basic/object/bo.c @@ -1154,6 +1154,22 @@ bool Binary_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) wp_data->object_instance, value.type.Boolean); } break; + case PROP_POLARITY: + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_ENUMERATED); + if (status) { + Binary_Output_Polarity_Set( + wp_data->object_instance, value.type.Enumerated); + } + break; + case PROP_RELINQUISH_DEFAULT: + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_ENUMERATED); + if (status) { + Binary_Output_Relinquish_Default_Set( + wp_data->object_instance, value.type.Enumerated); + } + break; default: if (property_lists_member( Properties_Required, Properties_Optional, diff --git a/src/bacnet/basic/object/mso.c b/src/bacnet/basic/object/mso.c index db526e45..36960de9 100644 --- a/src/bacnet/basic/object/mso.c +++ b/src/bacnet/basic/object/mso.c @@ -360,6 +360,58 @@ bool Multistate_Output_Relinquish_Default_Set( return status; } +/** + * @brief For a given object instance-number, writes the present-value to the + * remote node + * @param object_instance - object-instance number of the object + * @param value - floating point analog value + * @param priority - priority-array index value 1..16 + * @param error_class - the BACnet error class + * @param error_code - BACnet Error code + * @return true if values are within range and present-value is set. + */ +static bool Multistate_Output_Relinquish_Default_Write( + uint32_t object_instance, + uint32_t value, + BACNET_ERROR_CLASS *error_class, + BACNET_ERROR_CODE *error_code) +{ + bool status = false; + struct object_data *pObject; + uint32_t old_value = 0; + uint32_t new_value = 0; + unsigned max_states = 0; + + pObject = Keylist_Data(Object_List, object_instance); + if (pObject) { + max_states = state_name_count(pObject->State_Text); + if ((value >= 1) && (value <= max_states)) { + old_value = Object_Present_Value(pObject); + Multistate_Output_Relinquish_Default_Set(object_instance, value); + if (pObject->Out_Of_Service) { + /* The physical point that the object represents + is not in service. This means that changes to the + Present_Value property are decoupled from the + physical output when the value of Out_Of_Service + is true. */ + } else if (Multistate_Output_Write_Present_Value_Callback) { + new_value = Object_Present_Value(pObject); + Multistate_Output_Write_Present_Value_Callback( + object_instance, old_value, new_value); + } + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + } + + return status; +} + /** * @brief For a given object instance-number, sets the present-value * @param object_instance - object-instance number of the object @@ -1106,6 +1158,21 @@ bool Multistate_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) wp_data->object_instance, value.type.Boolean); } break; + case PROP_RELINQUISH_DEFAULT: + status = write_property_type_valid( + wp_data, &value, BACNET_APPLICATION_TAG_UNSIGNED_INT); + if (status) { + status = false; + if (value.type.Unsigned_Int <= UINT32_MAX) { + status = Multistate_Output_Relinquish_Default_Write( + wp_data->object_instance, value.type.Unsigned_Int, + &wp_data->error_class, &wp_data->error_code); + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } + break; default: if (property_lists_member( Properties_Required, Properties_Optional,