Support routed virtual device backup/restore reinitialization (#1320)

* Support routed virtual device backup restore reinitialization

Allow routed virtual devices to accept ReinitializeDevice so Backup and Restore
states can be handled per device. Gateway behavior remains unchanged, and
DeviceCommunicationControl remains disabled for virtual devices.

Virtual-device COLDSTART, WARMSTART, and ACTIVATE_CHANGES requests now return
OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED instead of being acknowledged.

* Cover routed device backup restore test variants

Add routed-device tests for ReinitializeDevice service approval, DCC blocking,
virtual-device unsupported reinitialize states, per-device Backup/Restore state,
and backup timeout countdown behavior.

Build device tests in four compile-time variants so BAC_ROUTING and
BACNET_BACKUP_RESTORE are covered in both enabled and disabled combinations.

* Keep routed device variant tests in CTest

Register each optional device test build as its own CTest build/run pair so BAC_ROUTING and BACNET_BACKUP_RESTORE variants keep the existing fixture-based build-before-run behavior without changing the top-level test CMake file.

Constraint: Top-level test/CMakeLists.txt remains unchanged to preserve the existing test registration convention
Confidence: high
Scope-risk: narrow
Tested: cmake -S test -B /tmp/bacnet-stack-test-cmake-pr1320
Tested: ctest --test-dir /tmp/bacnet-stack-test-cmake-pr1320 -R '^test_device(_.*)?$' --output-on-failure -j4
Not-tested: Full repository CTest suite

* Ensure Backup/Restore has real configuration-file storage

Centralize reinitialize state storage so routed devices and the default device use the same access path. Enforce BACNET_BACKUP_FILE_COUNT as a positive Backup/Restore invariant, while preserving BACNET_BACKUP_RESTORE guards for no-backup builds.

Constraint: BACNET_BACKUP_RESTORE performs backup and restore through Configuration_Files[0].
Rejected: Preserve BACNET_BACKUP_FILE_COUNT=0 support | it leaves only state/property handling without a usable backup file.
Confidence: high
Scope-risk: moderate
Directive: Guard no-backup builds with BACNET_BACKUP_RESTORE, not BACNET_BACKUP_FILE_COUNT.
Tested: ctest --test-dir test/build -R '^(build_device|test_device|build_device_backup_restore|test_device_backup_restore|build_device_bac_routing|test_device_bac_routing|build_device_bac_routing_backup_restore|test_device_bac_routing_backup_restore)$' --output-on-failure
Tested: cmake --build build --target server gateway gateway2 bacbasic
Not-tested: Runtime BACnet client backup/restore exchange

---------

Signed-off-by: kimhyeongjun <hjun1.kim@samsung.com>
Co-authored-by: OmX <omx@oh-my-codex.dev>
This commit is contained in:
Hyeongjun Kim
2026-04-30 23:05:14 +09:00
committed by GitHub
parent 1f75040b5c
commit b9dc173c57
6 changed files with 651 additions and 101 deletions
+281 -84
View File
@@ -1465,17 +1465,14 @@ static uint32_t Database_Revision = 0;
/* Auto_Slave_Discovery */ /* Auto_Slave_Discovery */
/* Slave_Address_Binding */ /* Slave_Address_Binding */
/* Profile_Name */ /* Profile_Name */
static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE; static BACNET_DEVICE_REINITIALIZE_DATA Reinitialize_Data = {
static const char *Reinit_Password = "filister"; .State = BACNET_REINIT_IDLE, .Password = "filister"
};
static write_property_function Device_Write_Property_Store_Callback; static write_property_function Device_Write_Property_Store_Callback;
static list_element_function Device_Add_List_Element_Callback; static list_element_function Device_Add_List_Element_Callback;
static list_element_function Device_Remove_List_Element_Callback; static list_element_function Device_Remove_List_Element_Callback;
/* backup and restore */ /* backup and restore */
#if defined BACNET_BACKUP_RESTORE #if defined BACNET_BACKUP_RESTORE
/* number of backup files */
#ifndef BACNET_BACKUP_FILE_COUNT
#define BACNET_BACKUP_FILE_COUNT 1
#endif
/* device A will read the Configuration_Files property of the Device object. /* device A will read the Configuration_Files property of the Device object.
This property will be used to determine the files to read and in what This property will be used to determine the files to read and in what
@@ -1520,6 +1517,140 @@ static BACNET_BACKUP_STATE Backup_State = BACKUP_STATE_IDLE;
#ifdef BAC_ROUTING #ifdef BAC_ROUTING
static bool Device_Router_Mode = false; static bool Device_Router_Mode = false;
static DEVICE_OBJECT_DATA *Device_Routed_Data(void)
{
if (Device_Router_Mode) {
return Get_Routed_Device_Object(-1);
}
return NULL;
}
static bool Device_Routed_Virtual_Device(void)
{
return Device_Router_Mode && (Routed_Device_Object_Index() > 0);
}
#endif
static BACNET_DEVICE_REINITIALIZE_DATA *Device_Reinitialize_Data(void)
{
#if defined(BAC_ROUTING)
DEVICE_OBJECT_DATA *pDev = Device_Routed_Data();
if (pDev) {
return &pDev->Reinitialize;
}
#endif
return &Reinitialize_Data;
}
#if defined(BACNET_BACKUP_RESTORE)
static uint32_t *Device_Configuration_Files_Value(void)
{
#if defined(BAC_ROUTING)
DEVICE_OBJECT_DATA *pDev = Device_Routed_Data();
if (pDev) {
return pDev->Backup.Configuration_Files;
}
#endif
return Configuration_Files;
}
static BACNET_TIMESTAMP *Device_Last_Restore_Time_Value(void)
{
#if defined(BAC_ROUTING)
DEVICE_OBJECT_DATA *pDev = Device_Routed_Data();
if (pDev) {
return &pDev->Backup.Last_Restore_Time;
}
#endif
return &Last_Restore_Time;
}
static uint16_t *Device_Backup_Failure_Timeout_Value(void)
{
#if defined(BAC_ROUTING)
DEVICE_OBJECT_DATA *pDev = Device_Routed_Data();
if (pDev) {
return &pDev->Backup.Backup_Failure_Timeout;
}
#endif
return &Backup_Failure_Timeout;
}
static uint32_t *Device_Backup_Failure_Timeout_Milliseconds_Value(void)
{
#if defined(BAC_ROUTING)
DEVICE_OBJECT_DATA *pDev = Device_Routed_Data();
if (pDev) {
return &pDev->Backup.Backup_Failure_Timeout_Milliseconds;
}
#endif
return &Backup_Failure_Timeout_Milliseconds;
}
static uint16_t *Device_Backup_Preparation_Time_Value(void)
{
#if defined(BAC_ROUTING)
DEVICE_OBJECT_DATA *pDev = Device_Routed_Data();
if (pDev) {
return &pDev->Backup.Backup_Preparation_Time;
}
#endif
return &Backup_Preparation_Time;
}
static uint16_t *Device_Restore_Preparation_Time_Value(void)
{
#if defined(BAC_ROUTING)
DEVICE_OBJECT_DATA *pDev = Device_Routed_Data();
if (pDev) {
return &pDev->Backup.Restore_Preparation_Time;
}
#endif
return &Restore_Preparation_Time;
}
static uint16_t *Device_Restore_Completion_Time_Value(void)
{
#if defined(BAC_ROUTING)
DEVICE_OBJECT_DATA *pDev = Device_Routed_Data();
if (pDev) {
return &pDev->Backup.Restore_Completion_Time;
}
#endif
return &Restore_Completion_Time;
}
static BACNET_BACKUP_STATE *Device_Backup_State_Value(void)
{
#if defined(BAC_ROUTING)
DEVICE_OBJECT_DATA *pDev = Device_Routed_Data();
if (pDev) {
return &pDev->Backup.Backup_State;
}
#endif
return &Backup_State;
}
#endif #endif
/** /**
@@ -1535,7 +1666,10 @@ static bool Device_Router_Mode = false;
*/ */
bool Device_Reinitialize_Password_Set(const char *password) bool Device_Reinitialize_Password_Set(const char *password)
{ {
Reinit_Password = password; BACNET_DEVICE_REINITIALIZE_DATA *reinitialize_data =
Device_Reinitialize_Data();
reinitialize_data->Password = password;
return true; return true;
} }
@@ -1559,6 +1693,13 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
bool password_success = false; bool password_success = false;
unsigned i; unsigned i;
size_t length; size_t length;
BACNET_DEVICE_REINITIALIZE_DATA *reinitialize_data =
Device_Reinitialize_Data();
BACNET_REINITIALIZED_STATE *reinitialize_state = &reinitialize_data->State;
const char *reinit_password = reinitialize_data->Password;
#if defined BACNET_BACKUP_RESTORE
BACNET_BACKUP_STATE *backup_state = Device_Backup_State_Value();
#endif
/* From 16.4.1.1.2 Password /* From 16.4.1.1.2 Password
This optional parameter shall be a CharacterString of up to This optional parameter shall be a CharacterString of up to
@@ -1566,7 +1707,7 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
protection, the service request shall be denied if the parameter protection, the service request shall be denied if the parameter
is absent or if the password is incorrect. For those devices that is absent or if the password is incorrect. For those devices that
do not require a password, this parameter shall be ignored.*/ do not require a password, this parameter shall be ignored.*/
if (Reinit_Password && strlen(Reinit_Password) > 0) { if (reinit_password && strlen(reinit_password) > 0) {
if (characterstring_encoding(&rd_data->password) == CHARACTER_UTF8) { if (characterstring_encoding(&rd_data->password) == CHARACTER_UTF8) {
length = characterstring_utf8_length(&rd_data->password); length = characterstring_utf8_length(&rd_data->password);
} else { } else {
@@ -1576,7 +1717,7 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
rd_data->error_class = ERROR_CLASS_SERVICES; rd_data->error_class = ERROR_CLASS_SERVICES;
rd_data->error_code = ERROR_CODE_PARAMETER_OUT_OF_RANGE; rd_data->error_code = ERROR_CODE_PARAMETER_OUT_OF_RANGE;
} else if (characterstring_ansi_same( } else if (characterstring_ansi_same(
&rd_data->password, Reinit_Password)) { &rd_data->password, reinit_password)) {
password_success = true; password_success = true;
} else { } else {
rd_data->error_class = ERROR_CLASS_SECURITY; rd_data->error_class = ERROR_CLASS_SECURITY;
@@ -1586,13 +1727,24 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
password_success = true; password_success = true;
} }
if (password_success) { if (password_success) {
#if defined(BAC_ROUTING)
if (Device_Routed_Virtual_Device() &&
((rd_data->state == BACNET_REINIT_COLDSTART) ||
(rd_data->state == BACNET_REINIT_WARMSTART) ||
(rd_data->state == BACNET_REINIT_ACTIVATE_CHANGES))) {
rd_data->error_class = ERROR_CLASS_SERVICES;
rd_data->error_code =
ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
return false;
}
#endif
switch (rd_data->state) { switch (rd_data->state) {
case BACNET_REINIT_COLDSTART: case BACNET_REINIT_COLDSTART:
dcc_set_status_duration(COMMUNICATION_ENABLE, 0); dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
/* note: you probably want to restart *after* the /* note: you probably want to restart *after* the
simple ack has been sent from the return handler simple ack has been sent from the return handler
so just set a flag from here */ so just set a flag from here */
Reinitialize_State = rd_data->state; *reinitialize_state = rd_data->state;
status = true; status = true;
break; break;
case BACNET_REINIT_WARMSTART: case BACNET_REINIT_WARMSTART:
@@ -1604,50 +1756,50 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
/* note: you probably want to restart *after* the /* note: you probably want to restart *after* the
simple ack has been sent from the return handler simple ack has been sent from the return handler
so just set a flag from here */ so just set a flag from here */
Reinitialize_State = rd_data->state; *reinitialize_state = rd_data->state;
status = true; status = true;
break; break;
#if defined BACNET_BACKUP_RESTORE #if defined BACNET_BACKUP_RESTORE
case BACNET_REINIT_STARTBACKUP: case BACNET_REINIT_STARTBACKUP:
if (Device_Backup_State_In_Progress(Backup_State)) { if (Device_Backup_State_In_Progress(*backup_state)) {
rd_data->error_class = ERROR_CLASS_DEVICE; rd_data->error_class = ERROR_CLASS_DEVICE;
rd_data->error_code = ERROR_CODE_CONFIGURATION_IN_PROGRESS; rd_data->error_code = ERROR_CODE_CONFIGURATION_IN_PROGRESS;
break; break;
} }
Backup_State = BACKUP_STATE_PREPARING_FOR_BACKUP; *backup_state = BACKUP_STATE_PREPARING_FOR_BACKUP;
Device_Backup_Failure_Timeout_Restart(); Device_Backup_Failure_Timeout_Restart();
Device_Start_Backup(); Device_Start_Backup();
Reinitialize_State = rd_data->state; *reinitialize_state = rd_data->state;
status = true; status = true;
break; break;
case BACNET_REINIT_STARTRESTORE: case BACNET_REINIT_STARTRESTORE:
if (Device_Backup_State_In_Progress(Backup_State)) { if (Device_Backup_State_In_Progress(*backup_state)) {
rd_data->error_class = ERROR_CLASS_DEVICE; rd_data->error_class = ERROR_CLASS_DEVICE;
rd_data->error_code = ERROR_CODE_CONFIGURATION_IN_PROGRESS; rd_data->error_code = ERROR_CODE_CONFIGURATION_IN_PROGRESS;
break; break;
} }
Backup_State = BACKUP_STATE_PREPARING_FOR_RESTORE; *backup_state = BACKUP_STATE_PREPARING_FOR_RESTORE;
Device_Backup_Failure_Timeout_Restart(); Device_Backup_Failure_Timeout_Restart();
Device_Start_Restore(); Device_Start_Restore();
Reinitialize_State = rd_data->state; *reinitialize_state = rd_data->state;
status = true; status = true;
break; break;
case BACNET_REINIT_ENDRESTORE: case BACNET_REINIT_ENDRESTORE:
if (Backup_State != BACKUP_STATE_PERFORMING_A_RESTORE) { if (*backup_state != BACKUP_STATE_PERFORMING_A_RESTORE) {
rd_data->error_class = ERROR_CLASS_DEVICE; rd_data->error_class = ERROR_CLASS_DEVICE;
rd_data->error_code = ERROR_CODE_CONFIGURATION_IN_PROGRESS; rd_data->error_code = ERROR_CODE_CONFIGURATION_IN_PROGRESS;
break; break;
} }
Device_Backup_Failure_Timeout_Restart(); Device_Backup_Failure_Timeout_Restart();
Device_End_Restore(); Device_End_Restore();
Reinitialize_State = rd_data->state; *reinitialize_state = rd_data->state;
status = true; status = true;
break; break;
case BACNET_REINIT_ENDBACKUP: case BACNET_REINIT_ENDBACKUP:
case BACNET_REINIT_ABORTRESTORE: case BACNET_REINIT_ABORTRESTORE:
Backup_State = BACKUP_STATE_IDLE; *backup_state = BACKUP_STATE_IDLE;
Device_Backup_Failure_Timeout_Reset(); Device_Backup_Failure_Timeout_Reset();
Reinitialize_State = rd_data->state; *reinitialize_state = rd_data->state;
status = true; status = true;
break; break;
#else #else
@@ -1672,7 +1824,7 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
Network_Port_Changes_Pending_Activate( Network_Port_Changes_Pending_Activate(
Network_Port_Index_To_Instance(i)); Network_Port_Index_To_Instance(i));
} }
Reinitialize_State = rd_data->state; *reinitialize_state = rd_data->state;
status = true; status = true;
break; break;
default: default:
@@ -1687,12 +1839,13 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
BACNET_REINITIALIZED_STATE Device_Reinitialized_State(void) BACNET_REINITIALIZED_STATE Device_Reinitialized_State(void)
{ {
return Reinitialize_State; return Device_Reinitialize_Data()->State;
} }
bool Device_Reinitialize_State_Set(BACNET_REINITIALIZED_STATE state) bool Device_Reinitialize_State_Set(BACNET_REINITIALIZED_STATE state)
{ {
Reinitialize_State = state; Device_Reinitialize_Data()->State = state;
return true; return true;
} }
@@ -2467,9 +2620,11 @@ uint32_t Device_Interval_Offset(void)
bool Device_Configuration_File_Set(unsigned index, uint32_t instance) bool Device_Configuration_File_Set(unsigned index, uint32_t instance)
{ {
bool status = false; bool status = false;
#if BACNET_BACKUP_FILE_COUNT #if defined(BACNET_BACKUP_RESTORE)
uint32_t *configuration_files = Device_Configuration_Files_Value();
if (index < BACNET_BACKUP_FILE_COUNT) { if (index < BACNET_BACKUP_FILE_COUNT) {
Configuration_Files[index] = instance; configuration_files[index] = instance;
status = true; status = true;
} }
#else #else
@@ -2483,10 +2638,11 @@ bool Device_Configuration_File_Set(unsigned index, uint32_t instance)
uint32_t Device_Configuration_File(unsigned index) uint32_t Device_Configuration_File(unsigned index)
{ {
uint32_t instance = BACNET_MAX_INSTANCE + 1; uint32_t instance = BACNET_MAX_INSTANCE + 1;
#if defined(BACNET_BACKUP_RESTORE)
uint32_t *configuration_files = Device_Configuration_Files_Value();
#if BACNET_BACKUP_FILE_COUNT
if (index < BACNET_BACKUP_FILE_COUNT) { if (index < BACNET_BACKUP_FILE_COUNT) {
instance = Configuration_Files[index]; instance = configuration_files[index];
} }
#else #else
(void)index; (void)index;
@@ -2505,11 +2661,12 @@ uint32_t Device_Configuration_File(unsigned index)
bool Device_Is_Configuration_File(uint32_t instance) bool Device_Is_Configuration_File(uint32_t instance)
{ {
bool status = false; bool status = false;
#if defined(BACNET_BACKUP_RESTORE)
#if BACNET_BACKUP_FILE_COUNT
unsigned i; unsigned i;
uint32_t *configuration_files = Device_Configuration_Files_Value();
for (i = 0; i < BACNET_BACKUP_FILE_COUNT; i++) { for (i = 0; i < BACNET_BACKUP_FILE_COUNT; i++) {
if (Configuration_Files[i] == instance) { if (configuration_files[i] == instance) {
status = true; status = true;
break; break;
} }
@@ -2537,10 +2694,12 @@ int Device_Configuration_File_Encode(
int apdu_len = BACNET_STATUS_ERROR; int apdu_len = BACNET_STATUS_ERROR;
(void)object_instance; (void)object_instance;
#if BACNET_BACKUP_FILE_COUNT #if defined(BACNET_BACKUP_RESTORE)
uint32_t *configuration_files = Device_Configuration_Files_Value();
if (array_index < BACNET_BACKUP_FILE_COUNT) { if (array_index < BACNET_BACKUP_FILE_COUNT) {
apdu_len = encode_application_object_id( apdu_len = encode_application_object_id(
apdu, OBJECT_FILE, Configuration_Files[array_index]); apdu, OBJECT_FILE, configuration_files[array_index]);
} }
#else #else
(void)array_index; (void)array_index;
@@ -2620,56 +2779,67 @@ static BACNET_ERROR_CODE Device_Configuration_File_Write(
uint16_t Device_Backup_Failure_Timeout(void) uint16_t Device_Backup_Failure_Timeout(void)
{ {
return Backup_Failure_Timeout; return *Device_Backup_Failure_Timeout_Value();
} }
bool Device_Backup_Failure_Timeout_Set(uint16_t timeout) bool Device_Backup_Failure_Timeout_Set(uint16_t timeout)
{ {
Backup_Failure_Timeout = timeout; uint16_t *backup_failure_timeout = Device_Backup_Failure_Timeout_Value();
*backup_failure_timeout = timeout;
return true; return true;
} }
uint16_t Device_Backup_Preparation_Time(void) uint16_t Device_Backup_Preparation_Time(void)
{ {
return Backup_Preparation_Time; return *Device_Backup_Preparation_Time_Value();
} }
bool Device_Backup_Preparation_Time_Set(uint16_t time) bool Device_Backup_Preparation_Time_Set(uint16_t time)
{ {
Backup_Preparation_Time = time; uint16_t *backup_preparation_time = Device_Backup_Preparation_Time_Value();
*backup_preparation_time = time;
return true; return true;
} }
uint16_t Device_Restore_Preparation_Time(void) uint16_t Device_Restore_Preparation_Time(void)
{ {
return Restore_Preparation_Time; return *Device_Restore_Preparation_Time_Value();
} }
bool Device_Restore_Preparation_Time_Set(uint16_t time) bool Device_Restore_Preparation_Time_Set(uint16_t time)
{ {
Restore_Preparation_Time = time; uint16_t *restore_preparation_time =
Device_Restore_Preparation_Time_Value();
*restore_preparation_time = time;
return true; return true;
} }
uint16_t Device_Restore_Completion_Time(void) uint16_t Device_Restore_Completion_Time(void)
{ {
return Restore_Completion_Time; return *Device_Restore_Completion_Time_Value();
} }
bool Device_Restore_Completion_Time_Set(uint16_t time) bool Device_Restore_Completion_Time_Set(uint16_t time)
{ {
Restore_Completion_Time = time; uint16_t *restore_completion_time = Device_Restore_Completion_Time_Value();
*restore_completion_time = time;
return true; return true;
} }
BACNET_BACKUP_STATE Device_Backup_And_Restore_State(void) BACNET_BACKUP_STATE Device_Backup_And_Restore_State(void)
{ {
return Backup_State; return *Device_Backup_State_Value();
} }
bool Device_Backup_And_Restore_State_Set(BACNET_BACKUP_STATE state) bool Device_Backup_And_Restore_State_Set(BACNET_BACKUP_STATE state)
{ {
Backup_State = state; BACNET_BACKUP_STATE *backup_state = Device_Backup_State_Value();
*backup_state = state;
return true; return true;
} }
@@ -2680,7 +2850,10 @@ bool Device_Backup_And_Restore_State_Set(BACNET_BACKUP_STATE state)
*/ */
void Device_Backup_Failure_Timeout_Reset(void) void Device_Backup_Failure_Timeout_Reset(void)
{ {
Backup_Failure_Timeout_Milliseconds = 0; uint32_t *backup_failure_timeout_milliseconds =
Device_Backup_Failure_Timeout_Milliseconds_Value();
*backup_failure_timeout_milliseconds = 0;
} }
#endif #endif
@@ -2709,10 +2882,15 @@ bool Device_Backup_State_In_Progress(BACNET_BACKUP_STATE state)
void Device_Backup_Failure_Timeout_Restart(void) void Device_Backup_Failure_Timeout_Restart(void)
{ {
#if defined(BACNET_BACKUP_RESTORE) #if defined(BACNET_BACKUP_RESTORE)
if (Device_Backup_State_In_Progress(Backup_State)) { BACNET_BACKUP_STATE *backup_state = Device_Backup_State_Value();
uint16_t *backup_failure_timeout = Device_Backup_Failure_Timeout_Value();
uint32_t *backup_failure_timeout_milliseconds =
Device_Backup_Failure_Timeout_Milliseconds_Value();
if (Device_Backup_State_In_Progress(*backup_state)) {
/* service related to backup & restore will reset the backup failure /* service related to backup & restore will reset the backup failure
timeout during a backup or restore operation */ timeout during a backup or restore operation */
Backup_Failure_Timeout_Milliseconds = Backup_Failure_Timeout * 1000UL; *backup_failure_timeout_milliseconds = *backup_failure_timeout * 1000UL;
} }
#endif #endif
} }
@@ -2734,20 +2912,24 @@ void Device_Backup_Failure_Timeout_Restart(void)
void Device_Backup_Failure_Timeout_Countdown(uint32_t milliseconds) void Device_Backup_Failure_Timeout_Countdown(uint32_t milliseconds)
{ {
#if defined(BACNET_BACKUP_RESTORE) #if defined(BACNET_BACKUP_RESTORE)
if (Device_Backup_State_In_Progress(Backup_State)) { BACNET_BACKUP_STATE *backup_state = Device_Backup_State_Value();
uint32_t *backup_failure_timeout_milliseconds =
Device_Backup_Failure_Timeout_Milliseconds_Value();
if (Device_Backup_State_In_Progress(*backup_state)) {
/* service related to backup & restore will restart the backup /* service related to backup & restore will restart the backup
failure timer during a backup or restore operation */ failure timer during a backup or restore operation */
if (Backup_Failure_Timeout_Milliseconds > 0) { if (*backup_failure_timeout_milliseconds > 0) {
if (milliseconds >= Backup_Failure_Timeout_Milliseconds) { if (milliseconds >= *backup_failure_timeout_milliseconds) {
Backup_Failure_Timeout_Milliseconds = 0; *backup_failure_timeout_milliseconds = 0;
} else { } else {
Backup_Failure_Timeout_Milliseconds -= milliseconds; *backup_failure_timeout_milliseconds -= milliseconds;
} }
if (Backup_Failure_Timeout_Milliseconds == 0) { if (*backup_failure_timeout_milliseconds == 0) {
if (Backup_State == BACKUP_STATE_PERFORMING_A_BACKUP) { if (*backup_state == BACKUP_STATE_PERFORMING_A_BACKUP) {
Backup_State = BACKUP_STATE_BACKUP_FAILURE; *backup_state = BACKUP_STATE_BACKUP_FAILURE;
} else if (Backup_State == BACKUP_STATE_PERFORMING_A_RESTORE) { } else if (*backup_state == BACKUP_STATE_PERFORMING_A_RESTORE) {
Backup_State = BACKUP_STATE_RESTORE_FAILURE; *backup_state = BACKUP_STATE_RESTORE_FAILURE;
} }
} }
} }
@@ -3888,6 +4070,8 @@ void Device_Start_Backup(void)
BACNET_CREATE_OBJECT_DATA create_data = { 0 }; BACNET_CREATE_OBJECT_DATA create_data = { 0 };
bool status = false; bool status = false;
int32_t len = 0, offset = 0; int32_t len = 0, offset = 0;
BACNET_BACKUP_STATE *backup_state = Device_Backup_State_Value();
uint32_t *configuration_files = Device_Configuration_Files_Value();
object_count = Device_Object_List_Count(); object_count = Device_Object_List_Count();
for (i = 0; i < object_count; i++) { for (i = 0; i < object_count; i++) {
@@ -3909,13 +4093,13 @@ void Device_Start_Backup(void)
Device_Read_Property); Device_Read_Property);
if (len > 0) { if (len > 0) {
(void)bacfile_write_offset( (void)bacfile_write_offset(
Configuration_Files[0], offset, &object_apdu[0], configuration_files[0], offset, &object_apdu[0],
(uint32_t)len); (uint32_t)len);
offset += len; offset += len;
} }
} }
} }
Backup_State = BACKUP_STATE_PERFORMING_A_BACKUP; *backup_state = BACKUP_STATE_PERFORMING_A_BACKUP;
#endif #endif
} }
@@ -3926,7 +4110,9 @@ void Device_Start_Backup(void)
void Device_Start_Restore(void) void Device_Start_Restore(void)
{ {
#if defined BACNET_BACKUP_RESTORE #if defined BACNET_BACKUP_RESTORE
Backup_State = BACKUP_STATE_PERFORMING_A_RESTORE; BACNET_BACKUP_STATE *backup_state = Device_Backup_State_Value();
*backup_state = BACKUP_STATE_PERFORMING_A_RESTORE;
#endif #endif
} }
@@ -3943,16 +4129,19 @@ void Device_End_Restore(void)
uint8_t apdu[MAX_APDU] = { 0 }; uint8_t apdu[MAX_APDU] = { 0 };
int32_t apdu_len = 0, offset = 0, file_size = 0; int32_t apdu_len = 0, offset = 0, file_size = 0;
int decoded_len = 0; int decoded_len = 0;
BACNET_BACKUP_STATE *backup_state = Device_Backup_State_Value();
BACNET_TIMESTAMP *last_restore_time = Device_Last_Restore_Time_Value();
uint32_t *configuration_files = Device_Configuration_Files_Value();
datetime_local(&bdateTime.date, &bdateTime.time, NULL, NULL); datetime_local(&bdateTime.date, &bdateTime.time, NULL, NULL);
bacapp_timestamp_datetime_set(&Last_Restore_Time, &bdateTime); bacapp_timestamp_datetime_set(last_restore_time, &bdateTime);
/* delete all existing objects before restore */ /* delete all existing objects before restore */
Device_Delete_Objects(); Device_Delete_Objects();
/* create objects from the backup file */ /* create objects from the backup file */
file_size = bacfile_file_size(Configuration_Files[0]); file_size = bacfile_file_size(configuration_files[0]);
while (offset < file_size) { while (offset < file_size) {
apdu_len = bacfile_read_offset( apdu_len = bacfile_read_offset(
Configuration_Files[0], offset, &apdu[0], sizeof(apdu)); configuration_files[0], offset, &apdu[0], sizeof(apdu));
if (apdu_len > 0) { if (apdu_len > 0) {
decoded_len = create_object_decode_service_request( decoded_len = create_object_decode_service_request(
apdu, apdu_len, &create_data); apdu, apdu_len, &create_data);
@@ -3967,18 +4156,18 @@ void Device_End_Restore(void)
/* error creating object - keep going */ /* error creating object - keep going */
} }
} else { } else {
Backup_State = BACKUP_STATE_RESTORE_FAILURE; *backup_state = BACKUP_STATE_RESTORE_FAILURE;
/* error while decoding object */ /* error while decoding object */
break; break;
} }
} else { } else {
Backup_State = BACKUP_STATE_RESTORE_FAILURE; *backup_state = BACKUP_STATE_RESTORE_FAILURE;
/* error while reading file */ /* error while reading file */
break; break;
} }
} }
if (Backup_State != BACKUP_STATE_RESTORE_FAILURE) { if (*backup_state != BACKUP_STATE_RESTORE_FAILURE) {
Backup_State = BACKUP_STATE_IDLE; *backup_state = BACKUP_STATE_IDLE;
} }
#endif #endif
} }
@@ -4163,23 +4352,31 @@ void Device_Timer(uint16_t milliseconds)
#ifdef BAC_ROUTING #ifdef BAC_ROUTING
uint16_t dev_id = 0; uint16_t dev_id = 0;
uint16_t current_dev_id = Routed_Device_Object_Index(); uint16_t current_dev_id = Routed_Device_Object_Index();
/* TODO: Multi-device Backup/Restore support
* Currently only Gateway (dev_id=0) supports Backup/Restore. if (Device_Router_Mode) {
* Virtual devices are blocked by Routed_Device_Service_Approval(). for (dev_id = 0; dev_id < Get_Num_Managed_Devices(); dev_id++) {
* Plan to support after discussing with maintainer. Set_Routed_Device_Object_Index(dev_id);
* Device_Backup_Failure_Timeout_Countdown(milliseconds);
* To enable per-device Backup/Restore: pObject = Object_Table;
* 1. Move Backup-related static variables to DEVICE_OBJECT_DATA: while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
* - Backup_State, Backup_Failure_Timeout_Milliseconds count = 0;
* - Backup_Failure_Timeout, Configuration_Files[] if (pObject->Object_Count) {
* - Last_Restore_Time, Backup/Restore_Preparation_Time count = pObject->Object_Count();
* 2. Modify Routed_Device_Service_Approval() to allow RD on virtual devices }
* 3. Call Device_Backup_Failure_Timeout_Countdown() inside the for loop while (count) {
* for each device count--;
*/ if ((pObject->Object_Timer) &&
Device_Backup_Failure_Timeout_Countdown(milliseconds); (pObject->Object_Index_To_Instance)) {
for (dev_id = 0; dev_id < Get_Num_Managed_Devices(); dev_id++) { instance = pObject->Object_Index_To_Instance(count);
Set_Routed_Device_Object_Index(dev_id); pObject->Object_Timer(instance, milliseconds);
}
}
pObject++;
}
}
Set_Routed_Device_Object_Index(current_dev_id);
} else {
Device_Backup_Failure_Timeout_Countdown(milliseconds);
pObject = Object_Table; pObject = Object_Table;
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
count = 0; count = 0;
@@ -4197,7 +4394,6 @@ void Device_Timer(uint16_t milliseconds)
pObject++; pObject++;
} }
} }
Set_Routed_Device_Object_Index(current_dev_id);
#else #else
Device_Backup_Failure_Timeout_Countdown(milliseconds); Device_Backup_Failure_Timeout_Countdown(milliseconds);
pObject = Object_Table; pObject = Object_Table;
@@ -4240,6 +4436,7 @@ void Routing_Device_Init(uint32_t first_object_instance)
Device_Router_Mode = true; Device_Router_Mode = true;
/* Initialize with our preset strings */ /* Initialize with our preset strings */
Routed_Device_Table_Reset();
Add_Routed_Device(first_object_instance, &My_Object_Name, Description); Add_Routed_Device(first_object_instance, &My_Object_Name, Description);
/* Now substitute our routed versions of the main object functions. */ /* Now substitute our routed versions of the main object functions. */
+37
View File
@@ -178,6 +178,34 @@ typedef struct commonBacObj_s {
* This may be useful for implementations which manage multiple Devices, * This may be useful for implementations which manage multiple Devices,
* eg, a Gateway. * eg, a Gateway.
*/ */
/* number of backup files */
#if defined(BACNET_BACKUP_RESTORE)
#ifndef BACNET_BACKUP_FILE_COUNT
#define BACNET_BACKUP_FILE_COUNT 1
#elif (BACNET_BACKUP_FILE_COUNT < 1)
#error \
"BACNET_BACKUP_FILE_COUNT must be at least 1 when BACNET_BACKUP_RESTORE is enabled"
#endif
#endif
#if defined(BAC_ROUTING) && defined(BACNET_BACKUP_RESTORE)
typedef struct bacnet_backup_restore_data_s {
BACNET_BACKUP_STATE Backup_State;
uint16_t Backup_Failure_Timeout;
uint32_t Backup_Failure_Timeout_Milliseconds;
uint32_t Configuration_Files[BACNET_BACKUP_FILE_COUNT];
BACNET_TIMESTAMP Last_Restore_Time;
uint16_t Backup_Preparation_Time;
uint16_t Restore_Preparation_Time;
uint16_t Restore_Completion_Time;
} BACNET_BACKUP_RESTORE_DATA;
#endif
typedef struct bacnet_device_reinitialize_data_s {
BACNET_REINITIALIZED_STATE State;
const char *Password;
} BACNET_DEVICE_REINITIALIZE_DATA;
typedef struct devObj_s { typedef struct devObj_s {
/** The BACnet Device Address for this device; ->len depends on DLL type. */ /** The BACnet Device Address for this device; ->len depends on DLL type. */
BACNET_ADDRESS bacDevAddr; BACNET_ADDRESS bacDevAddr;
@@ -191,6 +219,13 @@ typedef struct devObj_s {
/** The upcounter that shows if the Device ID or object structure has /** The upcounter that shows if the Device ID or object structure has
* changed. */ * changed. */
uint32_t Database_Revision; uint32_t Database_Revision;
#if defined(BAC_ROUTING)
BACNET_DEVICE_REINITIALIZE_DATA Reinitialize;
#if defined(BACNET_BACKUP_RESTORE)
BACNET_BACKUP_RESTORE_DATA Backup;
#endif
#endif
} DEVICE_OBJECT_DATA; } DEVICE_OBJECT_DATA;
#ifdef __cplusplus #ifdef __cplusplus
@@ -502,6 +537,8 @@ uint16_t Add_Routed_Device(
const BACNET_CHARACTER_STRING *Object_Name, const BACNET_CHARACTER_STRING *Object_Name,
const char *Description); const char *Description);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void Routed_Device_Table_Reset(void);
BACNET_STACK_EXPORT
DEVICE_OBJECT_DATA *Get_Routed_Device_Object(int idx); DEVICE_OBJECT_DATA *Get_Routed_Device_Object(int idx);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
BACNET_ADDRESS *Get_Routed_Device_Address(int idx); BACNET_ADDRESS *Get_Routed_Device_Address(int idx);
+22 -12
View File
@@ -75,6 +75,14 @@ uint16_t Num_Managed_Devices = 0;
*/ */
uint16_t iCurrent_Device_Idx = 0; uint16_t iCurrent_Device_Idx = 0;
/** Reset the routed Device table before rebuilding the gateway/virtual list. */
void Routed_Device_Table_Reset(void)
{
memset(&Devices[0], 0, sizeof(Devices));
Num_Managed_Devices = 0;
iCurrent_Device_Idx = 0;
}
/** Get the current routed device object index. /** Get the current routed device object index.
* @return Index of the currently active routed device in Devices[] array * @return Index of the currently active routed device in Devices[] array
*/ */
@@ -150,6 +158,15 @@ uint16_t Add_Routed_Device(
Routed_Device_Set_Description("No Descr", strlen("No Descr")); Routed_Device_Set_Description("No Descr", strlen("No Descr"));
} }
pDev->Database_Revision = 0; /* Reset/Initialize now */ pDev->Database_Revision = 0; /* Reset/Initialize now */
#if defined(BAC_ROUTING)
pDev->Reinitialize.State = BACNET_REINIT_IDLE;
pDev->Reinitialize.Password = "filister";
#if defined(BACNET_BACKUP_RESTORE)
memset(&pDev->Backup, 0, sizeof(pDev->Backup));
pDev->Backup.Backup_State = BACKUP_STATE_IDLE;
pDev->Backup.Backup_Failure_Timeout = 60 * 60;
#endif
#endif
return i; return i;
} else { } else {
return UINT16_MAX; return UINT16_MAX;
@@ -606,8 +623,8 @@ void Routed_Device_Inc_Database_Revision(void)
} }
/** Check to see if the current Device supports this service. /** Check to see if the current Device supports this service.
* Presently checks for RD and DCC and only allows them if the current * Presently allows ReinitializeDevice for routed virtual devices and keeps
* device is the gateway device. * DeviceCommunicationControl restricted to the gateway device.
* *
* @param service [in] The service being requested. * @param service [in] The service being requested.
* @param service_argument [in] An optional argument (eg, service type). * @param service_argument [in] An optional argument (eg, service type).
@@ -629,16 +646,9 @@ int Routed_Device_Service_Approval(
(void)service_argument; (void)service_argument;
switch (service) { switch (service) {
case SERVICE_SUPPORTED_REINITIALIZE_DEVICE: case SERVICE_SUPPORTED_REINITIALIZE_DEVICE:
/* If not the gateway device, we don't support RD */ /* RD is accepted for virtual devices. Device_Reinitialize()
if (iCurrent_Device_Idx > 0) { handles state-specific support and returns service errors for
if (apdu_buff != NULL) { virtual-device states that have gateway/system side effects. */
len = reject_encode_apdu(
apdu_buff, invoke_id,
REJECT_REASON_UNRECOGNIZED_SERVICE);
} else {
len = 1; /* Non-zero return */
}
}
break; break;
case SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL: case SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL:
/* If not the gateway device, we don't support DCC */ /* If not the gateway device, we don't support DCC */
+5 -4
View File
@@ -1364,7 +1364,7 @@ static const char *Device_Location_Default = BACNET_DEVICE_LOCATION_NAME;
static const char *Device_Description_Default = BACNET_DEVICE_DESCRIPTION; static const char *Device_Description_Default = BACNET_DEVICE_DESCRIPTION;
static uint32_t Database_Revision; static uint32_t Database_Revision;
static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE; static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE;
static BACNET_CHARACTER_STRING Reinit_Password; static const char *Reinit_Password = "filister";
static write_property_function Device_Write_Property_Store_Callback; static write_property_function Device_Write_Property_Store_Callback;
static list_element_function Device_Add_List_Element_Callback; static list_element_function Device_Add_List_Element_Callback;
static list_element_function Device_Remove_List_Element_Callback; static list_element_function Device_Remove_List_Element_Callback;
@@ -1448,7 +1448,7 @@ static BACNET_BACKUP_STATE Backup_State = BACKUP_STATE_IDLE;
*/ */
bool Device_Reinitialize_Password_Set(const char *password) bool Device_Reinitialize_Password_Set(const char *password)
{ {
characterstring_init_ansi(&Reinit_Password, password); Reinit_Password = password;
return true; return true;
} }
@@ -1480,7 +1480,7 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
protection, the service request shall be denied if the parameter protection, the service request shall be denied if the parameter
is absent or if the password is incorrect. For those devices that is absent or if the password is incorrect. For those devices that
do not require a password, this parameter shall be ignored.*/ do not require a password, this parameter shall be ignored.*/
if (characterstring_length(&Reinit_Password) > 0) { if (Reinit_Password && strlen(Reinit_Password) > 0) {
if (characterstring_encoding(&rd_data->password) == CHARACTER_UTF8) { if (characterstring_encoding(&rd_data->password) == CHARACTER_UTF8) {
length = characterstring_utf8_length(&rd_data->password); length = characterstring_utf8_length(&rd_data->password);
} else { } else {
@@ -1489,7 +1489,8 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
if (length > 20) { if (length > 20) {
rd_data->error_class = ERROR_CLASS_SERVICES; rd_data->error_class = ERROR_CLASS_SERVICES;
rd_data->error_code = ERROR_CODE_PARAMETER_OUT_OF_RANGE; rd_data->error_code = ERROR_CODE_PARAMETER_OUT_OF_RANGE;
} else if (characterstring_same(&rd_data->password, &Reinit_Password)) { } else if (characterstring_ansi_same(
&rd_data->password, Reinit_Password)) {
password_success = true; password_success = true;
} else { } else {
rd_data->error_class = ERROR_CLASS_SECURITY; rd_data->error_class = ERROR_CLASS_SECURITY;
+63 -1
View File
@@ -30,7 +30,7 @@ include_directories(
${TST_DIR}/ztest/include ${TST_DIR}/ztest/include
) )
add_executable(${PROJECT_NAME} set(TEST_DEVICE_SOURCES
# File(s) under test # File(s) under test
${SRC_DIR}/bacnet/basic/object/device.c ${SRC_DIR}/bacnet/basic/object/device.c
# Support files and stubs (pathname alphabetical) # Support files and stubs (pathname alphabetical)
@@ -140,3 +140,65 @@ add_executable(${PROJECT_NAME}
${ZTST_DIR}/ztest_mock.c ${ZTST_DIR}/ztest_mock.c
${ZTST_DIR}/ztest.c ${ZTST_DIR}/ztest.c
) )
function(configure_device_test_target
target_name routing_enabled backup_restore_enabled)
if(routing_enabled)
target_sources(${target_name} PRIVATE
${SRC_DIR}/bacnet/basic/object/gateway/gw_device.c
)
target_compile_definitions(${target_name} PRIVATE
BAC_ROUTING
)
endif()
if(backup_restore_enabled)
target_compile_definitions(${target_name} PRIVATE
BACNET_BACKUP_RESTORE
)
endif()
endfunction()
# Register a CTest build/run pair for one device test binary.
function(
add_device_ctest
target_name
test_name)
add_test(NAME build_${test_name} COMMAND ${CMAKE_COMMAND} --build "${CMAKE_BINARY_DIR}" --config $<CONFIG> --target
${target_name})
add_test(NAME test_${test_name} COMMAND $<TARGET_FILE:${target_name}>)
set_tests_properties(test_${test_name} PROPERTIES FIXTURES_REQUIRED fixture_${test_name})
set_tests_properties(build_${test_name} PROPERTIES FIXTURES_SETUP fixture_${test_name})
endfunction()
add_executable(${PROJECT_NAME}
${TEST_DEVICE_SOURCES}
)
configure_device_test_target(${PROJECT_NAME} OFF OFF)
# Backup/Restore-only test binary.
add_executable(${PROJECT_NAME}_backup_restore ${TEST_DEVICE_SOURCES})
configure_device_test_target(
${PROJECT_NAME}_backup_restore
OFF
ON)
# BAC_ROUTING-only test binary.
add_executable(${PROJECT_NAME}_bac_routing ${TEST_DEVICE_SOURCES})
configure_device_test_target(
${PROJECT_NAME}_bac_routing
ON
OFF)
# BAC_ROUTING with Backup/Restore test binary.
add_executable(${PROJECT_NAME}_bac_routing_backup_restore ${TEST_DEVICE_SOURCES})
configure_device_test_target(
${PROJECT_NAME}_bac_routing_backup_restore
ON
ON)
# CTest pair for the Backup/Restore-only binary.
add_device_ctest(${PROJECT_NAME}_backup_restore ${basename}_backup_restore)
# CTest pair for the BAC_ROUTING-only binary.
add_device_ctest(${PROJECT_NAME}_bac_routing ${basename}_bac_routing)
# CTest pair for the BAC_ROUTING with Backup/Restore binary.
add_device_ctest(${PROJECT_NAME}_bac_routing_backup_restore ${basename}_bac_routing_backup_restore)
+243
View File
@@ -91,6 +91,49 @@ static bool Write_Property_Proprietary(BACNET_WRITE_PROPERTY_DATA *data)
return status; return status;
} }
#if defined(BAC_ROUTING)
/**
* @brief Verify routed virtual devices still do not expose DCC.
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST(device_tests, test_Routed_Device_DCC_Remains_Blocked)
#else
static void test_Routed_Device_DCC_Remains_Blocked(void)
#endif
{
BACNET_CHARACTER_STRING object_name = { 0 };
uint8_t apdu[MAX_APDU] = { 0 };
uint16_t device_index = 0;
int len = 0;
bool status = false;
Device_Init(NULL);
Routing_Device_Init(1000);
status = characterstring_init_ansi(&object_name, "Virtual Device");
zassert_true(status, NULL);
device_index = Add_Routed_Device(1001, &object_name, "Virtual Device");
zassert_equal(device_index, 1, NULL);
status = Set_Routed_Device_Object_Index(0);
zassert_true(status, NULL);
len = Routed_Device_Service_Approval(
SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL, 0, NULL, 0);
zassert_equal(len, 0, NULL);
status = Set_Routed_Device_Object_Index(device_index);
zassert_true(status, NULL);
len = Routed_Device_Service_Approval(
SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL, 0, NULL, 0);
zassert_not_equal(len, 0, NULL);
len = Routed_Device_Service_Approval(
SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL, 0, apdu, 1);
zassert_true(len > 0, NULL);
status = Set_Routed_Device_Object_Index(0);
zassert_true(status, NULL);
}
#endif
/** /**
* @brief ReadProperty handler for this objects proprietary properties. * @brief ReadProperty handler for this objects proprietary properties.
* For the given ReadProperty data, the application_data is loaded * For the given ReadProperty data, the application_data is loaded
@@ -421,6 +464,190 @@ static void testDevice(void)
return; return;
} }
#if defined(BAC_ROUTING)
static void test_Routed_Device_Reinitialize_Unsupported_State(
BACNET_REINITIALIZED_STATE state)
{
bool status = false;
BACNET_REINITIALIZE_DEVICE_DATA rd_data = { 0 };
Device_Reinitialize_State_Set(BACNET_REINIT_IDLE);
Device_Reinitialize_Password_Set(NULL);
rd_data.error_class = ERROR_CLASS_DEVICE;
rd_data.error_code = ERROR_CODE_SUCCESS;
rd_data.state = state;
characterstring_init_ansi(&rd_data.password, NULL);
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_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED,
"error-code=%s", bactext_error_code_name(rd_data.error_code));
zassert_equal(Device_Reinitialized_State(), BACNET_REINIT_IDLE, NULL);
}
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST(device_tests, test_Routed_Device_Reinitialize)
#else
static void test_Routed_Device_Reinitialize(void)
#endif
{
bool status = false;
BACNET_CHARACTER_STRING object_name = { 0 };
BACNET_REINITIALIZE_DEVICE_DATA rd_data = { 0 };
Device_Init(NULL);
Routing_Device_Init(100);
characterstring_init_ansi(&object_name, "VirtualDevice");
zassert_equal(Add_Routed_Device(101, &object_name, "Virtual"), 1, NULL);
status = Set_Routed_Device_Object_Index(0);
zassert_true(status, NULL);
zassert_equal(
Routed_Device_Service_Approval(
SERVICE_SUPPORTED_REINITIALIZE_DEVICE, 0, NULL, 0),
0, NULL);
zassert_equal(
Routed_Device_Service_Approval(
SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL, 0, NULL, 0),
0, NULL);
Device_Reinitialize_State_Set(BACNET_REINIT_IDLE);
Device_Reinitialize_Password_Set(NULL);
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(&rd_data);
zassert_true(status, NULL);
zassert_equal(Device_Reinitialized_State(), BACNET_REINIT_COLDSTART, NULL);
status = Set_Routed_Device_Object_Index(1);
zassert_true(status, NULL);
zassert_equal(
Routed_Device_Service_Approval(
SERVICE_SUPPORTED_REINITIALIZE_DEVICE, 0, NULL, 0),
0, NULL);
zassert_not_equal(
Routed_Device_Service_Approval(
SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL, 0, NULL, 0),
0, NULL);
test_Routed_Device_Reinitialize_Unsupported_State(BACNET_REINIT_COLDSTART);
test_Routed_Device_Reinitialize_Unsupported_State(BACNET_REINIT_WARMSTART);
test_Routed_Device_Reinitialize_Unsupported_State(
BACNET_REINIT_ACTIVATE_CHANGES);
}
#endif
#if defined(BAC_ROUTING) && defined(BACNET_BACKUP_RESTORE)
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST(device_tests, test_Routed_Device_Backup_Restore_Independence)
#else
static void test_Routed_Device_Backup_Restore_Independence(void)
#endif
{
bool status = false;
BACNET_CHARACTER_STRING object_name = { 0 };
BACNET_REINITIALIZE_DEVICE_DATA rd_data = { 0 };
Device_Init(NULL);
Routing_Device_Init(200);
characterstring_init_ansi(&object_name, "VirtualDevice1");
zassert_equal(Add_Routed_Device(201, &object_name, "Virtual1"), 1, NULL);
characterstring_init_ansi(&object_name, "VirtualDevice2");
zassert_equal(Add_Routed_Device(202, &object_name, "Virtual2"), 2, NULL);
rd_data.error_class = ERROR_CLASS_DEVICE;
rd_data.error_code = ERROR_CODE_SUCCESS;
rd_data.state = BACNET_REINIT_STARTRESTORE;
characterstring_init_ansi(&rd_data.password, NULL);
Set_Routed_Device_Object_Index(1);
Device_Reinitialize_Password_Set(NULL);
status = Device_Reinitialize(&rd_data);
zassert_true(status, NULL);
zassert_equal(
Device_Backup_And_Restore_State(), BACKUP_STATE_PERFORMING_A_RESTORE,
NULL);
rd_data.error_class = ERROR_CLASS_DEVICE;
rd_data.error_code = ERROR_CODE_SUCCESS;
status = Device_Reinitialize(&rd_data);
zassert_false(status, NULL);
zassert_equal(rd_data.error_class, ERROR_CLASS_DEVICE, NULL);
zassert_equal(
rd_data.error_code, ERROR_CODE_CONFIGURATION_IN_PROGRESS, NULL);
Set_Routed_Device_Object_Index(0);
zassert_equal(Device_Backup_And_Restore_State(), BACKUP_STATE_IDLE, NULL);
Set_Routed_Device_Object_Index(2);
Device_Reinitialize_Password_Set(NULL);
zassert_equal(Device_Backup_And_Restore_State(), BACKUP_STATE_IDLE, NULL);
status = Device_Reinitialize(&rd_data);
zassert_true(status, NULL);
zassert_equal(
Device_Backup_And_Restore_State(), BACKUP_STATE_PERFORMING_A_RESTORE,
NULL);
Set_Routed_Device_Object_Index(1);
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_true(status, NULL);
zassert_equal(Device_Backup_And_Restore_State(), BACKUP_STATE_IDLE, NULL);
Set_Routed_Device_Object_Index(2);
zassert_equal(
Device_Backup_And_Restore_State(), BACKUP_STATE_PERFORMING_A_RESTORE,
NULL);
}
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST(device_tests, test_Routed_Device_Backup_Countdown_Per_Device)
#else
static void test_Routed_Device_Backup_Countdown_Per_Device(void)
#endif
{
bool status = false;
BACNET_CHARACTER_STRING object_name = { 0 };
Device_Init(NULL);
Routing_Device_Init(300);
characterstring_init_ansi(&object_name, "VirtualDevice1");
zassert_equal(Add_Routed_Device(301, &object_name, "Virtual1"), 1, NULL);
characterstring_init_ansi(&object_name, "VirtualDevice2");
zassert_equal(Add_Routed_Device(302, &object_name, "Virtual2"), 2, NULL);
status = Set_Routed_Device_Object_Index(1);
zassert_true(status, NULL);
Device_Backup_Failure_Timeout_Set(1);
Device_Backup_And_Restore_State_Set(BACKUP_STATE_PERFORMING_A_BACKUP);
Device_Backup_Failure_Timeout_Restart();
status = Set_Routed_Device_Object_Index(2);
zassert_true(status, NULL);
zassert_equal(Device_Backup_And_Restore_State(), BACKUP_STATE_IDLE, NULL);
status = Set_Routed_Device_Object_Index(1);
zassert_true(status, NULL);
Device_Timer(500);
zassert_equal(
Device_Backup_And_Restore_State(), BACKUP_STATE_PERFORMING_A_BACKUP,
NULL);
Device_Timer(500);
zassert_equal(
Device_Backup_And_Restore_State(), BACKUP_STATE_BACKUP_FAILURE, NULL);
status = Set_Routed_Device_Object_Index(2);
zassert_true(status, NULL);
zassert_equal(Device_Backup_And_Restore_State(), BACKUP_STATE_IDLE, NULL);
}
#endif
/** /**
* @} * @}
*/ */
@@ -430,9 +657,25 @@ ZTEST_SUITE(device_tests, NULL, NULL, NULL, NULL, NULL);
#else #else
void test_main(void) void test_main(void)
{ {
#if defined(BAC_ROUTING) && defined(BACNET_BACKUP_RESTORE)
ztest_test_suite(
device_tests, ztest_unit_test(testDevice),
ztest_unit_test(test_Device_Data_Sharing),
ztest_unit_test(test_Routed_Device_DCC_Remains_Blocked),
ztest_unit_test(test_Routed_Device_Reinitialize),
ztest_unit_test(test_Routed_Device_Backup_Restore_Independence),
ztest_unit_test(test_Routed_Device_Backup_Countdown_Per_Device));
#elif defined(BAC_ROUTING)
ztest_test_suite(
device_tests, ztest_unit_test(testDevice),
ztest_unit_test(test_Device_Data_Sharing),
ztest_unit_test(test_Routed_Device_DCC_Remains_Blocked),
ztest_unit_test(test_Routed_Device_Reinitialize));
#else
ztest_test_suite( ztest_test_suite(
device_tests, ztest_unit_test(testDevice), device_tests, ztest_unit_test(testDevice),
ztest_unit_test(test_Device_Data_Sharing)); ztest_unit_test(test_Device_Data_Sharing));
#endif
ztest_run_test_suite(device_tests); ztest_run_test_suite(device_tests);
} }