Fix lighting output commands for warn-off and warn-relinquish (#1212)
* Fixed lighting output object lighting-commands for warn-off and warn-relinquish when blink-warn notification shall not occur. * Fixed timer object task to initiate a write-request at expiration. * Added channel and timer object write-property observers in blinkt app to monitor internal writes. * Added vacancy timer command line argument in blinkt app for testing initial timer object vacancy time for lights channel.
This commit is contained in:
+7
-1
@@ -12,7 +12,7 @@ The git repositories are hosted at the following sites:
|
|||||||
* https://bacnet.sourceforge.net/
|
* https://bacnet.sourceforge.net/
|
||||||
* https://github.com/bacnet-stack/bacnet-stack/
|
* https://github.com/bacnet-stack/bacnet-stack/
|
||||||
|
|
||||||
## [Unreleased] - 2026-01-22
|
## [Unreleased] - 2026-01-28
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
@@ -32,6 +32,9 @@ The git repositories are hosted at the following sites:
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
* Added channel and timer object write-property observers in blinkt app
|
||||||
|
to monitor internal writes. Added vacancy timer command line argument
|
||||||
|
for testing initial timer object vacancy time for lights channel. (#1212)
|
||||||
* Added debug prints for lighting output properties to assist in identifying
|
* Added debug prints for lighting output properties to assist in identifying
|
||||||
out-of-range values. (#1211)
|
out-of-range values. (#1211)
|
||||||
* Added API to get the RGB pixel and brightness values from the blinkt
|
* Added API to get the RGB pixel and brightness values from the blinkt
|
||||||
@@ -117,6 +120,9 @@ The git repositories are hosted at the following sites:
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
* 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)
|
||||||
* Fixed the server name in the blinkt app and removed the unnecessary
|
* Fixed the server name in the blinkt app and removed the unnecessary
|
||||||
device.c module. (#1211)
|
device.c module. (#1211)
|
||||||
* Fixed Channel object for Color object present-value which does not
|
* Fixed Channel object for Color object present-value which does not
|
||||||
|
|||||||
+96
-3
@@ -52,11 +52,17 @@ static struct mstimer Blinkt_Task;
|
|||||||
static bool Blinkt_Test = false;
|
static bool Blinkt_Test = false;
|
||||||
/* observer for WriteGroup notifications */
|
/* observer for WriteGroup notifications */
|
||||||
static BACNET_WRITE_GROUP_NOTIFICATION Write_Group_Notification;
|
static BACNET_WRITE_GROUP_NOTIFICATION Write_Group_Notification;
|
||||||
|
/* observers for internal object to object writes */
|
||||||
|
static struct channel_write_property_notification
|
||||||
|
Channel_Write_Property_Observer;
|
||||||
|
static struct timer_write_property_notification Timer_Write_Property_Observer;
|
||||||
|
|
||||||
/* object instances */
|
/* object instances */
|
||||||
static uint32_t Light_Channel_Instance = 1;
|
static uint32_t Light_Channel_Instance = 1;
|
||||||
static uint32_t Color_Channel_Instance = 2;
|
static uint32_t Color_Channel_Instance = 2;
|
||||||
static uint32_t CCT_Channel_Instance = 3;
|
static uint32_t CCT_Channel_Instance = 3;
|
||||||
static uint32_t Vacancy_Timer_Instance = 1;
|
static uint32_t Vacancy_Timer_Instance = 1;
|
||||||
|
static uint32_t Vacancy_Timeout_Milliseconds = 30UL * 60UL * 1000UL;
|
||||||
static unsigned Default_Priority = 16;
|
static unsigned Default_Priority = 16;
|
||||||
/**
|
/**
|
||||||
* Clean up the Blinkt! interface
|
* Clean up the Blinkt! interface
|
||||||
@@ -66,6 +72,71 @@ static void blinkt_cleanup(void)
|
|||||||
blinkt_stop();
|
blinkt_stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Log internal object to object WriteProperty calls
|
||||||
|
* @param object_type The object type being written to
|
||||||
|
* @param instance The object instance being written to
|
||||||
|
* @param status The status of the WriteProperty
|
||||||
|
* @param wp_data The WriteProperty data
|
||||||
|
*/
|
||||||
|
static void write_property_observer(
|
||||||
|
BACNET_OBJECT_TYPE object_type,
|
||||||
|
uint32_t instance,
|
||||||
|
bool status,
|
||||||
|
BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
char value_string[64 + 1] = { 0 };
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
printf(
|
||||||
|
"WriteProperty: %s-%d to %s-%u %s@%u\n",
|
||||||
|
bactext_object_type_name(object_type), instance,
|
||||||
|
bactext_object_type_name(wp_data->object_type),
|
||||||
|
wp_data->object_instance,
|
||||||
|
bactext_property_name(wp_data->object_property), wp_data->priority);
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < wp_data->application_data_len &&
|
||||||
|
(i * 2) < sizeof(value_string) - 1;
|
||||||
|
i++) {
|
||||||
|
snprintf(
|
||||||
|
&value_string[i * 2], 3, "%02X", wp_data->application_data[i]);
|
||||||
|
}
|
||||||
|
printf(
|
||||||
|
"WriteProperty: %s-%d to %s-%u %s@%u %s %s-%s\n",
|
||||||
|
bactext_object_type_name(object_type), instance,
|
||||||
|
bactext_object_type_name(wp_data->object_type),
|
||||||
|
wp_data->object_instance,
|
||||||
|
bactext_property_name(wp_data->object_property), wp_data->priority,
|
||||||
|
value_string, bactext_error_class_name(wp_data->error_class),
|
||||||
|
bactext_error_code_name(wp_data->error_code));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Log internal object to object WriteProperty calls
|
||||||
|
* @param instance The object instance being written to
|
||||||
|
* @param status The status of the WriteProperty
|
||||||
|
* @param wp_data The WriteProperty data
|
||||||
|
*/
|
||||||
|
static void channel_write_property_observer(
|
||||||
|
uint32_t instance, bool status, BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||||
|
{
|
||||||
|
write_property_observer(OBJECT_CHANNEL, instance, status, wp_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Log internal object to object WriteProperty calls
|
||||||
|
* @param instance The object instance being written to
|
||||||
|
* @param status The status of the WriteProperty
|
||||||
|
* @param wp_data The WriteProperty data
|
||||||
|
*/
|
||||||
|
static void timer_write_property_observer(
|
||||||
|
uint32_t instance, bool status, BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||||
|
{
|
||||||
|
write_property_observer(OBJECT_TIMER, instance, status, wp_data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Callback for tracking value
|
* @brief Callback for tracking value
|
||||||
* @param object_instance - object-instance number of the object
|
* @param object_instance - object-instance number of the object
|
||||||
@@ -184,7 +255,11 @@ static void BACnet_Object_Table_Init(void *context)
|
|||||||
/* timer to automatically turn off the lights */
|
/* timer to automatically turn off the lights */
|
||||||
Timer_Create(Vacancy_Timer_Instance);
|
Timer_Create(Vacancy_Timer_Instance);
|
||||||
Timer_Name_Set(Vacancy_Timer_Instance, "Vacancy-Timer");
|
Timer_Name_Set(Vacancy_Timer_Instance, "Vacancy-Timer");
|
||||||
Timer_Default_Timeout_Set(Vacancy_Timer_Instance, 30UL * 60UL * 1000UL);
|
Timer_Default_Timeout_Set(
|
||||||
|
Vacancy_Timer_Instance, Vacancy_Timeout_Milliseconds);
|
||||||
|
printf(
|
||||||
|
"Vacancy timeout: %lu milliseconds\n",
|
||||||
|
(unsigned long)Vacancy_Timeout_Milliseconds);
|
||||||
/* to running */
|
/* to running */
|
||||||
timer_transition.next = NULL;
|
timer_transition.next = NULL;
|
||||||
timer_transition.tag = BACNET_APPLICATION_TAG_REAL;
|
timer_transition.tag = BACNET_APPLICATION_TAG_REAL;
|
||||||
@@ -205,6 +280,7 @@ static void BACnet_Object_Table_Init(void *context)
|
|||||||
Timer_State_Change_Value_Set(
|
Timer_State_Change_Value_Set(
|
||||||
Vacancy_Timer_Instance, TIMER_TRANSITION_RUNNING_TO_EXPIRED,
|
Vacancy_Timer_Instance, TIMER_TRANSITION_RUNNING_TO_EXPIRED,
|
||||||
&timer_transition);
|
&timer_transition);
|
||||||
|
/* timer members */
|
||||||
member.objectIdentifier.type = OBJECT_CHANNEL;
|
member.objectIdentifier.type = OBJECT_CHANNEL;
|
||||||
member.objectIdentifier.instance = Light_Channel_Instance;
|
member.objectIdentifier.instance = Light_Channel_Instance;
|
||||||
member.propertyIdentifier = PROP_PRESENT_VALUE;
|
member.propertyIdentifier = PROP_PRESENT_VALUE;
|
||||||
@@ -281,6 +357,11 @@ static void BACnet_Object_Table_Init(void *context)
|
|||||||
Color_Temperature_Write_Value_Handler);
|
Color_Temperature_Write_Value_Handler);
|
||||||
Lighting_Output_Write_Present_Value_Callback_Set(
|
Lighting_Output_Write_Present_Value_Callback_Set(
|
||||||
Lighting_Output_Write_Value_Handler);
|
Lighting_Output_Write_Value_Handler);
|
||||||
|
/* set the observer callbacks. log the internal object-to-object writes */
|
||||||
|
Channel_Write_Property_Observer.callback = channel_write_property_observer;
|
||||||
|
Channel_Write_Property_Notification_Add(&Channel_Write_Property_Observer);
|
||||||
|
Timer_Write_Property_Observer.callback = timer_write_property_observer;
|
||||||
|
Timer_Write_Property_Notification_Add(&Timer_Write_Property_Observer);
|
||||||
Write_Group_Notification.callback = Channel_Write_Group;
|
Write_Group_Notification.callback = Channel_Write_Group;
|
||||||
handler_write_group_notification_add(&Write_Group_Notification);
|
handler_write_group_notification_add(&Write_Group_Notification);
|
||||||
/* LEDs run at 0.1s intervals */
|
/* LEDs run at 0.1s intervals */
|
||||||
@@ -345,7 +426,7 @@ static void BACnet_Object_Task(void *context)
|
|||||||
static void print_usage(const char *filename)
|
static void print_usage(const char *filename)
|
||||||
{
|
{
|
||||||
printf("Usage: %s [device-instance]\n", filename);
|
printf("Usage: %s [device-instance]\n", filename);
|
||||||
printf(" [--device N][--test]\n");
|
printf(" [--device N][--test][--color COLOR][--vacancy MS]\n");
|
||||||
printf(" [--version][--help]\n");
|
printf(" [--version][--help]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,6 +448,9 @@ static void print_help(const char *filename)
|
|||||||
"--color:\n"
|
"--color:\n"
|
||||||
"Default CSS color name from W3C, such as black, red, green, etc.\n");
|
"Default CSS color name from W3C, such as black, red, green, etc.\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
printf("--vacancy:\n"
|
||||||
|
"Vacancy timeout in milliseconds.\n");
|
||||||
|
printf("\n");
|
||||||
printf("--test:\n"
|
printf("--test:\n"
|
||||||
"Test the Blinkt! RGB LEDs with a cycling pattern.\n");
|
"Test the Blinkt! RGB LEDs with a cycling pattern.\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@@ -384,7 +468,7 @@ static void print_help(const char *filename)
|
|||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
unsigned int target_args = 0;
|
unsigned int target_args = 0;
|
||||||
uint32_t device_id = BACNET_MAX_INSTANCE;
|
uint32_t device_id = BACNET_MAX_INSTANCE, vacancy_timeout = 0;
|
||||||
int argi = 0;
|
int argi = 0;
|
||||||
const char *filename = NULL;
|
const char *filename = NULL;
|
||||||
const char *color_name = "darkred";
|
const char *color_name = "darkred";
|
||||||
@@ -431,6 +515,15 @@ int main(int argc, char *argv[])
|
|||||||
print_usage(filename);
|
print_usage(filename);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
} else if (strcmp(argv[argi], "--vacancy") == 0) {
|
||||||
|
/* allow the device ID to be set */
|
||||||
|
if (++argi < argc) {
|
||||||
|
if (!bacnet_string_to_uint32(argv[argi], &vacancy_timeout)) {
|
||||||
|
fprintf(stderr, "vacancy=%s invalid\n", argv[argi]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
Vacancy_Timeout_Milliseconds = vacancy_timeout;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (target_args == 0) {
|
if (target_args == 0) {
|
||||||
/* allow the device ID to be set */
|
/* allow the device ID to be set */
|
||||||
|
|||||||
+179
-146
@@ -498,110 +498,6 @@ unsigned Lighting_Output_Present_Value_Priority(uint32_t object_instance)
|
|||||||
return priority;
|
return priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the lighting command if the priority is active
|
|
||||||
* @param object [in] BACnet object instance
|
|
||||||
* @param priority [in] BACnet priority array value 1..16
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
Lighting_Command_Warn(struct object_data *pObject, unsigned priority)
|
|
||||||
{
|
|
||||||
unsigned current_priority;
|
|
||||||
|
|
||||||
if (!pObject) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
current_priority = Present_Value_Priority(pObject);
|
|
||||||
if ((priority <= current_priority) &&
|
|
||||||
(Priority_Array_Active(pObject, priority - 1)) &&
|
|
||||||
(!is_float_equal(Priority_Array_Value(pObject, priority - 1), 0.0)) &&
|
|
||||||
pObject->Blink_Warn_Enable) {
|
|
||||||
/* The blink-warn notification shall not occur
|
|
||||||
if any of the following conditions occur:
|
|
||||||
(a) The specified priority is not the highest
|
|
||||||
active priority, or
|
|
||||||
(b) The value at the specified priority is 0.0%, or
|
|
||||||
(c) Blink_Warn_Enable is FALSE. */
|
|
||||||
lighting_command_blink_warn(
|
|
||||||
&pObject->Lighting_Command, BACNET_LIGHTS_WARN,
|
|
||||||
&pObject->Lighting_Command.Blink);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the lighting command if the priority is active
|
|
||||||
* @param object [in] BACnet object instance
|
|
||||||
* @param priority [in] BACnet priority array value 1..16
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
Lighting_Command_Warn_Off(struct object_data *pObject, unsigned priority)
|
|
||||||
{
|
|
||||||
unsigned current_priority;
|
|
||||||
|
|
||||||
if (!pObject) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
current_priority = Present_Value_Priority(pObject);
|
|
||||||
if ((priority <= current_priority) &&
|
|
||||||
(Priority_Array_Active(pObject, priority - 1)) &&
|
|
||||||
(!is_float_equal(Priority_Array_Value(pObject, priority - 1), 0.0)) &&
|
|
||||||
(is_float_equal(
|
|
||||||
Priority_Array_Next_Value(pObject, priority - 1), 0.0)) &&
|
|
||||||
pObject->Blink_Warn_Enable) {
|
|
||||||
/* The blink-warn notification shall not occur and
|
|
||||||
the value 0.0% written at the specified
|
|
||||||
priority immediately if any of the following
|
|
||||||
conditions occur:
|
|
||||||
(a) The specified priority is not the highest
|
|
||||||
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;
|
|
||||||
lighting_command_blink_warn(
|
|
||||||
&pObject->Lighting_Command, BACNET_LIGHTS_WARN_OFF,
|
|
||||||
&pObject->Lighting_Command.Blink);
|
|
||||||
}
|
|
||||||
Present_Value_Set(pObject, 0.0, priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the lighting command if the priority is active
|
|
||||||
* @param object [in] BACnet object instance
|
|
||||||
* @param priority [in] BACnet priority array value 1..16
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
Lighting_Command_Warn_Relinquish(struct object_data *pObject, unsigned priority)
|
|
||||||
{
|
|
||||||
unsigned current_priority;
|
|
||||||
|
|
||||||
if (!pObject) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
current_priority = Present_Value_Priority(pObject);
|
|
||||||
if ((priority <= current_priority) &&
|
|
||||||
(Priority_Array_Active(pObject, priority - 1)) &&
|
|
||||||
(!is_float_equal(Priority_Array_Value(pObject, priority - 1), 0.0)) &&
|
|
||||||
(is_float_equal(
|
|
||||||
Priority_Array_Next_Value(pObject, priority - 1), 0.0)) &&
|
|
||||||
pObject->Blink_Warn_Enable) {
|
|
||||||
/* The blink-warn notification shall not occur,
|
|
||||||
and the value at the specified priority shall be
|
|
||||||
relinquished immediately if any of the following
|
|
||||||
conditions occur:
|
|
||||||
(a) Blink_Warn_Enable is FALSE, or
|
|
||||||
(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;
|
|
||||||
lighting_command_blink_warn(
|
|
||||||
&pObject->Lighting_Command, BACNET_LIGHTS_WARN_RELINQUISH,
|
|
||||||
&pObject->Lighting_Command.Blink);
|
|
||||||
}
|
|
||||||
Present_Value_Relinquish(pObject, priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the lighting command if the priority is active
|
* @brief Set the lighting command if the priority is active
|
||||||
* @param object [in] BACnet object instance
|
* @param object [in] BACnet object instance
|
||||||
@@ -654,6 +550,182 @@ static void Lighting_Command_Ramp_To(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the lighting command using default values when the priority
|
||||||
|
* is active
|
||||||
|
* @param object [in] BACnet object instance
|
||||||
|
* @param priority [in] BACnet priority array value 1..16
|
||||||
|
* @param value - floating point analog value 0.0%, 1.0%-100.0%
|
||||||
|
*/
|
||||||
|
static void Lighting_Command_Transition_Default(
|
||||||
|
struct object_data *pObject, unsigned priority, float value)
|
||||||
|
{
|
||||||
|
unsigned current_priority;
|
||||||
|
|
||||||
|
if (!pObject) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
current_priority = Present_Value_Priority(pObject);
|
||||||
|
if (priority <= current_priority) {
|
||||||
|
/* we have priority - configure the Lighting Command */
|
||||||
|
if (pObject->Transition == BACNET_LIGHTING_TRANSITION_FADE) {
|
||||||
|
Lighting_Command_Fade_To(
|
||||||
|
pObject, priority, value, pObject->Default_Fade_Time);
|
||||||
|
} else if (pObject->Transition == BACNET_LIGHTING_TRANSITION_RAMP) {
|
||||||
|
Lighting_Command_Ramp_To(
|
||||||
|
pObject, priority, value, pObject->Default_Ramp_Rate);
|
||||||
|
} else {
|
||||||
|
Lighting_Command_Fade_To(pObject, priority, value, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the lighting command if the priority is active
|
||||||
|
* @param object [in] BACnet object instance
|
||||||
|
* @param priority [in] BACnet priority array value 1..16
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
Lighting_Command_Warn(struct object_data *pObject, unsigned priority)
|
||||||
|
{
|
||||||
|
unsigned current_priority;
|
||||||
|
|
||||||
|
if (!pObject) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
current_priority = Present_Value_Priority(pObject);
|
||||||
|
if ((priority <= current_priority) &&
|
||||||
|
(Priority_Array_Active(pObject, priority - 1)) &&
|
||||||
|
(!is_float_equal(Priority_Array_Value(pObject, priority - 1), 0.0)) &&
|
||||||
|
pObject->Blink_Warn_Enable) {
|
||||||
|
/* The blink-warn notification shall not occur
|
||||||
|
if any of the following conditions occur:
|
||||||
|
(a) The specified priority is not the highest
|
||||||
|
active priority, or
|
||||||
|
(b) The value at the specified priority is 0.0%, or
|
||||||
|
(c) Blink_Warn_Enable is FALSE. */
|
||||||
|
lighting_command_blink_warn(
|
||||||
|
&pObject->Lighting_Command, BACNET_LIGHTS_WARN,
|
||||||
|
&pObject->Lighting_Command.Blink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the lighting command if the priority is active
|
||||||
|
* @param object [in] BACnet object instance
|
||||||
|
* @param priority [in] BACnet priority array value 1..16
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
Lighting_Command_Warn_Off(struct object_data *pObject, unsigned priority)
|
||||||
|
{
|
||||||
|
unsigned current_priority;
|
||||||
|
|
||||||
|
if (!pObject) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
current_priority = Present_Value_Priority(pObject);
|
||||||
|
if (priority <= current_priority) {
|
||||||
|
if ((Priority_Array_Active(pObject, priority - 1)) &&
|
||||||
|
(!is_float_equal(
|
||||||
|
Priority_Array_Value(pObject, priority - 1), 0.0)) &&
|
||||||
|
pObject->Blink_Warn_Enable) {
|
||||||
|
/* The blink-warn notification shall not occur and
|
||||||
|
the value 0.0% written at the specified
|
||||||
|
priority immediately if any of the following
|
||||||
|
conditions occur:
|
||||||
|
(a) The specified priority is not the highest
|
||||||
|
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;
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
/* the value 0.0% written at the specified priority immediately */
|
||||||
|
Present_Value_Set(pObject, 0.0, priority);
|
||||||
|
Lighting_Command_Transition_Default(pObject, priority, 0.0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Present_Value_Set(pObject, 0.0, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the lighting command if the priority is active
|
||||||
|
* @param object [in] BACnet object instance
|
||||||
|
* @param priority [in] BACnet priority array value 1..16
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
Lighting_Command_Relinquish(struct object_data *pObject, unsigned priority)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
uint8_t old_priority, new_priority;
|
||||||
|
float value;
|
||||||
|
|
||||||
|
if (pObject) {
|
||||||
|
old_priority = Present_Value_Priority(pObject);
|
||||||
|
status = Present_Value_Relinquish(pObject, priority);
|
||||||
|
new_priority = Present_Value_Priority(pObject);
|
||||||
|
if (status && (old_priority != new_priority)) {
|
||||||
|
value = Priority_Array_Next_Value(pObject, 0);
|
||||||
|
/* we have priority - configure the Lighting Command */
|
||||||
|
Lighting_Command_Transition_Default(pObject, new_priority, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the lighting command if the priority is active
|
||||||
|
* @param object [in] BACnet object instance
|
||||||
|
* @param priority [in] BACnet priority array value 1..16
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
Lighting_Command_Warn_Relinquish(struct object_data *pObject, unsigned priority)
|
||||||
|
{
|
||||||
|
uint8_t current_priority;
|
||||||
|
|
||||||
|
if (!pObject) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
current_priority = Present_Value_Priority(pObject);
|
||||||
|
if (priority <= current_priority) {
|
||||||
|
if ((Priority_Array_Active(pObject, priority - 1)) &&
|
||||||
|
(!is_float_equal(
|
||||||
|
Priority_Array_Value(pObject, priority - 1), 0.0)) &&
|
||||||
|
(is_float_equal(
|
||||||
|
Priority_Array_Next_Value(pObject, priority - 1), 0.0)) &&
|
||||||
|
pObject->Blink_Warn_Enable) {
|
||||||
|
/* The blink-warn notification shall not occur,
|
||||||
|
and the value at the specified priority shall be
|
||||||
|
relinquished immediately if any of the following
|
||||||
|
conditions occur:
|
||||||
|
(a) Blink_Warn_Enable is FALSE, or
|
||||||
|
(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;
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
/* the value at the specified priority shall be
|
||||||
|
relinquished immediately */
|
||||||
|
Lighting_Command_Relinquish(pObject, priority);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Present_Value_Relinquish(pObject, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the lighting command if the priority is active
|
* @brief Set the lighting command if the priority is active
|
||||||
* @details Commands Present_Value to a value equal to the
|
* @details Commands Present_Value to a value equal to the
|
||||||
@@ -764,36 +836,6 @@ static void Lighting_Command_Step_Down_Off(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the lighting command using default values when the priority
|
|
||||||
* is active
|
|
||||||
* @param object [in] BACnet object instance
|
|
||||||
* @param priority [in] BACnet priority array value 1..16
|
|
||||||
* @param value - floating point analog value 0.0%, 1.0%-100.0%
|
|
||||||
*/
|
|
||||||
static void Lighting_Command_Transition_Default(
|
|
||||||
struct object_data *pObject, unsigned priority, float value)
|
|
||||||
{
|
|
||||||
unsigned current_priority;
|
|
||||||
|
|
||||||
if (!pObject) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
current_priority = Present_Value_Priority(pObject);
|
|
||||||
if (priority <= current_priority) {
|
|
||||||
/* we have priority - configure the Lighting Command */
|
|
||||||
if (pObject->Transition == BACNET_LIGHTING_TRANSITION_FADE) {
|
|
||||||
Lighting_Command_Fade_To(
|
|
||||||
pObject, priority, value, pObject->Default_Fade_Time);
|
|
||||||
} else if (pObject->Transition == BACNET_LIGHTING_TRANSITION_RAMP) {
|
|
||||||
Lighting_Command_Ramp_To(
|
|
||||||
pObject, priority, value, pObject->Default_Ramp_Rate);
|
|
||||||
} else {
|
|
||||||
Lighting_Command_Fade_To(pObject, priority, value, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (BACNET_PROTOCOL_REVISION >= 28)
|
#if (BACNET_PROTOCOL_REVISION >= 28)
|
||||||
/**
|
/**
|
||||||
* @brief Set the lighting command if the priority is active
|
* @brief Set the lighting command if the priority is active
|
||||||
@@ -1094,27 +1136,18 @@ float Lighting_Output_Priority_Array_Value(
|
|||||||
* @param object_instance - object-instance number of the object
|
* @param object_instance - object-instance number of the object
|
||||||
* @param priority - priority 1..16
|
* @param priority - priority 1..16
|
||||||
*
|
*
|
||||||
* @return true if priority is within range and priority-array slot is
|
* @return true if the object exists
|
||||||
* relinquished.
|
|
||||||
*/
|
*/
|
||||||
bool Lighting_Output_Present_Value_Relinquish(
|
bool Lighting_Output_Present_Value_Relinquish(
|
||||||
uint32_t object_instance, unsigned priority)
|
uint32_t object_instance, unsigned priority)
|
||||||
{
|
{
|
||||||
bool status = false;
|
bool status = false;
|
||||||
struct object_data *pObject;
|
struct object_data *pObject;
|
||||||
uint8_t old_priority, new_priority;
|
|
||||||
float value;
|
|
||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
pObject = Keylist_Data(Object_List, object_instance);
|
||||||
if (pObject) {
|
if (pObject) {
|
||||||
old_priority = Present_Value_Priority(pObject);
|
status = true;
|
||||||
status = Present_Value_Relinquish(pObject, priority);
|
Lighting_Command_Relinquish(pObject, priority);
|
||||||
new_priority = Present_Value_Priority(pObject);
|
|
||||||
if (status && (old_priority != new_priority)) {
|
|
||||||
value = Priority_Array_Next_Value(pObject, 0);
|
|
||||||
/* we have priority - configure the Lighting Command */
|
|
||||||
Lighting_Command_Transition_Default(pObject, new_priority, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
|||||||
@@ -2190,6 +2190,10 @@ void Timer_Task(uint32_t object_instance, uint16_t milliseconds)
|
|||||||
pObject->Timer_State = TIMER_STATE_EXPIRED;
|
pObject->Timer_State = TIMER_STATE_EXPIRED;
|
||||||
pObject->Last_State_Change =
|
pObject->Last_State_Change =
|
||||||
TIMER_TRANSITION_RUNNING_TO_EXPIRED;
|
TIMER_TRANSITION_RUNNING_TO_EXPIRED;
|
||||||
|
datetime_local(
|
||||||
|
&pObject->Update_Time.date, &pObject->Update_Time.time,
|
||||||
|
NULL, NULL);
|
||||||
|
Timer_Write_Request_Initiate(object_instance, pObject);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TIMER_STATE_EXPIRED:
|
case TIMER_STATE_EXPIRED:
|
||||||
|
|||||||
Reference in New Issue
Block a user