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:
@@ -1465,17 +1465,14 @@ static uint32_t Database_Revision = 0;
|
||||
/* Auto_Slave_Discovery */
|
||||
/* Slave_Address_Binding */
|
||||
/* Profile_Name */
|
||||
static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE;
|
||||
static const char *Reinit_Password = "filister";
|
||||
static BACNET_DEVICE_REINITIALIZE_DATA Reinitialize_Data = {
|
||||
.State = BACNET_REINIT_IDLE, .Password = "filister"
|
||||
};
|
||||
static write_property_function Device_Write_Property_Store_Callback;
|
||||
static list_element_function Device_Add_List_Element_Callback;
|
||||
static list_element_function Device_Remove_List_Element_Callback;
|
||||
/* backup and 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.
|
||||
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
|
||||
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
|
||||
|
||||
/**
|
||||
@@ -1535,7 +1666,10 @@ static bool Device_Router_Mode = false;
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@@ -1559,6 +1693,13 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
|
||||
bool password_success = false;
|
||||
unsigned i;
|
||||
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
|
||||
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
|
||||
is absent or if the password is incorrect. For those devices that
|
||||
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) {
|
||||
length = characterstring_utf8_length(&rd_data->password);
|
||||
} else {
|
||||
@@ -1576,7 +1717,7 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
|
||||
rd_data->error_class = ERROR_CLASS_SERVICES;
|
||||
rd_data->error_code = ERROR_CODE_PARAMETER_OUT_OF_RANGE;
|
||||
} else if (characterstring_ansi_same(
|
||||
&rd_data->password, Reinit_Password)) {
|
||||
&rd_data->password, reinit_password)) {
|
||||
password_success = true;
|
||||
} else {
|
||||
rd_data->error_class = ERROR_CLASS_SECURITY;
|
||||
@@ -1586,13 +1727,24 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
|
||||
password_success = true;
|
||||
}
|
||||
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) {
|
||||
case BACNET_REINIT_COLDSTART:
|
||||
dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
|
||||
/* note: you probably want to restart *after* the
|
||||
simple ack has been sent from the return handler
|
||||
so just set a flag from here */
|
||||
Reinitialize_State = rd_data->state;
|
||||
*reinitialize_state = rd_data->state;
|
||||
status = true;
|
||||
break;
|
||||
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
|
||||
simple ack has been sent from the return handler
|
||||
so just set a flag from here */
|
||||
Reinitialize_State = rd_data->state;
|
||||
*reinitialize_state = rd_data->state;
|
||||
status = true;
|
||||
break;
|
||||
#if defined BACNET_BACKUP_RESTORE
|
||||
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_code = ERROR_CODE_CONFIGURATION_IN_PROGRESS;
|
||||
break;
|
||||
}
|
||||
Backup_State = BACKUP_STATE_PREPARING_FOR_BACKUP;
|
||||
*backup_state = BACKUP_STATE_PREPARING_FOR_BACKUP;
|
||||
Device_Backup_Failure_Timeout_Restart();
|
||||
Device_Start_Backup();
|
||||
Reinitialize_State = rd_data->state;
|
||||
*reinitialize_state = rd_data->state;
|
||||
status = true;
|
||||
break;
|
||||
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_code = ERROR_CODE_CONFIGURATION_IN_PROGRESS;
|
||||
break;
|
||||
}
|
||||
Backup_State = BACKUP_STATE_PREPARING_FOR_RESTORE;
|
||||
*backup_state = BACKUP_STATE_PREPARING_FOR_RESTORE;
|
||||
Device_Backup_Failure_Timeout_Restart();
|
||||
Device_Start_Restore();
|
||||
Reinitialize_State = rd_data->state;
|
||||
*reinitialize_state = rd_data->state;
|
||||
status = true;
|
||||
break;
|
||||
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_code = ERROR_CODE_CONFIGURATION_IN_PROGRESS;
|
||||
break;
|
||||
}
|
||||
Device_Backup_Failure_Timeout_Restart();
|
||||
Device_End_Restore();
|
||||
Reinitialize_State = rd_data->state;
|
||||
*reinitialize_state = rd_data->state;
|
||||
status = true;
|
||||
break;
|
||||
case BACNET_REINIT_ENDBACKUP:
|
||||
case BACNET_REINIT_ABORTRESTORE:
|
||||
Backup_State = BACKUP_STATE_IDLE;
|
||||
*backup_state = BACKUP_STATE_IDLE;
|
||||
Device_Backup_Failure_Timeout_Reset();
|
||||
Reinitialize_State = rd_data->state;
|
||||
*reinitialize_state = rd_data->state;
|
||||
status = true;
|
||||
break;
|
||||
#else
|
||||
@@ -1672,7 +1824,7 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
|
||||
Network_Port_Changes_Pending_Activate(
|
||||
Network_Port_Index_To_Instance(i));
|
||||
}
|
||||
Reinitialize_State = rd_data->state;
|
||||
*reinitialize_state = rd_data->state;
|
||||
status = true;
|
||||
break;
|
||||
default:
|
||||
@@ -1687,12 +1839,13 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
|
||||
|
||||
BACNET_REINITIALIZED_STATE Device_Reinitialized_State(void)
|
||||
{
|
||||
return Reinitialize_State;
|
||||
return Device_Reinitialize_Data()->State;
|
||||
}
|
||||
|
||||
bool Device_Reinitialize_State_Set(BACNET_REINITIALIZED_STATE state)
|
||||
{
|
||||
Reinitialize_State = state;
|
||||
Device_Reinitialize_Data()->State = state;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2467,9 +2620,11 @@ uint32_t Device_Interval_Offset(void)
|
||||
bool Device_Configuration_File_Set(unsigned index, uint32_t instance)
|
||||
{
|
||||
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) {
|
||||
Configuration_Files[index] = instance;
|
||||
configuration_files[index] = instance;
|
||||
status = true;
|
||||
}
|
||||
#else
|
||||
@@ -2483,10 +2638,11 @@ bool Device_Configuration_File_Set(unsigned index, uint32_t instance)
|
||||
uint32_t Device_Configuration_File(unsigned index)
|
||||
{
|
||||
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) {
|
||||
instance = Configuration_Files[index];
|
||||
instance = configuration_files[index];
|
||||
}
|
||||
#else
|
||||
(void)index;
|
||||
@@ -2505,11 +2661,12 @@ uint32_t Device_Configuration_File(unsigned index)
|
||||
bool Device_Is_Configuration_File(uint32_t instance)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
#if BACNET_BACKUP_FILE_COUNT
|
||||
#if defined(BACNET_BACKUP_RESTORE)
|
||||
unsigned i;
|
||||
uint32_t *configuration_files = Device_Configuration_Files_Value();
|
||||
|
||||
for (i = 0; i < BACNET_BACKUP_FILE_COUNT; i++) {
|
||||
if (Configuration_Files[i] == instance) {
|
||||
if (configuration_files[i] == instance) {
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
@@ -2537,10 +2694,12 @@ int Device_Configuration_File_Encode(
|
||||
int apdu_len = BACNET_STATUS_ERROR;
|
||||
|
||||
(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) {
|
||||
apdu_len = encode_application_object_id(
|
||||
apdu, OBJECT_FILE, Configuration_Files[array_index]);
|
||||
apdu, OBJECT_FILE, configuration_files[array_index]);
|
||||
}
|
||||
#else
|
||||
(void)array_index;
|
||||
@@ -2620,56 +2779,67 @@ static BACNET_ERROR_CODE Device_Configuration_File_Write(
|
||||
|
||||
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)
|
||||
{
|
||||
Backup_Failure_Timeout = timeout;
|
||||
uint16_t *backup_failure_timeout = Device_Backup_Failure_Timeout_Value();
|
||||
|
||||
*backup_failure_timeout = timeout;
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Backup_Preparation_Time = time;
|
||||
uint16_t *backup_preparation_time = Device_Backup_Preparation_Time_Value();
|
||||
|
||||
*backup_preparation_time = time;
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Restore_Preparation_Time = time;
|
||||
uint16_t *restore_preparation_time =
|
||||
Device_Restore_Preparation_Time_Value();
|
||||
|
||||
*restore_preparation_time = time;
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Restore_Completion_Time = time;
|
||||
uint16_t *restore_completion_time = Device_Restore_Completion_Time_Value();
|
||||
|
||||
*restore_completion_time = time;
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Backup_State = state;
|
||||
BACNET_BACKUP_STATE *backup_state = Device_Backup_State_Value();
|
||||
|
||||
*backup_state = state;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2680,7 +2850,10 @@ bool Device_Backup_And_Restore_State_Set(BACNET_BACKUP_STATE state)
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -2709,10 +2882,15 @@ bool Device_Backup_State_In_Progress(BACNET_BACKUP_STATE state)
|
||||
void Device_Backup_Failure_Timeout_Restart(void)
|
||||
{
|
||||
#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
|
||||
timeout during a backup or restore operation */
|
||||
Backup_Failure_Timeout_Milliseconds = Backup_Failure_Timeout * 1000UL;
|
||||
*backup_failure_timeout_milliseconds = *backup_failure_timeout * 1000UL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -2734,20 +2912,24 @@ void Device_Backup_Failure_Timeout_Restart(void)
|
||||
void Device_Backup_Failure_Timeout_Countdown(uint32_t milliseconds)
|
||||
{
|
||||
#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
|
||||
failure timer during a backup or restore operation */
|
||||
if (Backup_Failure_Timeout_Milliseconds > 0) {
|
||||
if (milliseconds >= Backup_Failure_Timeout_Milliseconds) {
|
||||
Backup_Failure_Timeout_Milliseconds = 0;
|
||||
if (*backup_failure_timeout_milliseconds > 0) {
|
||||
if (milliseconds >= *backup_failure_timeout_milliseconds) {
|
||||
*backup_failure_timeout_milliseconds = 0;
|
||||
} else {
|
||||
Backup_Failure_Timeout_Milliseconds -= milliseconds;
|
||||
*backup_failure_timeout_milliseconds -= milliseconds;
|
||||
}
|
||||
if (Backup_Failure_Timeout_Milliseconds == 0) {
|
||||
if (Backup_State == BACKUP_STATE_PERFORMING_A_BACKUP) {
|
||||
Backup_State = BACKUP_STATE_BACKUP_FAILURE;
|
||||
} else if (Backup_State == BACKUP_STATE_PERFORMING_A_RESTORE) {
|
||||
Backup_State = BACKUP_STATE_RESTORE_FAILURE;
|
||||
if (*backup_failure_timeout_milliseconds == 0) {
|
||||
if (*backup_state == BACKUP_STATE_PERFORMING_A_BACKUP) {
|
||||
*backup_state = BACKUP_STATE_BACKUP_FAILURE;
|
||||
} else if (*backup_state == BACKUP_STATE_PERFORMING_A_RESTORE) {
|
||||
*backup_state = BACKUP_STATE_RESTORE_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3888,6 +4070,8 @@ void Device_Start_Backup(void)
|
||||
BACNET_CREATE_OBJECT_DATA create_data = { 0 };
|
||||
bool status = false;
|
||||
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();
|
||||
for (i = 0; i < object_count; i++) {
|
||||
@@ -3909,13 +4093,13 @@ void Device_Start_Backup(void)
|
||||
Device_Read_Property);
|
||||
if (len > 0) {
|
||||
(void)bacfile_write_offset(
|
||||
Configuration_Files[0], offset, &object_apdu[0],
|
||||
configuration_files[0], offset, &object_apdu[0],
|
||||
(uint32_t)len);
|
||||
offset += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
Backup_State = BACKUP_STATE_PERFORMING_A_BACKUP;
|
||||
*backup_state = BACKUP_STATE_PERFORMING_A_BACKUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3926,7 +4110,9 @@ void Device_Start_Backup(void)
|
||||
void Device_Start_Restore(void)
|
||||
{
|
||||
#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
|
||||
}
|
||||
|
||||
@@ -3943,16 +4129,19 @@ void Device_End_Restore(void)
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int32_t apdu_len = 0, offset = 0, file_size = 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);
|
||||
bacapp_timestamp_datetime_set(&Last_Restore_Time, &bdateTime);
|
||||
bacapp_timestamp_datetime_set(last_restore_time, &bdateTime);
|
||||
/* delete all existing objects before restore */
|
||||
Device_Delete_Objects();
|
||||
/* 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) {
|
||||
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) {
|
||||
decoded_len = create_object_decode_service_request(
|
||||
apdu, apdu_len, &create_data);
|
||||
@@ -3967,18 +4156,18 @@ void Device_End_Restore(void)
|
||||
/* error creating object - keep going */
|
||||
}
|
||||
} else {
|
||||
Backup_State = BACKUP_STATE_RESTORE_FAILURE;
|
||||
*backup_state = BACKUP_STATE_RESTORE_FAILURE;
|
||||
/* error while decoding object */
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Backup_State = BACKUP_STATE_RESTORE_FAILURE;
|
||||
*backup_state = BACKUP_STATE_RESTORE_FAILURE;
|
||||
/* error while reading file */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Backup_State != BACKUP_STATE_RESTORE_FAILURE) {
|
||||
Backup_State = BACKUP_STATE_IDLE;
|
||||
if (*backup_state != BACKUP_STATE_RESTORE_FAILURE) {
|
||||
*backup_state = BACKUP_STATE_IDLE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -4163,23 +4352,11 @@ void Device_Timer(uint16_t milliseconds)
|
||||
#ifdef BAC_ROUTING
|
||||
uint16_t dev_id = 0;
|
||||
uint16_t current_dev_id = Routed_Device_Object_Index();
|
||||
/* TODO: Multi-device Backup/Restore support
|
||||
* Currently only Gateway (dev_id=0) supports Backup/Restore.
|
||||
* Virtual devices are blocked by Routed_Device_Service_Approval().
|
||||
* Plan to support after discussing with maintainer.
|
||||
*
|
||||
* To enable per-device Backup/Restore:
|
||||
* 1. Move Backup-related static variables to DEVICE_OBJECT_DATA:
|
||||
* - Backup_State, Backup_Failure_Timeout_Milliseconds
|
||||
* - Backup_Failure_Timeout, Configuration_Files[]
|
||||
* - Last_Restore_Time, Backup/Restore_Preparation_Time
|
||||
* 2. Modify Routed_Device_Service_Approval() to allow RD on virtual devices
|
||||
* 3. Call Device_Backup_Failure_Timeout_Countdown() inside the for loop
|
||||
* for each device
|
||||
*/
|
||||
Device_Backup_Failure_Timeout_Countdown(milliseconds);
|
||||
|
||||
if (Device_Router_Mode) {
|
||||
for (dev_id = 0; dev_id < Get_Num_Managed_Devices(); dev_id++) {
|
||||
Set_Routed_Device_Object_Index(dev_id);
|
||||
Device_Backup_Failure_Timeout_Countdown(milliseconds);
|
||||
pObject = Object_Table;
|
||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||
count = 0;
|
||||
@@ -4198,6 +4375,25 @@ void Device_Timer(uint16_t milliseconds)
|
||||
}
|
||||
}
|
||||
Set_Routed_Device_Object_Index(current_dev_id);
|
||||
} else {
|
||||
Device_Backup_Failure_Timeout_Countdown(milliseconds);
|
||||
pObject = Object_Table;
|
||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||
count = 0;
|
||||
if (pObject->Object_Count) {
|
||||
count = pObject->Object_Count();
|
||||
}
|
||||
while (count) {
|
||||
count--;
|
||||
if ((pObject->Object_Timer) &&
|
||||
(pObject->Object_Index_To_Instance)) {
|
||||
instance = pObject->Object_Index_To_Instance(count);
|
||||
pObject->Object_Timer(instance, milliseconds);
|
||||
}
|
||||
}
|
||||
pObject++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
Device_Backup_Failure_Timeout_Countdown(milliseconds);
|
||||
pObject = Object_Table;
|
||||
@@ -4240,6 +4436,7 @@ void Routing_Device_Init(uint32_t first_object_instance)
|
||||
Device_Router_Mode = true;
|
||||
|
||||
/* Initialize with our preset strings */
|
||||
Routed_Device_Table_Reset();
|
||||
Add_Routed_Device(first_object_instance, &My_Object_Name, Description);
|
||||
|
||||
/* Now substitute our routed versions of the main object functions. */
|
||||
|
||||
@@ -178,6 +178,34 @@ typedef struct commonBacObj_s {
|
||||
* This may be useful for implementations which manage multiple Devices,
|
||||
* 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 {
|
||||
/** The BACnet Device Address for this device; ->len depends on DLL type. */
|
||||
BACNET_ADDRESS bacDevAddr;
|
||||
@@ -191,6 +219,13 @@ typedef struct devObj_s {
|
||||
/** The upcounter that shows if the Device ID or object structure has
|
||||
* changed. */
|
||||
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;
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -502,6 +537,8 @@ uint16_t Add_Routed_Device(
|
||||
const BACNET_CHARACTER_STRING *Object_Name,
|
||||
const char *Description);
|
||||
BACNET_STACK_EXPORT
|
||||
void Routed_Device_Table_Reset(void);
|
||||
BACNET_STACK_EXPORT
|
||||
DEVICE_OBJECT_DATA *Get_Routed_Device_Object(int idx);
|
||||
BACNET_STACK_EXPORT
|
||||
BACNET_ADDRESS *Get_Routed_Device_Address(int idx);
|
||||
|
||||
@@ -75,6 +75,14 @@ uint16_t Num_Managed_Devices = 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.
|
||||
* @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"));
|
||||
}
|
||||
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;
|
||||
} else {
|
||||
return UINT16_MAX;
|
||||
@@ -606,8 +623,8 @@ void Routed_Device_Inc_Database_Revision(void)
|
||||
}
|
||||
|
||||
/** Check to see if the current Device supports this service.
|
||||
* Presently checks for RD and DCC and only allows them if the current
|
||||
* device is the gateway device.
|
||||
* Presently allows ReinitializeDevice for routed virtual devices and keeps
|
||||
* DeviceCommunicationControl restricted to the gateway device.
|
||||
*
|
||||
* @param service [in] The service being requested.
|
||||
* @param service_argument [in] An optional argument (eg, service type).
|
||||
@@ -629,16 +646,9 @@ int Routed_Device_Service_Approval(
|
||||
(void)service_argument;
|
||||
switch (service) {
|
||||
case SERVICE_SUPPORTED_REINITIALIZE_DEVICE:
|
||||
/* If not the gateway device, we don't support RD */
|
||||
if (iCurrent_Device_Idx > 0) {
|
||||
if (apdu_buff != NULL) {
|
||||
len = reject_encode_apdu(
|
||||
apdu_buff, invoke_id,
|
||||
REJECT_REASON_UNRECOGNIZED_SERVICE);
|
||||
} else {
|
||||
len = 1; /* Non-zero return */
|
||||
}
|
||||
}
|
||||
/* RD is accepted for virtual devices. Device_Reinitialize()
|
||||
handles state-specific support and returns service errors for
|
||||
virtual-device states that have gateway/system side effects. */
|
||||
break;
|
||||
case SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL:
|
||||
/* If not the gateway device, we don't support DCC */
|
||||
|
||||
@@ -1364,7 +1364,7 @@ static const char *Device_Location_Default = BACNET_DEVICE_LOCATION_NAME;
|
||||
static const char *Device_Description_Default = BACNET_DEVICE_DESCRIPTION;
|
||||
static uint32_t Database_Revision;
|
||||
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 list_element_function Device_Add_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)
|
||||
{
|
||||
characterstring_init_ansi(&Reinit_Password, password);
|
||||
Reinit_Password = password;
|
||||
|
||||
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
|
||||
is absent or if the password is incorrect. For those devices that
|
||||
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) {
|
||||
length = characterstring_utf8_length(&rd_data->password);
|
||||
} else {
|
||||
@@ -1489,7 +1489,8 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
|
||||
if (length > 20) {
|
||||
rd_data->error_class = ERROR_CLASS_SERVICES;
|
||||
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;
|
||||
} else {
|
||||
rd_data->error_class = ERROR_CLASS_SECURITY;
|
||||
|
||||
@@ -30,7 +30,7 @@ include_directories(
|
||||
${TST_DIR}/ztest/include
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
set(TEST_DEVICE_SOURCES
|
||||
# File(s) under test
|
||||
${SRC_DIR}/bacnet/basic/object/device.c
|
||||
# Support files and stubs (pathname alphabetical)
|
||||
@@ -140,3 +140,65 @@ add_executable(${PROJECT_NAME}
|
||||
${ZTST_DIR}/ztest_mock.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)
|
||||
|
||||
@@ -91,6 +91,49 @@ static bool Write_Property_Proprietary(BACNET_WRITE_PROPERTY_DATA *data)
|
||||
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.
|
||||
* For the given ReadProperty data, the application_data is loaded
|
||||
@@ -421,6 +464,190 @@ static void testDevice(void)
|
||||
|
||||
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
|
||||
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(
|
||||
device_tests, ztest_unit_test(testDevice),
|
||||
ztest_unit_test(test_Device_Data_Sharing));
|
||||
#endif
|
||||
|
||||
ztest_run_test_suite(device_tests);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user