Bugfix/lighting output dimming refactor (#855)
* Refactored lighting command operations from the lighting output object, and added unit testing. Integrated the result back into lighting-output object.
This commit is contained in:
@@ -536,6 +536,8 @@ add_library(${PROJECT_NAME}
|
|||||||
src/bacnet/basic/sys/keylist.h
|
src/bacnet/basic/sys/keylist.h
|
||||||
src/bacnet/basic/sys/linear.c
|
src/bacnet/basic/sys/linear.c
|
||||||
src/bacnet/basic/sys/linear.h
|
src/bacnet/basic/sys/linear.h
|
||||||
|
src/bacnet/basic/sys/lighting_command.c
|
||||||
|
src/bacnet/basic/sys/lighting_command.h
|
||||||
src/bacnet/basic/sys/mstimer.c
|
src/bacnet/basic/sys/mstimer.c
|
||||||
src/bacnet/basic/sys/mstimer.h
|
src/bacnet/basic/sys/mstimer.h
|
||||||
src/bacnet/basic/sys/ringbuf.c
|
src/bacnet/basic/sys/ringbuf.c
|
||||||
|
|||||||
@@ -225,10 +225,17 @@ static void bacnet_output_init(void)
|
|||||||
|
|
||||||
Channel_Create(light_channel_instance);
|
Channel_Create(light_channel_instance);
|
||||||
Channel_Name_Set(light_channel_instance, "Lights");
|
Channel_Name_Set(light_channel_instance, "Lights");
|
||||||
|
Channel_Number_Set(light_channel_instance, 1);
|
||||||
|
Channel_Control_Groups_Element_Set(light_channel_instance, 1, 1);
|
||||||
Channel_Create(color_channel_instance);
|
Channel_Create(color_channel_instance);
|
||||||
Channel_Name_Set(color_channel_instance, "Colors");
|
Channel_Name_Set(color_channel_instance, "Colors");
|
||||||
|
Channel_Number_Set(color_channel_instance, 2);
|
||||||
|
Channel_Control_Groups_Element_Set(color_channel_instance, 1, 2);
|
||||||
Channel_Create(temp_channel_instance);
|
Channel_Create(temp_channel_instance);
|
||||||
Channel_Name_Set(temp_channel_instance, "Color-Temperatures");
|
Channel_Name_Set(temp_channel_instance, "Color-Temperatures");
|
||||||
|
Channel_Number_Set(temp_channel_instance, 3);
|
||||||
|
Channel_Control_Groups_Element_Set(temp_channel_instance, 1, 3);
|
||||||
|
/* configure outputs and bindings */
|
||||||
led_max = blinkt_led_count();
|
led_max = blinkt_led_count();
|
||||||
for (i = 0; i < led_max; i++) {
|
for (i = 0; i < led_max; i++) {
|
||||||
/* color */
|
/* color */
|
||||||
|
|||||||
@@ -148,6 +148,7 @@
|
|||||||
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\filename.c" />
|
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\filename.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\keylist.c" />
|
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\keylist.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\linear.c" />
|
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\linear.c" />
|
||||||
|
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\lighting_command.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\mstimer.c" />
|
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\mstimer.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\ringbuf.c" />
|
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\ringbuf.c" />
|
||||||
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\sbuf.c" />
|
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\sbuf.c" />
|
||||||
|
|||||||
@@ -588,6 +588,9 @@
|
|||||||
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\linear.c">
|
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\linear.c">
|
||||||
<Filter>Source Files\src\bacnet\basic\sys</Filter>
|
<Filter>Source Files\src\bacnet\basic\sys</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\..\src\bacnet\basic\sys\lighting_command.c">
|
||||||
|
<Filter>Source Files\src\bacnet\basic\sys</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\bip-init.c">
|
<ClCompile Include="..\..\bip-init.c">
|
||||||
<Filter>Source Files\ports\win32</Filter>
|
<Filter>Source Files\ports\win32</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
+143
-478
@@ -23,6 +23,7 @@
|
|||||||
#include "bacnet/basic/sys/keylist.h"
|
#include "bacnet/basic/sys/keylist.h"
|
||||||
#include "bacnet/basic/sys/linear.h"
|
#include "bacnet/basic/sys/linear.h"
|
||||||
#include "bacnet/basic/sys/debug.h"
|
#include "bacnet/basic/sys/debug.h"
|
||||||
|
#include "bacnet/basic/sys/lighting_command.h"
|
||||||
#include "bacnet/bactext.h"
|
#include "bacnet/bactext.h"
|
||||||
#include "bacnet/proplist.h"
|
#include "bacnet/proplist.h"
|
||||||
/* me! */
|
/* me! */
|
||||||
@@ -30,10 +31,9 @@
|
|||||||
|
|
||||||
struct object_data {
|
struct object_data {
|
||||||
float Present_Value;
|
float Present_Value;
|
||||||
float Tracking_Value;
|
BACNET_LIGHTING_COMMAND_DATA Lighting_Command;
|
||||||
|
BACNET_LIGHTING_COMMAND Last_Lighting_Command;
|
||||||
float Physical_Value;
|
float Physical_Value;
|
||||||
BACNET_LIGHTING_COMMAND Lighting_Command;
|
|
||||||
BACNET_LIGHTING_IN_PROGRESS In_Progress;
|
|
||||||
uint32_t Egress_Time;
|
uint32_t Egress_Time;
|
||||||
uint32_t Default_Fade_Time;
|
uint32_t Default_Fade_Time;
|
||||||
float Default_Ramp_Rate;
|
float Default_Ramp_Rate;
|
||||||
@@ -45,15 +45,12 @@ struct object_data {
|
|||||||
float Relinquish_Default;
|
float Relinquish_Default;
|
||||||
float Power;
|
float Power;
|
||||||
float Instantaneous_Power;
|
float Instantaneous_Power;
|
||||||
float Min_Actual_Value;
|
|
||||||
float Max_Actual_Value;
|
|
||||||
uint8_t Lighting_Command_Default_Priority;
|
uint8_t Lighting_Command_Default_Priority;
|
||||||
BACNET_OBJECT_ID Color_Reference;
|
BACNET_OBJECT_ID Color_Reference;
|
||||||
BACNET_OBJECT_ID Override_Color_Reference;
|
BACNET_OBJECT_ID Override_Color_Reference;
|
||||||
const char *Object_Name;
|
const char *Object_Name;
|
||||||
const char *Description;
|
const char *Description;
|
||||||
/* bits */
|
/* bits */
|
||||||
bool Out_Of_Service : 1;
|
|
||||||
bool Blink_Warn_Enable : 1;
|
bool Blink_Warn_Enable : 1;
|
||||||
bool Egress_Active : 1;
|
bool Egress_Active : 1;
|
||||||
bool Color_Override : 1;
|
bool Color_Override : 1;
|
||||||
@@ -61,8 +58,8 @@ struct object_data {
|
|||||||
/* Key List for storing the object data sorted by instance number */
|
/* Key List for storing the object data sorted by instance number */
|
||||||
static OS_Keylist Object_List;
|
static OS_Keylist Object_List;
|
||||||
/* callback for present value writes */
|
/* callback for present value writes */
|
||||||
static lighting_output_write_present_value_callback
|
static lighting_command_tracking_value_callback
|
||||||
Lighting_Output_Write_Present_Value_Callback;
|
Lighting_Command_Tracking_Value_Callback;
|
||||||
|
|
||||||
/* These arrays are used by the ReadPropertyMultiple handler and
|
/* These arrays are used by the ReadPropertyMultiple handler and
|
||||||
property-list property (as of protocol-revision 14) */
|
property-list property (as of protocol-revision 14) */
|
||||||
@@ -455,7 +452,9 @@ Lighting_Command_Warn(struct object_data *pObject, unsigned priority)
|
|||||||
active priority, or
|
active priority, or
|
||||||
(b) The value at the specified priority is 0.0%, or
|
(b) The value at the specified priority is 0.0%, or
|
||||||
(c) Blink_Warn_Enable is FALSE. */
|
(c) Blink_Warn_Enable is FALSE. */
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_WARN;
|
lighting_command_blink_warn(
|
||||||
|
&pObject->Lighting_Command, BACNET_LIGHTS_WARN,
|
||||||
|
&pObject->Lighting_Command.Blink);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,7 +484,9 @@ Lighting_Command_Warn_Off(struct object_data *pObject, unsigned priority)
|
|||||||
active priority, or
|
active priority, or
|
||||||
(b) The Present_Value is 0.0%, or
|
(b) The Present_Value is 0.0%, or
|
||||||
(c) Blink_Warn_Enable is FALSE. */
|
(c) Blink_Warn_Enable is FALSE. */
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_WARN_OFF;
|
lighting_command_blink_warn(
|
||||||
|
&pObject->Lighting_Command, BACNET_LIGHTS_WARN_OFF,
|
||||||
|
&pObject->Lighting_Command.Blink);
|
||||||
} else {
|
} else {
|
||||||
Present_Value_Set(pObject, 0.0, priority);
|
Present_Value_Set(pObject, 0.0, priority);
|
||||||
}
|
}
|
||||||
@@ -521,7 +522,9 @@ Lighting_Command_Warn_Relinquish(struct object_data *pObject, unsigned priority)
|
|||||||
priority, including Relinquish_Default,
|
priority, including Relinquish_Default,
|
||||||
is greater than 0.0%, or
|
is greater than 0.0%, or
|
||||||
(d) Blink_Warn_Enable is FALSE. */
|
(d) Blink_Warn_Enable is FALSE. */
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_WARN_RELINQUISH;
|
lighting_command_blink_warn(
|
||||||
|
&pObject->Lighting_Command, BACNET_LIGHTS_WARN_RELINQUISH,
|
||||||
|
&pObject->Lighting_Command.Blink);
|
||||||
} else {
|
} else {
|
||||||
Present_Value_Relinquish(pObject, priority);
|
Present_Value_Relinquish(pObject, priority);
|
||||||
}
|
}
|
||||||
@@ -549,9 +552,7 @@ static void Lighting_Command_Fade_To(
|
|||||||
current_priority = Present_Value_Priority(pObject);
|
current_priority = Present_Value_Priority(pObject);
|
||||||
if (priority <= current_priority) {
|
if (priority <= current_priority) {
|
||||||
/* we have priority - configure the Lighting Command */
|
/* we have priority - configure the Lighting Command */
|
||||||
pObject->Lighting_Command.fade_time = fade_time;
|
lighting_command_fade_to(&pObject->Lighting_Command, value, fade_time);
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_FADE_TO;
|
|
||||||
pObject->Lighting_Command.target_level = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,9 +578,7 @@ static void Lighting_Command_Ramp_To(
|
|||||||
current_priority = Present_Value_Priority(pObject);
|
current_priority = Present_Value_Priority(pObject);
|
||||||
if (priority <= current_priority) {
|
if (priority <= current_priority) {
|
||||||
/* we have priority - configure the Lighting Command */
|
/* we have priority - configure the Lighting Command */
|
||||||
pObject->Lighting_Command.ramp_rate = ramp_rate;
|
lighting_command_ramp_to(&pObject->Lighting_Command, value, ramp_rate);
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_RAMP_TO;
|
|
||||||
pObject->Lighting_Command.target_level = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,10 +603,8 @@ static void Lighting_Command_Step(
|
|||||||
current_priority = Present_Value_Priority(pObject);
|
current_priority = Present_Value_Priority(pObject);
|
||||||
if (priority <= current_priority) {
|
if (priority <= current_priority) {
|
||||||
/* we have priority - configure the Lighting Command */
|
/* we have priority - configure the Lighting Command */
|
||||||
pObject->Lighting_Command.operation = operation;
|
lighting_command_step(
|
||||||
pObject->Lighting_Command.fade_time = 0;
|
&pObject->Lighting_Command, operation, step_increment);
|
||||||
pObject->Lighting_Command.ramp_rate = 0.0f;
|
|
||||||
pObject->Lighting_Command.step_increment = step_increment;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -669,23 +666,18 @@ static bool Lighting_Output_Present_Value_Write(
|
|||||||
/* we have priority - configure the Lighting Command */
|
/* we have priority - configure the Lighting Command */
|
||||||
if (pObject->Transition ==
|
if (pObject->Transition ==
|
||||||
BACNET_LIGHTING_TRANSITION_FADE) {
|
BACNET_LIGHTING_TRANSITION_FADE) {
|
||||||
pObject->Lighting_Command.fade_time =
|
Lighting_Command_Fade_To(
|
||||||
pObject->Default_Fade_Time;
|
pObject, priority, value,
|
||||||
pObject->Lighting_Command.operation =
|
pObject->Default_Fade_Time);
|
||||||
BACNET_LIGHTS_FADE_TO;
|
|
||||||
} else if (
|
} else if (
|
||||||
pObject->Transition ==
|
pObject->Transition ==
|
||||||
BACNET_LIGHTING_TRANSITION_RAMP) {
|
BACNET_LIGHTING_TRANSITION_RAMP) {
|
||||||
pObject->Lighting_Command.ramp_rate =
|
Lighting_Command_Ramp_To(
|
||||||
pObject->Default_Ramp_Rate;
|
pObject, priority, value,
|
||||||
pObject->Lighting_Command.operation =
|
pObject->Default_Ramp_Rate);
|
||||||
BACNET_LIGHTS_RAMP_TO;
|
|
||||||
} else {
|
} else {
|
||||||
pObject->Lighting_Command.fade_time = 0;
|
Lighting_Command_Fade_To(pObject, priority, value, 0);
|
||||||
pObject->Lighting_Command.operation =
|
|
||||||
BACNET_LIGHTS_FADE_TO;
|
|
||||||
}
|
}
|
||||||
pObject->Lighting_Command.target_level = value;
|
|
||||||
}
|
}
|
||||||
status = true;
|
status = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -773,19 +765,17 @@ static bool Lighting_Output_Present_Value_Relinquish_Write(
|
|||||||
}
|
}
|
||||||
/* we have priority - configure the Lighting Command */
|
/* we have priority - configure the Lighting Command */
|
||||||
if (pObject->Transition == BACNET_LIGHTING_TRANSITION_FADE) {
|
if (pObject->Transition == BACNET_LIGHTING_TRANSITION_FADE) {
|
||||||
pObject->Lighting_Command.fade_time =
|
Lighting_Command_Fade_To(
|
||||||
pObject->Default_Fade_Time;
|
pObject, new_priority, value,
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_FADE_TO;
|
pObject->Default_Fade_Time);
|
||||||
} else if (
|
} else if (
|
||||||
pObject->Transition == BACNET_LIGHTING_TRANSITION_RAMP) {
|
pObject->Transition == BACNET_LIGHTING_TRANSITION_RAMP) {
|
||||||
pObject->Lighting_Command.ramp_rate =
|
Lighting_Command_Ramp_To(
|
||||||
pObject->Default_Ramp_Rate;
|
pObject, new_priority, value,
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_RAMP_TO;
|
pObject->Default_Ramp_Rate);
|
||||||
} else {
|
} else {
|
||||||
pObject->Lighting_Command.fade_time = 0;
|
Lighting_Command_Fade_To(pObject, new_priority, value, 0);
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_FADE_TO;
|
|
||||||
}
|
}
|
||||||
pObject->Lighting_Command.target_level = value;
|
|
||||||
}
|
}
|
||||||
status = true;
|
status = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -920,28 +910,6 @@ bool Lighting_Output_Description_Set(
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* For a given object instance-number, sets the lighting-command.
|
|
||||||
*
|
|
||||||
* @param object_instance - object-instance number of the object
|
|
||||||
* @param value - holds the lighting command value
|
|
||||||
*
|
|
||||||
* @return true if lighting command was set
|
|
||||||
*/
|
|
||||||
bool Lighting_Output_Lighting_Command_Set(
|
|
||||||
uint32_t object_instance, const BACNET_LIGHTING_COMMAND *value)
|
|
||||||
{
|
|
||||||
bool status = false;
|
|
||||||
struct object_data *pObject;
|
|
||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
|
||||||
if (pObject) {
|
|
||||||
status = lighting_command_copy(&pObject->Lighting_Command, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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
|
||||||
@@ -958,7 +926,7 @@ Lighting_Command_Stop(struct object_data *pObject, unsigned priority)
|
|||||||
current_priority = Present_Value_Priority(pObject);
|
current_priority = Present_Value_Priority(pObject);
|
||||||
if (priority <= current_priority) {
|
if (priority <= current_priority) {
|
||||||
/* we have priority - configure the Lighting Command */
|
/* we have priority - configure the Lighting Command */
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_STOP;
|
lighting_command_stop(&pObject->Lighting_Command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1085,6 +1053,9 @@ static bool Lighting_Output_Lighting_Command_Write(
|
|||||||
/**
|
/**
|
||||||
* For a given object instance-number, gets the lighting-command.
|
* For a given object instance-number, gets the lighting-command.
|
||||||
*
|
*
|
||||||
|
* @note The Lighting_Command property shall indicate the last written
|
||||||
|
* value or NONE if it has not yet been written.
|
||||||
|
*
|
||||||
* @param object_instance - object-instance number of the object
|
* @param object_instance - object-instance number of the object
|
||||||
* @param value - holds the lighting command value
|
* @param value - holds the lighting command value
|
||||||
*
|
*
|
||||||
@@ -1098,7 +1069,81 @@ bool Lighting_Output_Lighting_Command(
|
|||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
pObject = Keylist_Data(Object_List, object_instance);
|
||||||
if (pObject) {
|
if (pObject) {
|
||||||
status = lighting_command_copy(value, &pObject->Lighting_Command);
|
status = lighting_command_copy(value, &pObject->Last_Lighting_Command);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For a given object instance-number, sets the lighting-command.
|
||||||
|
*
|
||||||
|
* @param object_instance - object-instance number of the object
|
||||||
|
* @param value - holds the lighting command value
|
||||||
|
*
|
||||||
|
* @return true if lighting command was set
|
||||||
|
*/
|
||||||
|
bool Lighting_Output_Lighting_Command_Set(
|
||||||
|
uint32_t object_instance, const BACNET_LIGHTING_COMMAND *value)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
struct object_data *pObject;
|
||||||
|
|
||||||
|
pObject = Keylist_Data(Object_List, object_instance);
|
||||||
|
if (pObject) {
|
||||||
|
switch (value->operation) {
|
||||||
|
case BACNET_LIGHTS_NONE:
|
||||||
|
status = true;
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_FADE_TO:
|
||||||
|
Lighting_Command_Fade_To(
|
||||||
|
pObject, value->priority, value->target_level,
|
||||||
|
value->fade_time);
|
||||||
|
status = true;
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_RAMP_TO:
|
||||||
|
Lighting_Command_Ramp_To(
|
||||||
|
pObject, value->priority, value->target_level,
|
||||||
|
value->ramp_rate);
|
||||||
|
status = true;
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_STEP_UP:
|
||||||
|
case BACNET_LIGHTS_STEP_DOWN:
|
||||||
|
case BACNET_LIGHTS_STEP_ON:
|
||||||
|
case BACNET_LIGHTS_STEP_OFF:
|
||||||
|
Lighting_Command_Step(
|
||||||
|
pObject, value->priority, value->operation,
|
||||||
|
value->step_increment);
|
||||||
|
status = true;
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_WARN:
|
||||||
|
/* Provides the same functionality as the
|
||||||
|
WARN lighting command. */
|
||||||
|
Lighting_Command_Warn(pObject, value->priority);
|
||||||
|
status = true;
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_WARN_OFF:
|
||||||
|
/* Provides the same functionality as the
|
||||||
|
WARN_OFF lighting command. */
|
||||||
|
Lighting_Command_Warn_Off(pObject, value->priority);
|
||||||
|
status = true;
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_WARN_RELINQUISH:
|
||||||
|
/* Provides the same functionality as the
|
||||||
|
WARN_RELINQUISH lighting command. */
|
||||||
|
Lighting_Command_Warn_Relinquish(pObject, value->priority);
|
||||||
|
status = true;
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_STOP:
|
||||||
|
Lighting_Command_Stop(pObject, value->priority);
|
||||||
|
status = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (status) {
|
||||||
|
lighting_command_copy(&pObject->Last_Lighting_Command, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@@ -1119,7 +1164,7 @@ Lighting_Output_In_Progress(uint32_t object_instance)
|
|||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
pObject = Keylist_Data(Object_List, object_instance);
|
||||||
if (pObject) {
|
if (pObject) {
|
||||||
value = pObject->In_Progress;
|
value = pObject->Lighting_Command.In_Progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@@ -1142,7 +1187,7 @@ bool Lighting_Output_In_Progress_Set(
|
|||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
pObject = Keylist_Data(Object_List, object_instance);
|
||||||
if (pObject) {
|
if (pObject) {
|
||||||
pObject->In_Progress = in_progress;
|
pObject->Lighting_Command.In_Progress = in_progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@@ -1162,7 +1207,7 @@ float Lighting_Output_Tracking_Value(uint32_t object_instance)
|
|||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
pObject = Keylist_Data(Object_List, object_instance);
|
||||||
if (pObject) {
|
if (pObject) {
|
||||||
value = pObject->Tracking_Value;
|
value = pObject->Lighting_Command.Tracking_Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@@ -1184,7 +1229,7 @@ bool Lighting_Output_Tracking_Value_Set(uint32_t object_instance, float value)
|
|||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
pObject = Keylist_Data(Object_List, object_instance);
|
||||||
if (pObject) {
|
if (pObject) {
|
||||||
pObject->Tracking_Value = value;
|
pObject->Lighting_Command.Tracking_Value = value;
|
||||||
status = true;
|
status = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1627,7 +1672,7 @@ bool Lighting_Output_Out_Of_Service(uint32_t object_instance)
|
|||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
pObject = Keylist_Data(Object_List, object_instance);
|
||||||
if (pObject) {
|
if (pObject) {
|
||||||
value = pObject->Out_Of_Service;
|
value = pObject->Lighting_Command.Out_Of_Service;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@@ -1647,7 +1692,7 @@ void Lighting_Output_Out_Of_Service_Set(uint32_t object_instance, bool value)
|
|||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
pObject = Keylist_Data(Object_List, object_instance);
|
||||||
if (pObject) {
|
if (pObject) {
|
||||||
pObject->Out_Of_Service = value;
|
pObject->Lighting_Command.Out_Of_Service = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2276,366 +2321,6 @@ bool Lighting_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the timing for a single Lighting Output object Fade
|
|
||||||
*
|
|
||||||
* @param object_instance - Lighting Output object
|
|
||||||
* @param milliseconds - number of milliseconds elapsed since previously
|
|
||||||
* called. Works best when called about every 10 milliseconds.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
Lighting_Output_Fade_Handler(uint32_t object_instance, uint16_t milliseconds)
|
|
||||||
{
|
|
||||||
struct object_data *pObject;
|
|
||||||
float old_value;
|
|
||||||
float x1, x2, x3, y1, y3;
|
|
||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
|
||||||
if (!pObject) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
old_value = pObject->Tracking_Value;
|
|
||||||
if (milliseconds >= pObject->Lighting_Command.fade_time) {
|
|
||||||
/* stop fading */
|
|
||||||
pObject->Tracking_Value = pObject->Lighting_Command.target_level;
|
|
||||||
pObject->In_Progress = BACNET_LIGHTING_IDLE;
|
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_STOP;
|
|
||||||
pObject->Lighting_Command.fade_time = 0;
|
|
||||||
} else {
|
|
||||||
if (!islessgreater(
|
|
||||||
pObject->Tracking_Value,
|
|
||||||
pObject->Lighting_Command.target_level)) {
|
|
||||||
/* stop fading */
|
|
||||||
pObject->Tracking_Value = pObject->Lighting_Command.target_level;
|
|
||||||
pObject->In_Progress = BACNET_LIGHTING_IDLE;
|
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_STOP;
|
|
||||||
pObject->Lighting_Command.fade_time = 0;
|
|
||||||
} else {
|
|
||||||
/* fading */
|
|
||||||
x1 = 0.0f;
|
|
||||||
x2 = (float)milliseconds;
|
|
||||||
x3 = (float)pObject->Lighting_Command.fade_time;
|
|
||||||
y1 = old_value;
|
|
||||||
y3 = pObject->Lighting_Command.target_level;
|
|
||||||
pObject->Tracking_Value = linear_interpolate(x1, x2, x3, y1, y3);
|
|
||||||
pObject->Lighting_Command.fade_time -= milliseconds;
|
|
||||||
pObject->In_Progress = BACNET_LIGHTING_FADE_ACTIVE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Lighting_Output_Write_Present_Value_Callback) {
|
|
||||||
Lighting_Output_Write_Present_Value_Callback(
|
|
||||||
object_instance, old_value, pObject->Tracking_Value);
|
|
||||||
} else {
|
|
||||||
debug_printf(
|
|
||||||
"LO[%u] Fade Handler Operation=%s Value=%f\n", object_instance,
|
|
||||||
bactext_lighting_operation_name(
|
|
||||||
pObject->Lighting_Command.operation),
|
|
||||||
(double)pObject->Tracking_Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the object tracking value while ramping
|
|
||||||
*
|
|
||||||
* Commands Present_Value to ramp from the current Tracking_Value to the
|
|
||||||
* target-level specified in the command. The ramp operation
|
|
||||||
* changes the output from its current value to target-level,
|
|
||||||
* at a particular percent per second defined by ramp-rate.
|
|
||||||
* While the ramp operation is executing, In_Progress shall be set
|
|
||||||
* to RAMP_ACTIVE, and Tracking_Value shall be updated to reflect the current
|
|
||||||
* progress of the ramp. <target-level> shall be clamped to
|
|
||||||
* Min_Actual_Value and Max_Actual_Value.
|
|
||||||
*
|
|
||||||
* @param object_instance - object-instance number of the object
|
|
||||||
* @param milliseconds - number of milliseconds elapsed
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
Lighting_Output_Ramp_Handler(uint32_t object_instance, uint16_t milliseconds)
|
|
||||||
{
|
|
||||||
float old_value, target_value, min_value, max_value, step_value, steps;
|
|
||||||
struct object_data *pObject;
|
|
||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
|
||||||
if (!pObject) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
old_value = pObject->Tracking_Value;
|
|
||||||
min_value = pObject->Min_Actual_Value;
|
|
||||||
max_value = pObject->Max_Actual_Value;
|
|
||||||
target_value = pObject->Lighting_Command.target_level;
|
|
||||||
/* clamp target within min/max, if needed */
|
|
||||||
if (isgreater(target_value, max_value)) {
|
|
||||||
target_value = max_value;
|
|
||||||
}
|
|
||||||
if (isless(target_value, min_value)) {
|
|
||||||
target_value = min_value;
|
|
||||||
}
|
|
||||||
/* determine the number of steps */
|
|
||||||
if (milliseconds <= 1000) {
|
|
||||||
/* percent per second */
|
|
||||||
steps = linear_interpolate(
|
|
||||||
0.0f, (float)milliseconds, 1000.0f, 0.0f,
|
|
||||||
pObject->Lighting_Command.ramp_rate);
|
|
||||||
} else {
|
|
||||||
steps = ((float)milliseconds * pObject->Lighting_Command.ramp_rate) /
|
|
||||||
1000.0f;
|
|
||||||
}
|
|
||||||
if (!islessgreater(pObject->Tracking_Value, target_value)) {
|
|
||||||
/* stop ramping */
|
|
||||||
pObject->Tracking_Value = target_value;
|
|
||||||
pObject->In_Progress = BACNET_LIGHTING_IDLE;
|
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_STOP;
|
|
||||||
} else {
|
|
||||||
if (isless(old_value, target_value)) {
|
|
||||||
step_value = old_value + steps;
|
|
||||||
if (isgreater(step_value, target_value)) {
|
|
||||||
/* stop ramping */
|
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_STOP;
|
|
||||||
}
|
|
||||||
} else if (isgreater(old_value, target_value)) {
|
|
||||||
debug_printf(
|
|
||||||
"LO[%u] Ramp Handler Down steps=%f tracking=%f\n",
|
|
||||||
object_instance, (double)steps, (double)old_value);
|
|
||||||
if (isgreater(old_value, steps)) {
|
|
||||||
step_value = old_value - steps;
|
|
||||||
} else {
|
|
||||||
step_value = target_value;
|
|
||||||
}
|
|
||||||
if (isless(step_value, target_value)) {
|
|
||||||
/* stop ramping */
|
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_STOP;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
debug_printf(
|
|
||||||
"LO[%u] Ramp Handler at target=%f tracking=%f\n",
|
|
||||||
object_instance, (double)target_value, (double)old_value);
|
|
||||||
/* stop ramping */
|
|
||||||
step_value = target_value;
|
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_STOP;
|
|
||||||
}
|
|
||||||
/* clamp target within min/max, if needed */
|
|
||||||
if (isgreater(step_value, max_value)) {
|
|
||||||
step_value = max_value;
|
|
||||||
}
|
|
||||||
if (isless(step_value, min_value)) {
|
|
||||||
step_value = min_value;
|
|
||||||
}
|
|
||||||
pObject->Tracking_Value = step_value;
|
|
||||||
if (pObject->Lighting_Command.operation == BACNET_LIGHTS_STOP) {
|
|
||||||
pObject->In_Progress = BACNET_LIGHTING_IDLE;
|
|
||||||
} else {
|
|
||||||
pObject->In_Progress = BACNET_LIGHTING_RAMP_ACTIVE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Lighting_Output_Write_Present_Value_Callback) {
|
|
||||||
Lighting_Output_Write_Present_Value_Callback(
|
|
||||||
object_instance, old_value, pObject->Tracking_Value);
|
|
||||||
} else {
|
|
||||||
debug_printf(
|
|
||||||
"LO[%u] Ramp Handler Operation=%s Value=%f\n", object_instance,
|
|
||||||
bactext_lighting_operation_name(
|
|
||||||
pObject->Lighting_Command.operation),
|
|
||||||
(double)pObject->Tracking_Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the object tracking value while stepping
|
|
||||||
*
|
|
||||||
* Commands Present_Value to a value equal to the Tracking_Value
|
|
||||||
* plus the step-increment. The resulting sum shall be clamped to
|
|
||||||
* Min_Actual_Value and Max_Actual_Value
|
|
||||||
*
|
|
||||||
* @param object_instance - object-instance number of the object
|
|
||||||
*/
|
|
||||||
static void Lighting_Output_Step_Up_Handler(uint32_t object_instance)
|
|
||||||
{
|
|
||||||
float old_value, target_value, min_value, max_value, step_value;
|
|
||||||
struct object_data *pObject;
|
|
||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
|
||||||
if (!pObject) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
old_value = pObject->Tracking_Value;
|
|
||||||
min_value = pObject->Min_Actual_Value;
|
|
||||||
max_value = pObject->Max_Actual_Value;
|
|
||||||
step_value = pObject->Lighting_Command.step_increment;
|
|
||||||
/* inhibit ON if the value is already OFF */
|
|
||||||
if (isgreaterequal(old_value, min_value)) {
|
|
||||||
target_value = old_value + step_value;
|
|
||||||
/* clamp target within min/max, if needed */
|
|
||||||
if (isgreater(target_value, max_value)) {
|
|
||||||
target_value = max_value;
|
|
||||||
}
|
|
||||||
if (isless(target_value, min_value)) {
|
|
||||||
target_value = min_value;
|
|
||||||
}
|
|
||||||
pObject->Present_Value = target_value;
|
|
||||||
pObject->Tracking_Value = target_value;
|
|
||||||
pObject->In_Progress = BACNET_LIGHTING_IDLE;
|
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_STOP;
|
|
||||||
if (Lighting_Output_Write_Present_Value_Callback) {
|
|
||||||
Lighting_Output_Write_Present_Value_Callback(
|
|
||||||
object_instance, old_value, pObject->Tracking_Value);
|
|
||||||
} else {
|
|
||||||
debug_printf(
|
|
||||||
"LO[%u] Step Up Handler Operation=%s Value=%f\n",
|
|
||||||
object_instance,
|
|
||||||
bactext_lighting_operation_name(
|
|
||||||
pObject->Lighting_Command.operation),
|
|
||||||
(double)pObject->Tracking_Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the object tracking value while stepping
|
|
||||||
*
|
|
||||||
* Commands Present_Value to a value equal to the Tracking_Value
|
|
||||||
* plus the step-increment. The resulting sum shall be clamped to
|
|
||||||
* Min_Actual_Value and Max_Actual_Value
|
|
||||||
*
|
|
||||||
* @param object_instance - object-instance number of the object
|
|
||||||
*/
|
|
||||||
static void Lighting_Output_Step_Down_Handler(uint32_t object_instance)
|
|
||||||
{
|
|
||||||
float old_value, target_value, min_value, max_value, step_value;
|
|
||||||
struct object_data *pObject;
|
|
||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
|
||||||
if (!pObject) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
old_value = target_value = pObject->Tracking_Value;
|
|
||||||
min_value = pObject->Min_Actual_Value;
|
|
||||||
max_value = pObject->Max_Actual_Value;
|
|
||||||
step_value = pObject->Lighting_Command.step_increment;
|
|
||||||
if (isgreaterequal(target_value, step_value)) {
|
|
||||||
target_value -= step_value;
|
|
||||||
} else {
|
|
||||||
target_value = 0.0;
|
|
||||||
}
|
|
||||||
/* clamp target within min/max, if needed */
|
|
||||||
if (isgreater(target_value, max_value)) {
|
|
||||||
target_value = max_value;
|
|
||||||
}
|
|
||||||
if (isless(target_value, min_value)) {
|
|
||||||
target_value = min_value;
|
|
||||||
}
|
|
||||||
pObject->Present_Value = target_value;
|
|
||||||
pObject->Tracking_Value = target_value;
|
|
||||||
pObject->In_Progress = BACNET_LIGHTING_IDLE;
|
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_STOP;
|
|
||||||
if (Lighting_Output_Write_Present_Value_Callback) {
|
|
||||||
Lighting_Output_Write_Present_Value_Callback(
|
|
||||||
object_instance, old_value, pObject->Tracking_Value);
|
|
||||||
} else {
|
|
||||||
debug_printf(
|
|
||||||
"LO[%u] Step Down Handler Operation=%s Value=%f\n", object_instance,
|
|
||||||
bactext_lighting_operation_name(
|
|
||||||
pObject->Lighting_Command.operation),
|
|
||||||
(double)pObject->Tracking_Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the object tracking value while stepping
|
|
||||||
*
|
|
||||||
* Commands Present_Value to a value equal to the Tracking_Value
|
|
||||||
* plus the step-increment. The resulting sum shall be clamped to
|
|
||||||
* Min_Actual_Value and Max_Actual_Value
|
|
||||||
*
|
|
||||||
* @param object_instance - object-instance number of the object
|
|
||||||
*/
|
|
||||||
static void Lighting_Output_Step_On_Handler(uint32_t object_instance)
|
|
||||||
{
|
|
||||||
float old_value, target_value, min_value, max_value, step_value;
|
|
||||||
struct object_data *pObject;
|
|
||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
|
||||||
if (!pObject) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
old_value = target_value = pObject->Tracking_Value;
|
|
||||||
min_value = pObject->Min_Actual_Value;
|
|
||||||
max_value = pObject->Max_Actual_Value;
|
|
||||||
step_value = pObject->Lighting_Command.step_increment;
|
|
||||||
target_value += step_value;
|
|
||||||
/* clamp target within min/max, if needed */
|
|
||||||
if (isgreater(target_value, max_value)) {
|
|
||||||
target_value = max_value;
|
|
||||||
}
|
|
||||||
if (isless(target_value, min_value)) {
|
|
||||||
target_value = min_value;
|
|
||||||
}
|
|
||||||
pObject->Present_Value = target_value;
|
|
||||||
pObject->Tracking_Value = target_value;
|
|
||||||
pObject->In_Progress = BACNET_LIGHTING_IDLE;
|
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_STOP;
|
|
||||||
if (Lighting_Output_Write_Present_Value_Callback) {
|
|
||||||
Lighting_Output_Write_Present_Value_Callback(
|
|
||||||
object_instance, old_value, pObject->Tracking_Value);
|
|
||||||
} else {
|
|
||||||
debug_printf(
|
|
||||||
"LO[%u] Step On Handler Operation=%s Value=%f\n", object_instance,
|
|
||||||
bactext_lighting_operation_name(
|
|
||||||
pObject->Lighting_Command.operation),
|
|
||||||
(double)pObject->Tracking_Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the object tracking value while stepping
|
|
||||||
*
|
|
||||||
* Commands Present_Value to a value equal to the Tracking_Value
|
|
||||||
* plus the step-increment. The resulting sum shall be clamped to
|
|
||||||
* Min_Actual_Value and Max_Actual_Value
|
|
||||||
*
|
|
||||||
* @param object_instance - object-instance number of the object
|
|
||||||
*/
|
|
||||||
static void Lighting_Output_Step_Off_Handler(uint32_t object_instance)
|
|
||||||
{
|
|
||||||
float old_value, target_value, min_value, max_value, step_value;
|
|
||||||
struct object_data *pObject;
|
|
||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
|
||||||
if (!pObject) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
old_value = target_value = pObject->Tracking_Value;
|
|
||||||
min_value = pObject->Min_Actual_Value;
|
|
||||||
max_value = pObject->Max_Actual_Value;
|
|
||||||
step_value = pObject->Lighting_Command.step_increment;
|
|
||||||
if (isgreaterequal(target_value, step_value)) {
|
|
||||||
target_value -= step_value;
|
|
||||||
} else {
|
|
||||||
target_value = 0.0f;
|
|
||||||
}
|
|
||||||
/* clamp target within max */
|
|
||||||
if (isgreater(target_value, max_value)) {
|
|
||||||
target_value = max_value;
|
|
||||||
}
|
|
||||||
/* jump target to OFF if below min */
|
|
||||||
if (isless(target_value, min_value)) {
|
|
||||||
target_value = 0.0f;
|
|
||||||
}
|
|
||||||
pObject->Present_Value = target_value;
|
|
||||||
pObject->Tracking_Value = target_value;
|
|
||||||
pObject->In_Progress = BACNET_LIGHTING_IDLE;
|
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_STOP;
|
|
||||||
if (Lighting_Output_Write_Present_Value_Callback) {
|
|
||||||
Lighting_Output_Write_Present_Value_Callback(
|
|
||||||
object_instance, old_value, pObject->Tracking_Value);
|
|
||||||
} else {
|
|
||||||
debug_printf(
|
|
||||||
"LO[%u] Step Off Handler Operation=%s Value=%f\n", object_instance,
|
|
||||||
bactext_lighting_operation_name(
|
|
||||||
pObject->Lighting_Command.operation),
|
|
||||||
(double)pObject->Tracking_Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the lighting object tracking value per ramp or fade or step
|
* @brief Updates the lighting object tracking value per ramp or fade or step
|
||||||
* @param object_instance - object-instance number of the object
|
* @param object_instance - object-instance number of the object
|
||||||
@@ -2648,39 +2333,20 @@ void Lighting_Output_Timer(uint32_t object_instance, uint16_t milliseconds)
|
|||||||
|
|
||||||
pObject = Keylist_Data(Object_List, object_instance);
|
pObject = Keylist_Data(Object_List, object_instance);
|
||||||
if (pObject) {
|
if (pObject) {
|
||||||
switch (pObject->Lighting_Command.operation) {
|
lighting_command_timer(&pObject->Lighting_Command, milliseconds);
|
||||||
case BACNET_LIGHTS_NONE:
|
}
|
||||||
pObject->In_Progress = BACNET_LIGHTING_IDLE;
|
}
|
||||||
break;
|
|
||||||
case BACNET_LIGHTS_FADE_TO:
|
static void Lighting_Output_Tracking_Value_Callback(
|
||||||
Lighting_Output_Fade_Handler(object_instance, milliseconds);
|
uint32_t object_instance, float old_value, float value)
|
||||||
break;
|
{
|
||||||
case BACNET_LIGHTS_RAMP_TO:
|
struct object_data *pObject;
|
||||||
Lighting_Output_Ramp_Handler(object_instance, milliseconds);
|
|
||||||
break;
|
pObject = Keylist_Data(Object_List, object_instance);
|
||||||
case BACNET_LIGHTS_STEP_UP:
|
if (pObject) {
|
||||||
Lighting_Output_Step_Up_Handler(object_instance);
|
if (Lighting_Command_Tracking_Value_Callback) {
|
||||||
break;
|
Lighting_Command_Tracking_Value_Callback(
|
||||||
case BACNET_LIGHTS_STEP_DOWN:
|
object_instance, old_value, value);
|
||||||
Lighting_Output_Step_Down_Handler(object_instance);
|
|
||||||
break;
|
|
||||||
case BACNET_LIGHTS_STEP_ON:
|
|
||||||
Lighting_Output_Step_On_Handler(object_instance);
|
|
||||||
break;
|
|
||||||
case BACNET_LIGHTS_STEP_OFF:
|
|
||||||
Lighting_Output_Step_Off_Handler(object_instance);
|
|
||||||
break;
|
|
||||||
case BACNET_LIGHTS_WARN:
|
|
||||||
break;
|
|
||||||
case BACNET_LIGHTS_WARN_OFF:
|
|
||||||
break;
|
|
||||||
case BACNET_LIGHTS_WARN_RELINQUISH:
|
|
||||||
break;
|
|
||||||
case BACNET_LIGHTS_STOP:
|
|
||||||
pObject->In_Progress = BACNET_LIGHTING_IDLE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2690,9 +2356,9 @@ void Lighting_Output_Timer(uint32_t object_instance, uint16_t milliseconds)
|
|||||||
* @param cb - callback used to provide indications
|
* @param cb - callback used to provide indications
|
||||||
*/
|
*/
|
||||||
void Lighting_Output_Write_Present_Value_Callback_Set(
|
void Lighting_Output_Write_Present_Value_Callback_Set(
|
||||||
lighting_output_write_present_value_callback cb)
|
lighting_command_tracking_value_callback cb)
|
||||||
{
|
{
|
||||||
Lighting_Output_Write_Present_Value_Callback = cb;
|
Lighting_Command_Tracking_Value_Callback = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2725,16 +2391,17 @@ uint32_t Lighting_Output_Create(uint32_t object_instance)
|
|||||||
pObject->Object_Name = NULL;
|
pObject->Object_Name = NULL;
|
||||||
pObject->Description = NULL;
|
pObject->Description = NULL;
|
||||||
pObject->Present_Value = 0.0f;
|
pObject->Present_Value = 0.0f;
|
||||||
pObject->Tracking_Value = 0.0f;
|
|
||||||
pObject->Physical_Value = 0.0f;
|
pObject->Physical_Value = 0.0f;
|
||||||
pObject->Lighting_Command.operation = BACNET_LIGHTS_NONE;
|
lighting_command_init(&pObject->Lighting_Command);
|
||||||
pObject->Lighting_Command.use_target_level = false;
|
pObject->Lighting_Command.Key = object_instance;
|
||||||
pObject->Lighting_Command.use_ramp_rate = false;
|
pObject->Lighting_Command.Tracking_Value_Callback =
|
||||||
pObject->Lighting_Command.use_step_increment = false;
|
Lighting_Output_Tracking_Value_Callback;
|
||||||
pObject->Lighting_Command.use_fade_time = false;
|
pObject->Last_Lighting_Command.operation = BACNET_LIGHTS_NONE;
|
||||||
pObject->Lighting_Command.use_priority = false;
|
pObject->Last_Lighting_Command.use_target_level = false;
|
||||||
pObject->In_Progress = BACNET_LIGHTING_IDLE;
|
pObject->Last_Lighting_Command.use_ramp_rate = false;
|
||||||
pObject->Out_Of_Service = false;
|
pObject->Last_Lighting_Command.use_step_increment = false;
|
||||||
|
pObject->Last_Lighting_Command.use_fade_time = false;
|
||||||
|
pObject->Last_Lighting_Command.use_priority = false;
|
||||||
pObject->Blink_Warn_Enable = false;
|
pObject->Blink_Warn_Enable = false;
|
||||||
pObject->Egress_Active = false;
|
pObject->Egress_Active = false;
|
||||||
pObject->Egress_Time = 0;
|
pObject->Egress_Time = 0;
|
||||||
@@ -2750,8 +2417,6 @@ uint32_t Lighting_Output_Create(uint32_t object_instance)
|
|||||||
pObject->Relinquish_Default = 0.0f;
|
pObject->Relinquish_Default = 0.0f;
|
||||||
pObject->Power = 0.0f;
|
pObject->Power = 0.0f;
|
||||||
pObject->Instantaneous_Power = 0.0f;
|
pObject->Instantaneous_Power = 0.0f;
|
||||||
pObject->Min_Actual_Value = 0.0f;
|
|
||||||
pObject->Max_Actual_Value = 100.0f;
|
|
||||||
pObject->Lighting_Command_Default_Priority = 16;
|
pObject->Lighting_Command_Default_Priority = 16;
|
||||||
pObject->Color_Override = false;
|
pObject->Color_Override = false;
|
||||||
pObject->Color_Reference.type = OBJECT_COLOR;
|
pObject->Color_Reference.type = OBJECT_COLOR;
|
||||||
|
|||||||
@@ -15,15 +15,7 @@
|
|||||||
#include "bacnet/bacerror.h"
|
#include "bacnet/bacerror.h"
|
||||||
#include "bacnet/rp.h"
|
#include "bacnet/rp.h"
|
||||||
#include "bacnet/wp.h"
|
#include "bacnet/wp.h"
|
||||||
|
#include "bacnet/basic/sys/lighting_command.h"
|
||||||
/**
|
|
||||||
* @brief Callback for write present value request
|
|
||||||
* @param object_instance - object-instance number of the object
|
|
||||||
* @param old_value - value prior to write
|
|
||||||
* @param value - value of the write
|
|
||||||
*/
|
|
||||||
typedef void (*lighting_output_write_present_value_callback)(
|
|
||||||
uint32_t object_instance, float old_value, float value);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -177,7 +169,7 @@ void Lighting_Output_Timer(uint32_t object_instance, uint16_t milliseconds);
|
|||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void Lighting_Output_Write_Present_Value_Callback_Set(
|
void Lighting_Output_Write_Present_Value_Callback_Set(
|
||||||
lighting_output_write_present_value_callback cb);
|
lighting_command_tracking_value_callback cb);
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
uint32_t Lighting_Output_Create(uint32_t object_instance);
|
uint32_t Lighting_Output_Create(uint32_t object_instance);
|
||||||
|
|||||||
@@ -0,0 +1,644 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief dimming brightness engine based on lighting commands
|
||||||
|
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
* @date 2022
|
||||||
|
* @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
|
||||||
|
*/
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "linear.h"
|
||||||
|
#include "debug.h"
|
||||||
|
/* me! */
|
||||||
|
#include "lighting_command.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for tracking value updates
|
||||||
|
* @param data - dimmer data
|
||||||
|
* @param old_value - value prior to write
|
||||||
|
* @param value - value of the write
|
||||||
|
*/
|
||||||
|
static void lighting_command_tracking_value_notify(
|
||||||
|
struct bacnet_lighting_command_data *data, float old_value, float value)
|
||||||
|
{
|
||||||
|
if (data->Tracking_Value_Callback) {
|
||||||
|
if (!data->Out_Of_Service) {
|
||||||
|
/* clamp value within trim values, if non-zero */
|
||||||
|
if (isless(value, 1.0f)) {
|
||||||
|
/* jump target to OFF if below normalized min */
|
||||||
|
value = 0.0f;
|
||||||
|
} else if (isgreater(value, data->High_Trim_Value)) {
|
||||||
|
value = data->High_Trim_Value;
|
||||||
|
} else if (isless(value, data->Low_Trim_Value)) {
|
||||||
|
value = data->Low_Trim_Value;
|
||||||
|
}
|
||||||
|
data->Tracking_Value_Callback(data->Key, old_value, value);
|
||||||
|
} else {
|
||||||
|
debug_printf("Lighting-Command[%lu]-Out-of-Service\n", data->Key);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug_printf(
|
||||||
|
"Lighting-Command[%lu]-Tracking-Value=%f\n", data->Key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the timing for a single Lighting Output object Fade
|
||||||
|
*
|
||||||
|
* @param data [in] dimmer data
|
||||||
|
* @param milliseconds - number of milliseconds elapsed since previously
|
||||||
|
* called. Works best when called about every 10 milliseconds.
|
||||||
|
*/
|
||||||
|
static void lighting_command_fade_handler(
|
||||||
|
struct bacnet_lighting_command_data *data, uint16_t milliseconds)
|
||||||
|
{
|
||||||
|
float old_value;
|
||||||
|
float x1, x2, x3, y1, y3;
|
||||||
|
float target_value, min_value, max_value;
|
||||||
|
|
||||||
|
old_value = data->Tracking_Value;
|
||||||
|
min_value = data->Min_Actual_Value;
|
||||||
|
max_value = data->Max_Actual_Value;
|
||||||
|
target_value = data->Target_Level;
|
||||||
|
/* clamp target within min/max */
|
||||||
|
if (isgreater(target_value, max_value)) {
|
||||||
|
target_value = max_value;
|
||||||
|
}
|
||||||
|
if (isless(target_value, min_value)) {
|
||||||
|
target_value = min_value;
|
||||||
|
}
|
||||||
|
if ((milliseconds >= data->Fade_Time) ||
|
||||||
|
(!islessgreater(data->Tracking_Value, target_value))) {
|
||||||
|
/* stop fading */
|
||||||
|
if (isless(data->Target_Level, 1.0f)) {
|
||||||
|
/* jump target to OFF if below normalized min */
|
||||||
|
data->Tracking_Value = 0.0f;
|
||||||
|
} else {
|
||||||
|
data->Tracking_Value = target_value;
|
||||||
|
}
|
||||||
|
data->In_Progress = BACNET_LIGHTING_IDLE;
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||||
|
data->Fade_Time = 0;
|
||||||
|
} else {
|
||||||
|
/* fading */
|
||||||
|
x1 = 0.0f;
|
||||||
|
x2 = (float)milliseconds;
|
||||||
|
x3 = (float)data->Fade_Time;
|
||||||
|
if (isless(old_value, min_value)) {
|
||||||
|
y1 = min_value;
|
||||||
|
} else {
|
||||||
|
y1 = old_value;
|
||||||
|
}
|
||||||
|
y3 = target_value;
|
||||||
|
data->Tracking_Value = linear_interpolate(x1, x2, x3, y1, y3);
|
||||||
|
data->Fade_Time -= milliseconds;
|
||||||
|
data->In_Progress = BACNET_LIGHTING_FADE_ACTIVE;
|
||||||
|
}
|
||||||
|
lighting_command_tracking_value_notify(
|
||||||
|
data, old_value, data->Tracking_Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the object tracking value while ramping
|
||||||
|
*
|
||||||
|
* Commands the dimmer to ramp from the current Tracking_Value to the
|
||||||
|
* target-level specified in the command. The ramp operation
|
||||||
|
* changes the output from its current value to target-level,
|
||||||
|
* at a particular percent per second defined by ramp-rate.
|
||||||
|
* While the ramp operation is executing, In_Progress shall be set
|
||||||
|
* to RAMP_ACTIVE, and Tracking_Value shall be updated to reflect the current
|
||||||
|
* progress of the ramp. <target-level> shall be clamped to
|
||||||
|
* Min_Actual_Value and Max_Actual_Value.
|
||||||
|
*
|
||||||
|
* @param data [in] dimmer data
|
||||||
|
* @param milliseconds - number of milliseconds elapsed
|
||||||
|
*/
|
||||||
|
static void lighting_command_ramp_handler(
|
||||||
|
struct bacnet_lighting_command_data *data, uint16_t milliseconds)
|
||||||
|
{
|
||||||
|
float old_value, target_value, min_value, max_value, step_value, steps;
|
||||||
|
|
||||||
|
old_value = data->Tracking_Value;
|
||||||
|
min_value = data->Min_Actual_Value;
|
||||||
|
max_value = data->Max_Actual_Value;
|
||||||
|
target_value = data->Target_Level;
|
||||||
|
/* clamp target within min/max, if needed */
|
||||||
|
if (isgreater(target_value, max_value)) {
|
||||||
|
target_value = max_value;
|
||||||
|
}
|
||||||
|
if (isless(target_value, min_value)) {
|
||||||
|
target_value = min_value;
|
||||||
|
}
|
||||||
|
/* determine the number of steps */
|
||||||
|
if (milliseconds <= 1000) {
|
||||||
|
/* percent per second */
|
||||||
|
steps = linear_interpolate(
|
||||||
|
0.0f, (float)milliseconds, 1000.0f, 0.0f, data->Ramp_Rate);
|
||||||
|
} else {
|
||||||
|
steps = ((float)milliseconds * data->Ramp_Rate) / 1000.0f;
|
||||||
|
}
|
||||||
|
if (!islessgreater(data->Tracking_Value, target_value)) {
|
||||||
|
/* stop ramping */
|
||||||
|
if (isless(data->Target_Level, 1.0f)) {
|
||||||
|
/* jump target to OFF if below normalized min */
|
||||||
|
data->Tracking_Value = 0.0f;
|
||||||
|
} else {
|
||||||
|
data->Tracking_Value = target_value;
|
||||||
|
}
|
||||||
|
data->In_Progress = BACNET_LIGHTING_IDLE;
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||||
|
} else {
|
||||||
|
if (isless(old_value, target_value)) {
|
||||||
|
step_value = old_value + steps;
|
||||||
|
if (isgreater(step_value, target_value)) {
|
||||||
|
/* stop ramping */
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||||
|
}
|
||||||
|
} else if (isgreater(old_value, target_value)) {
|
||||||
|
if (isgreater(old_value, steps)) {
|
||||||
|
step_value = old_value - steps;
|
||||||
|
} else {
|
||||||
|
step_value = target_value;
|
||||||
|
}
|
||||||
|
if (isless(step_value, target_value)) {
|
||||||
|
/* stop ramping */
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* stop ramping */
|
||||||
|
step_value = target_value;
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||||
|
}
|
||||||
|
/* clamp target within min/max, if needed */
|
||||||
|
if (isgreater(step_value, max_value)) {
|
||||||
|
step_value = max_value;
|
||||||
|
}
|
||||||
|
if (isless(step_value, min_value)) {
|
||||||
|
step_value = min_value;
|
||||||
|
}
|
||||||
|
if (data->Lighting_Operation == BACNET_LIGHTS_STOP) {
|
||||||
|
if (isless(data->Target_Level, 1.0f)) {
|
||||||
|
/* jump target to OFF if below normalized min */
|
||||||
|
data->Tracking_Value = 0.0f;
|
||||||
|
} else {
|
||||||
|
data->Tracking_Value = step_value;
|
||||||
|
}
|
||||||
|
data->In_Progress = BACNET_LIGHTING_IDLE;
|
||||||
|
} else {
|
||||||
|
data->Tracking_Value = step_value;
|
||||||
|
data->In_Progress = BACNET_LIGHTING_RAMP_ACTIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lighting_command_tracking_value_notify(
|
||||||
|
data, old_value, data->Tracking_Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clamps the step increment value
|
||||||
|
*
|
||||||
|
* @param step_increment [in] step increment value
|
||||||
|
* @return clamped step increment value
|
||||||
|
*/
|
||||||
|
static float lighting_command_step_increment_clamp(float step_increment)
|
||||||
|
{
|
||||||
|
if (isless(step_increment, 0.1f)) {
|
||||||
|
step_increment = 0.1f;
|
||||||
|
}
|
||||||
|
if (isgreater(step_increment, 100.0f)) {
|
||||||
|
step_increment = 100.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return step_increment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the object tracking value while stepping
|
||||||
|
*
|
||||||
|
* Commands the dimmer to a value equal to the Tracking_Value
|
||||||
|
* plus the step-increment. The resulting sum shall be clamped to
|
||||||
|
* Min_Actual_Value and Max_Actual_Value
|
||||||
|
*
|
||||||
|
* @param data [in] dimmer data
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
lighting_command_step_up_handler(struct bacnet_lighting_command_data *data)
|
||||||
|
{
|
||||||
|
float old_value, target_value, min_value, max_value, step_value;
|
||||||
|
|
||||||
|
old_value = data->Tracking_Value;
|
||||||
|
min_value = data->Min_Actual_Value;
|
||||||
|
max_value = data->Max_Actual_Value;
|
||||||
|
step_value = lighting_command_step_increment_clamp(data->Step_Increment);
|
||||||
|
/* inhibit ON if the value is already OFF */
|
||||||
|
if (isgreaterequal(old_value, min_value)) {
|
||||||
|
target_value = old_value + step_value;
|
||||||
|
/* clamp target within min/max, if needed */
|
||||||
|
if (isgreater(target_value, max_value)) {
|
||||||
|
target_value = max_value;
|
||||||
|
}
|
||||||
|
if (isless(target_value, min_value)) {
|
||||||
|
target_value = min_value;
|
||||||
|
}
|
||||||
|
data->Tracking_Value = target_value;
|
||||||
|
data->In_Progress = BACNET_LIGHTING_IDLE;
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||||
|
lighting_command_tracking_value_notify(
|
||||||
|
data, old_value, data->Tracking_Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize the value to the min/max range
|
||||||
|
* @param value [in] value to normalize
|
||||||
|
* @param min_value [in] minimum value
|
||||||
|
* @param max_value [in] maximum value
|
||||||
|
* @return normalized value
|
||||||
|
*/
|
||||||
|
static float
|
||||||
|
lighting_command_normalize_value(float value, float min_value, float max_value)
|
||||||
|
{
|
||||||
|
float normalized_value;
|
||||||
|
/* clamp target within min/max, if needed */
|
||||||
|
if (isgreater(value, max_value)) {
|
||||||
|
/* clamp target within max */
|
||||||
|
normalized_value = max_value;
|
||||||
|
} else if (isless(value, 1.0f)) {
|
||||||
|
/* jump target to OFF if below normalized min */
|
||||||
|
normalized_value = 0.0f;
|
||||||
|
} else if (isless(value, min_value)) {
|
||||||
|
/* clamp target within min */
|
||||||
|
normalized_value = min_value;
|
||||||
|
} else {
|
||||||
|
normalized_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the object tracking value while stepping
|
||||||
|
*
|
||||||
|
* Commands the dimmer to a value equal to the Tracking_Value
|
||||||
|
* plus the step-increment. The resulting sum shall be clamped to
|
||||||
|
* Min_Actual_Value and Max_Actual_Value
|
||||||
|
*
|
||||||
|
* @param data [in] dimmer data
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
lighting_command_step_down_handler(struct bacnet_lighting_command_data *data)
|
||||||
|
{
|
||||||
|
float old_value, target_value, min_value, max_value, step_value;
|
||||||
|
|
||||||
|
old_value = target_value = data->Tracking_Value;
|
||||||
|
min_value = data->Min_Actual_Value;
|
||||||
|
max_value = data->Max_Actual_Value;
|
||||||
|
step_value = lighting_command_step_increment_clamp(data->Step_Increment);
|
||||||
|
if (isgreaterequal(target_value, step_value)) {
|
||||||
|
target_value -= step_value;
|
||||||
|
} else {
|
||||||
|
target_value = 0.0f;
|
||||||
|
}
|
||||||
|
/* clamp target within min/max, if needed */
|
||||||
|
if (isgreater(target_value, max_value)) {
|
||||||
|
/* clamp target within max */
|
||||||
|
target_value = max_value;
|
||||||
|
}
|
||||||
|
if (isless(target_value, min_value)) {
|
||||||
|
/* clamp target within min */
|
||||||
|
target_value = min_value;
|
||||||
|
}
|
||||||
|
data->Tracking_Value = target_value;
|
||||||
|
data->In_Progress = BACNET_LIGHTING_IDLE;
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||||
|
lighting_command_tracking_value_notify(
|
||||||
|
data, old_value, data->Tracking_Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the object tracking value while stepping
|
||||||
|
*
|
||||||
|
* Commands the dimmer to a value equal to the Tracking_Value
|
||||||
|
* plus the step-increment. The resulting sum shall be clamped to
|
||||||
|
* Min_Actual_Value and Max_Actual_Value
|
||||||
|
*
|
||||||
|
* @param data [in] dimmer data
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
lighting_command_step_on_handler(struct bacnet_lighting_command_data *data)
|
||||||
|
{
|
||||||
|
float old_value, target_value, min_value, max_value, step_value;
|
||||||
|
|
||||||
|
old_value = target_value = data->Tracking_Value;
|
||||||
|
min_value = data->Min_Actual_Value;
|
||||||
|
max_value = data->Max_Actual_Value;
|
||||||
|
step_value = lighting_command_step_increment_clamp(data->Step_Increment);
|
||||||
|
target_value += step_value;
|
||||||
|
data->Tracking_Value =
|
||||||
|
lighting_command_normalize_value(target_value, min_value, max_value);
|
||||||
|
data->In_Progress = BACNET_LIGHTING_IDLE;
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||||
|
lighting_command_tracking_value_notify(
|
||||||
|
data, old_value, data->Tracking_Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the object tracking value while stepping
|
||||||
|
*
|
||||||
|
* Commands the dimmer to a value equal to the Tracking_Value
|
||||||
|
* plus the step-increment. The resulting sum shall be clamped to
|
||||||
|
* Min_Actual_Value and Max_Actual_Value
|
||||||
|
*
|
||||||
|
* @param data [in] dimmer data
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
lighting_command_step_off_handler(struct bacnet_lighting_command_data *data)
|
||||||
|
{
|
||||||
|
float old_value, target_value, min_value, max_value, step_value;
|
||||||
|
|
||||||
|
old_value = target_value = data->Tracking_Value;
|
||||||
|
min_value = data->Min_Actual_Value;
|
||||||
|
max_value = data->Max_Actual_Value;
|
||||||
|
step_value = lighting_command_step_increment_clamp(data->Step_Increment);
|
||||||
|
if (isgreaterequal(target_value, step_value)) {
|
||||||
|
target_value -= step_value;
|
||||||
|
} else {
|
||||||
|
target_value = 0.0f;
|
||||||
|
}
|
||||||
|
data->Tracking_Value =
|
||||||
|
lighting_command_normalize_value(target_value, min_value, max_value);
|
||||||
|
data->In_Progress = BACNET_LIGHTING_IDLE;
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||||
|
lighting_command_tracking_value_notify(
|
||||||
|
data, old_value, data->Tracking_Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the object tracking value while blinking
|
||||||
|
*
|
||||||
|
* @note When the value of In_Progress is NOT_CONTROLLED or OTHER,
|
||||||
|
* the value of Tracking_Value shall be a local matter.
|
||||||
|
*
|
||||||
|
* @note The WARN, WARN_RELINQUISH, and WARN_OFF lighting
|
||||||
|
* commands, as well as writing one of the special values to the
|
||||||
|
* Present_Value property, cause a blink-warn notification
|
||||||
|
* to occur at the specified priority. A blink-warn
|
||||||
|
* notification is used to warn the occupants that the lights
|
||||||
|
* are about to turn off, giving the occupants the opportunity
|
||||||
|
* to exit the space or to override the lights for a period of time.
|
||||||
|
*
|
||||||
|
* The actual blink-warn notification mechanism shall be a local matter.
|
||||||
|
* The physical lights may blink once, multiple times, or
|
||||||
|
* repeatedly. They may also go bright, go dim, or signal a notification
|
||||||
|
* through some other means. In some circumstances, no blink-warn
|
||||||
|
* notification will occur at all. The blink-warn notification
|
||||||
|
* shall not be reflected in the priority array or the tracking
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* @param data [in] dimmer data
|
||||||
|
* @param milliseconds - number of milliseconds elapsed
|
||||||
|
*/
|
||||||
|
static void lighting_command_blink_handler(
|
||||||
|
struct bacnet_lighting_command_data *data, uint16_t milliseconds)
|
||||||
|
{
|
||||||
|
float old_value, target_value, min_value, max_value;
|
||||||
|
|
||||||
|
old_value = data->Tracking_Value;
|
||||||
|
min_value = data->Min_Actual_Value;
|
||||||
|
max_value = data->Max_Actual_Value;
|
||||||
|
/* detect 'end' operation */
|
||||||
|
if (data->Blink.Duration > milliseconds) {
|
||||||
|
data->Blink.Duration -= milliseconds;
|
||||||
|
} else {
|
||||||
|
data->Blink.Duration = 0;
|
||||||
|
}
|
||||||
|
if (data->Blink.Duration == 0) {
|
||||||
|
/* 'end' operation */
|
||||||
|
data->In_Progress = BACNET_LIGHTING_IDLE;
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||||
|
target_value = data->Blink.End_Value;
|
||||||
|
} else if (data->Blink.Target_Interval == 0) {
|
||||||
|
/* only 'on' level */
|
||||||
|
target_value = data->Blink.On_Value;
|
||||||
|
} else {
|
||||||
|
/* 'blink' operation */
|
||||||
|
if (data->Blink.State) {
|
||||||
|
target_value = data->Blink.On_Value;
|
||||||
|
} else {
|
||||||
|
target_value = data->Blink.Off_Value;
|
||||||
|
}
|
||||||
|
/* detect next interval */
|
||||||
|
if (data->Blink.Interval > milliseconds) {
|
||||||
|
data->Blink.Interval -= milliseconds;
|
||||||
|
} else {
|
||||||
|
data->Blink.Interval = 0;
|
||||||
|
}
|
||||||
|
if (data->Blink.Interval == 0) {
|
||||||
|
/* next blink */
|
||||||
|
data->Blink.Interval = data->Blink.Target_Interval;
|
||||||
|
data->Blink.State = !data->Blink.State;
|
||||||
|
if (data->Blink.State) {
|
||||||
|
/* end of 'off' operation when counting */
|
||||||
|
if ((data->Blink.Count > 0) &&
|
||||||
|
(data->Blink.Count != UINT16_MAX)) {
|
||||||
|
data->Blink.Count--;
|
||||||
|
}
|
||||||
|
if (data->Blink.Count == 0) {
|
||||||
|
/* 'end' operation */
|
||||||
|
data->In_Progress = BACNET_LIGHTING_IDLE;
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||||
|
target_value = data->Blink.End_Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
target_value =
|
||||||
|
lighting_command_normalize_value(target_value, min_value, max_value);
|
||||||
|
/* note: The blink-warn notifications shall not be reflected
|
||||||
|
in the tracking value. */
|
||||||
|
if (data->In_Progress == BACNET_LIGHTING_IDLE) {
|
||||||
|
data->Tracking_Value = target_value;
|
||||||
|
}
|
||||||
|
lighting_command_tracking_value_notify(data, old_value, target_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Updates the dimmer tracking value per ramp or fade or step
|
||||||
|
* @param data [in] dimmer data
|
||||||
|
* @param milliseconds - number of milliseconds elapsed since previously
|
||||||
|
* called. Suggest that this is called every 10 milliseconds.
|
||||||
|
*/
|
||||||
|
void lighting_command_timer(
|
||||||
|
struct bacnet_lighting_command_data *data, uint16_t milliseconds)
|
||||||
|
{
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (data->Lighting_Operation) {
|
||||||
|
case BACNET_LIGHTS_NONE:
|
||||||
|
data->In_Progress = BACNET_LIGHTING_IDLE;
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_FADE_TO:
|
||||||
|
lighting_command_fade_handler(data, milliseconds);
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_RAMP_TO:
|
||||||
|
lighting_command_ramp_handler(data, milliseconds);
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_STEP_UP:
|
||||||
|
lighting_command_step_up_handler(data);
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_STEP_DOWN:
|
||||||
|
lighting_command_step_down_handler(data);
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_STEP_ON:
|
||||||
|
lighting_command_step_on_handler(data);
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_STEP_OFF:
|
||||||
|
lighting_command_step_off_handler(data);
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_WARN:
|
||||||
|
case BACNET_LIGHTS_WARN_OFF:
|
||||||
|
case BACNET_LIGHTS_WARN_RELINQUISH:
|
||||||
|
lighting_command_blink_handler(data, milliseconds);
|
||||||
|
break;
|
||||||
|
case BACNET_LIGHTS_STOP:
|
||||||
|
data->In_Progress = BACNET_LIGHTING_IDLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the lighting command if the priority is active
|
||||||
|
* @param data [in] dimmer data
|
||||||
|
* @param value [in] BACnet lighting value
|
||||||
|
* @param fade_time [in] BACnet lighting fade time
|
||||||
|
*/
|
||||||
|
void lighting_command_fade_to(
|
||||||
|
struct bacnet_lighting_command_data *data, float value, uint32_t fade_time)
|
||||||
|
{
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data->Fade_Time = fade_time;
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_FADE_TO;
|
||||||
|
data->Target_Level = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the dimmer command to perform a ramp to value operation
|
||||||
|
* @param data [in] dimmer object instance
|
||||||
|
* @param value [in] target lighting value
|
||||||
|
* @param ramp_rate [in] target ramp rate in percent per second 0.1 to 100.0
|
||||||
|
*/
|
||||||
|
void lighting_command_ramp_to(
|
||||||
|
struct bacnet_lighting_command_data *data, float value, float ramp_rate)
|
||||||
|
{
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data->Ramp_Rate = ramp_rate;
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_RAMP_TO;
|
||||||
|
data->Target_Level = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the lighting command if the priority is active
|
||||||
|
* @param data [in] dimmer object instance
|
||||||
|
* @param operation [in] BACnet lighting operation
|
||||||
|
* @param step_increment [in] BACnet lighting step increment value
|
||||||
|
*/
|
||||||
|
void lighting_command_step(
|
||||||
|
struct bacnet_lighting_command_data *data,
|
||||||
|
BACNET_LIGHTING_OPERATION operation,
|
||||||
|
float step_increment)
|
||||||
|
{
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data->Lighting_Operation = operation;
|
||||||
|
data->Fade_Time = 0;
|
||||||
|
data->Ramp_Rate = 0.0f;
|
||||||
|
data->Step_Increment = step_increment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the lighting command to blink mode
|
||||||
|
* @param data [in] dimmer object instance
|
||||||
|
* @param operation [in] BACnet lighting operation for blink warn
|
||||||
|
* @param blink [in] BACnet blink data
|
||||||
|
*/
|
||||||
|
void lighting_command_blink_warn(
|
||||||
|
struct bacnet_lighting_command_data *data,
|
||||||
|
BACNET_LIGHTING_OPERATION operation,
|
||||||
|
struct bacnet_lighting_command_warn_data *blink)
|
||||||
|
{
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data->Lighting_Operation = operation;
|
||||||
|
data->Blink.Target_Interval = blink->Interval;
|
||||||
|
data->Blink.Duration = blink->Duration;
|
||||||
|
data->Blink.Count = blink->Count;
|
||||||
|
data->Blink.On_Value = blink->On_Value;
|
||||||
|
data->Blink.Off_Value = blink->Off_Value;
|
||||||
|
data->Blink.End_Value = blink->End_Value;
|
||||||
|
/* start blinking */
|
||||||
|
data->In_Progress = BACNET_LIGHTING_OTHER;
|
||||||
|
/* configure next interval */
|
||||||
|
data->Blink.State = false;
|
||||||
|
data->Blink.Interval = blink->Interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
void lighting_command_stop(struct bacnet_lighting_command_data *data)
|
||||||
|
{
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
void lighting_command_none(struct bacnet_lighting_command_data *data)
|
||||||
|
{
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lighting_command_init(struct bacnet_lighting_command_data *data)
|
||||||
|
{
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data->Tracking_Value = 0.0f;
|
||||||
|
data->Lighting_Operation = BACNET_LIGHTS_NONE;
|
||||||
|
data->In_Progress = BACNET_LIGHTING_IDLE;
|
||||||
|
data->Out_Of_Service = false;
|
||||||
|
data->Min_Actual_Value = 1.0f;
|
||||||
|
data->Max_Actual_Value = 100.0f;
|
||||||
|
data->Low_Trim_Value = 1.0f;
|
||||||
|
data->High_Trim_Value = 100.0f;
|
||||||
|
data->Blink.On_Value = 100.0f;
|
||||||
|
data->Blink.Off_Value = 0.0f;
|
||||||
|
data->Blink.End_Value = 0.0f;
|
||||||
|
data->Blink.Target_Interval = 0;
|
||||||
|
data->Blink.Count = 0;
|
||||||
|
data->Blink.Interval = 0;
|
||||||
|
data->Blink.Duration = 0;
|
||||||
|
data->Blink.State = false;
|
||||||
|
data->Tracking_Value_Callback = NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief API for lighting command brightness control engine
|
||||||
|
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
* @date 2022
|
||||||
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
#ifndef BACNET_BASIC_SYS_LIGHTING_COMMAND_H
|
||||||
|
#define BACNET_BASIC_SYS_LIGHTING_COMMAND_H
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
/* BACnet Stack defines - first */
|
||||||
|
#include "bacnet/bacdef.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for tracking value updates
|
||||||
|
* @param old_value - value prior to write
|
||||||
|
* @param value - value of the write
|
||||||
|
*/
|
||||||
|
typedef void (*lighting_command_tracking_value_callback)(
|
||||||
|
uint32_t key, float old_value, float value);
|
||||||
|
|
||||||
|
typedef struct bacnet_lighting_command_warn_data {
|
||||||
|
/* warn */
|
||||||
|
float On_Value;
|
||||||
|
float Off_Value;
|
||||||
|
float End_Value;
|
||||||
|
uint16_t Target_Interval;
|
||||||
|
/* internal tracking */
|
||||||
|
uint16_t Interval;
|
||||||
|
uint32_t Duration;
|
||||||
|
uint16_t Count;
|
||||||
|
/* bits */
|
||||||
|
bool State : 1;
|
||||||
|
} BACNET_LIGHTING_COMMAND_WARN_DATA;
|
||||||
|
|
||||||
|
typedef struct bacnet_lighting_command_data {
|
||||||
|
float Tracking_Value;
|
||||||
|
BACNET_LIGHTING_OPERATION Lighting_Operation;
|
||||||
|
float Target_Level;
|
||||||
|
float Ramp_Rate;
|
||||||
|
float Step_Increment;
|
||||||
|
uint32_t Fade_Time;
|
||||||
|
BACNET_LIGHTING_IN_PROGRESS In_Progress;
|
||||||
|
float Min_Actual_Value;
|
||||||
|
float Max_Actual_Value;
|
||||||
|
float High_Trim_Value;
|
||||||
|
float Low_Trim_Value;
|
||||||
|
BACNET_LIGHTING_COMMAND_WARN_DATA Blink;
|
||||||
|
/* bits - in common area of structure */
|
||||||
|
bool Out_Of_Service : 1;
|
||||||
|
/* key used with callback */
|
||||||
|
uint32_t Key;
|
||||||
|
lighting_command_tracking_value_callback Tracking_Value_Callback;
|
||||||
|
} BACNET_LIGHTING_COMMAND_DATA;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
void lighting_command_timer(
|
||||||
|
struct bacnet_lighting_command_data *data, uint16_t milliseconds);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
void lighting_command_fade_to(
|
||||||
|
struct bacnet_lighting_command_data *data, float value, uint32_t fade_time);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
void lighting_command_ramp_to(
|
||||||
|
struct bacnet_lighting_command_data *data, float value, float ramp_rate);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
void lighting_command_step(
|
||||||
|
struct bacnet_lighting_command_data *data,
|
||||||
|
BACNET_LIGHTING_OPERATION operation,
|
||||||
|
float step_increment);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
void lighting_command_blink_warn(
|
||||||
|
struct bacnet_lighting_command_data *data,
|
||||||
|
BACNET_LIGHTING_OPERATION operation,
|
||||||
|
struct bacnet_lighting_command_warn_data *blink);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
void lighting_command_stop(struct bacnet_lighting_command_data *data);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
void lighting_command_none(struct bacnet_lighting_command_data *data);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
void lighting_command_init(struct bacnet_lighting_command_data *data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif
|
||||||
@@ -171,6 +171,7 @@ list(APPEND testdirs
|
|||||||
# basic/sys
|
# basic/sys
|
||||||
bacnet/basic/sys/color_rgb
|
bacnet/basic/sys/color_rgb
|
||||||
bacnet/basic/sys/days
|
bacnet/basic/sys/days
|
||||||
|
bacnet/basic/sys/lighting_command
|
||||||
bacnet/basic/sys/fifo
|
bacnet/basic/sys/fifo
|
||||||
bacnet/basic/sys/filename
|
bacnet/basic/sys/filename
|
||||||
bacnet/basic/sys/keylist
|
bacnet/basic/sys/keylist
|
||||||
|
|||||||
@@ -48,7 +48,9 @@ add_executable(${PROJECT_NAME}
|
|||||||
${SRC_DIR}/bacnet/bactext.c
|
${SRC_DIR}/bacnet/bactext.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/bigend.c
|
${SRC_DIR}/bacnet/basic/sys/bigend.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/days.c
|
${SRC_DIR}/bacnet/basic/sys/days.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/debug.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/keylist.c
|
${SRC_DIR}/bacnet/basic/sys/keylist.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/lighting_command.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/linear.c
|
${SRC_DIR}/bacnet/basic/sys/linear.c
|
||||||
${SRC_DIR}/bacnet/datetime.c
|
${SRC_DIR}/bacnet/datetime.c
|
||||||
${SRC_DIR}/bacnet/indtext.c
|
${SRC_DIR}/bacnet/indtext.c
|
||||||
|
|||||||
@@ -46,11 +46,13 @@ add_executable(${PROJECT_NAME}
|
|||||||
${SRC_DIR}/bacnet/bacstr.c
|
${SRC_DIR}/bacnet/bacstr.c
|
||||||
${SRC_DIR}/bacnet/bactext.c
|
${SRC_DIR}/bacnet/bactext.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/bigend.c
|
${SRC_DIR}/bacnet/basic/sys/bigend.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/days.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/debug.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/keylist.c
|
${SRC_DIR}/bacnet/basic/sys/keylist.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/lighting_command.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/linear.c
|
${SRC_DIR}/bacnet/basic/sys/linear.c
|
||||||
${SRC_DIR}/bacnet/cov.c
|
${SRC_DIR}/bacnet/cov.c
|
||||||
${SRC_DIR}/bacnet/datetime.c
|
${SRC_DIR}/bacnet/datetime.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/days.c
|
|
||||||
${SRC_DIR}/bacnet/indtext.c
|
${SRC_DIR}/bacnet/indtext.c
|
||||||
${SRC_DIR}/bacnet/hostnport.c
|
${SRC_DIR}/bacnet/hostnport.c
|
||||||
${SRC_DIR}/bacnet/lighting.c
|
${SRC_DIR}/bacnet/lighting.c
|
||||||
|
|||||||
@@ -46,11 +46,13 @@ add_executable(${PROJECT_NAME}
|
|||||||
${SRC_DIR}/bacnet/bacstr.c
|
${SRC_DIR}/bacnet/bacstr.c
|
||||||
${SRC_DIR}/bacnet/bactext.c
|
${SRC_DIR}/bacnet/bactext.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/bigend.c
|
${SRC_DIR}/bacnet/basic/sys/bigend.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/days.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/debug.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/keylist.c
|
${SRC_DIR}/bacnet/basic/sys/keylist.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/lighting_command.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/linear.c
|
${SRC_DIR}/bacnet/basic/sys/linear.c
|
||||||
${SRC_DIR}/bacnet/cov.c
|
${SRC_DIR}/bacnet/cov.c
|
||||||
${SRC_DIR}/bacnet/datetime.c
|
${SRC_DIR}/bacnet/datetime.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/days.c
|
|
||||||
${SRC_DIR}/bacnet/indtext.c
|
${SRC_DIR}/bacnet/indtext.c
|
||||||
${SRC_DIR}/bacnet/hostnport.c
|
${SRC_DIR}/bacnet/hostnport.c
|
||||||
${SRC_DIR}/bacnet/lighting.c
|
${SRC_DIR}/bacnet/lighting.c
|
||||||
|
|||||||
@@ -83,14 +83,15 @@ add_executable(${PROJECT_NAME}
|
|||||||
${SRC_DIR}/bacnet/basic/service/h_cov.c
|
${SRC_DIR}/bacnet/basic/service/h_cov.c
|
||||||
${SRC_DIR}/bacnet/basic/service/h_wp.c
|
${SRC_DIR}/bacnet/basic/service/h_wp.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/bigend.c
|
${SRC_DIR}/bacnet/basic/sys/bigend.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/days.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/debug.c
|
${SRC_DIR}/bacnet/basic/sys/debug.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/keylist.c
|
${SRC_DIR}/bacnet/basic/sys/keylist.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/lighting_command.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/linear.c
|
${SRC_DIR}/bacnet/basic/sys/linear.c
|
||||||
${SRC_DIR}/bacnet/basic/tsm/tsm.c
|
${SRC_DIR}/bacnet/basic/tsm/tsm.c
|
||||||
${SRC_DIR}/bacnet/datalink/bvlc.c
|
${SRC_DIR}/bacnet/datalink/bvlc.c
|
||||||
${SRC_DIR}/bacnet/cov.c
|
${SRC_DIR}/bacnet/cov.c
|
||||||
${SRC_DIR}/bacnet/datetime.c
|
${SRC_DIR}/bacnet/datetime.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/days.c
|
|
||||||
${SRC_DIR}/bacnet/dcc.c
|
${SRC_DIR}/bacnet/dcc.c
|
||||||
${SRC_DIR}/bacnet/indtext.c
|
${SRC_DIR}/bacnet/indtext.c
|
||||||
${SRC_DIR}/bacnet/hostnport.c
|
${SRC_DIR}/bacnet/hostnport.c
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ add_executable(${PROJECT_NAME}
|
|||||||
${SRC_DIR}/bacnet/basic/sys/color_rgb.c
|
${SRC_DIR}/bacnet/basic/sys/color_rgb.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/debug.c
|
${SRC_DIR}/bacnet/basic/sys/debug.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/keylist.c
|
${SRC_DIR}/bacnet/basic/sys/keylist.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/lighting_command.c
|
||||||
${SRC_DIR}/bacnet/basic/sys/linear.c
|
${SRC_DIR}/bacnet/basic/sys/linear.c
|
||||||
${SRC_DIR}/bacnet/datetime.c
|
${SRC_DIR}/bacnet/datetime.c
|
||||||
${SRC_DIR}/bacnet/indtext.c
|
${SRC_DIR}/bacnet/indtext.c
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
|
||||||
|
|
||||||
|
get_filename_component(basename ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
|
project(test_${basename}
|
||||||
|
VERSION 1.0.0
|
||||||
|
LANGUAGES C)
|
||||||
|
|
||||||
|
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"/test/bacnet/[a-zA-Z_/-]*$"
|
||||||
|
"/src"
|
||||||
|
SRC_DIR
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"/test/bacnet/[a-zA-Z_/-]*$"
|
||||||
|
"/test"
|
||||||
|
TST_DIR
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
set(ZTST_DIR "${TST_DIR}/ztest/src")
|
||||||
|
|
||||||
|
add_compile_definitions(
|
||||||
|
BIG_ENDIAN=0
|
||||||
|
CONFIG_ZTEST=1
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${SRC_DIR}
|
||||||
|
${TST_DIR}/ztest/include
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME}
|
||||||
|
# File(s) under test
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/lighting_command.c
|
||||||
|
# Support files and stubs (pathname alphabetical)
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/debug.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/linear.c
|
||||||
|
# Test and test library files
|
||||||
|
./src/main.c
|
||||||
|
${ZTST_DIR}/ztest_mock.c
|
||||||
|
${ZTST_DIR}/ztest.c
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||||
|
m)
|
||||||
@@ -0,0 +1,380 @@
|
|||||||
|
/* @file
|
||||||
|
* @brief test BACnet integer encode/decode APIs
|
||||||
|
* @date June 2022
|
||||||
|
* @brief tests sRGB to and from from CIE xy and brightness API
|
||||||
|
*
|
||||||
|
* @section LICENSE
|
||||||
|
* Copyright (c) 2022 Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <zephyr/ztest.h>
|
||||||
|
#include <bacnet/basic/sys/lighting_command.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup bacnet_tests
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
static float Tracking_Value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for tracking value updates
|
||||||
|
* @param old_value - value prior to write
|
||||||
|
* @param value - value of the write
|
||||||
|
*/
|
||||||
|
static void dimmer_tracking_value(uint32_t key, float old_value, float value)
|
||||||
|
{
|
||||||
|
(void)key;
|
||||||
|
(void)old_value;
|
||||||
|
Tracking_Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief compare two floating point values to 3 decimal places
|
||||||
|
*
|
||||||
|
* @param x1 - first comparison value
|
||||||
|
* @param x2 - second comparison value
|
||||||
|
* @return true if the value is the same to 3 decimal points
|
||||||
|
*/
|
||||||
|
static bool is_float_equal(float x1, float x2)
|
||||||
|
{
|
||||||
|
return fabs(x1 - x2) < 0.001;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief test dimmer blink handler
|
||||||
|
* @param data - dimmer data
|
||||||
|
* @param blink - blink data
|
||||||
|
* @param milliseconds - number of milliseconds per timer call
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (blink->Duration == 0) {
|
||||||
|
/* immediate */
|
||||||
|
lighting_command_blink_warn(data, BACNET_LIGHTS_WARN, 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);
|
||||||
|
} else if (blink->Interval == 0) {
|
||||||
|
/* no blink, just egress timing */
|
||||||
|
lighting_command_blink_warn(data, BACNET_LIGHTS_WARN, 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_timer(data, milliseconds);
|
||||||
|
zassert_true(data->In_Progress == BACNET_LIGHTING_IDLE, 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)) {
|
||||||
|
duration = blink->Count * blink->Interval * 2UL;
|
||||||
|
if (duration > blink->Duration) {
|
||||||
|
duration = blink->Duration;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
duration = blink->Duration;
|
||||||
|
}
|
||||||
|
milliseconds = blink->Interval;
|
||||||
|
do {
|
||||||
|
lighting_command_blink_warn(data, BACNET_LIGHTS_WARN, blink);
|
||||||
|
lighting_command_timer(data, milliseconds);
|
||||||
|
if (blink->Duration) {
|
||||||
|
zassert_true(
|
||||||
|
data->In_Progress == BACNET_LIGHTING_OTHER,
|
||||||
|
"In_Progress=%d", data->In_Progress);
|
||||||
|
if (data->Blink.State) {
|
||||||
|
zassert_true(
|
||||||
|
is_float_equal(Tracking_Value, blink->Off_Value),
|
||||||
|
"Tracking_Value=%f", Tracking_Value);
|
||||||
|
} else {
|
||||||
|
zassert_true(
|
||||||
|
is_float_equal(Tracking_Value, blink->On_Value),
|
||||||
|
"Tracking_Value=%f", Tracking_Value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zassert_true(
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for Dimmer Command
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_ZTEST_NEW_API)
|
||||||
|
ZTEST(lighting_command_tests, test_lighting_command_command_unit)
|
||||||
|
#else
|
||||||
|
static void test_lighting_command_command_unit(void)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
BACNET_LIGHTING_COMMAND_DATA data = { 0 };
|
||||||
|
uint16_t milliseconds = 10;
|
||||||
|
uint32_t fade_time = 1000;
|
||||||
|
float target_level = 100.0f;
|
||||||
|
float target_step = 1.0f;
|
||||||
|
|
||||||
|
lighting_command_init(&data);
|
||||||
|
data.Tracking_Value_Callback = dimmer_tracking_value;
|
||||||
|
lighting_command_stop(&data);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
lighting_command_none(&data);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
/* fade up */
|
||||||
|
lighting_command_fade_to(&data, 100.0f, fade_time);
|
||||||
|
milliseconds = fade_time / 2;
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_FADE_ACTIVE, NULL);
|
||||||
|
zassert_true(
|
||||||
|
is_float_equal(Tracking_Value, 50.5f), "Tracking_Value=%f",
|
||||||
|
Tracking_Value);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, target_level), NULL);
|
||||||
|
/* fade down */
|
||||||
|
target_level = 0.0f;
|
||||||
|
lighting_command_fade_to(&data, target_level, fade_time);
|
||||||
|
milliseconds = fade_time / 2;
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_FADE_ACTIVE, NULL);
|
||||||
|
zassert_true(
|
||||||
|
is_float_equal(Tracking_Value, 50.5f), "Tracking_Value=%f",
|
||||||
|
Tracking_Value);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, 0.0f), NULL);
|
||||||
|
/* low trim */
|
||||||
|
data.Low_Trim_Value = 10.0f;
|
||||||
|
target_level = 1.0f;
|
||||||
|
milliseconds = 10;
|
||||||
|
lighting_command_fade_to(&data, target_level, 0);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, data.Low_Trim_Value), NULL);
|
||||||
|
target_level = 0.0f;
|
||||||
|
milliseconds = 10;
|
||||||
|
lighting_command_fade_to(&data, target_level, 0);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, target_level), NULL);
|
||||||
|
data.Low_Trim_Value = data.Min_Actual_Value;
|
||||||
|
/* high trim */
|
||||||
|
data.High_Trim_Value = 90.0f;
|
||||||
|
target_level = 100.0f;
|
||||||
|
milliseconds = 10;
|
||||||
|
lighting_command_fade_to(&data, target_level, 0);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, data.High_Trim_Value), NULL);
|
||||||
|
data.High_Trim_Value = data.Max_Actual_Value;
|
||||||
|
|
||||||
|
/* step UP - inhibit ON */
|
||||||
|
target_step = 1.0f;
|
||||||
|
target_level = 0.0f;
|
||||||
|
milliseconds = 10;
|
||||||
|
lighting_command_fade_to(&data, target_level, 0);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, target_level), NULL);
|
||||||
|
lighting_command_step(&data, BACNET_LIGHTS_STEP_UP, target_step);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, 0.0f), NULL);
|
||||||
|
/* step UP while ON */
|
||||||
|
target_step = 1.0f;
|
||||||
|
target_level = 1.0f;
|
||||||
|
milliseconds = 10;
|
||||||
|
lighting_command_fade_to(&data, target_level, 0);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, target_level), NULL);
|
||||||
|
lighting_command_step(&data, BACNET_LIGHTS_STEP_UP, target_step);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(
|
||||||
|
is_float_equal(Tracking_Value, target_step + target_level), NULL);
|
||||||
|
/* clamp to max */
|
||||||
|
target_step = 100.0f;
|
||||||
|
lighting_command_step(&data, BACNET_LIGHTS_STEP_UP, target_step);
|
||||||
|
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);
|
||||||
|
/* turn ON, then step UP */
|
||||||
|
target_step = 1.0f;
|
||||||
|
target_level = 0.0f;
|
||||||
|
milliseconds = 10;
|
||||||
|
lighting_command_fade_to(&data, target_level, 0);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, target_level), NULL);
|
||||||
|
lighting_command_step(&data, BACNET_LIGHTS_STEP_ON, target_step);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, 1.0f), NULL);
|
||||||
|
/* clamp to max */
|
||||||
|
target_step = 100.0f;
|
||||||
|
lighting_command_step(&data, BACNET_LIGHTS_STEP_ON, target_step);
|
||||||
|
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);
|
||||||
|
/* step DOWN, not off */
|
||||||
|
target_step = 1.0f;
|
||||||
|
target_level = data.Min_Actual_Value + target_step;
|
||||||
|
milliseconds = 10;
|
||||||
|
lighting_command_fade_to(&data, target_level, 0);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, target_level), NULL);
|
||||||
|
lighting_command_step(&data, BACNET_LIGHTS_STEP_DOWN, target_step);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, data.Min_Actual_Value), NULL);
|
||||||
|
/* clamp to min */
|
||||||
|
target_step = 100.0f;
|
||||||
|
lighting_command_step(&data, BACNET_LIGHTS_STEP_DOWN, target_step);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, data.Min_Actual_Value), NULL);
|
||||||
|
/* step DOWN and off */
|
||||||
|
target_step = 100.0f;
|
||||||
|
target_level = data.Min_Actual_Value;
|
||||||
|
milliseconds = 10;
|
||||||
|
lighting_command_fade_to(&data, target_level, 0);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, target_level), NULL);
|
||||||
|
lighting_command_step(&data, BACNET_LIGHTS_STEP_OFF, target_step);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, 0.0f), NULL);
|
||||||
|
/* blink warn - immediate off */
|
||||||
|
data.Blink.Interval = 0;
|
||||||
|
data.Blink.Duration = 0;
|
||||||
|
data.Blink.State = false;
|
||||||
|
data.Blink.On_Value = 100.0f;
|
||||||
|
data.Blink.Off_Value = 0.0f;
|
||||||
|
data.Blink.End_Value = 0.0f;
|
||||||
|
data.Blink.Count = UINT16_MAX;
|
||||||
|
test_lighting_command_blink_unit(&data);
|
||||||
|
/* blink warn - off after duration */
|
||||||
|
data.Blink.Interval = 0;
|
||||||
|
data.Blink.Duration = 1000;
|
||||||
|
data.Blink.State = false;
|
||||||
|
data.Blink.On_Value = 100.0f;
|
||||||
|
data.Blink.Off_Value = 0.0f;
|
||||||
|
data.Blink.End_Value = 0.0f;
|
||||||
|
data.Blink.Count = UINT16_MAX;
|
||||||
|
test_lighting_command_blink_unit(&data);
|
||||||
|
/* blink warn - on/off for duration */
|
||||||
|
data.Blink.Interval = 500;
|
||||||
|
data.Blink.Duration = 2000;
|
||||||
|
data.Blink.State = false;
|
||||||
|
data.Blink.On_Value = 100.0f;
|
||||||
|
data.Blink.Off_Value = 0.0f;
|
||||||
|
data.Blink.End_Value = 0.0f;
|
||||||
|
data.Blink.Count = UINT16_MAX;
|
||||||
|
test_lighting_command_blink_unit(&data);
|
||||||
|
|
||||||
|
/* quick ramp */
|
||||||
|
target_level = 0.0f;
|
||||||
|
milliseconds = 1000;
|
||||||
|
lighting_command_fade_to(&data, target_level, 0);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, target_level), NULL);
|
||||||
|
target_level = 100.0f;
|
||||||
|
lighting_command_ramp_to(&data, target_level, 100.0f);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(
|
||||||
|
data.In_Progress == BACNET_LIGHTING_RAMP_ACTIVE, "In_Progress=%d",
|
||||||
|
data.In_Progress);
|
||||||
|
zassert_true(is_float_equal(Tracking_Value, target_level), NULL);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
zassert_true(
|
||||||
|
data.In_Progress == BACNET_LIGHTING_IDLE, "In_Progress=%d",
|
||||||
|
data.In_Progress);
|
||||||
|
/* slower ramp up */
|
||||||
|
target_level = 100.0f;
|
||||||
|
milliseconds = 100;
|
||||||
|
do {
|
||||||
|
lighting_command_ramp_to(&data, target_level, 1.0f);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
if (data.Lighting_Operation == BACNET_LIGHTS_RAMP_TO) {
|
||||||
|
zassert_true(
|
||||||
|
data.In_Progress == BACNET_LIGHTING_RAMP_ACTIVE,
|
||||||
|
"In_Progress=%d", data.In_Progress);
|
||||||
|
zassert_true(
|
||||||
|
isgreater(data.Tracking_Value, data.Min_Actual_Value),
|
||||||
|
"Tracking_Value=%f", Tracking_Value);
|
||||||
|
zassert_true(
|
||||||
|
isless(data.Tracking_Value, data.Max_Actual_Value),
|
||||||
|
"Tracking_Value=%f", Tracking_Value);
|
||||||
|
}
|
||||||
|
} while (data.Lighting_Operation != BACNET_LIGHTS_STOP);
|
||||||
|
|
||||||
|
/* slower ramp down */
|
||||||
|
target_level = data.Min_Actual_Value;
|
||||||
|
milliseconds = 33;
|
||||||
|
do {
|
||||||
|
lighting_command_ramp_to(&data, target_level, 0.1f);
|
||||||
|
lighting_command_timer(&data, milliseconds);
|
||||||
|
if (data.Lighting_Operation == BACNET_LIGHTS_RAMP_TO) {
|
||||||
|
zassert_true(
|
||||||
|
data.In_Progress == BACNET_LIGHTING_RAMP_ACTIVE,
|
||||||
|
"In_Progress=%d", data.In_Progress);
|
||||||
|
zassert_true(
|
||||||
|
isgreater(data.Tracking_Value, data.Min_Actual_Value),
|
||||||
|
"Tracking_Value=%f", Tracking_Value);
|
||||||
|
zassert_true(
|
||||||
|
isless(data.Tracking_Value, data.Max_Actual_Value),
|
||||||
|
"Tracking_Value=%f", Tracking_Value);
|
||||||
|
}
|
||||||
|
} while (data.Lighting_Operation != BACNET_LIGHTS_STOP);
|
||||||
|
|
||||||
|
/* null check code coverage */
|
||||||
|
lighting_command_fade_to(NULL, 0.0f, 0);
|
||||||
|
lighting_command_ramp_to(NULL, 0.0f, 0.0f);
|
||||||
|
lighting_command_step(NULL, BACNET_LIGHTS_STEP_OFF, 0.0f);
|
||||||
|
lighting_command_blink_warn(NULL, BACNET_LIGHTS_WARN, NULL);
|
||||||
|
lighting_command_stop(NULL);
|
||||||
|
lighting_command_none(NULL);
|
||||||
|
lighting_command_timer(NULL, 0);
|
||||||
|
lighting_command_init(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(CONFIG_ZTEST_NEW_API)
|
||||||
|
ZTEST_SUITE(lighting_command_tests, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
#else
|
||||||
|
void test_main(void)
|
||||||
|
{
|
||||||
|
ztest_test_suite(
|
||||||
|
lighting_command_tests,
|
||||||
|
ztest_unit_test(test_lighting_command_command_unit));
|
||||||
|
|
||||||
|
ztest_run_test_suite(lighting_command_tests);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user