Bugfix/backup restore failure timeout (#1247)

* Added backup failure timeout functionality and related methods in device management

* Fixed STARTBACKUP to hold at PERFORMING_A_BACKUP per spec, not IDLE.

* Added error handling for reinitialization during restore process to prevent accidental delete of all objects.

* Added some missing Create/Delete object functions. Formatting.

* Fixed Program object type in bacnet_device.c module.
This commit is contained in:
Steve Karg
2026-02-27 10:33:10 -06:00
committed by GitHub
parent 1437a68ce1
commit 1e9347f8f3
4 changed files with 1564 additions and 726 deletions
+4
View File
@@ -176,6 +176,10 @@ The git repositories are hosted at the following sites:
### Fixed ### Fixed
* Fixed Device Management-Backup and Restore-B Backup_Failure_Timeout
to count down and abort at BACKUP_FAILURE or RESTORE_FAILURE states,
successful STARTBACKUP to end in PERFORMING_A_BACKUP state,
and moved STARTRESTORE functionality into ENDRESTORE. (#1247)
* Fixed the basic Schedule object to set the correct present-value * Fixed the basic Schedule object to set the correct present-value
based on the Device object date and time. (#1236) based on the Device object date and time. (#1236)
* Fixed dlenv_init() for BACnet/SC. bsc_register_as_node() was blocking * Fixed dlenv_init() for BACnet/SC. bsc_register_as_node() was blocking
File diff suppressed because it is too large Load Diff
+12
View File
@@ -251,6 +251,12 @@ uint16_t Device_Backup_Failure_Timeout(void);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
bool Device_Backup_Failure_Timeout_Set(uint16_t timeout); bool Device_Backup_Failure_Timeout_Set(uint16_t timeout);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void Device_Backup_Failure_Timeout_Reset(void);
BACNET_STACK_EXPORT
void Device_Backup_Failure_Timeout_Restart(void);
BACNET_STACK_EXPORT
void Device_Backup_Failure_Timeout_Countdown(uint32_t milliseconds);
BACNET_STACK_EXPORT
uint16_t Device_Backup_Preparation_Time(void); uint16_t Device_Backup_Preparation_Time(void);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
bool Device_Backup_Preparation_Time_Set(uint16_t time); bool Device_Backup_Preparation_Time_Set(uint16_t time);
@@ -266,6 +272,8 @@ BACNET_STACK_EXPORT
BACNET_BACKUP_STATE Device_Backup_And_Restore_State(void); BACNET_BACKUP_STATE Device_Backup_And_Restore_State(void);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
bool Device_Backup_And_Restore_State_Set(BACNET_BACKUP_STATE state); bool Device_Backup_And_Restore_State_Set(BACNET_BACKUP_STATE state);
BACNET_STACK_EXPORT
bool Device_Backup_State_In_Progress(BACNET_BACKUP_STATE state);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void Device_Property_Lists( void Device_Property_Lists(
@@ -330,11 +338,15 @@ BACNET_STACK_EXPORT
bool Device_Create_Object(BACNET_CREATE_OBJECT_DATA *data); bool Device_Create_Object(BACNET_CREATE_OBJECT_DATA *data);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
bool Device_Delete_Object(BACNET_DELETE_OBJECT_DATA *data); bool Device_Delete_Object(BACNET_DELETE_OBJECT_DATA *data);
BACNET_STACK_EXPORT
void Device_Delete_Objects(void);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void Device_Start_Backup(void); void Device_Start_Backup(void);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void Device_Start_Restore(void); void Device_Start_Restore(void);
BACNET_STACK_EXPORT
void Device_End_Restore(void);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
unsigned Device_Count(void); unsigned Device_Count(void);
+424 -277
View File
@@ -65,7 +65,6 @@
#include "bacnet/basic/object/netport.h" #include "bacnet/basic/object/netport.h"
#include "bacnet/basic/object/color_object.h" #include "bacnet/basic/object/color_object.h"
#include "bacnet/basic/object/color_temperature.h" #include "bacnet/basic/object/color_temperature.h"
#include "bacnet/basic/object/program.h"
#ifdef CONFIG_BACNET_BASIC_DEVICE_OBJECT_VERSION #ifdef CONFIG_BACNET_BASIC_DEVICE_OBJECT_VERSION
#define BACNET_DEVICE_VERSION CONFIG_BACNET_BASIC_DEVICE_OBJECT_VERSION #define BACNET_DEVICE_VERSION CONFIG_BACNET_BASIC_DEVICE_OBJECT_VERSION
@@ -221,9 +220,10 @@
/* may be overridden by outside table */ /* may be overridden by outside table */
static object_functions_t *Object_Table; static object_functions_t *Object_Table;
static object_functions_t My_Object_Table[] = { static object_functions_t My_Object_Table[] = {
{ OBJECT_DEVICE, { OBJECT_DEVICE,
NULL, /* don't init - recursive! */ NULL /* Init - don't init Device or it will recourse! */,
Device_Count, Device_Count,
Device_Index_To_Instance, Device_Index_To_Instance,
Device_Valid_Object_Instance_Number, Device_Valid_Object_Instance_Number,
@@ -231,7 +231,7 @@ static object_functions_t My_Object_Table[] = {
Device_Read_Property_Local, Device_Read_Property_Local,
Device_Write_Property_Local, Device_Write_Property_Local,
Device_Property_Lists, Device_Property_Lists,
NULL /* ReadRangeInfo */, DeviceGetRRInfo,
NULL /* Iterator */, NULL /* Iterator */,
NULL /* Value_Lists */, NULL /* Value_Lists */,
NULL /* COV */, NULL /* COV */,
@@ -243,6 +243,52 @@ static object_functions_t My_Object_Table[] = {
NULL /* Delete */, NULL /* Delete */,
NULL /* Timer */, NULL /* Timer */,
Device_Writable_Property_List }, Device_Writable_Property_List },
#if defined(CONFIG_BACNET_BASIC_OBJECT_NETWORK_PORT)
{ OBJECT_NETWORK_PORT,
Network_Port_Init,
Network_Port_Count,
Network_Port_Index_To_Instance,
Network_Port_Valid_Instance,
Network_Port_Object_Name,
Network_Port_Read_Property,
Network_Port_Write_Property,
Network_Port_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
NULL /* Value_Lists */,
NULL /* COV */,
NULL /* COV Clear */,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
NULL /* Create */,
NULL /* Delete */,
NULL /* Timer */,
Network_Port_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_TIMER)
{ OBJECT_TIMER,
Timer_Init,
Timer_Count,
Timer_Index_To_Instance,
Timer_Valid_Instance,
Timer_Object_Name,
Timer_Read_Property,
Timer_Write_Property,
Timer_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
NULL /* Value_Lists */,
NULL /* COV */,
NULL /* COV Clear */,
NULL /* Intrinsic Reporting */,
Timer_Add_List_Element,
Timer_Remove_List_Element,
Timer_Create,
Timer_Delete,
Timer_Task,
Timer_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_ANALOG_INPUT) #if defined(CONFIG_BACNET_BASIC_OBJECT_ANALOG_INPUT)
{ OBJECT_ANALOG_INPUT, { OBJECT_ANALOG_INPUT,
Analog_Input_Init, Analog_Input_Init,
@@ -312,29 +358,6 @@ static object_functions_t My_Object_Table[] = {
NULL /* Timer */, NULL /* Timer */,
Analog_Value_Writable_Property_List }, Analog_Value_Writable_Property_List },
#endif #endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_AUDIT_LOG)
{ OBJECT_AUDIT_LOG,
Audit_Log_Init,
Audit_Log_Count,
Audit_Log_Index_To_Instance,
Audit_Log_Valid_Instance,
Audit_Log_Object_Name,
Audit_Log_Read_Property,
Audit_Log_Write_Property,
Audit_Log_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
NULL /* Value_Lists */,
NULL /* COV */,
NULL /* COV Clear */,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
Audit_Log_Create,
Audit_Log_Delete,
NULL /* Timer */,
Audit_Log_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_BINARY_INPUT) #if defined(CONFIG_BACNET_BASIC_OBJECT_BINARY_INPUT)
{ OBJECT_BINARY_INPUT, { OBJECT_BINARY_INPUT,
Binary_Input_Init, Binary_Input_Init,
@@ -404,98 +427,6 @@ static object_functions_t My_Object_Table[] = {
NULL /* Timer */, NULL /* Timer */,
Binary_Value_Writable_Property_List }, Binary_Value_Writable_Property_List },
#endif #endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_MULTISTATE_INPUT)
{ OBJECT_MULTI_STATE_INPUT,
Multistate_Input_Init,
Multistate_Input_Count,
Multistate_Input_Index_To_Instance,
Multistate_Input_Valid_Instance,
Multistate_Input_Object_Name,
Multistate_Input_Read_Property,
Multistate_Input_Write_Property,
Multistate_Input_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
Multistate_Input_Encode_Value_List,
Multistate_Input_Change_Of_Value,
Multistate_Input_Change_Of_Value_Clear,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
Multistate_Input_Create,
Multistate_Input_Delete,
NULL /* Timer */,
Multistate_Input_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_MULTISTATE_OUTPUT)
{ OBJECT_MULTI_STATE_OUTPUT,
Multistate_Output_Init,
Multistate_Output_Count,
Multistate_Output_Index_To_Instance,
Multistate_Output_Valid_Instance,
Multistate_Output_Object_Name,
Multistate_Output_Read_Property,
Multistate_Output_Write_Property,
Multistate_Output_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
Multistate_Output_Encode_Value_List,
Multistate_Output_Change_Of_Value,
Multistate_Output_Change_Of_Value_Clear,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
Multistate_Output_Create,
Multistate_Output_Delete,
NULL /* Timer */,
Multistate_Output_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_MULTISTATE_VALUE)
{ OBJECT_MULTI_STATE_VALUE,
Multistate_Value_Init,
Multistate_Value_Count,
Multistate_Value_Index_To_Instance,
Multistate_Value_Valid_Instance,
Multistate_Value_Object_Name,
Multistate_Value_Read_Property,
Multistate_Value_Write_Property,
Multistate_Value_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
Multistate_Value_Encode_Value_List,
Multistate_Value_Change_Of_Value,
Multistate_Value_Change_Of_Value_Clear,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
Multistate_Value_Create,
Multistate_Value_Delete,
NULL /* Timer */,
Multistate_Value_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_NETWORK_PORT)
{ OBJECT_NETWORK_PORT,
Network_Port_Init,
Network_Port_Count,
Network_Port_Index_To_Instance,
Network_Port_Valid_Instance,
Network_Port_Object_Name,
Network_Port_Read_Property,
Network_Port_Write_Property,
Network_Port_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
NULL /* Value_Lists */,
NULL /* COV */,
NULL /* COV Clear */,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
NULL /* Create */,
NULL /* Delete */,
NULL /* Timer */,
Network_Port_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_CALENDAR) #if defined(CONFIG_BACNET_BASIC_OBJECT_CALENDAR)
{ OBJECT_CALENDAR, { OBJECT_CALENDAR,
Calendar_Init, Calendar_Init,
@@ -519,6 +450,121 @@ static object_functions_t My_Object_Table[] = {
NULL /* Timer */, NULL /* Timer */,
Calendar_Writable_Property_List }, Calendar_Writable_Property_List },
#endif #endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_BITSTRING_VALUE)
{ OBJECT_BITSTRING_VALUE,
BitString_Value_Init,
BitString_Value_Count,
BitString_Value_Index_To_Instance,
BitString_Value_Valid_Instance,
BitString_Value_Object_Name,
BitString_Value_Read_Property,
BitString_Value_Write_Property,
BitString_Value_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
BitString_Value_Encode_Value_List,
BitString_Value_Change_Of_Value,
BitString_Value_Change_Of_Value_Clear,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
BitString_Value_Create,
BitString_Value_Delete,
NULL /* Timer */,
BitString_Value_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_CHARACTERSTRING_VALUE)
{ OBJECT_CHARACTERSTRING_VALUE,
CharacterString_Value_Init,
CharacterString_Value_Count,
CharacterString_Value_Index_To_Instance,
CharacterString_Value_Valid_Instance,
CharacterString_Value_Object_Name,
CharacterString_Value_Read_Property,
CharacterString_Value_Write_Property,
CharacterString_Value_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
CharacterString_Value_Encode_Value_List,
CharacterString_Value_Change_Of_Value,
CharacterString_Value_Change_Of_Value_Clear,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
CharacterString_Value_Create,
CharacterString_Value_Delete,
NULL /* Timer */,
CharacterString_Value_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_OCTETSTRING_VALUE)
{ OBJECT_OCTETSTRING_VALUE,
OctetString_Value_Init,
OctetString_Value_Count,
OctetString_Value_Index_To_Instance,
OctetString_Value_Valid_Instance,
OctetString_Value_Object_Name,
OctetString_Value_Read_Property,
OctetString_Value_Write_Property,
OctetString_Value_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
NULL /* Value_Lists */,
NULL /* COV */,
NULL /* COV Clear */,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
OctetString_Value_Create,
OctetString_Value_Delete,
NULL /* Timer */,
OctetString_Value_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_POSITIVE_INTEGER_VALUE)
{ OBJECT_POSITIVE_INTEGER_VALUE,
PositiveInteger_Value_Init,
PositiveInteger_Value_Count,
PositiveInteger_Value_Index_To_Instance,
PositiveInteger_Value_Valid_Instance,
PositiveInteger_Value_Object_Name,
PositiveInteger_Value_Read_Property,
PositiveInteger_Value_Write_Property,
PositiveInteger_Value_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
NULL /* Value_Lists */,
NULL /* COV */,
NULL /* COV Clear */,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
PositiveInteger_Value_Create,
PositiveInteger_Value_Delete,
NULL /* Timer */,
PositiveInteger_Value_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_TIME_VALUE)
{ OBJECT_TIME_VALUE,
Time_Value_Init,
Time_Value_Count,
Time_Value_Index_To_Instance,
Time_Value_Valid_Instance,
Time_Value_Object_Name,
Time_Value_Read_Property,
Time_Value_Write_Property,
Time_Value_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
NULL /* Value_Lists */,
NULL /* COV */,
NULL /* COV Clear */,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
Time_Value_Create,
Time_Value_Delete,
NULL /* Timer */,
Time_Value_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_INTEGER_VALUE) #if defined(CONFIG_BACNET_BASIC_OBJECT_INTEGER_VALUE)
{ OBJECT_INTEGER_VALUE, { OBJECT_INTEGER_VALUE,
Integer_Value_Init, Integer_Value_Init,
@@ -612,6 +658,75 @@ static object_functions_t My_Object_Table[] = {
Load_Control_Timer, Load_Control_Timer,
Load_Control_Writable_Property_List }, Load_Control_Writable_Property_List },
#endif #endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_MULTISTATE_INPUT)
{ OBJECT_MULTI_STATE_INPUT,
Multistate_Input_Init,
Multistate_Input_Count,
Multistate_Input_Index_To_Instance,
Multistate_Input_Valid_Instance,
Multistate_Input_Object_Name,
Multistate_Input_Read_Property,
Multistate_Input_Write_Property,
Multistate_Input_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
Multistate_Input_Encode_Value_List,
Multistate_Input_Change_Of_Value,
Multistate_Input_Change_Of_Value_Clear,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
Multistate_Input_Create,
Multistate_Input_Delete,
NULL /* Timer */,
Multistate_Input_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_MULTISTATE_OUTPUT)
{ OBJECT_MULTI_STATE_OUTPUT,
Multistate_Output_Init,
Multistate_Output_Count,
Multistate_Output_Index_To_Instance,
Multistate_Output_Valid_Instance,
Multistate_Output_Object_Name,
Multistate_Output_Read_Property,
Multistate_Output_Write_Property,
Multistate_Output_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
Multistate_Output_Encode_Value_List,
Multistate_Output_Change_Of_Value,
Multistate_Output_Change_Of_Value_Clear,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
Multistate_Output_Create,
Multistate_Output_Delete,
NULL /* Timer */,
Multistate_Output_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_MULTISTATE_VALUE)
{ OBJECT_MULTI_STATE_VALUE,
Multistate_Value_Init,
Multistate_Value_Count,
Multistate_Value_Index_To_Instance,
Multistate_Value_Valid_Instance,
Multistate_Value_Object_Name,
Multistate_Value_Read_Property,
Multistate_Value_Write_Property,
Multistate_Value_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
Multistate_Value_Encode_Value_List,
Multistate_Value_Change_Of_Value,
Multistate_Value_Change_Of_Value_Clear,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
Multistate_Value_Create,
Multistate_Value_Delete,
NULL /* Timer */,
Multistate_Value_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_LIGHTING_OUTPUT) #if defined(CONFIG_BACNET_BASIC_OBJECT_LIGHTING_OUTPUT)
{ OBJECT_LIGHTING_OUTPUT, { OBJECT_LIGHTING_OUTPUT,
Lighting_Output_Init, Lighting_Output_Init,
@@ -773,144 +888,6 @@ static object_functions_t My_Object_Table[] = {
NULL /* Timer */, NULL /* Timer */,
NULL /* Writable_Property_List */ }, NULL /* Writable_Property_List */ },
#endif #endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_BITSTRING_VALUE)
{ OBJECT_BITSTRING_VALUE,
BitString_Value_Init,
BitString_Value_Count,
BitString_Value_Index_To_Instance,
BitString_Value_Valid_Instance,
BitString_Value_Object_Name,
BitString_Value_Read_Property,
BitString_Value_Write_Property,
BitString_Value_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
BitString_Value_Encode_Value_List,
BitString_Value_Change_Of_Value,
BitString_Value_Change_Of_Value_Clear,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
BitString_Value_Create,
BitString_Value_Delete,
NULL /* Timer */,
BitString_Value_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_CHARACTERSTRING_VALUE)
{ OBJECT_CHARACTERSTRING_VALUE,
CharacterString_Value_Init,
CharacterString_Value_Count,
CharacterString_Value_Index_To_Instance,
CharacterString_Value_Valid_Instance,
CharacterString_Value_Object_Name,
CharacterString_Value_Read_Property,
CharacterString_Value_Write_Property,
CharacterString_Value_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
CharacterString_Value_Encode_Value_List,
CharacterString_Value_Change_Of_Value,
CharacterString_Value_Change_Of_Value_Clear,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
CharacterString_Value_Create,
CharacterString_Value_Delete,
NULL /* Timer */,
CharacterString_Value_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_OCTETSTRING_VALUE)
{ OBJECT_OCTETSTRING_VALUE,
OctetString_Value_Init,
OctetString_Value_Count,
OctetString_Value_Index_To_Instance,
OctetString_Value_Valid_Instance,
OctetString_Value_Object_Name,
OctetString_Value_Read_Property,
OctetString_Value_Write_Property,
OctetString_Value_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
NULL /* Value_Lists */,
NULL /* COV */,
NULL /* COV Clear */,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
OctetString_Value_Create,
OctetString_Value_Delete,
NULL /* Timer */,
OctetString_Value_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_POSITIVE_INTEGER_VALUE)
{ OBJECT_POSITIVE_INTEGER_VALUE,
PositiveInteger_Value_Init,
PositiveInteger_Value_Count,
PositiveInteger_Value_Index_To_Instance,
PositiveInteger_Value_Valid_Instance,
PositiveInteger_Value_Object_Name,
PositiveInteger_Value_Read_Property,
PositiveInteger_Value_Write_Property,
PositiveInteger_Value_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
NULL /* Value_Lists */,
NULL /* COV */,
NULL /* COV Clear */,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
PositiveInteger_Value_Create,
PositiveInteger_Value_Delete,
NULL /* Timer */,
PositiveInteger_Value_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_TIME_VALUE)
{ OBJECT_TIME_VALUE,
Time_Value_Init,
Time_Value_Count,
Time_Value_Index_To_Instance,
Time_Value_Valid_Instance,
Time_Value_Object_Name,
Time_Value_Read_Property,
Time_Value_Write_Property,
Time_Value_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
NULL /* Value_Lists */,
NULL /* COV */,
NULL /* COV Clear */,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
Time_Value_Create,
Time_Value_Delete,
NULL /* Timer */,
Time_Value_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_TIMER)
{ OBJECT_TIMER,
Timer_Init,
Timer_Count,
Timer_Index_To_Instance,
Timer_Valid_Instance,
Timer_Object_Name,
Timer_Read_Property,
Timer_Write_Property,
Timer_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
NULL /* Value_Lists */,
NULL /* COV */,
NULL /* COV Clear */,
NULL /* Intrinsic Reporting */,
Timer_Add_List_Element,
Timer_Remove_List_Element,
Timer_Create,
Timer_Delete,
Timer_Task,
Timer_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_LOOP) #if defined(CONFIG_BACNET_BASIC_OBJECT_LOOP)
{ OBJECT_LOOP, { OBJECT_LOOP,
Loop_Init, Loop_Init,
@@ -935,7 +912,7 @@ static object_functions_t My_Object_Table[] = {
Loop_Writable_Property_List }, Loop_Writable_Property_List },
#endif #endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_PROGRAM) #if defined(CONFIG_BACNET_BASIC_OBJECT_PROGRAM)
{ OBJECT_BITSTRING_VALUE, { OBJECT_PROGRAM,
Program_Init, Program_Init,
Program_Count, Program_Count,
Program_Index_To_Instance, Program_Index_To_Instance,
@@ -956,6 +933,29 @@ static object_functions_t My_Object_Table[] = {
Program_Delete, Program_Delete,
Program_Timer, Program_Timer,
Program_Writable_Property_List }, Program_Writable_Property_List },
#endif
#if defined(CONFIG_BACNET_BASIC_OBJECT_AUDIT_LOG)
{ OBJECT_AUDIT_LOG,
Audit_Log_Init,
Audit_Log_Count,
Audit_Log_Index_To_Instance,
Audit_Log_Valid_Instance,
Audit_Log_Object_Name,
Audit_Log_Read_Property,
Audit_Log_Write_Property,
Audit_Log_Property_Lists,
NULL /* ReadRangeInfo */,
NULL /* Iterator */,
NULL /* Value_Lists */,
NULL /* COV */,
NULL /* COV Clear */,
NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */,
NULL /* Remove_List_Element */,
Audit_Log_Create,
Audit_Log_Delete,
NULL /* Timer */,
Audit_Log_Writable_Property_List },
#endif #endif
{ {
MAX_BACNET_OBJECT_TYPE, MAX_BACNET_OBJECT_TYPE,
@@ -1287,8 +1287,6 @@ void Device_Property_Lists(
const int32_t **pOptional, const int32_t **pOptional,
const int32_t **pProprietary) const int32_t **pProprietary)
{ {
uint32_t instance;
if (pRequired) { if (pRequired) {
*pRequired = Device_Properties_Required; *pRequired = Device_Properties_Required;
} }
@@ -1296,16 +1294,7 @@ void Device_Property_Lists(
*pOptional = Device_Properties_Optional; *pOptional = Device_Properties_Optional;
} }
if (pProprietary) { if (pProprietary) {
if (Property_List_Proprietary_Callback) { *pProprietary = Device_Properties_Proprietary;
instance = Device_Object_Instance_Number();
if (Property_List_Proprietary_Callback(
OBJECT_DEVICE, instance, pProprietary)) {
} else {
*pProprietary = Device_Properties_Proprietary;
}
} else {
*pProprietary = Device_Properties_Proprietary;
}
} }
return; return;
@@ -1418,7 +1407,8 @@ static BACNET_TIMESTAMP Last_Restore_Time;
in the Backup_Failure_Timeout property of its Device object, in the Backup_Failure_Timeout property of its Device object,
device B should assume that the restore procedure has been aborted, device B should assume that the restore procedure has been aborted,
and device B should exit restore mode.*/ and device B should exit restore mode.*/
static uint16_t Backup_Failure_Timeout; static uint16_t Backup_Failure_Timeout = 60 * 60;
static uint32_t Backup_Failure_Timeout_Milliseconds;
/* This property indicates the amount of time in seconds /* This property indicates the amount of time in seconds
that the device might remain unresponsive after the sending that the device might remain unresponsive after the sending
of a ReinitializeDevice-ACK at the start of a backup procedure. of a ReinitializeDevice-ACK at the start of a backup procedure.
@@ -1529,18 +1519,44 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
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)) {
rd_data->error_class = ERROR_CLASS_DEVICE;
rd_data->error_code = ERROR_CODE_CONFIGURATION_IN_PROGRESS;
break;
}
Backup_State = BACKUP_STATE_PREPARING_FOR_BACKUP;
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)) {
rd_data->error_class = ERROR_CLASS_DEVICE;
rd_data->error_code = ERROR_CODE_CONFIGURATION_IN_PROGRESS;
break;
}
Backup_State = BACKUP_STATE_PREPARING_FOR_RESTORE;
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_ENDBACKUP:
case BACNET_REINIT_ENDRESTORE: case BACNET_REINIT_ENDRESTORE:
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;
status = true;
break;
case BACNET_REINIT_ENDBACKUP:
case BACNET_REINIT_ABORTRESTORE: case BACNET_REINIT_ABORTRESTORE:
Backup_State = BACKUP_STATE_IDLE;
Device_Backup_Failure_Timeout_Reset();
Reinitialize_State = rd_data->state; Reinitialize_State = rd_data->state;
status = true; status = true;
break; break;
@@ -2453,8 +2469,91 @@ bool Device_Backup_And_Restore_State_Set(BACNET_BACKUP_STATE state)
Backup_State = state; Backup_State = state;
return true; return true;
} }
/**
* @brief Reset the backup failure timeout countdown to zero
* @note This should be called when the backup failure timeout is no longer
* needed, such as when a backup or restore operation has completed or failed.
*/
void Device_Backup_Failure_Timeout_Reset(void)
{
Backup_Failure_Timeout_Milliseconds = 0;
}
#endif #endif
/**
* @brief Determine if a backup or restore operation is currently in progress
* @param state The current backup state to check
* @return True if a backup or restore operation is in progress, else False
*/
bool Device_Backup_State_In_Progress(BACNET_BACKUP_STATE state)
{
if ((state != BACKUP_STATE_IDLE) &&
(state != BACKUP_STATE_BACKUP_FAILURE) &&
(state != BACKUP_STATE_RESTORE_FAILURE)) {
return true;
}
return false;
}
/**
* @brief Start the backup failure timeout countdown by converting the value to
* milliseconds
* @note This should be called when starting a backup or restore operation, and
* the Backup_Failure_Timeout_Milliseconds variable should be decremented in
* the main loop or a timer interrupt to track the timeout.
*/
void Device_Backup_Failure_Timeout_Restart(void)
{
#if defined(BACNET_BACKUP_RESTORE)
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;
}
#endif
}
/**
* @brief Decrement the backup failure timeout countdown by the given number of
* milliseconds, and update the backup state if the timeout has expired.
* @param milliseconds The number of milliseconds to decrement from the backup
* failure timeout countdown.
* @details If device B does not receive any messages related to the backup
* procedure from device A for the number of seconds specified in the
* Backup_Failure_Timeout property of its Device object, device B should
* assume that the backup procedure has been aborted, and device B should
* exit backup mode. A message related to the backup procedure is defined
* to be any ReadProperty, ReadPropertyMultiple, WriteProperty,
* WritePropertyMultiple, CreateObject, or AtomicReadFile request
* that directly accesses a configuration File object.
*/
void Device_Backup_Failure_Timeout_Countdown(uint32_t milliseconds)
{
#if defined(BACNET_BACKUP_RESTORE)
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;
} else {
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;
}
}
}
}
#else
(void)milliseconds;
#endif
}
/** /**
* ReadProperty handler for this object. For the given ReadProperty * ReadProperty handler for this object. For the given ReadProperty
* data, the application_data is loaded or the error flags are set. * data, the application_data is loaded or the error flags are set.
@@ -2797,6 +2896,7 @@ int Device_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
if (!rpdata) { if (!rpdata) {
return 0; return 0;
} }
Device_Backup_Failure_Timeout_Restart();
/* initialize the default return values */ /* initialize the default return values */
rpdata->error_class = ERROR_CLASS_OBJECT; rpdata->error_class = ERROR_CLASS_OBJECT;
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT; rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
@@ -3206,6 +3306,7 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
bool status = false; /* Ever the pessimist! */ bool status = false; /* Ever the pessimist! */
struct object_functions *pObject = NULL; struct object_functions *pObject = NULL;
Device_Backup_Failure_Timeout_Restart();
/* initialize the default return values */ /* initialize the default return values */
wp_data->error_class = ERROR_CLASS_OBJECT; wp_data->error_class = ERROR_CLASS_OBJECT;
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT; wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
@@ -3446,6 +3547,7 @@ bool Device_Create_Object(BACNET_CREATE_OBJECT_DATA *data)
bool object_exists = false; bool object_exists = false;
bool object_supported = false; bool object_supported = false;
Device_Backup_Failure_Timeout_Restart();
pObject = Device_Object_Functions_Find(data->object_type); pObject = Device_Object_Functions_Find(data->object_type);
if (pObject != NULL) { if (pObject != NULL) {
if (pObject->Object_Valid_Instance && if (pObject->Object_Valid_Instance &&
@@ -3479,6 +3581,7 @@ bool Device_Delete_Object(BACNET_DELETE_OBJECT_DATA *data)
bool status = false; bool status = false;
struct object_functions *pObject = NULL; struct object_functions *pObject = NULL;
Device_Backup_Failure_Timeout_Restart();
pObject = Device_Object_Functions_Find(data->object_type); pObject = Device_Object_Functions_Find(data->object_type);
if (pObject != NULL) { if (pObject != NULL) {
if (!pObject->Object_Delete) { if (!pObject->Object_Delete) {
@@ -3513,6 +3616,34 @@ bool Device_Delete_Object(BACNET_DELETE_OBJECT_DATA *data)
return status; return status;
} }
/**
* @brief Loops through all the objects and deletes them,
* if DeleteObject service is supported by the object type.
*/
void Device_Delete_Objects(void)
{
struct object_functions *pObject = NULL;
uint32_t instance = 0;
unsigned count = 0;
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_Delete) &&
(pObject->Object_Index_To_Instance)) {
instance = pObject->Object_Index_To_Instance(count);
pObject->Object_Delete(instance);
}
}
pObject++;
}
}
/** /**
* @brief Loop through the Device object-list property and export to * @brief Loop through the Device object-list property and export to
* a file as BACnet CreateObject services with List of Initial Values * a file as BACnet CreateObject services with List of Initial Values
@@ -3532,9 +3663,7 @@ void Device_Start_Backup(void)
bool status = false; bool status = false;
int32_t len = 0, offset = 0; int32_t len = 0, offset = 0;
Backup_State = BACKUP_STATE_PREPARING_FOR_BACKUP;
object_count = Device_Object_List_Count(); object_count = Device_Object_List_Count();
Backup_State = BACKUP_STATE_PERFORMING_A_BACKUP;
for (i = 0; i < object_count; i++) { for (i = 0; i < object_count; i++) {
/* get the object type and instance from the device object list */ /* get the object type and instance from the device object list */
status = Device_Object_List_Identifier( status = Device_Object_List_Identifier(
@@ -3560,7 +3689,18 @@ void Device_Start_Backup(void)
} }
} }
} }
Backup_State = BACKUP_STATE_IDLE; Backup_State = BACKUP_STATE_PERFORMING_A_BACKUP;
#endif
}
/**
* @brief Create files for backup and restore, if supported, and set the state
* to performing a restore
*/
void Device_Start_Restore(void)
{
#if defined BACNET_BACKUP_RESTORE
Backup_State = BACKUP_STATE_PERFORMING_A_RESTORE;
#endif #endif
} }
@@ -3569,7 +3709,7 @@ void Device_Start_Backup(void)
* a file as BACnet CreateObject services with List of Initial Values * a file as BACnet CreateObject services with List of Initial Values
* for every writable property * for every writable property
*/ */
void Device_Start_Restore(void) void Device_End_Restore(void)
{ {
#if defined BACNET_BACKUP_RESTORE #if defined BACNET_BACKUP_RESTORE
BACNET_DATE_TIME bdateTime = { 0 }; BACNET_DATE_TIME bdateTime = { 0 };
@@ -3580,7 +3720,8 @@ void Device_Start_Restore(void)
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);
Backup_State = BACKUP_STATE_PREPARING_FOR_RESTORE; /* delete all existing objects before restore */
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) {
@@ -3600,15 +3741,19 @@ void Device_Start_Restore(void)
/* error creating object - keep going */ /* error creating object - keep going */
} }
} else { } else {
Backup_State = BACKUP_STATE_RESTORE_FAILURE;
/* error while decoding object */ /* error while decoding object */
break; break;
} }
} else { } else {
Backup_State = BACKUP_STATE_RESTORE_FAILURE;
/* error while reading file */ /* error while reading file */
break; break;
} }
} }
Backup_State = BACKUP_STATE_IDLE; if (Backup_State != BACKUP_STATE_RESTORE_FAILURE) {
Backup_State = BACKUP_STATE_IDLE;
}
#endif #endif
} }
@@ -3778,8 +3923,10 @@ void Device_Timer(uint16_t milliseconds)
unsigned count = 0; unsigned count = 0;
uint32_t instance; uint32_t instance;
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;
if (pObject->Object_Count) { if (pObject->Object_Count) {
count = pObject->Object_Count(); count = pObject->Object_Count();
} }