/** * @file * @brief test BACnet Device object APIs * @author Steve Karg * @date 2004 * @copyright SPDX-License-Identifier: MIT */ #include #include #include #include /** * @addtogroup bacnet_tests * @{ */ static BACNET_WRITE_PROPERTY_DATA Test_Write_Property_Store_Data; bool Test_Write_Property_Return_Value; static bool Test_Write_Property_Store(BACNET_WRITE_PROPERTY_DATA *wp_data) { Test_Write_Property_Store_Data = *wp_data; return Test_Write_Property_Return_Value; } /** * @brief Test ReadProperty API */ static void test_Device_Data_Sharing(void) { const uint32_t instance = 123; unsigned count; bool status = false; uint32_t test_instance; const int32_t skip_fail_property_list[] = { -1 }; Device_Init(NULL); Device_Write_Property_Store_Callback_Set(Test_Write_Property_Store); status = Device_Set_Object_Instance_Number(instance); zassert_true(status, NULL); test_instance = Device_Object_Instance_Number(); zassert_equal(test_instance, instance, NULL); status = Device_Valid_Object_Instance_Number(BACNET_MAX_INSTANCE); zassert_false(status, NULL); count = Device_Count(); zassert_equal(count, 1, NULL); test_instance = Device_Index_To_Instance(0); zassert_equal(test_instance, instance, NULL); /* perform a general test for RP/WP */ bacnet_object_properties_read_write_test( OBJECT_DEVICE, instance, Device_Property_Lists, Device_Read_Property, Device_Write_Property, skip_fail_property_list); } /** * @brief Test basic API */ #if defined(CONFIG_ZTEST_NEW_API) ZTEST(device_tests, testDevice) #else static void testDevice(void) #endif { bool status = false; const char *name = "Patricia"; BACNET_REINITIALIZE_DEVICE_DATA rd_data = { 0 }; BACNET_READ_PROPERTY_DATA rpdata = { 0 }; BACNET_CREATE_OBJECT_DATA create_data = { 0 }; BACNET_DELETE_OBJECT_DATA delete_data = { 0 }; BACNET_LIST_ELEMENT_DATA list_data = { 0 }; BACNET_PROPERTY_ID property = 0; BACNET_OBJECT_TYPE object_type = OBJECT_NONE; uint32_t object_instance = 0; BACNET_CHARACTER_STRING char_string = { 0 }, test_char_string = { 0 }; uint8_t uuid[16] = { 0 }, test_uuid[16] = { 0 }; BACNET_TIMESTAMP time_of_restart = { 0 }, test_time_of_restart = { 0 }; BACNET_DATE_TIME date_time = { 0 }, test_date_time = { 0 }; const char *name_string = NULL; unsigned count = 0, test_count = 0; int len = 0, time_diff = 0; unsigned i, writable; const int32_t *properties; struct special_property_list_t property_list; Device_Init(NULL); status = Device_Set_Object_Instance_Number(0); zassert_equal(Device_Object_Instance_Number(), 0, NULL); zassert_true(status, NULL); status = Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); zassert_equal(Device_Object_Instance_Number(), BACNET_MAX_INSTANCE, NULL); zassert_true(status, NULL); status = Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE / 2); zassert_equal( Device_Object_Instance_Number(), (BACNET_MAX_INSTANCE / 2), NULL); zassert_true(status, NULL); status = Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE + 1); zassert_not_equal( Device_Object_Instance_Number(), (BACNET_MAX_INSTANCE + 1), NULL); zassert_false(status, NULL); Device_Set_System_Status(STATUS_NON_OPERATIONAL, true); zassert_equal(Device_System_Status(), STATUS_NON_OPERATIONAL, NULL); zassert_equal(Device_Vendor_Identifier(), BACNET_VENDOR_ID, NULL); Device_Set_Model_Name(name, strlen(name)); zassert_equal(strcmp(Device_Model_Name(), name), 0, NULL); /* Reinitialize with no device password */ rd_data.error_class = ERROR_CLASS_DEVICE; rd_data.error_code = ERROR_CODE_SUCCESS; rd_data.state = BACNET_REINIT_COLDSTART; characterstring_init_ansi(&rd_data.password, NULL); status = Device_Reinitialize_Password_Set(NULL); status = Device_Reinitialize(&rd_data); zassert_true(status, NULL); zassert_equal( rd_data.error_class, ERROR_CLASS_DEVICE, "error-class=%s", bactext_error_class_name(rd_data.error_class)); zassert_equal( rd_data.error_code, ERROR_CODE_SUCCESS, "error-code=%s", bactext_error_code_name(rd_data.error_code)); /* Reinitialize with device valid password, service no password */ status = Device_Reinitialize_Password_Set("valid"); zassert_true(status, NULL); status = characterstring_init_ansi(&rd_data.password, NULL); zassert_true(status, NULL); status = Device_Reinitialize(&rd_data); zassert_false(status, NULL); zassert_equal( rd_data.error_class, ERROR_CLASS_SECURITY, "error-class=%s", bactext_error_class_name(rd_data.error_class)); zassert_equal( rd_data.error_code, ERROR_CODE_PASSWORD_FAILURE, "error-code=%s", bactext_error_code_name(rd_data.error_code)); /* Reinitialize with device valid password, service invalid password */ status = characterstring_init_ansi(&rd_data.password, "invalid"); zassert_true(status, NULL); status = Device_Reinitialize(&rd_data); zassert_false(status, NULL); zassert_equal( rd_data.error_class, ERROR_CLASS_SECURITY, "error-class=%s", bactext_error_class_name(rd_data.error_class)); zassert_equal( rd_data.error_code, ERROR_CODE_PASSWORD_FAILURE, "error-code=%s", bactext_error_code_name(rd_data.error_code)); /* Reinitialize with device valid password, service valid password */ characterstring_init_ansi(&rd_data.password, "valid"); status = Device_Reinitialize(&rd_data); zassert_true(status, NULL); /* Reinitialize with device valid password, service too long password */ characterstring_init_ansi(&rd_data.password, "abcdefghijklmnopqrstuvwxyz"); status = Device_Reinitialize(&rd_data); zassert_false(status, NULL); zassert_equal( rd_data.error_class, ERROR_CLASS_SERVICES, "error-class=%s", bactext_error_class_name(rd_data.error_class)); zassert_equal( rd_data.error_code, ERROR_CODE_PARAMETER_OUT_OF_RANGE, "error-code=%s", bactext_error_code_name(rd_data.error_code)); /* Reinitialize with device no password, unsupported state */ status = Device_Reinitialize_Password_Set(NULL); zassert_true(status, NULL); rd_data.state = BACNET_REINIT_MAX; status = Device_Reinitialize(&rd_data); zassert_false(status, NULL); zassert_equal( rd_data.error_class, ERROR_CLASS_SERVICES, "error-class=%s", bactext_error_class_name(rd_data.error_class)); zassert_equal( rd_data.error_code, ERROR_CODE_PARAMETER_OUT_OF_RANGE, "error-code=%s", bactext_error_code_name(rd_data.error_code)); rd_data.error_class = ERROR_CLASS_DEVICE; rd_data.error_code = ERROR_CODE_SUCCESS; rd_data.state = BACNET_REINIT_STARTBACKUP; status = Device_Reinitialize(&rd_data); zassert_false(status, NULL); zassert_equal( rd_data.error_class, ERROR_CLASS_SERVICES, "error-class=%s", bactext_error_class_name(rd_data.error_class)); rd_data.error_class = ERROR_CLASS_DEVICE; rd_data.error_code = ERROR_CODE_SUCCESS; rd_data.state = BACNET_REINIT_ENDBACKUP; status = Device_Reinitialize(&rd_data); zassert_false(status, NULL); zassert_equal( rd_data.error_class, ERROR_CLASS_SERVICES, "error-class=%s", bactext_error_class_name(rd_data.error_class)); rd_data.error_class = ERROR_CLASS_DEVICE; rd_data.error_code = ERROR_CODE_SUCCESS; rd_data.state = BACNET_REINIT_STARTRESTORE; status = Device_Reinitialize(&rd_data); zassert_false(status, NULL); zassert_equal( rd_data.error_class, ERROR_CLASS_SERVICES, "error-class=%s", bactext_error_class_name(rd_data.error_class)); rd_data.error_class = ERROR_CLASS_DEVICE; rd_data.error_code = ERROR_CODE_SUCCESS; rd_data.state = BACNET_REINIT_ENDRESTORE; status = Device_Reinitialize(&rd_data); zassert_false(status, NULL); zassert_equal( rd_data.error_class, ERROR_CLASS_SERVICES, "error-class=%s", bactext_error_class_name(rd_data.error_class)); rd_data.error_class = ERROR_CLASS_DEVICE; rd_data.error_code = ERROR_CODE_SUCCESS; rd_data.state = BACNET_REINIT_ABORTRESTORE; status = Device_Reinitialize(&rd_data); zassert_false(status, NULL); zassert_equal( rd_data.error_class, ERROR_CLASS_SERVICES, "error-class=%s", bactext_error_class_name(rd_data.error_class)); rd_data.error_class = ERROR_CLASS_DEVICE; rd_data.error_code = ERROR_CODE_SUCCESS; rd_data.state = BACNET_REINIT_ACTIVATE_CHANGES; status = Device_Reinitialize(&rd_data); zassert_true(status, NULL); zassert_equal( rd_data.state, Device_Reinitialized_State(), "state=%d", rd_data.state); Device_Reinitialize_State_Set(BACNET_REINIT_IDLE); zassert_equal(Device_Reinitialized_State(), BACNET_REINIT_IDLE, NULL); /* test Object_List API */ count = Device_Object_List_Count(); zassert_true(count > 0, NULL); status = Device_Object_List_Identifier(0, &object_type, &object_instance); zassert_false(status, NULL); status = Device_Object_List_Identifier(1, &object_type, &object_instance); zassert_true(status, NULL); status = Device_Valid_Object_Id(object_type, object_instance); zassert_true(status, NULL); object_type = OBJECT_DEVICE; object_instance = Device_Object_Instance_Number(); for (property = 0; property < MAX_BACNET_PROPERTY_ID; property++) { if (Device_Objects_Property_List_Member( object_type, object_instance, property)) { continue; } if ((property == PROP_ALL) || (property == PROP_REQUIRED) || (property == PROP_OPTIONAL) || (property == PROP_PROPERTY_LIST)) { continue; } rpdata.object_property = property; rpdata.array_index = BACNET_ARRAY_ALL; len = Device_Read_Property(&rpdata); zassert_equal( len, BACNET_STATUS_ERROR, "property '%s' array_index=ALL: Missing.\n", bactext_property_name(rpdata.object_property)); /* shrink the number space and skip proprietary range values */ if (property == PROP_RESERVED_RANGE_MAX) { property = PROP_RESERVED_RANGE_MIN2 - 1; } /* shrink the number space to known values */ if (property == PROP_RESERVED_RANGE_LAST) { break; } } /* test Object Name API */ status = Device_Set_Object_Name(NULL); zassert_false(status, NULL); characterstring_init_ansi(&char_string, "Teddy"); status = Device_Set_Object_Name(&char_string); zassert_true(status, NULL); Device_Object_Name(Device_Object_Instance_Number(), &test_char_string); status = characterstring_same(&char_string, &test_char_string); zassert_true(status, NULL); Device_Object_Name_ANSI_Init("Tuxedo"); name_string = Device_Object_Name_ANSI(); zassert_not_null(name_string, NULL); zassert_equal(strcmp(name_string, "Tuxedo"), 0, NULL); status = Device_Object_Name_Copy( OBJECT_DEVICE, Device_Object_Instance_Number(), &test_char_string); zassert_true(status, NULL); status = characterstring_same(&char_string, &test_char_string); /* UUID tests */ Device_UUID_Get(NULL, 0); Device_UUID_Set(NULL, 0); Device_UUID_Get(test_uuid, sizeof(test_uuid)); for (int i = 0; i < 16; i++) { zassert_equal(test_uuid[i], 0, NULL); } Device_UUID_Init(); Device_UUID_Get(uuid, sizeof(uuid)); status = false; for (int i = 0; i < 16; i++) { if (uuid[i] != test_uuid[i]) { status = true; } } zassert_true(status, NULL); Device_UUID_Set(test_uuid, sizeof(test_uuid)); Device_UUID_Get(uuid, sizeof(uuid)); for (int i = 0; i < 16; i++) { zassert_equal(uuid[i], test_uuid[i], NULL); } name_string = Device_Vendor_Name(); zassert_not_null(name_string, NULL); zassert_true(strlen(name_string) > 0, NULL); status = Device_Set_Vendor_Name(NULL, 0); zassert_true(status, NULL); name_string = Device_Firmware_Revision(); zassert_not_null(name_string, NULL); zassert_true(strlen(name_string) > 0, NULL); status = Device_Set_Firmware_Revision(NULL, 0); zassert_true(status, NULL); name_string = Device_Description(); zassert_not_null(name_string, NULL); zassert_true(strlen(name_string) > 0, NULL); status = Device_Set_Description(NULL, 0); zassert_true(status, NULL); name_string = Device_Location(); zassert_not_null(name_string, NULL); zassert_true(strlen(name_string) > 0, NULL); status = Device_Set_Location(NULL, 0); zassert_true(status, NULL); name_string = Device_Serial_Number(); zassert_not_null(name_string, NULL); zassert_true(strlen(name_string) > 0, NULL); status = Device_Serial_Number_Set(NULL, 0); zassert_true(status, NULL); Device_Set_Time_Of_Restart(NULL); time_of_restart.tag = TIME_STAMP_TIME; time_of_restart.value.time.hour = 1; time_of_restart.value.time.min = 2; time_of_restart.value.time.sec = 3; time_of_restart.value.time.hundredths = 4; Device_Set_Time_Of_Restart(&time_of_restart); Device_Time_Of_Restart(&test_time_of_restart); status = bacapp_timestamp_same(&time_of_restart, &test_time_of_restart); zassert_true(status, NULL); Device_Set_Database_Revision(0); zassert_equal(Device_Database_Revision(), 0, NULL); Device_Inc_Database_Revision(); zassert_equal(Device_Database_Revision(), 1, NULL); Device_Inc_Database_Revision(); zassert_equal(Device_Database_Revision(), 2, NULL); Device_getCurrentDateTime(&date_time); datetime_local(&date_time.date, &date_time.time, NULL, NULL); time_diff = datetime_compare(&date_time, &test_date_time); zassert_equal(time_diff, 0, NULL); Device_UTC_Offset_Set(-60); time_diff = Device_UTC_Offset(); zassert_equal(time_diff, -60, NULL); status = Device_Daylight_Savings_Status(); zassert_false(status, NULL); name_string = Device_Application_Software_Version(); zassert_not_null(name_string, NULL); zassert_true(strlen(name_string) > 0, NULL); status = Device_Set_Application_Software_Version( name_string, strlen(name_string)); zassert_true(status, NULL); /* Add/Remove List Elements */ list_data.object_type = OBJECT_DEVICE; list_data.object_instance = Device_Object_Instance_Number(); list_data.object_property = PROP_ACTIVE_COV_SUBSCRIPTIONS; list_data.array_index = BACNET_ARRAY_ALL; list_data.application_data = NULL; list_data.application_data_len = 0; list_data.first_failed_element_number = 0; list_data.error_class = ERROR_CLASS_DEVICE; list_data.error_code = ERROR_CODE_SUCCESS; len = Device_Add_List_Element(&list_data); zassert_true(len < 0, NULL); list_data.object_type = OBJECT_ANALOG_VALUE; list_data.object_instance = BACNET_MAX_INSTANCE; len = Device_Add_List_Element(&list_data); zassert_true(len < 0, NULL); list_data.object_instance = 1; len = Device_Add_List_Element(&list_data); zassert_true(len < 0, NULL); zassert_equal( list_data.error_code, ERROR_CODE_UNKNOWN_OBJECT, "error-code=%s", bactext_error_code_name(list_data.error_code)); Device_Remove_List_Element(&list_data); zassert_equal( list_data.error_code, ERROR_CODE_UNKNOWN_OBJECT, "error-code=%s", bactext_error_code_name(list_data.error_code)); list_data.object_type = OBJECT_ANALOG_INPUT; len = Device_Add_List_Element(&list_data); zassert_true(len < 0, NULL); zassert_equal( list_data.error_code, ERROR_CODE_UNKNOWN_OBJECT, "error-code=%s", bactext_error_code_name(list_data.error_code)); /* COV API tests */ status = Device_COV(OBJECT_ANALOG_VALUE, BACNET_MAX_INSTANCE); zassert_false(status, NULL); Device_COV_Clear(OBJECT_ANALOG_VALUE, BACNET_MAX_INSTANCE); status = Device_Encode_Value_List( OBJECT_ANALOG_VALUE, BACNET_MAX_INSTANCE, NULL); zassert_false(status, NULL); /* create/delete object tests */ count = Device_Object_List_Count(); create_data.object_type = OBJECT_ANALOG_VALUE; create_data.object_instance = BACNET_MAX_INSTANCE; create_data.application_data_len = 0; create_data.error_class = ERROR_CLASS_DEVICE; create_data.error_code = ERROR_CODE_SUCCESS; create_data.first_failed_element_number = 0; status = Device_Create_Object(&create_data); zassert_true(status, NULL); zassert_equal(create_data.error_code, ERROR_CODE_SUCCESS, NULL); zassert_equal(create_data.object_instance, 1, NULL); test_count = Device_Object_List_Count(); zassert_equal(count + 1, test_count, NULL); delete_data.object_type = create_data.object_type; delete_data.object_instance = create_data.object_instance; delete_data.error_class = ERROR_CLASS_DEVICE; delete_data.error_code = ERROR_CODE_SUCCESS; status = Device_Delete_Object(&delete_data); zassert_true(status, NULL); zassert_equal(delete_data.error_code, ERROR_CODE_SUCCESS, NULL); test_count = Device_Object_List_Count(); zassert_equal(count, test_count, NULL); status = Device_Delete_Object(&delete_data); zassert_false(status, NULL); /* known object without delete */ delete_data.object_type = OBJECT_DEVICE; delete_data.object_instance = Device_Object_Instance_Number(); delete_data.error_class = ERROR_CLASS_DEVICE; delete_data.error_code = ERROR_CODE_SUCCESS; status = Device_Delete_Object(&delete_data); zassert_false(status, NULL); delete_data.object_type = MAX_BACNET_OBJECT_TYPE; status = Device_Delete_Object(&delete_data); zassert_false(status, NULL); /* known object without create */ create_data.object_type = OBJECT_DEVICE; create_data.object_instance = BACNET_MAX_INSTANCE; create_data.application_data_len = 0; create_data.error_class = ERROR_CLASS_DEVICE; create_data.error_code = ERROR_CODE_SUCCESS; create_data.first_failed_element_number = 0; status = Device_Create_Object(&create_data); zassert_false(status, NULL); create_data.object_type = MAX_BACNET_OBJECT_TYPE; status = Device_Create_Object(&create_data); zassert_false(status, NULL); /* COV value list */ status = Device_Value_List_Supported(OBJECT_DEVICE); zassert_false(status, NULL); /* object timers */ Device_Timer(1000); /* property lists */ count = Device_Object_List_Count(); for (i = 1; i <= count; i++) { bool valid = false; valid = Device_Object_List_Identifier(i, &object_type, &object_instance); zassert_true(valid, "object-list[%u] is not valid", i); valid = Device_Valid_Object_Id(object_type, object_instance); zassert_true(valid, NULL); Device_Objects_Writable_Property_List( object_type, object_instance, &properties); zassert_not_null(properties, NULL); writable = property_list_count(properties); zassert_true( writable > 0, "%s-%u has no writable properties", bactext_object_type_name(object_type), object_instance); Device_Objects_Property_List( object_type, object_instance, &property_list); zassert_true(property_list.Required.count > 0, NULL); } } /** * @} */ #if defined(CONFIG_ZTEST_NEW_API) ZTEST_SUITE(device_tests, NULL, NULL, NULL, NULL, NULL); #else void test_main(void) { ztest_test_suite( device_tests, ztest_unit_test(testDevice), ztest_unit_test(test_Device_Data_Sharing)); ztest_run_test_suite(device_tests); } #endif