Added end-of-blink callback for warn-off and warn-relinquish lighting commands (#1214)
* Added Blink.Callback and Blink.Priority to support end-of-blink actions for WARN_OFF/WARN_RELINQUISH. The Blink.Callback is invoked when a blink sequence ends or when a new command interrupts a WARN_OFF/WARN_RELINQUISH in progress. * Added Lighting Output (LO) WARN_OFF/WARN_RELINQUISH post-egress priority array handling using the Blink.Callback
This commit is contained in:
@@ -120,6 +120,9 @@ The git repositories are hosted at the following sites:
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed lighting output object lighting-commands for warn-off and
|
||||
warn-relinquish when an update at the specified priority slot
|
||||
shall occur after an egress time delay. (#1214)
|
||||
* Fixed lighting output object lighting-commands for warn-off and
|
||||
warn-relinquish when blink-warn notification shall not occur. (#1212)
|
||||
* Fixed timer object task to initiate a write-request at expiration. (#1212)
|
||||
|
||||
@@ -610,6 +610,42 @@ Lighting_Command_Warn(struct object_data *pObject, unsigned priority)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback that manipulates the value at the specified priority slot
|
||||
after a delay of Egress_Time seconds.
|
||||
* @param object_instance object-instance number of the object
|
||||
* @param operation BACnet lighting operation
|
||||
* @param priority BACnet priority array value 1..16
|
||||
*/
|
||||
static void Lighting_Command_Blink_Stop(
|
||||
uint32_t object_instance,
|
||||
BACNET_LIGHTING_OPERATION operation,
|
||||
uint8_t priority)
|
||||
{
|
||||
struct object_data *pObject;
|
||||
|
||||
switch (operation) {
|
||||
case BACNET_LIGHTS_WARN_OFF:
|
||||
/* writes the value 0.0% to the specified priority slot
|
||||
after a delay of Egress_Time seconds. */
|
||||
pObject = Keylist_Data(Object_List, object_instance);
|
||||
if (pObject) {
|
||||
(void)Present_Value_Set(pObject, 0.0, priority);
|
||||
}
|
||||
break;
|
||||
case BACNET_LIGHTS_WARN_RELINQUISH:
|
||||
/* relinquishes the value at the specified priority slot
|
||||
after a delay of Egress_Time seconds. */
|
||||
pObject = Keylist_Data(Object_List, object_instance);
|
||||
if (pObject) {
|
||||
(void)Present_Value_Relinquish(pObject, priority);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the lighting command if the priority is active
|
||||
* @param object [in] BACnet object instance
|
||||
@@ -619,6 +655,7 @@ static void
|
||||
Lighting_Command_Warn_Off(struct object_data *pObject, unsigned priority)
|
||||
{
|
||||
unsigned current_priority;
|
||||
BACNET_LIGHTING_COMMAND_WARN_DATA blink;
|
||||
|
||||
if (!pObject) {
|
||||
return;
|
||||
@@ -637,14 +674,14 @@ Lighting_Command_Warn_Off(struct object_data *pObject, unsigned priority)
|
||||
active priority, or
|
||||
(b) The Present_Value is 0.0%, or
|
||||
(c) Blink_Warn_Enable is FALSE. */
|
||||
pObject->Lighting_Command.Blink.Duration =
|
||||
pObject->Egress_Time_Seconds * 1000UL;
|
||||
memmove(
|
||||
&blink, &pObject->Lighting_Command.Blink,
|
||||
sizeof(BACNET_LIGHTING_COMMAND_WARN_DATA));
|
||||
blink.Duration = pObject->Egress_Time_Seconds * 1000UL;
|
||||
blink.Priority = priority;
|
||||
blink.Callback = Lighting_Command_Blink_Stop;
|
||||
lighting_command_blink_warn(
|
||||
&pObject->Lighting_Command, BACNET_LIGHTS_WARN_OFF,
|
||||
&pObject->Lighting_Command.Blink);
|
||||
/* FIXME: writes the value 0.0% to the specified slot
|
||||
in the priority array after a delay of Egress_Time seconds. */
|
||||
Present_Value_Set(pObject, 0.0, priority);
|
||||
&pObject->Lighting_Command, BACNET_LIGHTS_WARN_OFF, &blink);
|
||||
} else {
|
||||
/* the value 0.0% written at the specified priority immediately */
|
||||
Present_Value_Set(pObject, 0.0, priority);
|
||||
@@ -688,6 +725,7 @@ static void
|
||||
Lighting_Command_Warn_Relinquish(struct object_data *pObject, unsigned priority)
|
||||
{
|
||||
uint8_t current_priority;
|
||||
BACNET_LIGHTING_COMMAND_WARN_DATA blink;
|
||||
|
||||
if (!pObject) {
|
||||
return;
|
||||
@@ -708,14 +746,15 @@ Lighting_Command_Warn_Relinquish(struct object_data *pObject, unsigned priority)
|
||||
(b) The Present_Value is 0.0%, or
|
||||
(c) The Present_Value would not evaluate to 0.0% after
|
||||
the priority slot is relinquished. */
|
||||
pObject->Lighting_Command.Blink.Duration =
|
||||
pObject->Egress_Time_Seconds * 1000UL;
|
||||
memmove(
|
||||
&blink, &pObject->Lighting_Command.Blink,
|
||||
sizeof(BACNET_LIGHTING_COMMAND_WARN_DATA));
|
||||
blink.Duration = pObject->Egress_Time_Seconds * 1000UL;
|
||||
blink.Priority = priority;
|
||||
blink.Callback = Lighting_Command_Blink_Stop;
|
||||
lighting_command_blink_warn(
|
||||
&pObject->Lighting_Command, BACNET_LIGHTS_WARN_RELINQUISH,
|
||||
&pObject->Lighting_Command.Blink);
|
||||
/* FIXME: relinquishes the value at the specified priority slot
|
||||
after a delay of Egress_Time seconds.*/
|
||||
Present_Value_Relinquish(pObject, priority);
|
||||
&blink);
|
||||
} else {
|
||||
/* the value at the specified priority shall be
|
||||
relinquished immediately */
|
||||
|
||||
@@ -63,8 +63,7 @@ void lighting_command_notification_add(
|
||||
/**
|
||||
* @brief call the lighting command tracking value callbacks
|
||||
* @param data - dimmer data structure
|
||||
* @param old_value - value prior to write
|
||||
* @param value - value of the write
|
||||
* @param milliseconds - number of elapsed milliseconds since the last call
|
||||
*/
|
||||
static void lighting_command_timer_notify(
|
||||
struct bacnet_lighting_command_data *data, uint16_t milliseconds)
|
||||
@@ -105,6 +104,31 @@ void lighting_command_timer_notfication_add(
|
||||
} while (head);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief call the lighting command blink stop callback
|
||||
* for WARN_OFF/WARN_RELINQUISH operations
|
||||
* @param data - dimmer data structure
|
||||
*/
|
||||
static void
|
||||
lighting_command_blink_stop_notify(struct bacnet_lighting_command_data *data)
|
||||
{
|
||||
if (data->Blink.Callback) {
|
||||
/* do some checking to avoid extra callbacks */
|
||||
switch (data->Lighting_Operation) {
|
||||
case BACNET_LIGHTS_WARN_OFF:
|
||||
case BACNET_LIGHTS_WARN_RELINQUISH:
|
||||
if (data->Blink.Priority != 0) {
|
||||
data->Blink.Callback(
|
||||
data->Key, data->Lighting_Operation,
|
||||
data->Blink.Priority);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clamps the ramp rate value
|
||||
* @param ramp_rate [in] ramp rate value
|
||||
@@ -570,6 +594,7 @@ static void lighting_command_blink_handler(
|
||||
}
|
||||
if (data->Blink.Duration == 0) {
|
||||
/* 'end' operation */
|
||||
lighting_command_blink_stop_notify(data);
|
||||
data->In_Progress = BACNET_LIGHTING_IDLE;
|
||||
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||
target_value = data->Blink.End_Value;
|
||||
@@ -601,6 +626,7 @@ static void lighting_command_blink_handler(
|
||||
}
|
||||
if (data->Blink.Count == 0) {
|
||||
/* 'end' operation */
|
||||
lighting_command_blink_stop_notify(data);
|
||||
data->In_Progress = BACNET_LIGHTING_IDLE;
|
||||
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||
target_value = data->Blink.End_Value;
|
||||
@@ -718,6 +744,9 @@ void lighting_command_fade_to(
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
/* possibly interrupting a blink warn, so notify */
|
||||
lighting_command_blink_stop_notify(data);
|
||||
/* configure the lighting operation */
|
||||
data->Fade_Time = fade_time;
|
||||
data->Lighting_Operation = BACNET_LIGHTS_FADE_TO;
|
||||
data->Target_Level = value;
|
||||
@@ -739,6 +768,9 @@ void lighting_command_ramp_to(
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
/* possibly interrupting a blink warn, so notify */
|
||||
lighting_command_blink_stop_notify(data);
|
||||
/* configure the lighting operation */
|
||||
data->Ramp_Rate = lighting_command_ramp_rate_clamp(ramp_rate);
|
||||
data->Lighting_Operation = BACNET_LIGHTS_RAMP_TO;
|
||||
data->Target_Level = value;
|
||||
@@ -764,6 +796,9 @@ void lighting_command_step(
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
/* possibly interrupting a blink warn, so notify */
|
||||
lighting_command_blink_stop_notify(data);
|
||||
/* configure the lighting operation */
|
||||
if (((operation == BACNET_LIGHTS_STEP_UP) ||
|
||||
(operation == BACNET_LIGHTS_STEP_DOWN)) &&
|
||||
(!islessgreater(data->Tracking_Value, 0.0))) {
|
||||
@@ -818,9 +853,14 @@ void lighting_command_blink_warn(
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
/* possibly interrupting a blink warn, so notify */
|
||||
lighting_command_blink_stop_notify(data);
|
||||
/* configure the new warning */
|
||||
data->Lighting_Operation = operation;
|
||||
data->Blink.Target_Interval = blink->Interval;
|
||||
data->Blink.Duration = blink->Duration;
|
||||
data->Blink.Priority = blink->Priority;
|
||||
data->Blink.Callback = blink->Callback;
|
||||
data->Blink.Count = blink->Count;
|
||||
data->Blink.On_Value = blink->On_Value;
|
||||
data->Blink.Off_Value = blink->Off_Value;
|
||||
@@ -842,6 +882,9 @@ void lighting_command_stop(struct bacnet_lighting_command_data *data)
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
/* possibly interrupting a blink warn, so notify */
|
||||
lighting_command_blink_stop_notify(data);
|
||||
/* configure the lighting operation */
|
||||
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||
if (isgreaterequal(data->Tracking_Value, 1.0)) {
|
||||
/* the last value that was greater than or equal to 1.0%.*/
|
||||
@@ -859,6 +902,9 @@ void lighting_command_none(struct bacnet_lighting_command_data *data)
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
/* possibly interrupting a blink warn, so notify */
|
||||
lighting_command_blink_stop_notify(data);
|
||||
/* configure the lighting operation */
|
||||
data->Lighting_Operation = BACNET_LIGHTS_NONE;
|
||||
}
|
||||
|
||||
@@ -873,6 +919,9 @@ void lighting_command_restore_on(
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
/* possibly interrupting a blink warn, so notify */
|
||||
lighting_command_blink_stop_notify(data);
|
||||
/* configure the lighting operation */
|
||||
data->Fade_Time = fade_time;
|
||||
data->Lighting_Operation = BACNET_LIGHTS_RESTORE_ON;
|
||||
data->Target_Level = data->Last_On_Value;
|
||||
@@ -889,6 +938,9 @@ void lighting_command_default_on(
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
/* possibly interrupting a blink warn, so notify */
|
||||
lighting_command_blink_stop_notify(data);
|
||||
/* configure the lighting operation */
|
||||
data->Fade_Time = fade_time;
|
||||
data->Lighting_Operation = BACNET_LIGHTS_DEFAULT_ON;
|
||||
data->Target_Level = data->Default_On_Value;
|
||||
@@ -905,6 +957,9 @@ void lighting_command_toggle_restore(
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
/* possibly interrupting a blink warn, so notify */
|
||||
lighting_command_blink_stop_notify(data);
|
||||
/* configure the lighting operation */
|
||||
data->Fade_Time = fade_time;
|
||||
data->Lighting_Operation = BACNET_LIGHTS_TOGGLE_RESTORE;
|
||||
if (isless(data->Tracking_Value, 1.0f)) {
|
||||
@@ -927,6 +982,9 @@ void lighting_command_toggle_default(
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
/* possibly interrupting a blink warn, so notify */
|
||||
lighting_command_blink_stop_notify(data);
|
||||
/* configure the lighting operation */
|
||||
data->Fade_Time = fade_time;
|
||||
data->Lighting_Operation = BACNET_LIGHTS_TOGGLE_DEFAULT;
|
||||
if (isless(data->Tracking_Value, 1.0f)) {
|
||||
@@ -962,6 +1020,8 @@ void lighting_command_init(struct bacnet_lighting_command_data *data)
|
||||
data->Blink.Interval = 0;
|
||||
data->Blink.Duration = 0;
|
||||
data->Blink.State = false;
|
||||
data->Blink.Callback = NULL;
|
||||
data->Blink.State = false;
|
||||
data->Notification_Head.next = NULL;
|
||||
data->Notification_Head.callback = NULL;
|
||||
}
|
||||
|
||||
@@ -41,11 +41,23 @@ struct lighting_command_timer_notification {
|
||||
lighting_command_timer_callback callback;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Callback that manipulates the value at the specified priority slot
|
||||
after a delay of Egress_Time seconds.
|
||||
* @param object_instance object-instance number of the object
|
||||
* @param operation BACnet lighting operation
|
||||
* @param priority BACnet priority array value 1..16
|
||||
*/
|
||||
typedef void (*lighting_command_blink_callback)(
|
||||
uint32_t key, BACNET_LIGHTING_OPERATION operation, uint8_t priority);
|
||||
|
||||
typedef struct bacnet_lighting_command_warn_data {
|
||||
/* warn */
|
||||
float On_Value;
|
||||
float Off_Value;
|
||||
float End_Value;
|
||||
uint8_t Priority;
|
||||
lighting_command_blink_callback Callback;
|
||||
uint16_t Target_Interval;
|
||||
/* internal tracking */
|
||||
uint16_t Interval;
|
||||
|
||||
@@ -61,6 +61,25 @@ static bool is_float_equal(float x1, float x2)
|
||||
return fabs(x1 - x2) < 0.001;
|
||||
}
|
||||
|
||||
static uint32_t Test_Blink_End_Key;
|
||||
static BACNET_LIGHTING_OPERATION Test_Blink_End_Operation;
|
||||
static uint8_t Test_Blink_End_Priority;
|
||||
|
||||
/**
|
||||
* @brief Callback that manipulates the value at the specified priority slot
|
||||
after a delay of Egress_Time seconds.
|
||||
* @param object_instance object-instance number of the object
|
||||
* @param operation BACnet lighting operation
|
||||
* @param priority BACnet priority array value 1..16
|
||||
*/
|
||||
static void test_blink_end(
|
||||
uint32_t key, BACNET_LIGHTING_OPERATION operation, uint8_t priority)
|
||||
{
|
||||
Test_Blink_End_Key = key;
|
||||
Test_Blink_End_Operation = operation;
|
||||
Test_Blink_End_Priority = priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief test dimmer blink handler
|
||||
* @param data - dimmer data
|
||||
@@ -72,28 +91,40 @@ static void test_lighting_command_blink_unit(BACNET_LIGHTING_COMMAND_DATA *data)
|
||||
uint16_t milliseconds = 10;
|
||||
uint32_t duration = 0;
|
||||
BACNET_LIGHTING_COMMAND_WARN_DATA *blink = &data->Blink;
|
||||
BACNET_LIGHTING_OPERATION operation[] = { BACNET_LIGHTS_WARN,
|
||||
BACNET_LIGHTS_WARN_OFF,
|
||||
BACNET_LIGHTS_WARN_RELINQUISH };
|
||||
unsigned i;
|
||||
|
||||
lighting_command_fade_to(data, data->Max_Actual_Value, 0);
|
||||
lighting_command_timer(data, milliseconds);
|
||||
zassert_true(data->In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||
zassert_true(is_float_equal(Tracking_Value, data->Max_Actual_Value), NULL);
|
||||
for (i = 0; i < ARRAY_SIZE(operation); i++) {
|
||||
/* blink warn - common */
|
||||
data->Blink.Callback = test_blink_end;
|
||||
data->Blink.Priority = 8;
|
||||
Test_Blink_End_Priority = 0;
|
||||
/* special cases */
|
||||
if (blink->Duration == 0) {
|
||||
/* immediate */
|
||||
lighting_command_blink_warn(data, BACNET_LIGHTS_WARN, blink);
|
||||
lighting_command_blink_warn(data, operation[i], blink);
|
||||
lighting_command_timer(data, milliseconds);
|
||||
zassert_true(data->In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||
zassert_true(is_float_equal(Tracking_Value, blink->End_Value), NULL);
|
||||
zassert_true(
|
||||
is_float_equal(Tracking_Value, blink->End_Value), NULL);
|
||||
} else if (blink->Interval == 0) {
|
||||
/* no blink, just egress timing */
|
||||
lighting_command_blink_warn(data, BACNET_LIGHTS_WARN, blink);
|
||||
lighting_command_blink_warn(data, operation[i], blink);
|
||||
lighting_command_timer(data, milliseconds);
|
||||
zassert_true(data->In_Progress == BACNET_LIGHTING_OTHER, NULL);
|
||||
zassert_true(is_float_equal(Tracking_Value, blink->On_Value), NULL);
|
||||
milliseconds = blink->Duration;
|
||||
lighting_command_blink_warn(data, BACNET_LIGHTS_WARN, blink);
|
||||
lighting_command_blink_warn(data, operation[i], blink);
|
||||
lighting_command_timer(data, milliseconds);
|
||||
zassert_true(data->In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||
zassert_true(is_float_equal(Tracking_Value, blink->End_Value), NULL);
|
||||
zassert_true(
|
||||
is_float_equal(Tracking_Value, blink->End_Value), NULL);
|
||||
} else {
|
||||
/* blinking and egress timing */
|
||||
if ((blink->Count > 0) && (blink->Count < UINT16_MAX)) {
|
||||
@@ -106,7 +137,7 @@ static void test_lighting_command_blink_unit(BACNET_LIGHTING_COMMAND_DATA *data)
|
||||
}
|
||||
milliseconds = blink->Interval;
|
||||
do {
|
||||
lighting_command_blink_warn(data, BACNET_LIGHTS_WARN, blink);
|
||||
lighting_command_blink_warn(data, operation[i], blink);
|
||||
lighting_command_timer(data, milliseconds);
|
||||
if (blink->Duration) {
|
||||
zassert_true(
|
||||
@@ -123,14 +154,21 @@ static void test_lighting_command_blink_unit(BACNET_LIGHTING_COMMAND_DATA *data)
|
||||
}
|
||||
} else {
|
||||
zassert_true(
|
||||
data->In_Progress == BACNET_LIGHTING_IDLE, "In_Progress=%d",
|
||||
data->In_Progress);
|
||||
data->In_Progress == BACNET_LIGHTING_IDLE,
|
||||
"In_Progress=%d", data->In_Progress);
|
||||
zassert_true(
|
||||
is_float_equal(Tracking_Value, blink->End_Value),
|
||||
"Tracking_Value=%f", Tracking_Value);
|
||||
}
|
||||
} while (blink->Duration);
|
||||
}
|
||||
if (operation[i] != BACNET_LIGHTS_WARN) {
|
||||
/* callback was called */
|
||||
zassert_equal(Test_Blink_End_Priority, blink->Priority, NULL);
|
||||
zassert_equal(Test_Blink_End_Operation, operation[i], NULL);
|
||||
zassert_equal(Test_Blink_End_Key, data->Key, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user