From 8aa5a451a4bf03ddddd4aba6a385f0d7fcd15721 Mon Sep 17 00:00:00 2001 From: Tony Date: Mon, 4 May 2026 01:18:44 +0800 Subject: [PATCH] feat(gateway_bacnet): add support for new BACnet object types and enhance state management functions Co-authored-by: Copilot --- components/gateway_bacnet/CMakeLists.txt | 4 + .../include/gateway_bacnet_stack_port.h | 4 + .../gateway_bacnet/src/gateway_bacnet.cpp | 24 +++ .../src/gateway_bacnet_stack_port.c | 165 +++++++++++++++++- 4 files changed, 196 insertions(+), 1 deletion(-) diff --git a/components/gateway_bacnet/CMakeLists.txt b/components/gateway_bacnet/CMakeLists.txt index 8ac9763..c936b39 100644 --- a/components/gateway_bacnet/CMakeLists.txt +++ b/components/gateway_bacnet/CMakeLists.txt @@ -49,11 +49,15 @@ set(BACNET_BASIC_SRCS "${BACNET_SRC_ROOT}/bacnet/basic/binding/address.c" "${BACNET_SRC_ROOT}/bacnet/basic/npdu/h_npdu.c" "${BACNET_SRC_ROOT}/bacnet/basic/npdu/s_router.c" + "${BACNET_SRC_ROOT}/bacnet/basic/object/ai.c" "${BACNET_SRC_ROOT}/bacnet/basic/object/ao.c" "${BACNET_SRC_ROOT}/bacnet/basic/object/av.c" + "${BACNET_SRC_ROOT}/bacnet/basic/object/bi.c" "${BACNET_SRC_ROOT}/bacnet/basic/object/bo.c" "${BACNET_SRC_ROOT}/bacnet/basic/object/bv.c" "${BACNET_SRC_ROOT}/bacnet/basic/object/device.c" + "${BACNET_SRC_ROOT}/bacnet/basic/object/ms-input.c" + "${BACNET_SRC_ROOT}/bacnet/basic/object/mso.c" "${BACNET_SRC_ROOT}/bacnet/basic/object/msv.c" "${BACNET_SRC_ROOT}/bacnet/basic/service/h_apdu.c" "${BACNET_SRC_ROOT}/bacnet/basic/service/h_cov.c" diff --git a/components/gateway_bacnet/include/gateway_bacnet_stack_port.h b/components/gateway_bacnet/include/gateway_bacnet_stack_port.h index af90ac4..28a2465 100644 --- a/components/gateway_bacnet/include/gateway_bacnet_stack_port.h +++ b/components/gateway_bacnet/include/gateway_bacnet_stack_port.h @@ -9,11 +9,15 @@ extern "C" { typedef enum gateway_bacnet_object_kind { GW_BACNET_OBJECT_UNKNOWN = 0, + GW_BACNET_OBJECT_ANALOG_INPUT, GW_BACNET_OBJECT_ANALOG_VALUE, GW_BACNET_OBJECT_ANALOG_OUTPUT, + GW_BACNET_OBJECT_BINARY_INPUT, GW_BACNET_OBJECT_BINARY_VALUE, GW_BACNET_OBJECT_BINARY_OUTPUT, + GW_BACNET_OBJECT_MULTI_STATE_INPUT, GW_BACNET_OBJECT_MULTI_STATE_VALUE, + GW_BACNET_OBJECT_MULTI_STATE_OUTPUT, } gateway_bacnet_object_kind_t; typedef enum gateway_bacnet_write_value_kind { diff --git a/components/gateway_bacnet/src/gateway_bacnet.cpp b/components/gateway_bacnet/src/gateway_bacnet.cpp index e4a959a..7466b33 100644 --- a/components/gateway_bacnet/src/gateway_bacnet.cpp +++ b/components/gateway_bacnet/src/gateway_bacnet.cpp @@ -42,16 +42,32 @@ GatewayBacnetServer* g_server = nullptr; gateway_bacnet_object_kind_t ToBacnetKind(BridgeObjectType type) { switch (type) { + case BridgeObjectType::analogInput: + return GW_BACNET_OBJECT_ANALOG_INPUT; case BridgeObjectType::analogValue: return GW_BACNET_OBJECT_ANALOG_VALUE; case BridgeObjectType::analogOutput: return GW_BACNET_OBJECT_ANALOG_OUTPUT; + case BridgeObjectType::binaryInput: + return GW_BACNET_OBJECT_BINARY_INPUT; case BridgeObjectType::binaryValue: return GW_BACNET_OBJECT_BINARY_VALUE; case BridgeObjectType::binaryOutput: return GW_BACNET_OBJECT_BINARY_OUTPUT; + case BridgeObjectType::multiStateInput: + return GW_BACNET_OBJECT_MULTI_STATE_INPUT; case BridgeObjectType::multiStateValue: return GW_BACNET_OBJECT_MULTI_STATE_VALUE; + case BridgeObjectType::multiStateOutput: + return GW_BACNET_OBJECT_MULTI_STATE_OUTPUT; + case BridgeObjectType::holdingRegister: + return GW_BACNET_OBJECT_ANALOG_VALUE; + case BridgeObjectType::inputRegister: + return GW_BACNET_OBJECT_ANALOG_INPUT; + case BridgeObjectType::coil: + return GW_BACNET_OBJECT_BINARY_OUTPUT; + case BridgeObjectType::discreteInput: + return GW_BACNET_OBJECT_BINARY_INPUT; default: return GW_BACNET_OBJECT_UNKNOWN; } @@ -59,16 +75,24 @@ gateway_bacnet_object_kind_t ToBacnetKind(BridgeObjectType type) { BridgeObjectType FromBacnetKind(gateway_bacnet_object_kind_t kind) { switch (kind) { + case GW_BACNET_OBJECT_ANALOG_INPUT: + return BridgeObjectType::analogInput; case GW_BACNET_OBJECT_ANALOG_VALUE: return BridgeObjectType::analogValue; case GW_BACNET_OBJECT_ANALOG_OUTPUT: return BridgeObjectType::analogOutput; + case GW_BACNET_OBJECT_BINARY_INPUT: + return BridgeObjectType::binaryInput; case GW_BACNET_OBJECT_BINARY_VALUE: return BridgeObjectType::binaryValue; case GW_BACNET_OBJECT_BINARY_OUTPUT: return BridgeObjectType::binaryOutput; + case GW_BACNET_OBJECT_MULTI_STATE_INPUT: + return BridgeObjectType::multiStateInput; case GW_BACNET_OBJECT_MULTI_STATE_VALUE: return BridgeObjectType::multiStateValue; + case GW_BACNET_OBJECT_MULTI_STATE_OUTPUT: + return BridgeObjectType::multiStateOutput; default: return BridgeObjectType::unknown; } diff --git a/components/gateway_bacnet/src/gateway_bacnet_stack_port.c b/components/gateway_bacnet/src/gateway_bacnet_stack_port.c index 8752de1..060b48a 100644 --- a/components/gateway_bacnet/src/gateway_bacnet_stack_port.c +++ b/components/gateway_bacnet/src/gateway_bacnet_stack_port.c @@ -5,11 +5,15 @@ #include "bacnet/apdu.h" #include "bacnet/basic/binding/address.h" +#include "bacnet/basic/object/ai.h" #include "bacnet/basic/object/ao.h" #include "bacnet/basic/object/av.h" +#include "bacnet/basic/object/bi.h" #include "bacnet/basic/object/bo.h" #include "bacnet/basic/object/bv.h" #include "bacnet/basic/object/device.h" +#include "bacnet/basic/object/ms-input.h" +#include "bacnet/basic/object/mso.h" #include "bacnet/basic/object/msv.h" #include "bacnet/basic/service/h_apdu.h" #include "bacnet/basic/services.h" @@ -89,6 +93,46 @@ static bool clear_multistate_value_objects(void) return true; } +static bool clear_analog_input_objects(void) +{ + unsigned count = Analog_Input_Count(); + while (count > 0) { + count--; + Analog_Input_Delete(Analog_Input_Index_To_Instance(count)); + } + return true; +} + +static bool clear_binary_input_objects(void) +{ + unsigned count = Binary_Input_Count(); + while (count > 0) { + count--; + Binary_Input_Delete(Binary_Input_Index_To_Instance(count)); + } + return true; +} + +static bool clear_multistate_input_objects(void) +{ + unsigned count = Multistate_Input_Count(); + while (count > 0) { + count--; + Multistate_Input_Delete(Multistate_Input_Index_To_Instance(count)); + } + return true; +} + +static bool clear_multistate_output_objects(void) +{ + unsigned count = Multistate_Output_Count(); + while (count > 0) { + count--; + Multistate_Output_Delete(Multistate_Output_Index_To_Instance(count)); + } + return true; +} + static void set_analog_value_state( uint32_t object_instance, bool out_of_service, BACNET_RELIABILITY reliability) { @@ -124,6 +168,34 @@ static void set_multistate_value_state( Multistate_Value_Reliability_Set(object_instance, reliability); } +static void set_analog_input_state( + uint32_t object_instance, bool out_of_service, BACNET_RELIABILITY reliability) +{ + Analog_Input_Out_Of_Service_Set(object_instance, out_of_service); + Analog_Input_Reliability_Set(object_instance, reliability); +} + +static void set_binary_input_state( + uint32_t object_instance, bool out_of_service, BACNET_RELIABILITY reliability) +{ + Binary_Input_Out_Of_Service_Set(object_instance, out_of_service); + Binary_Input_Reliability_Set(object_instance, reliability); +} + +static void set_multistate_input_state( + uint32_t object_instance, bool out_of_service, BACNET_RELIABILITY reliability) +{ + Multistate_Input_Out_Of_Service_Set(object_instance, out_of_service); + Multistate_Input_Reliability_Set(object_instance, reliability); +} + +static void set_multistate_output_state( + uint32_t object_instance, bool out_of_service, BACNET_RELIABILITY reliability) +{ + Multistate_Output_Out_Of_Service_Set(object_instance, out_of_service); + Multistate_Output_Reliability_Set(object_instance, reliability); +} + static void notify_write_real( gateway_bacnet_object_kind_t object_kind, uint32_t object_instance, double value) { @@ -198,6 +270,25 @@ static void multistate_value_write(uint32_t object_instance, uint32_t old_value, notify_write_unsigned(GW_BACNET_OBJECT_MULTI_STATE_VALUE, object_instance, value); } +static void binary_input_write( + uint32_t object_instance, BACNET_BINARY_PV old_value, BACNET_BINARY_PV value) +{ + (void)old_value; + notify_write_boolean(GW_BACNET_OBJECT_BINARY_INPUT, object_instance, value == BINARY_ACTIVE); +} + +static void multistate_input_write(uint32_t object_instance, uint32_t old_value, uint32_t value) +{ + (void)old_value; + notify_write_unsigned(GW_BACNET_OBJECT_MULTI_STATE_INPUT, object_instance, value); +} + +static void multistate_output_write(uint32_t object_instance, uint32_t old_value, uint32_t value) +{ + (void)old_value; + notify_write_unsigned(GW_BACNET_OBJECT_MULTI_STATE_OUTPUT, object_instance, value); +} + static object_functions_t Object_Table[] = { { OBJECT_DEVICE, NULL, Device_Count, Device_Index_To_Instance, Device_Valid_Object_Instance_Number, Device_Object_Name, Device_Read_Property_Local, @@ -234,6 +325,32 @@ static object_functions_t Object_Table[] = { Multistate_Value_Encode_Value_List, Multistate_Value_Change_Of_Value, Multistate_Value_Change_Of_Value_Clear, NULL, NULL, NULL, Multistate_Value_Create, Multistate_Value_Delete, NULL, Multistate_Value_Writable_Property_List }, + { OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count, + Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance, Analog_Input_Object_Name, + Analog_Input_Read_Property, Analog_Input_Write_Property, Analog_Input_Property_Lists, + NULL, NULL, Analog_Input_Encode_Value_List, Analog_Input_Change_Of_Value, + Analog_Input_Change_Of_Value_Clear, NULL, NULL, NULL, Analog_Input_Create, + Analog_Input_Delete, NULL, Analog_Input_Writable_Property_List }, + { OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count, + Binary_Input_Index_To_Instance, Binary_Input_Valid_Instance, Binary_Input_Object_Name, + Binary_Input_Read_Property, Binary_Input_Write_Property, Binary_Input_Property_Lists, + NULL, NULL, Binary_Input_Encode_Value_List, Binary_Input_Change_Of_Value, + Binary_Input_Change_Of_Value_Clear, NULL, NULL, NULL, Binary_Input_Create, + Binary_Input_Delete, NULL, Binary_Input_Writable_Property_List }, + { OBJECT_MULTI_STATE_INPUT, Multistate_Input_Init, Multistate_Input_Count, + Multistate_Input_Index_To_Instance, Multistate_Input_Valid_Instance, + Multistate_Input_Object_Name, Multistate_Input_Read_Property, + Multistate_Input_Write_Property, Multistate_Input_Property_Lists, NULL, NULL, + Multistate_Input_Encode_Value_List, Multistate_Input_Change_Of_Value, + Multistate_Input_Change_Of_Value_Clear, NULL, NULL, NULL, Multistate_Input_Create, + Multistate_Input_Delete, NULL, Multistate_Input_Writable_Property_List }, + { OBJECT_MULTI_STATE_OUTPUT, Multistate_Output_Init, Multistate_Output_Count, + Multistate_Output_Index_To_Instance, Multistate_Output_Valid_Instance, + Multistate_Output_Object_Name, Multistate_Output_Read_Property, + Multistate_Output_Write_Property, Multistate_Output_Property_Lists, NULL, NULL, + Multistate_Output_Encode_Value_List, Multistate_Output_Change_Of_Value, + Multistate_Output_Change_Of_Value_Clear, NULL, NULL, NULL, Multistate_Output_Create, + Multistate_Output_Delete, NULL, Multistate_Output_Writable_Property_List }, { MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, }; @@ -269,6 +386,9 @@ bool gateway_bacnet_stack_start( Binary_Value_Write_Present_Value_Callback_Set(binary_value_write); Binary_Output_Write_Present_Value_Callback_Set(binary_output_write); Multistate_Value_Write_Present_Value_Callback_Set(multistate_value_write); + Binary_Input_Write_Present_Value_Callback_Set(binary_input_write); + Multistate_Input_Write_Present_Value_Callback_Set(multistate_input_write); + Multistate_Output_Write_Present_Value_Callback_Set(multistate_output_write); apdu_set_unrecognized_service_handler_handler(handler_unrecognized_service); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); @@ -358,6 +478,45 @@ bool gateway_bacnet_stack_upsert_object( Multistate_Value_Present_Value_Set(object_instance, 1); set_multistate_value_state(object_instance, out_of_service, object_reliability); return true; + case GW_BACNET_OBJECT_ANALOG_INPUT: + if (!Analog_Input_Valid_Instance(object_instance)) { + Analog_Input_Create(object_instance); + } + Analog_Input_Name_Set(object_instance, object_name); + Analog_Input_Description_Set(object_instance, description); + Analog_Input_Units_Set(object_instance, UNITS_PERCENT); + Analog_Input_Present_Value_Set(object_instance, 0.0f); + set_analog_input_state(object_instance, out_of_service, object_reliability); + return true; + case GW_BACNET_OBJECT_BINARY_INPUT: + if (!Binary_Input_Valid_Instance(object_instance)) { + Binary_Input_Create(object_instance); + } + Binary_Input_Name_Set(object_instance, object_name); + Binary_Input_Description_Set(object_instance, description); + Binary_Input_Present_Value_Set(object_instance, BINARY_INACTIVE); + set_binary_input_state(object_instance, out_of_service, object_reliability); + return true; + case GW_BACNET_OBJECT_MULTI_STATE_INPUT: + if (!Multistate_Input_Valid_Instance(object_instance)) { + Multistate_Input_Create(object_instance); + } + Multistate_Input_Name_Set(object_instance, object_name); + Multistate_Input_Description_Set(object_instance, description); + Multistate_Input_State_Text_List_Set(object_instance, Multistate_Value_States); + Multistate_Input_Present_Value_Set(object_instance, 1); + set_multistate_input_state(object_instance, out_of_service, object_reliability); + return true; + case GW_BACNET_OBJECT_MULTI_STATE_OUTPUT: + if (!Multistate_Output_Valid_Instance(object_instance)) { + Multistate_Output_Create(object_instance); + } + Multistate_Output_Name_Set(object_instance, object_name); + Multistate_Output_Description_Set(object_instance, description); + Multistate_Output_State_Text_List_Set(object_instance, Multistate_Value_States); + Multistate_Output_Present_Value_Set(object_instance, 1, BACNET_MAX_PRIORITY); + set_multistate_output_state(object_instance, out_of_service, object_reliability); + return true; default: return false; } @@ -367,9 +526,13 @@ bool gateway_bacnet_stack_clear_objects(void) { return clear_analog_value_objects() && clear_analog_output_objects() && + clear_analog_input_objects() && clear_binary_value_objects() && clear_binary_output_objects() && - clear_multistate_value_objects(); + clear_binary_input_objects() && + clear_multistate_value_objects() && + clear_multistate_input_objects() && + clear_multistate_output_objects(); } void gateway_bacnet_stack_send_i_am(void)