Added basic timer object, internal state machine, and unit tests (#1123)
* Added basic timer object, internal state machine, and unit tests * Added BACnetTimerStateChangeValue encode, decode, parse, print, and diff with unit tests * Changed handler of add/remove list element to check if the property is a BACnetLIST * Added BACnetLIST utility for handling WriteProperty to a list. * Fixed outlier ReadProperty object handlers to return zero when the RP parameter is NULL.
This commit is contained in:
@@ -1032,7 +1032,7 @@ int Binary_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
uint8_t *apdu = NULL;
|
||||
int apdu_size = 0;
|
||||
|
||||
if ((rpdata->application_data == NULL) ||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1216,6 +1216,9 @@ int Device_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
struct special_property_list_t property_list;
|
||||
#endif
|
||||
|
||||
if (!rpdata) {
|
||||
return 0;
|
||||
}
|
||||
/* initialize the default return values */
|
||||
rpdata->error_class = ERROR_CLASS_OBJECT;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
#include "bacnet/basic/object/osv.h"
|
||||
#include "bacnet/basic/object/piv.h"
|
||||
#include "bacnet/basic/object/time_value.h"
|
||||
#include "bacnet/basic/object/timer.h"
|
||||
#include "bacnet/basic/object/channel.h"
|
||||
#include "bacnet/basic/object/lo.h"
|
||||
#include "bacnet/basic/object/blo.h"
|
||||
@@ -207,6 +208,14 @@ static object_functions_t My_Object_Table[] = {
|
||||
NULL /* COV */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */,
|
||||
NULL /* Add_List_Element */, NULL /* Remove_List_Element */,
|
||||
NULL /* Create */, NULL /* Delete */, NULL /* 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 },
|
||||
{ OBJECT_INTEGER_VALUE, Integer_Value_Init, Integer_Value_Count,
|
||||
Integer_Value_Index_To_Instance, Integer_Value_Valid_Instance,
|
||||
Integer_Value_Object_Name, Integer_Value_Read_Property,
|
||||
|
||||
@@ -803,11 +803,15 @@ int Notification_Class_Add_List_Element(BACNET_LIST_ELEMENT_DATA *list_element)
|
||||
return BACNET_STATUS_ABORT;
|
||||
}
|
||||
if (list_element->object_property != PROP_RECIPIENT_LIST) {
|
||||
list_element->error_class = ERROR_CLASS_SERVICES;
|
||||
list_element->error_code = ERROR_CODE_PROPERTY_IS_NOT_A_LIST;
|
||||
/* The specified property is currently not modifiable
|
||||
by the requester.*/
|
||||
list_element->error_class = ERROR_CLASS_PROPERTY;
|
||||
list_element->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (list_element->array_index != BACNET_ARRAY_ALL) {
|
||||
/* An array index is provided but the property is
|
||||
not a BACnetARRAY of BACnetLIST.*/
|
||||
list_element->error_class = ERROR_CLASS_PROPERTY;
|
||||
list_element->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return BACNET_STATUS_ERROR;
|
||||
@@ -963,11 +967,15 @@ int Notification_Class_Remove_List_Element(
|
||||
return BACNET_STATUS_ABORT;
|
||||
}
|
||||
if (list_element->object_property != PROP_RECIPIENT_LIST) {
|
||||
list_element->error_class = ERROR_CLASS_SERVICES;
|
||||
list_element->error_code = ERROR_CODE_PROPERTY_IS_NOT_A_LIST;
|
||||
/* The specified property is currently not modifiable
|
||||
by the requester.*/
|
||||
list_element->error_class = ERROR_CLASS_PROPERTY;
|
||||
list_element->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (list_element->array_index != BACNET_ARRAY_ALL) {
|
||||
/* An array index is provided but the property is
|
||||
not a BACnetARRAY of BACnetLIST.*/
|
||||
list_element->error_class = ERROR_CLASS_PROPERTY;
|
||||
list_element->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return BACNET_STATUS_ERROR;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief API for Timer object type
|
||||
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||
* @date October 2025
|
||||
* @copyright SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef BACNET_BASIC_OBJECT_TIMER_H
|
||||
#define BACNET_BASIC_OBJECT_TIMER_H
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
/* BACnet Stack defines - first */
|
||||
#include "bacnet/bacdef.h"
|
||||
/* BACnet Stack API */
|
||||
#include "bacnet/bacerror.h"
|
||||
#include "bacnet/timer_value.h"
|
||||
#include "bacnet/wp.h"
|
||||
#include "bacnet/rp.h"
|
||||
#include "bacnet/list_element.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void Timer_Property_Lists(
|
||||
const int **pRequired, const int **pOptional, const int **pProprietary);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Valid_Instance(uint32_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
unsigned Timer_Count(void);
|
||||
BACNET_STACK_EXPORT
|
||||
uint32_t Timer_Index_To_Instance(unsigned index);
|
||||
BACNET_STACK_EXPORT
|
||||
unsigned Timer_Instance_To_Index(uint32_t object_instance);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Object_Name(
|
||||
uint32_t object_instance, BACNET_CHARACTER_STRING *object_name);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Name_Set(uint32_t object_instance, const char *new_name);
|
||||
BACNET_STACK_EXPORT
|
||||
const char *Timer_Name_ASCII(uint32_t object_instance);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int Timer_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Description(
|
||||
uint32_t object_instance, BACNET_CHARACTER_STRING *description);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Description_Set(uint32_t instance, const char *new_name);
|
||||
BACNET_STACK_EXPORT
|
||||
const char *Timer_Description_ANSI(uint32_t object_instance);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Out_Of_Service(uint32_t instance);
|
||||
BACNET_STACK_EXPORT
|
||||
void Timer_Out_Of_Service_Set(uint32_t instance, bool oos_flag);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
BACNET_RELIABILITY Timer_Reliability(uint32_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Reliability_Set(uint32_t object_instance, BACNET_RELIABILITY value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint32_t Timer_Present_Value(uint32_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Present_Value_Set(uint32_t object_instance, uint32_t value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
BACNET_TIMER_STATE Timer_State(uint32_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_State_Set(uint32_t object_instance, BACNET_TIMER_STATE value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
BACNET_TIMER_TRANSITION Timer_Last_State_Change(uint32_t object_instance);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Running(uint32_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Running_Set(uint32_t object_instance, bool running);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Update_Time(uint32_t object_instance, BACNET_DATE_TIME *bdatetime);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Update_Time_Set(
|
||||
uint32_t object_instance, BACNET_DATE_TIME *bdatetime);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Expiration_Time(
|
||||
uint32_t object_instance, BACNET_DATE_TIME *bdatetime);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint32_t Timer_Initial_Timeout(uint32_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Initial_Timeout_Set(uint32_t object_instance, uint32_t value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint32_t Timer_Default_Timeout(uint32_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Default_Timeout_Set(uint32_t object_instance, uint32_t value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint32_t Timer_Min_Pres_Value(uint32_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Min_Pres_Value_Set(uint32_t object_instance, uint32_t value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint32_t Timer_Max_Pres_Value(uint32_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Max_Pres_Value_Set(uint32_t object_instance, uint32_t value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint32_t Timer_Resolution(uint32_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Resolution_Set(uint32_t object_instance, uint32_t value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint8_t Timer_Priority_For_Writing(uint8_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Priority_For_Writing_Set(uint32_t object_instance, uint8_t value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
unsigned Timer_Reference_List_Member_Capacity(uint32_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *Timer_Reference_List_Member_Element(
|
||||
uint32_t object_instance, unsigned list_index);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Reference_List_Member_Element_Set(
|
||||
uint32_t object_instance,
|
||||
unsigned index,
|
||||
const BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *pMember);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Reference_List_Member_Element_Add(
|
||||
uint32_t object_instance,
|
||||
const BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *pNewMember);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Reference_List_Member_Element_Remove(
|
||||
uint32_t object_instance,
|
||||
const BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *pRemoveMember);
|
||||
BACNET_STACK_EXPORT
|
||||
unsigned Timer_Reference_List_Member_Element_Count(uint32_t object_instance);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
BACNET_TIMER_STATE_CHANGE_VALUE *Timer_State_Change_Value(
|
||||
uint32_t object_instance, BACNET_TIMER_TRANSITION transition);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_State_Change_Value_Set(
|
||||
uint32_t object_instance,
|
||||
BACNET_TIMER_TRANSITION transition,
|
||||
BACNET_TIMER_STATE_CHANGE_VALUE *value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void Timer_Task(uint32_t object_instance, uint16_t milliseconds);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void Timer_Write_Property_Internal_Callback_Set(write_property_function cb);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int Timer_Add_List_Element(BACNET_LIST_ELEMENT_DATA *list_element);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int Timer_Remove_List_Element(BACNET_LIST_ELEMENT_DATA *list_element);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint32_t Timer_Create(uint32_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Timer_Delete(uint32_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
void Timer_Cleanup(void);
|
||||
BACNET_STACK_EXPORT
|
||||
void Timer_Init(void);
|
||||
|
||||
/* API for the program requests
|
||||
note: return value is 0 for success, non-zero for failure
|
||||
*/
|
||||
BACNET_STACK_EXPORT
|
||||
void *Timer_Context_Get(uint32_t object_instance);
|
||||
BACNET_STACK_EXPORT
|
||||
void Timer_Context_Set(uint32_t object_instance, void *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
Reference in New Issue
Block a user