Added post-write notifications for channel, timer, and loop objects. (#1204)

This commit is contained in:
Steve Karg
2026-01-20 13:13:45 -06:00
committed by GitHub
parent 5802bd0ecc
commit 89cf25c2b2
10 changed files with 367 additions and 13 deletions
+50 -1
View File
@@ -52,8 +52,11 @@ struct object_data {
/* Key List for storing the object data sorted by instance number */
static OS_Keylist Object_List;
/* Internal write property callback */
static write_property_function Write_Property_Internal_Callback;
/* Write Property notification callbacks for logging or other purposes */
static struct channel_write_property_notification
Write_Property_Notification_Head;
/* These arrays are used by the ReadPropertyMultiple handler
property-list property (as of protocol-revision 14) */
@@ -735,12 +738,15 @@ static bool Channel_Write_Members(
bactext_error_code_name(wp_data.error_code));
}
} else {
wp_data.error_code = ERROR_CODE_PARAMETER_OUT_OF_RANGE;
debug_printf(
"channel[%lu].Channel_Write_Member[%u] "
"coercion failed!\n",
(unsigned long)object_instance, m);
pObject->Write_Status = BACNET_WRITE_STATUS_FAILED;
}
Channel_Write_Property_Notify(
object_instance, status, &wp_data);
} else {
debug_printf(
"channel[%lu].Channel_Write_Member[%u] invalid!\n",
@@ -1380,6 +1386,49 @@ void Channel_Write_Property_Internal_Callback_Set(write_property_function cb)
Write_Property_Internal_Callback = cb;
}
/**
* @brief Add a Channel notification callback
* @param notification - pointer to the notification structure
*/
void Channel_Write_Property_Notification_Add(
struct channel_write_property_notification *notification)
{
struct channel_write_property_notification *head;
head = &Write_Property_Notification_Head;
do {
if (head->next == notification) {
/* already here! */
break;
} else if (!head->next) {
/* first available node */
head->next = notification;
break;
}
head = head->next;
} while (head);
}
/**
* @brief call the channel WriteProperty notification callbacks
* @param instance - object instance number
* @param status - status of the write
* @param wp_data - write property data
*/
void Channel_Write_Property_Notify(
uint32_t instance, bool status, BACNET_WRITE_PROPERTY_DATA *wp_data)
{
struct channel_write_property_notification *head;
head = &Write_Property_Notification_Head;
do {
if (head->callback) {
head->callback(instance, status, wp_data);
}
head = head->next;
} while (head);
}
/**
* @brief Set the context used with a specific object instance
* @param object_instance [in] BACnet object instance number
+21
View File
@@ -19,6 +19,21 @@
#include "bacnet/basic/object/lo.h"
#include "bacnet/channel_value.h"
/**
* @brief Callback for tracking the channel writes for logging or other purposes
* @param instance - channel object instance number
* @param status - true if write was successful
* @param wp_data - pointer to the write property data structure
*/
typedef void (*channel_write_property_callback)(
uint32_t instance, bool status, BACNET_WRITE_PROPERTY_DATA *wp_data);
/* linked list structure for notifications */
struct channel_write_property_notification;
struct channel_write_property_notification {
struct channel_write_property_notification *next;
channel_write_property_callback callback;
};
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
@@ -104,6 +119,12 @@ bool Channel_Write_Member_Value(
BACNET_STACK_EXPORT
void Channel_Write_Property_Internal_Callback_Set(write_property_function cb);
BACNET_STACK_EXPORT
void Channel_Write_Property_Notification_Add(
struct channel_write_property_notification *notification);
BACNET_STACK_EXPORT
void Channel_Write_Property_Notify(
uint32_t instance, bool status, BACNET_WRITE_PROPERTY_DATA *wp_data);
BACNET_STACK_EXPORT
void *Channel_Context_Get(uint32_t object_instance);
+46
View File
@@ -40,6 +40,8 @@ static const BACNET_OBJECT_TYPE Object_Type = OBJECT_LOOP;
/* handling for manipulated and reference properties */
static write_property_function Write_Property_Internal_Callback;
static read_property_function Read_Property_Internal_Callback;
/* Write Property notification callbacks for logging or other purposes */
static struct loop_write_property_notification Write_Property_Notification_Head;
struct object_data {
/* internal variables for PID calculations */
@@ -2016,6 +2018,49 @@ void Loop_Write_Property_Internal_Callback_Set(write_property_function cb)
Write_Property_Internal_Callback = cb;
}
/**
* @brief Add a Loop notification callback
* @param notification - pointer to the notification structure
*/
void Loop_Write_Property_Notification_Add(
struct loop_write_property_notification *notification)
{
struct loop_write_property_notification *head;
head = &Write_Property_Notification_Head;
do {
if (head->next == notification) {
/* already here! */
break;
} else if (!head->next) {
/* first available node */
head->next = notification;
break;
}
head = head->next;
} while (head);
}
/**
* @brief Calls all registered Loop write property notification callbacks
* @param instance - object instance number
* @param status - write property status
* @param wp_data - write property data
*/
void Loop_Write_Property_Notify(
uint32_t instance, bool status, BACNET_WRITE_PROPERTY_DATA *wp_data)
{
struct loop_write_property_notification *head;
head = &Write_Property_Notification_Head;
do {
if (head->callback) {
head->callback(instance, status, wp_data);
}
head = head->next;
} while (head);
}
/**
* @brief For a given object, writes to the manipulated-variable-reference
* @param pObject - object instance data
@@ -2059,6 +2104,7 @@ static bool Loop_Write_Manipulated_Variable(
}
}
}
Loop_Write_Property_Notify(object_instance, status, &wp_data);
}
}
+21
View File
@@ -18,6 +18,21 @@
#include "bacnet/rp.h"
#include "bacnet/list_element.h"
/**
* @brief Callback for tracking the loop writes for logging or other purposes
* @param instance - loop object instance number
* @param status - true if write was successful
* @param wp_data - pointer to the write property data structure
*/
typedef void (*loop_write_property_callback)(
uint32_t instance, bool status, BACNET_WRITE_PROPERTY_DATA *wp_data);
/* linked list structure for notifications */
struct loop_write_property_notification;
struct loop_write_property_notification {
struct loop_write_property_notification *next;
loop_write_property_callback callback;
};
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
@@ -191,6 +206,12 @@ BACNET_STACK_EXPORT
void Loop_Write_Property_Internal_Callback_Set(write_property_function cb);
BACNET_STACK_EXPORT
void Loop_Read_Property_Internal_Callback_Set(read_property_function cb);
BACNET_STACK_EXPORT
void Loop_Write_Property_Notification_Add(
struct loop_write_property_notification *notification);
BACNET_STACK_EXPORT
void Loop_Write_Property_Notify(
uint32_t instance, bool status, BACNET_WRITE_PROPERTY_DATA *wp_data);
BACNET_STACK_EXPORT
int Loop_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata);
+61 -11
View File
@@ -39,6 +39,9 @@ static OS_Keylist Object_List = NULL;
/* common object type */
static const BACNET_OBJECT_TYPE Object_Type = OBJECT_TIMER;
static write_property_function Write_Property_Internal_Callback;
/* Write Property notification callbacks for logging or other purposes */
static struct timer_write_property_notification
Write_Property_Notification_Head;
struct object_data {
uint32_t Present_Value;
@@ -459,7 +462,7 @@ unsigned Timer_Reference_List_Member_Element_Count(uint32_t object_instance)
/**
* For a given object instance-number, sets the present-value at a given
* priority 1..16.
*
* @param object_instance - object-instance number of the object
* @param pObject - object instance data
* @param value - application value
* @param priority - BACnet priority 0=none,1..16
@@ -467,6 +470,7 @@ unsigned Timer_Reference_List_Member_Element_Count(uint32_t object_instance)
* @return true if values are within range and present-value is sent.
*/
static bool Timer_Write_Members(
uint32_t object_instance,
struct object_data *pObject,
const BACNET_TIMER_STATE_CHANGE_VALUE *value,
uint8_t priority)
@@ -504,6 +508,7 @@ static bool Timer_Write_Members(
}
}
}
Timer_Write_Property_Notify(object_instance, status, &wp_data);
}
}
}
@@ -514,9 +519,11 @@ static bool Timer_Write_Members(
/**
* @brief initiate the write requests for the current transition
* @param object_instance - object-instance number of the object
* @param pObject - object instance data
* @return true if the write occurred
*/
static bool Timer_Write_Request_Initiate(struct object_data *pObject)
static bool Timer_Write_Request_Initiate(
uint32_t object_instance, struct object_data *pObject)
{
bool status = false;
unsigned index = 0;
@@ -532,7 +539,7 @@ static bool Timer_Write_Request_Initiate(struct object_data *pObject)
}
if (value) {
status = Timer_Write_Members(
pObject, value, pObject->Priority_For_Writing);
object_instance, pObject, value, pObject->Priority_For_Writing);
}
}
@@ -600,7 +607,7 @@ bool Timer_State_Set(uint32_t object_instance, BACNET_TIMER_STATE value)
&pObject->Update_Time.date, &pObject->Update_Time.time,
NULL, NULL);
pObject->Last_State_Change = TIMER_TRANSITION_RUNNING_TO_IDLE;
Timer_Write_Request_Initiate(pObject);
Timer_Write_Request_Initiate(object_instance, pObject);
} else if (pObject->Timer_State == TIMER_STATE_EXPIRED) {
pObject->Last_State_Change = TIMER_TRANSITION_EXPIRED_TO_IDLE;
/* then set Timer_State to IDLE;
@@ -614,7 +621,7 @@ bool Timer_State_Set(uint32_t object_instance, BACNET_TIMER_STATE value)
&pObject->Update_Time.date, &pObject->Update_Time.time,
NULL, NULL);
pObject->Last_State_Change = TIMER_TRANSITION_EXPIRED_TO_IDLE;
Timer_Write_Request_Initiate(pObject);
Timer_Write_Request_Initiate(object_instance, pObject);
} else if (pObject->Timer_State == TIMER_STATE_IDLE) {
/* then no properties shall be changed;
no write requests shall be initiated;
@@ -695,7 +702,7 @@ bool Timer_Running_Set(uint32_t object_instance, bool start)
datetime_local(
&pObject->Update_Time.date, &pObject->Update_Time.time,
NULL, NULL);
Timer_Write_Request_Initiate(pObject);
Timer_Write_Request_Initiate(object_instance, pObject);
} else if (pObject->Timer_State == TIMER_STATE_RUNNING) {
/* If a value of TRUE is written to the Timer_Running property,
then set Last_State_Change to RUNNING_TO_RUNNING;
@@ -712,7 +719,7 @@ bool Timer_Running_Set(uint32_t object_instance, bool start)
datetime_local(
&pObject->Update_Time.date, &pObject->Update_Time.time,
NULL, NULL);
Timer_Write_Request_Initiate(pObject);
Timer_Write_Request_Initiate(object_instance, pObject);
} else if (pObject->Timer_State == TIMER_STATE_EXPIRED) {
/* If a value of TRUE is written to the Timer_Running property,
set Timer_State to RUNNING;
@@ -730,7 +737,7 @@ bool Timer_Running_Set(uint32_t object_instance, bool start)
datetime_local(
&pObject->Update_Time.date, &pObject->Update_Time.time,
NULL, NULL);
Timer_Write_Request_Initiate(pObject);
Timer_Write_Request_Initiate(object_instance, pObject);
}
} else {
if (pObject->Timer_State == TIMER_STATE_RUNNING) {
@@ -749,7 +756,7 @@ bool Timer_Running_Set(uint32_t object_instance, bool start)
datetime_local(
&pObject->Update_Time.date, &pObject->Update_Time.time,
NULL, NULL);
Timer_Write_Request_Initiate(pObject);
Timer_Write_Request_Initiate(object_instance, pObject);
}
}
status = true;
@@ -1079,7 +1086,7 @@ bool Timer_Present_Value_Set(uint32_t object_instance, uint32_t value)
datetime_local(
&pObject->Update_Time.date, &pObject->Update_Time.time,
NULL, NULL);
Timer_Write_Request_Initiate(pObject);
Timer_Write_Request_Initiate(object_instance, pObject);
}
status = true;
} else {
@@ -1112,7 +1119,7 @@ bool Timer_Present_Value_Set(uint32_t object_instance, uint32_t value)
datetime_local(
&pObject->Update_Time.date, &pObject->Update_Time.time,
NULL, NULL);
Timer_Write_Request_Initiate(pObject);
Timer_Write_Request_Initiate(object_instance, pObject);
status = true;
} else {
status = false;
@@ -2082,6 +2089,49 @@ void Timer_Write_Property_Internal_Callback_Set(write_property_function cb)
Write_Property_Internal_Callback = cb;
}
/**
* @brief Add a Timer write property notification callback
* @param notification - pointer to the notification structure
*/
void Timer_Write_Property_Notification_Add(
struct timer_write_property_notification *notification)
{
struct timer_write_property_notification *head;
head = &Write_Property_Notification_Head;
do {
if (head->next == notification) {
/* already here! */
break;
} else if (!head->next) {
/* first available node */
head->next = notification;
break;
}
head = head->next;
} while (head);
}
/**
* @brief Calls all registered Timer write property notification callbacks
* @param instance - object instance number
* @param status - write property status
* @param wp_data - write property data
*/
void Timer_Write_Property_Notify(
uint32_t instance, bool status, BACNET_WRITE_PROPERTY_DATA *wp_data)
{
struct timer_write_property_notification *head;
head = &Write_Property_Notification_Head;
do {
if (head->callback) {
head->callback(instance, status, wp_data);
}
head = head->next;
} while (head);
}
/**
* @brief Updates the object program operation
* @details In the RUNNING state, the timer is active
+21
View File
@@ -18,6 +18,21 @@
#include "bacnet/rp.h"
#include "bacnet/list_element.h"
/**
* @brief Callback for tracking the timer writes for logging or other purposes
* @param instance - timer object instance number
* @param status - true if write was successful
* @param wp_data - pointer to the write property data structure
*/
typedef void (*timer_write_property_callback)(
uint32_t instance, bool status, BACNET_WRITE_PROPERTY_DATA *wp_data);
/* linked list structure for notifications */
struct timer_write_property_notification;
struct timer_write_property_notification {
struct timer_write_property_notification *next;
timer_write_property_callback callback;
};
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
@@ -166,6 +181,12 @@ 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
void Timer_Write_Property_Notification_Add(
struct timer_write_property_notification *notification);
BACNET_STACK_EXPORT
void Timer_Write_Property_Notify(
uint32_t instance, bool status, BACNET_WRITE_PROPERTY_DATA *wp_data);
BACNET_STACK_EXPORT
int Timer_Add_List_Element(BACNET_LIST_ELEMENT_DATA *list_element);