bugfix: change lighting command update notifications to use scaled physical values using min/max actual value. (#1315)

This commit is contained in:
Steve Karg
2026-04-27 16:43:04 -05:00
committed by GitHub
parent ce875c004b
commit d53d9ea371
3 changed files with 375 additions and 371 deletions
+325 -327
View File
@@ -16,12 +16,142 @@
#include "lighting_command.h" #include "lighting_command.h"
/** /**
* @brief call the lighting command tracking value callbacks * @brief compare two floating point values to 3 decimal places
* @param data - dimmer data structure *
* @param old_value - value prior to write * @param x1 - first comparison value
* @param value - value of the write * @param x2 - second comparison value
* @return true if the value is the same to 3 decimal points
*/ */
static void lighting_command_tracking_value_notify( static bool is_float_equal(float x1, float x2)
{
return fabs(x1 - x2) < 0.001;
}
/**
* @brief Clamp the value within the normalized range
* @details The normalized output level is specified as the
* linearized percentage (0..100%) of the possible light output range
* with 0.0% being off, 1.0% being dimmest, and 100.0% being brightest.
* @param value [in] value to clamp within the normalized range
* @return value clamped within the normalized range of 0.0% to 100.0%
*/
float lighting_command_normalized_range_clamp(float value)
{
float physical_value;
/* clamp value within physical values, if non-zero */
if (isless(value, 1.0f)) {
/* jump target to OFF */
physical_value = 0.0f;
} else if (isgreater(value, 100.0f)) {
physical_value = 100.0f;
} else {
physical_value = value;
}
return physical_value;
}
/**
* @brief Clamp the value within the normal ON range
* @details The normal ON output level is specified as the linearized
* percentage (1..100%) of the possible light output range with 1.0% being
* dimmest, and 100.0% being brightest.
* @param value [in] value to clamp within the normalized ON range
* @return value clamped within the normalized ON range of 1.0% to 100.0%
*/
float lighting_command_normalized_on_range_clamp(float value)
{
float normalized_on_value;
/* clamp value within 1.0 and 100.0 values */
if (isless(value, 1.0f)) {
normalized_on_value = 1.0f;
} else if (isgreater(value, 100.0f)) {
normalized_on_value = 100.0f;
} else {
normalized_on_value = value;
}
return normalized_on_value;
}
/**
* @brief Adjust Min/Max Actual Value Range
* @details Min_Actual_Value property, of type Real, shall specify
* the physical output level that corresponds to a Present_Value of 1.0%.
* Changing Min_Actual_Value to a value greater than Max_Actual_Value
* shall force Max_Actual_Value to become equal to Min_Actual_Value.
* Min_Actual_Value shall always be a positive number in the
* range 1.0% to 100.0%.
*
* Max_Actual_Value property, of type Real, shall specify the physical
* output level that corresponds to a Present_Value of 100.0%.
* Changing Max_Actual_Value to a value less than Min_Actual_Value
* shall force Min_Actual_Value to become equal to Max_Actual_Value.
* Max_Actual_Value shall always be a positive number in the range
* 1.0% to 100.0%.
*/
static void lighting_command_min_max_value_range_adjust(
struct bacnet_lighting_command_data *data)
{
float swap_value, min_value, max_value;
min_value =
lighting_command_normalized_on_range_clamp(data->Min_Actual_Value);
max_value =
lighting_command_normalized_on_range_clamp(data->Max_Actual_Value);
if (isgreater(min_value, max_value)) {
/* swap the configured high and low actual values if they are inverse */
swap_value = min_value;
min_value = max_value;
max_value = swap_value;
}
data->Min_Actual_Value = min_value;
data->Max_Actual_Value = max_value;
}
/**
* @brief Calculate the Feedback_Value property value
*
* This property, of type Real, shall indicate the actual value
* of the physical lighting output within the normalized range.
* If the actual value of the physical lighting output in the
* non-normalized range is not off but is less than the
* Min_Actual_Value, then Feedback_Value shall be set to 1.0%.
* If the actual value in the non-normalized range is greater than
* Max_Actual_Value, then Feedback_Value shall be set to 100.0%.
* @param data - dimmer data structure
* @return calculated feedback-value
*/
float lighting_command_normalized_to_physical_value(
float min_value, float max_value, float normalized_value)
{
float physical_value, x1, x2, x3, y1, y3;
if (isless(normalized_value, 1.0f)) {
physical_value = 0.0f;
} else if (isgreater(normalized_value, 100.0f)) {
physical_value = max_value;
} else {
x1 = 1.0f;
x2 = normalized_value;
x3 = 100.0f;
y1 = min_value;
y3 = max_value;
physical_value = linear_interpolate(x1, x2, x3, y1, y3);
}
return physical_value;
}
/**
* @brief call the lighting command notification callbacks
* @param data - dimmer data structure
* @param old_value - physical value prior to write
* @param value - physical value of the write
*/
static void lighting_command_notify(
struct bacnet_lighting_command_data *data, float old_value, float value) struct bacnet_lighting_command_data *data, float old_value, float value)
{ {
struct lighting_command_notification *head; struct lighting_command_notification *head;
@@ -175,32 +305,6 @@ float lighting_command_step_increment_clamp(float step_increment)
return step_increment; return step_increment;
} }
/**
* @brief Clamp the value within the physical min/max range
* @details The physical output level, or non-normalized range,
* is specified as the linearized percentage (0..100%)
* of the possible light output range with 0.0% being off,
* 1.0% being dimmest, and 100.0% being brightest.
* @param value [in] value to clamp within the physical min/max range
* @return value clamped within the physical min/max range of 0.0% to 100.0%
*/
float lighting_command_physical_range_clamp(float value)
{
float physical_value;
/* clamp value within physical values, if non-zero */
if (isless(value, 1.0f)) {
/* jump target to OFF */
physical_value = 0.0f;
} else if (isgreater(value, 100.0f)) {
physical_value = 100.0f;
} else {
physical_value = value;
}
return physical_value;
}
/** /**
* @brief Calculate the target value for a step down command * @brief Calculate the target value for a step down command
* @param tracking_value [in] current tracking value * @param tracking_value [in] current tracking value
@@ -305,36 +409,23 @@ static float lighting_command_operating_range_clamp_fade_nolock(
float value, float value,
uint16_t milliseconds) uint16_t milliseconds)
{ {
float high_trim, low_trim, swap_value;
if (data) { if (data) {
/* clamp range within physical limits */
high_trim =
lighting_command_physical_range_clamp(data->High_Trim_Value);
low_trim = lighting_command_physical_range_clamp(data->Low_Trim_Value);
/* valid range check for high and low trim values */
if (isgreater(low_trim, high_trim)) {
/* swap the trims if they are inverse */
swap_value = low_trim;
low_trim = high_trim;
high_trim = swap_value;
}
/* clamp value within trim values, if non-zero */ /* clamp value within trim values, if non-zero */
if (isless(value, 1.0f)) { if (isless(value, 1.0f)) {
/* jump target to OFF if below normalized min */ /* jump target to OFF if below normalized min */
value = 0.0f; value = 0.0f;
} else if (isgreater(value, high_trim)) { } else if (isgreater(value, data->High_Trim_Value)) {
value = lighting_command_trim_fade( value = lighting_command_trim_fade(
data, value, high_trim, milliseconds); data, value, data->High_Trim_Value, milliseconds);
data->In_Progress = BACNET_LIGHTING_TRIM_ACTIVE; data->In_Progress = BACNET_LIGHTING_TRIM_ACTIVE;
} else if (isless(value, low_trim)) { } else if (isless(value, data->Low_Trim_Value)) {
value = value = lighting_command_trim_fade(
lighting_command_trim_fade(data, value, low_trim, milliseconds); data, value, data->Low_Trim_Value, milliseconds);
data->In_Progress = BACNET_LIGHTING_TRIM_ACTIVE; data->In_Progress = BACNET_LIGHTING_TRIM_ACTIVE;
} }
} else { } else {
/* no data, so just clamp value within physical limits */ /* no data, so just clamp value within physical limits */
value = lighting_command_physical_range_clamp(value); value = lighting_command_normalized_range_clamp(value);
} }
return value; return value;
@@ -358,195 +449,6 @@ float lighting_command_operating_range_clamp_fade(
return clamped_value; return clamped_value;
} }
/**
* @brief Clamp the value within the operating range between low and high
* end trim values immediately.
* @details The Operating Range is a subset of the Normalized Range,
* that represents the range of acceptable values for control of the object.
* The Operating Range is defined by the High_End_Trim and Low_End_Trim
* property values. When values are written outside of the Operating Range,
* the Tracking_Value will reflect the actual, clamped normalized light
* output while the Present_Value will reflect the original target value.
* @param data - dimmer data structure
* @param value the value that will be subject to clamping
* @return value clamped within the operating range defined by the High_End_Trim
* and Low_End_Trim property values
*/
static float lighting_command_operating_range_clamp_nolock(
struct bacnet_lighting_command_data *data, float value)
{
return lighting_command_operating_range_clamp_fade_nolock(data, value, 0);
}
float lighting_command_operating_range_clamp(
struct bacnet_lighting_command_data *data, float value)
{
float clamped_value;
if (!data) {
return value;
}
lighting_command_lock(data);
clamped_value = lighting_command_operating_range_clamp_nolock(data, value);
lighting_command_unlock(data);
return clamped_value;
}
/**
* @brief Determine if the values are both within the normalized OFF range
* @details The physical output level, or non-normalized range,
* is specified as the linearized percentage (0..100%)
* of the possible light output range with 0.0% being off,
* 1.0% being dimmest, and 100.0% being brightest.
* The actual range represents the subset of physical output levels
* defined by Min_Actual_Value and Max_Actual_Value
* (or 1.0 to 100.0% if these properties are not present).
* The normalized range is always 0.0 to 100.0% where
* 1.0% = bottom of the actual range and 100.0% = top of the actual range.
* @param data - dimmer data structure
* @param value1 [in] value to check if it is within the normalized OFF range
* @param value2 [in] value to check if it is within the normalized OFF range
* @return true if both values are within the normalized OFF range, false
* otherwise
*/
static bool lighting_command_is_normalized_off_to_off_nolock(
struct bacnet_lighting_command_data *data, float value1, float value2)
{
float min_value, max_value;
/* check normalized range within physical limits */
max_value = lighting_command_physical_range_clamp(data->Max_Actual_Value);
min_value = lighting_command_physical_range_clamp(data->Min_Actual_Value);
if (isgreater(min_value, max_value)) {
/* the high and low configured actual values are swapped */
min_value = max_value;
}
if (isless(value1, min_value) && isless(value2, min_value)) {
return true;
}
return false;
}
/**
* @brief Clamp the value within the normalized ON range 1% to 100%.
* @details The physical output level, or non-normalized range,
* is specified as the linearized percentage (0..100%)
* of the possible light output range with 0.0% being off,
* 1.0% being dimmest, and 100.0% being brightest.
* The actual range represents the subset of physical output levels
* defined by Min_Actual_Value and Max_Actual_Value
* (or 1.0 to 100.0% if these properties are not present).
* The normalized range is always 0.0 to 100.0% where
* 1.0% = bottom of the actual range and 100.0% = top of the actual range.
* @param data - dimmer data structure
* @param value [in] value to normalize
* @return normalized value within the range defined by Min_Actual_Value
* and Max_Actual_Value
*/
static float lighting_command_normalized_on_range_clamp_nolock(
struct bacnet_lighting_command_data *data, float value)
{
float min_value, max_value, swap_value;
/* clamp range within physical limits */
max_value = lighting_command_physical_range_clamp(data->Max_Actual_Value);
min_value = lighting_command_physical_range_clamp(data->Min_Actual_Value);
if (isgreater(min_value, max_value)) {
/* swap the configured high and low actual values if they are inverse */
swap_value = min_value;
min_value = max_value;
max_value = swap_value;
}
/* clamp value within actual min/max values */
if (isgreater(value, max_value)) {
value = max_value;
} else if (isless(value, min_value)) {
value = min_value;
}
return value;
}
float lighting_command_normalized_on_range_clamp(
struct bacnet_lighting_command_data *data, float value)
{
float clamped_value;
if (!data) {
return value;
}
lighting_command_lock(data);
clamped_value =
lighting_command_normalized_on_range_clamp_nolock(data, value);
lighting_command_unlock(data);
return clamped_value;
}
/**
* @brief Normalize the value to the min/max range
* @details The physical output level, or non-normalized range,
* is specified as the linearized percentage (0..100%)
* of the possible light output range with 0.0% being off,
* 1.0% being dimmest, and 100.0% being brightest.
* The actual range represents the subset of physical output levels
* defined by Min_Actual_Value and Max_Actual_Value
* (or 1.0 to 100.0% if these properties are not present).
* The normalized range is always 0.0 to 100.0% where
* 1.0% = bottom of the actual range and 100.0% = top of the actual range.
* @param data - dimmer data structure
* @param value [in] value to normalize
* @return normalized value within the range defined by
* 0.0%, Min_Actual_Value, and Max_Actual_Value
*/
static float lighting_command_normalized_range_clamp_nolock(
struct bacnet_lighting_command_data *data, float value)
{
float normalized_value;
float min_value, max_value, swap_value;
/* clamp range within physical limits */
max_value = lighting_command_physical_range_clamp(data->Max_Actual_Value);
min_value = lighting_command_physical_range_clamp(data->Min_Actual_Value);
/* valid range check for high and low trim values */
if (isgreater(min_value, max_value)) {
/* swap the trims if they are inverse */
swap_value = min_value;
min_value = max_value;
max_value = swap_value;
}
/* clamp value within normalized values, if non-zero */
if (isless(value, 1.0f)) {
/* jump target to OFF if below normalized min */
normalized_value = 0.0f;
} else if (isgreater(value, max_value)) {
normalized_value = max_value;
} else if (isless(value, min_value)) {
normalized_value = min_value;
} else {
normalized_value = value;
}
return normalized_value;
}
float lighting_command_normalized_range_clamp(
struct bacnet_lighting_command_data *data, float value)
{
float clamped_value;
if (!data) {
return value;
}
lighting_command_lock(data);
clamped_value = lighting_command_normalized_range_clamp_nolock(data, value);
lighting_command_unlock(data);
return clamped_value;
}
/** /**
* @brief Callback for tracking value updates * @brief Callback for tracking value updates
* @param data - dimmer data structure * @param data - dimmer data structure
@@ -555,16 +457,25 @@ float lighting_command_normalized_range_clamp(
* @param milliseconds - number of milliseconds elapsed * @param milliseconds - number of milliseconds elapsed
*/ */
static void lighting_command_tracking_value_event( static void lighting_command_tracking_value_event(
struct bacnet_lighting_command_data *data, float old_value, float value) struct bacnet_lighting_command_data *data,
float old_value,
float tracking_value)
{ {
float physical_value, old_physical_value;
lighting_command_min_max_value_range_adjust(data);
physical_value = lighting_command_normalized_to_physical_value(
data->Min_Actual_Value, data->Max_Actual_Value, tracking_value);
old_physical_value = lighting_command_normalized_to_physical_value(
data->Min_Actual_Value, data->Max_Actual_Value, old_value);
if (data->Overridden) { if (data->Overridden) {
lighting_command_tracking_value_notify(data, old_value, value); lighting_command_notify(data, old_physical_value, physical_value);
if (data->Overridden_Momentary) { if (data->Overridden_Momentary) {
data->Overridden = false; data->Overridden = false;
} }
} else if (!data->Out_Of_Service) { } else if (!data->Out_Of_Service) {
data->Overridden_Momentary = false; data->Overridden_Momentary = false;
lighting_command_tracking_value_notify(data, old_value, value); lighting_command_notify(data, old_physical_value, physical_value);
} else { } else {
debug_printf( debug_printf(
"Lighting-Command[%lu]-Out-of-Service\n", (unsigned long)data->Key); "Lighting-Command[%lu]-Out-of-Service\n", (unsigned long)data->Key);
@@ -586,18 +497,17 @@ static void lighting_command_fade_handler(
float target_value; float target_value;
old_value = data->Tracking_Value; old_value = data->Tracking_Value;
if (lighting_command_is_normalized_off_to_off_nolock( if (isless(old_value, 1.0f) && isless(data->Target_Level, 1.0f)) {
data, old_value, data->Target_Level)) {
/* check for OFF to OFF transition */ /* check for OFF to OFF transition */
data->Tracking_Value = 0.0f; data->Tracking_Value = 0.0f;
data->In_Progress = BACNET_LIGHTING_IDLE; data->In_Progress = BACNET_LIGHTING_IDLE;
data->Lighting_Operation = BACNET_LIGHTS_STOP; data->Lighting_Operation = BACNET_LIGHTS_STOP;
} else { } else {
/* clamp Target value within the Normalized ON Range */ /* clamp Target value within the Normalized ON Range */
target_value = lighting_command_normalized_on_range_clamp_nolock( target_value =
data, data->Target_Level); lighting_command_normalized_on_range_clamp(data->Target_Level);
if ((milliseconds >= data->Fade_Time) || if ((milliseconds >= data->Fade_Time) ||
(!islessgreater(data->Tracking_Value, target_value))) { (is_float_equal(data->Tracking_Value, target_value))) {
/* stop fading */ /* stop fading */
if (isless(data->Target_Level, 1.0f)) { if (isless(data->Target_Level, 1.0f)) {
/* jump target to OFF if below normalized min */ /* jump target to OFF if below normalized min */
@@ -609,12 +519,12 @@ static void lighting_command_fade_handler(
data->Lighting_Operation = BACNET_LIGHTS_STOP; data->Lighting_Operation = BACNET_LIGHTS_STOP;
data->Fade_Time = 0; data->Fade_Time = 0;
} else { } else {
/* fading */ /* fading in the normalized ON range */
x1 = 0.0f; x1 = 0.0f;
x2 = (float)milliseconds; x2 = (float)milliseconds;
x3 = (float)data->Fade_Time; x3 = (float)data->Fade_Time;
if (isless(old_value, data->Min_Actual_Value)) { if (isless(old_value, 1.0f)) {
y1 = data->Min_Actual_Value; y1 = 1.0f;
} else { } else {
y1 = old_value; y1 = old_value;
} }
@@ -642,8 +552,7 @@ static void lighting_command_fade_handler(
* at a particular percent per second defined by ramp-rate. * at a particular percent per second defined by ramp-rate.
* While the ramp operation is executing, In_Progress shall be set * While the ramp operation is executing, In_Progress shall be set
* to RAMP_ACTIVE, and Tracking_Value shall be updated to reflect the current * to RAMP_ACTIVE, and Tracking_Value shall be updated to reflect the current
* progress of the ramp. <target-level> shall be clamped to * progress of the ramp.
* Min_Actual_Value and Max_Actual_Value.
* *
* @param data - dimmer data structure * @param data - dimmer data structure
* @param milliseconds - number of milliseconds elapsed * @param milliseconds - number of milliseconds elapsed
@@ -655,17 +564,16 @@ static void lighting_command_ramp_handler(
operating_value; operating_value;
old_value = data->Tracking_Value; old_value = data->Tracking_Value;
if (lighting_command_is_normalized_off_to_off_nolock( if (isless(old_value, 1.0f) && isless(data->Target_Level, 1.0f)) {
data, old_value, data->Target_Level)) {
/* check for OFF to OFF transition */ /* check for OFF to OFF transition */
data->Tracking_Value = 0.0f; data->Tracking_Value = 0.0f;
data->In_Progress = BACNET_LIGHTING_IDLE; data->In_Progress = BACNET_LIGHTING_IDLE;
data->Lighting_Operation = BACNET_LIGHTS_STOP; data->Lighting_Operation = BACNET_LIGHTS_STOP;
} else { } else {
/* clamp Target value within the Normalized ON Range */ /* clamp Target value within the Normalized ON Range */
target_value = lighting_command_normalized_on_range_clamp_nolock( target_value =
data, data->Target_Level); lighting_command_normalized_on_range_clamp(data->Target_Level);
if (!islessgreater(data->Tracking_Value, target_value)) { if (is_float_equal(data->Tracking_Value, target_value)) {
/* stop ramping */ /* stop ramping */
if (isless(data->Target_Level, 1.0f)) { if (isless(data->Target_Level, 1.0f)) {
/* jump target to OFF if below normalized min */ /* jump target to OFF if below normalized min */
@@ -706,9 +614,7 @@ static void lighting_command_ramp_handler(
step_value = target_value; step_value = target_value;
data->Lighting_Operation = BACNET_LIGHTS_STOP; data->Lighting_Operation = BACNET_LIGHTS_STOP;
} }
/* clamp target within min/max, if needed */ step_value = lighting_command_normalized_on_range_clamp(step_value);
step_value = lighting_command_normalized_on_range_clamp_nolock(
data, step_value);
if (data->Lighting_Operation == BACNET_LIGHTS_STOP) { if (data->Lighting_Operation == BACNET_LIGHTS_STOP) {
if (isless(data->Target_Level, 1.0f)) { if (isless(data->Target_Level, 1.0f)) {
/* jump target to OFF if below normalized min */ /* jump target to OFF if below normalized min */
@@ -736,31 +642,26 @@ static void lighting_command_ramp_handler(
* Updates the object tracking value while stepping * Updates the object tracking value while stepping
* *
* Commands the dimmer to a value equal to the Tracking_Value * Commands the dimmer to a value equal to the Tracking_Value
* plus the step-increment. The resulting sum shall be clamped to * plus the step-increment. If the result of the addition is
* Min_Actual_Value and Max_Actual_Value * greater than 100.0%, the value shall be set to 100.0%.
* *
* @param data [in] dimmer data * @param data [in] dimmer data
*/ */
static void static void
lighting_command_step_up_handler(struct bacnet_lighting_command_data *data) lighting_command_step_up_handler(struct bacnet_lighting_command_data *data)
{ {
float old_value, target_value, operating_value; float old_value, target_value;
old_value = data->Tracking_Value; old_value = data->Tracking_Value;
if (isgreaterequal(old_value, data->Min_Actual_Value)) { if (isgreaterequal(old_value, 1.0f)) {
/* inhibit ON if the value is already OFF */ /* inhibit ON if the value is currently OFF */
target_value = lighting_command_step_up_target_value( target_value = lighting_command_step_up_target_value(
data->Tracking_Value, data->Step_Increment); data->Tracking_Value, data->Step_Increment);
/* clamp Tracking value within the Normalized ON Range */ /* clamp Tracking value inclusively within the Operating Range */
data->Tracking_Value = data->Tracking_Value =
lighting_command_normalized_on_range_clamp_nolock( lighting_command_normalized_on_range_clamp(target_value);
data, target_value);
data->In_Progress = BACNET_LIGHTING_IDLE; data->In_Progress = BACNET_LIGHTING_IDLE;
data->Lighting_Operation = BACNET_LIGHTS_STOP; data->Lighting_Operation = BACNET_LIGHTS_STOP;
/* clamp Tracking value inclusively within the Operating Range */
operating_value = lighting_command_operating_range_clamp_nolock(
data, data->Tracking_Value);
data->Tracking_Value = operating_value;
/* notify */ /* notify */
lighting_command_tracking_value_event( lighting_command_tracking_value_event(
data, old_value, data->Tracking_Value); data, old_value, data->Tracking_Value);
@@ -771,8 +672,7 @@ lighting_command_step_up_handler(struct bacnet_lighting_command_data *data)
* Updates the object tracking value while stepping * Updates the object tracking value while stepping
* *
* Commands the dimmer to a value equal to the Tracking_Value * Commands the dimmer to a value equal to the Tracking_Value
* plus the step-increment. The resulting sum shall be clamped to * plus the step-increment.
* Min_Actual_Value and Max_Actual_Value
* *
* @param data [in] dimmer data * @param data [in] dimmer data
*/ */
@@ -784,14 +684,13 @@ lighting_command_step_down_handler(struct bacnet_lighting_command_data *data)
old_value = data->Tracking_Value; old_value = data->Tracking_Value;
target_value = lighting_command_step_down_target_value( target_value = lighting_command_step_down_target_value(
data->Tracking_Value, data->Step_Increment); data->Tracking_Value, data->Step_Increment);
/* clamp Tracking value within the Normalized ON Range */
data->Tracking_Value = data->Tracking_Value =
lighting_command_normalized_on_range_clamp_nolock(data, target_value); lighting_command_normalized_on_range_clamp(target_value);
data->In_Progress = BACNET_LIGHTING_IDLE; data->In_Progress = BACNET_LIGHTING_IDLE;
data->Lighting_Operation = BACNET_LIGHTS_STOP; data->Lighting_Operation = BACNET_LIGHTS_STOP;
/* clamp Tracking value inclusively within the Operating Range */ /* clamp Tracking value inclusively within the Operating Range */
operating_value = lighting_command_operating_range_clamp_nolock( operating_value =
data, data->Tracking_Value); lighting_command_normalized_range_clamp(data->Tracking_Value);
data->Tracking_Value = operating_value; data->Tracking_Value = operating_value;
/* notify */ /* notify */
lighting_command_tracking_value_event( lighting_command_tracking_value_event(
@@ -802,27 +701,32 @@ lighting_command_step_down_handler(struct bacnet_lighting_command_data *data)
* Updates the object tracking value while stepping * Updates the object tracking value while stepping
* *
* Commands the dimmer to a value equal to the Tracking_Value * Commands the dimmer to a value equal to the Tracking_Value
* plus the step-increment. The resulting sum shall be clamped to * plus the step-increment.
* Min_Actual_Value and Max_Actual_Value * If the result of the addition is greater than 100.0%,
* the value shall be set to 100.0%.
* When the Tracking_Value is 0.0%, 1.0% is written
* to the specified slot in the priority array.
* *
* @param data [in] dimmer data * @param data [in] dimmer data
*/ */
static void static void
lighting_command_step_on_handler(struct bacnet_lighting_command_data *data) lighting_command_step_on_handler(struct bacnet_lighting_command_data *data)
{ {
float old_value, target_value, operating_value; float old_value, target_value;
old_value = data->Tracking_Value; old_value = data->Tracking_Value;
target_value = lighting_command_step_up_target_value( if (isless(data->Tracking_Value, 1.0f)) {
data->Tracking_Value, data->Step_Increment); /* step is ignored when starting at OFF */
data->Tracking_Value = data->Tracking_Value = 1.0f;
lighting_command_normalized_range_clamp_nolock(data, target_value); } else {
target_value = lighting_command_step_up_target_value(
data->Tracking_Value, data->Step_Increment);
/* clamp Tracking value inclusively within the Normalized Range */
data->Tracking_Value =
lighting_command_normalized_range_clamp(target_value);
}
data->In_Progress = BACNET_LIGHTING_IDLE; data->In_Progress = BACNET_LIGHTING_IDLE;
data->Lighting_Operation = BACNET_LIGHTS_STOP; data->Lighting_Operation = BACNET_LIGHTS_STOP;
/* clamp Tracking value inclusively within the Operating Range */
operating_value = lighting_command_operating_range_clamp_nolock(
data, data->Tracking_Value);
data->Tracking_Value = operating_value;
/* notify */ /* notify */
lighting_command_tracking_value_event( lighting_command_tracking_value_event(
data, old_value, data->Tracking_Value); data, old_value, data->Tracking_Value);
@@ -831,28 +735,28 @@ lighting_command_step_on_handler(struct bacnet_lighting_command_data *data)
/** /**
* Updates the object tracking value while stepping * Updates the object tracking value while stepping
* *
* Commands the dimmer to a value equal to the Tracking_Value * Commands Present_Value to a value equal to the Tracking_Value
* plus the step-increment. The resulting sum shall be clamped to * minus the step-increment at the specified priority.
* Min_Actual_Value and Max_Actual_Value * The step-down operation is implemented by writing
* the Tracking_Value minus step-increment to the specified
* slot in the priority array.
* If the result of the subtraction is less than 1.0%,
* 0.0% is written to the specified slot in the priority array.
* *
* @param data [in] dimmer data * @param data [in] dimmer data
*/ */
static void static void
lighting_command_step_off_handler(struct bacnet_lighting_command_data *data) lighting_command_step_off_handler(struct bacnet_lighting_command_data *data)
{ {
float old_value, target_value, operating_value; float old_value, target_value;
old_value = data->Tracking_Value; old_value = data->Tracking_Value;
target_value = lighting_command_step_down_target_value( target_value = lighting_command_step_down_target_value(
data->Tracking_Value, data->Step_Increment); data->Tracking_Value, data->Step_Increment);
data->Tracking_Value = data->Tracking_Value =
lighting_command_normalized_range_clamp_nolock(data, target_value); lighting_command_normalized_range_clamp(target_value);
data->In_Progress = BACNET_LIGHTING_IDLE; data->In_Progress = BACNET_LIGHTING_IDLE;
data->Lighting_Operation = BACNET_LIGHTS_STOP; data->Lighting_Operation = BACNET_LIGHTS_STOP;
/* clamp Tracking value inclusively within the Operating Range */
operating_value = lighting_command_operating_range_clamp_nolock(
data, data->Tracking_Value);
data->Tracking_Value = operating_value;
/* notify */ /* notify */
lighting_command_tracking_value_event( lighting_command_tracking_value_event(
data, old_value, data->Tracking_Value); data, old_value, data->Tracking_Value);
@@ -936,11 +840,8 @@ static void lighting_command_blink_handler(
} }
} }
} }
target_value =
lighting_command_normalized_range_clamp_nolock(data, target_value);
/* clamp Tracking value inclusively within the Operating Range */ /* clamp Tracking value inclusively within the Operating Range */
operating_value = operating_value = lighting_command_normalized_range_clamp(target_value);
lighting_command_operating_range_clamp_nolock(data, target_value);
/* note: The blink-warn notifications shall not be reflected /* note: The blink-warn notifications shall not be reflected
in the tracking value. */ in the tracking value. */
if (data->In_Progress == BACNET_LIGHTING_IDLE) { if (data->In_Progress == BACNET_LIGHTING_IDLE) {
@@ -959,7 +860,7 @@ static void lighting_command_override_nolock(
float old_value; float old_value;
old_value = data->Tracking_Value; old_value = data->Tracking_Value;
data->Tracking_Value = lighting_command_physical_range_clamp(value); data->Tracking_Value = lighting_command_normalized_range_clamp(value);
lighting_command_tracking_value_event( lighting_command_tracking_value_event(
data, old_value, data->Tracking_Value); data, old_value, data->Tracking_Value);
} }
@@ -1003,7 +904,7 @@ void lighting_command_override_set(
void lighting_command_override_clear( void lighting_command_override_clear(
struct bacnet_lighting_command_data *data, float value) struct bacnet_lighting_command_data *data, float value)
{ {
float old_value, normalized_value, operating_value; float old_value;
if (!data) { if (!data) {
return; return;
@@ -1013,13 +914,9 @@ void lighting_command_override_clear(
data->Overridden_Momentary = false; data->Overridden_Momentary = false;
old_value = data->Tracking_Value; old_value = data->Tracking_Value;
/* clamp Tracking value within the Normalized Range */ /* clamp Tracking value within the Normalized Range */
normalized_value = data->Tracking_Value = lighting_command_normalized_range_clamp(value);
lighting_command_normalized_range_clamp_nolock(data, value); lighting_command_tracking_value_event(
/* clamp Tracking value inclusively within the Operating Range */ data, old_value, data->Tracking_Value);
operating_value =
lighting_command_operating_range_clamp_nolock(data, normalized_value);
data->Tracking_Value = operating_value;
lighting_command_tracking_value_event(data, old_value, operating_value);
lighting_command_unlock(data); lighting_command_unlock(data);
} }
@@ -1190,7 +1087,7 @@ void lighting_command_step(
/* configure the lighting operation */ /* configure the lighting operation */
if (((operation == BACNET_LIGHTS_STEP_UP) || if (((operation == BACNET_LIGHTS_STEP_UP) ||
(operation == BACNET_LIGHTS_STEP_DOWN)) && (operation == BACNET_LIGHTS_STEP_DOWN)) &&
(!islessgreater(data->Tracking_Value, 0.0))) { (is_float_equal(data->Tracking_Value, 0.0))) {
/* If the starting level of Tracking_Value is 0.0%, /* If the starting level of Tracking_Value is 0.0%,
then this operation is ignored. */ then this operation is ignored. */
goto done; goto done;
@@ -1202,23 +1099,19 @@ void lighting_command_step(
if (operation == BACNET_LIGHTS_STEP_UP) { if (operation == BACNET_LIGHTS_STEP_UP) {
target_value = lighting_command_step_up_target_value( target_value = lighting_command_step_up_target_value(
data->Tracking_Value, data->Step_Increment); data->Tracking_Value, data->Step_Increment);
target_value = lighting_command_normalized_on_range_clamp_nolock( target_value = lighting_command_normalized_on_range_clamp(target_value);
data, target_value);
} else if (operation == BACNET_LIGHTS_STEP_DOWN) { } else if (operation == BACNET_LIGHTS_STEP_DOWN) {
target_value = lighting_command_step_down_target_value( target_value = lighting_command_step_down_target_value(
data->Tracking_Value, data->Step_Increment); data->Tracking_Value, data->Step_Increment);
target_value = lighting_command_normalized_on_range_clamp_nolock( target_value = lighting_command_normalized_on_range_clamp(target_value);
data, target_value);
} else if (operation == BACNET_LIGHTS_STEP_ON) { } else if (operation == BACNET_LIGHTS_STEP_ON) {
target_value = lighting_command_step_up_target_value( target_value = lighting_command_step_up_target_value(
data->Tracking_Value, data->Step_Increment); data->Tracking_Value, data->Step_Increment);
target_value = target_value = lighting_command_normalized_range_clamp(target_value);
lighting_command_normalized_range_clamp_nolock(data, target_value);
} else if (operation == BACNET_LIGHTS_STEP_OFF) { } else if (operation == BACNET_LIGHTS_STEP_OFF) {
target_value = lighting_command_step_down_target_value( target_value = lighting_command_step_down_target_value(
data->Tracking_Value, data->Step_Increment); data->Tracking_Value, data->Step_Increment);
target_value = target_value = lighting_command_normalized_range_clamp(target_value);
lighting_command_normalized_range_clamp_nolock(data, target_value);
} else { } else {
goto done; goto done;
} }
@@ -1431,24 +1324,43 @@ void lighting_command_toggle_default(
/** /**
* @brief Configure the lighting command to apply low or high trim * @brief Configure the lighting command to apply low or high trim
* @param data [in] dimmer data * @param data [in] dimmer data
* @param high_end_trim [in] BACnet lighting high end trim
* @param low_end_trim [in] BACnet lighting low end trim
* @param trim_fade_time [in] BACnet lighting trim fade time
*/ */
void lighting_command_trim_set( void lighting_command_trim_set(
struct bacnet_lighting_command_data *data, struct bacnet_lighting_command_data *data,
float High_End_Trim, float high_end_trim,
float Low_End_Trim, float low_end_trim,
uint32_t Trim_Fade_Time) uint32_t trim_fade_time)
{ {
float swap_value, high_trim, low_trim;
if (!data) { if (!data) {
return; return;
} }
lighting_command_lock(data); lighting_command_lock(data);
/* apply high and low trim */ /* clamp range within normalized limits */
data->High_Trim_Value = High_End_Trim; high_trim = lighting_command_normalized_on_range_clamp(high_end_trim);
data->Low_Trim_Value = Low_End_Trim; low_trim = lighting_command_normalized_on_range_clamp(low_end_trim);
data->Trim_Fade_Time = Trim_Fade_Time; /* valid range check for high and low trim values */
if (isgreater(low_trim, high_trim)) {
/* swap the trims if they are inverse */
swap_value = low_trim;
low_trim = high_trim;
high_trim = swap_value;
}
data->High_Trim_Value = high_trim;
data->Low_Trim_Value = low_trim;
data->Trim_Fade_Time = trim_fade_time;
lighting_command_unlock(data); lighting_command_unlock(data);
} }
/**
* @brief Set the lighting command key
* @param data [in] dimmer data
* @param key [in] BACnet lighting key
*/
void lighting_command_key_set( void lighting_command_key_set(
struct bacnet_lighting_command_data *data, uint32_t key) struct bacnet_lighting_command_data *data, uint32_t key)
{ {
@@ -1460,6 +1372,11 @@ void lighting_command_key_set(
lighting_command_unlock(data); lighting_command_unlock(data);
} }
/**
* @brief Set the lighting command tracking value callback
* @param data [in] dimmer data
* @param cb [in] BACnet lighting tracking value callback
*/
void lighting_command_tracking_value_callback_set( void lighting_command_tracking_value_callback_set(
struct bacnet_lighting_command_data *data, struct bacnet_lighting_command_data *data,
lighting_command_tracking_value_callback cb) lighting_command_tracking_value_callback cb)
@@ -1472,6 +1389,11 @@ void lighting_command_tracking_value_callback_set(
lighting_command_unlock(data); lighting_command_unlock(data);
} }
/**
* @brief Get the lighting command in progress
* @param data [in] dimmer data
* @return BACNET_LIGHTING_IN_PROGRESS - lighting command in progress
*/
BACNET_LIGHTING_IN_PROGRESS BACNET_LIGHTING_IN_PROGRESS
lighting_command_in_progress_get(struct bacnet_lighting_command_data *data) lighting_command_in_progress_get(struct bacnet_lighting_command_data *data)
{ {
@@ -1487,6 +1409,11 @@ lighting_command_in_progress_get(struct bacnet_lighting_command_data *data)
return in_progress; return in_progress;
} }
/**
* @brief Set the lighting command in progress
* @param data [in] dimmer data
* @param in_progress [in] BACnet lighting in progress
*/
void lighting_command_in_progress_set( void lighting_command_in_progress_set(
struct bacnet_lighting_command_data *data, struct bacnet_lighting_command_data *data,
BACNET_LIGHTING_IN_PROGRESS in_progress) BACNET_LIGHTING_IN_PROGRESS in_progress)
@@ -1499,6 +1426,11 @@ void lighting_command_in_progress_set(
lighting_command_unlock(data); lighting_command_unlock(data);
} }
/**
* @brief Get the lighting command tracking value
* @param data [in] dimmer data
* @return float - lighting command tracking value
*/
float lighting_command_tracking_value_get( float lighting_command_tracking_value_get(
struct bacnet_lighting_command_data *data) struct bacnet_lighting_command_data *data)
{ {
@@ -1514,6 +1446,11 @@ float lighting_command_tracking_value_get(
return value; return value;
} }
/**
* @brief Set the lighting command tracking value
* @param data [in] dimmer data
* @param value [in] BACnet lighting tracking value
*/
void lighting_command_tracking_value_set( void lighting_command_tracking_value_set(
struct bacnet_lighting_command_data *data, float value) struct bacnet_lighting_command_data *data, float value)
{ {
@@ -1541,6 +1478,11 @@ void lighting_command_blink_warn_feature_set(
lighting_command_unlock(data); lighting_command_unlock(data);
} }
/**
* @brief Check if the lighting command blink egress is active
* @param data [in] dimmer data
* @return bool - true if the lighting command blink egress is active
*/
bool lighting_command_blink_egress_active( bool lighting_command_blink_egress_active(
struct bacnet_lighting_command_data *data) struct bacnet_lighting_command_data *data)
{ {
@@ -1556,6 +1498,11 @@ bool lighting_command_blink_egress_active(
return active; return active;
} }
/**
* @brief Get the lighting command out of service
* @param data [in] dimmer data
* @return bool - true if the lighting command is out of service
*/
bool lighting_command_out_of_service_get( bool lighting_command_out_of_service_get(
struct bacnet_lighting_command_data *data) struct bacnet_lighting_command_data *data)
{ {
@@ -1571,6 +1518,11 @@ bool lighting_command_out_of_service_get(
return value; return value;
} }
/**
* @brief Set the lighting command out of service
* @param data [in] dimmer data
* @param value [in] BACnet lighting out of service
*/
void lighting_command_out_of_service_set( void lighting_command_out_of_service_set(
struct bacnet_lighting_command_data *data, bool value) struct bacnet_lighting_command_data *data, bool value)
{ {
@@ -1582,6 +1534,11 @@ void lighting_command_out_of_service_set(
lighting_command_unlock(data); lighting_command_unlock(data);
} }
/**
* @brief Get the lighting command last on value
* @param data [in] dimmer data
* @return float - lighting command last on value
*/
float lighting_command_last_on_value_get( float lighting_command_last_on_value_get(
struct bacnet_lighting_command_data *data) struct bacnet_lighting_command_data *data)
{ {
@@ -1597,6 +1554,11 @@ float lighting_command_last_on_value_get(
return value; return value;
} }
/**
* @brief Set the lighting command last on value
* @param data [in] dimmer data
* @param value [in] BACnet lighting last on value
*/
void lighting_command_last_on_value_set( void lighting_command_last_on_value_set(
struct bacnet_lighting_command_data *data, float value) struct bacnet_lighting_command_data *data, float value)
{ {
@@ -1608,6 +1570,11 @@ void lighting_command_last_on_value_set(
lighting_command_unlock(data); lighting_command_unlock(data);
} }
/**
* @brief Get the lighting command default on value
* @param data [in] dimmer data
* @return float - lighting command default on value
*/
float lighting_command_default_on_value_get( float lighting_command_default_on_value_get(
struct bacnet_lighting_command_data *data) struct bacnet_lighting_command_data *data)
{ {
@@ -1623,6 +1590,11 @@ float lighting_command_default_on_value_get(
return value; return value;
} }
/**
* @brief Set the lighting command default on value
* @param data [in] dimmer data
* @param value [in] BACnet lighting default on value
*/
void lighting_command_default_on_value_set( void lighting_command_default_on_value_set(
struct bacnet_lighting_command_data *data, float value) struct bacnet_lighting_command_data *data, float value)
{ {
@@ -1634,6 +1606,11 @@ void lighting_command_default_on_value_set(
lighting_command_unlock(data); lighting_command_unlock(data);
} }
/**
* @brief Get the lighting command overridden status
* @param data [in] dimmer data
* @return bool - true if the lighting command is overridden
*/
bool lighting_command_overridden_status( bool lighting_command_overridden_status(
struct bacnet_lighting_command_data *data) struct bacnet_lighting_command_data *data)
{ {
@@ -1649,6 +1626,27 @@ bool lighting_command_overridden_status(
return status; return status;
} }
/**
* @brief Get the lighting command feedback value
* @param data [in] dimmer data
* @return float - lighting command feedback value
*/
float lighting_command_feedback_value(struct bacnet_lighting_command_data *data)
{
float feedback_value;
if (!data) {
return 0.0f;
}
lighting_command_lock(data);
lighting_command_min_max_value_range_adjust(data);
feedback_value = lighting_command_normalized_to_physical_value(
data->Min_Actual_Value, data->Max_Actual_Value, data->Tracking_Value);
lighting_command_unlock(data);
return feedback_value;
}
/** /**
* @brief Determine if fade, ramp, or warn command is currently executing * @brief Determine if fade, ramp, or warn command is currently executing
* @param pObject [in] object to apply the trim values to * @param pObject [in] object to apply the trim values to
+12 -11
View File
@@ -13,10 +13,10 @@
#include "bacnet/bacdef.h" #include "bacnet/bacdef.h"
/** /**
* @brief Callback for tracking value updates * @brief Callback for lighting command notifications
* @param key - key used to link to specific light * @param key - key used to link to specific light
* @param old_value - value prior to write * @param old_value - physical value prior to write
* @param value - value of the write * @param value - physical value of the write
*/ */
typedef void (*lighting_command_tracking_value_callback)( typedef void (*lighting_command_tracking_value_callback)(
uint32_t key, float old_value, float value); uint32_t key, float old_value, float value);
@@ -165,22 +165,23 @@ BACNET_STACK_EXPORT
float lighting_command_ramp_rate_clamp(float ramp_rate); float lighting_command_ramp_rate_clamp(float ramp_rate);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
float lighting_command_step_increment_clamp(float step_increment); float lighting_command_step_increment_clamp(float step_increment);
BACNET_STACK_EXPORT
float lighting_command_operating_range_clamp(
struct bacnet_lighting_command_data *data, float value);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
float lighting_command_operating_range_clamp_fade( float lighting_command_operating_range_clamp_fade(
struct bacnet_lighting_command_data *data, struct bacnet_lighting_command_data *data,
float value, float value,
uint16_t milliseconds); uint16_t milliseconds);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
float lighting_command_normalized_range_clamp( float lighting_command_normalized_range_clamp(float value);
struct bacnet_lighting_command_data *data, float value);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
float lighting_command_normalized_on_range_clamp( float lighting_command_normalized_on_range_clamp(float value);
struct bacnet_lighting_command_data *data, float value);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
float lighting_command_physical_range_clamp(float value); float lighting_command_normalized_to_physical_value(
float min_value, float max_value, float normalized_value);
BACNET_STACK_EXPORT
float lighting_command_feedback_value(
struct bacnet_lighting_command_data *data);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void lighting_command_trim_set( void lighting_command_trim_set(
@@ -235,15 +235,23 @@ static void test_lighting_command_unit(void)
lighting_command_timer(&data, milliseconds); lighting_command_timer(&data, milliseconds);
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL); zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
/* normalized range clamp testing */ /* normalized range scaling to physical values */
data.Max_Actual_Value = 95.0f; data.Max_Actual_Value = 95.0f;
data.Min_Actual_Value = 5.0f; data.Min_Actual_Value = 5.0f;
target_level = lighting_command_normalized_range_clamp(&data, 0.1f); target_level = lighting_command_normalized_to_physical_value(
data.Min_Actual_Value, data.Max_Actual_Value, 0.1f);
zassert_true(is_float_equal(target_level, 0.0f), NULL); zassert_true(is_float_equal(target_level, 0.0f), NULL);
target_level = lighting_command_normalized_range_clamp(&data, 100.0f); target_level = lighting_command_normalized_to_physical_value(
data.Min_Actual_Value, data.Max_Actual_Value, 100.1f);
zassert_true(is_float_equal(target_level, data.Max_Actual_Value), NULL); zassert_true(is_float_equal(target_level, data.Max_Actual_Value), NULL);
target_level = lighting_command_normalized_range_clamp(&data, 1.0f); target_level = lighting_command_normalized_to_physical_value(
zassert_true(is_float_equal(target_level, data.Min_Actual_Value), NULL); data.Min_Actual_Value, data.Max_Actual_Value, 50.0f);
zassert_true(
islessequal(target_level, data.Max_Actual_Value), "physical-value=%.2f",
target_level);
zassert_true(
isgreaterequal(target_level, data.Min_Actual_Value),
"physical-value=%.2f", target_level);
data.Max_Actual_Value = 100.0f; data.Max_Actual_Value = 100.0f;
data.Min_Actual_Value = 1.0f; data.Min_Actual_Value = 1.0f;
@@ -306,8 +314,8 @@ static void test_lighting_command_unit(void)
lighting_command_timer(&data, milliseconds); lighting_command_timer(&data, milliseconds);
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL); zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
zassert_true(is_float_equal(Tracking_Value, target_level), NULL); zassert_true(is_float_equal(Tracking_Value, target_level), NULL);
data.Low_Trim_Value = data.Min_Actual_Value;
zassert_true(is_float_equal(data.Last_On_Value, 1.0f), NULL); zassert_true(is_float_equal(data.Last_On_Value, 1.0f), NULL);
data.Low_Trim_Value = 1.0f;
/* high trim */ /* high trim */
data.High_Trim_Value = 90.0f; data.High_Trim_Value = 90.0f;
target_level = 100.0f; target_level = 100.0f;
@@ -317,8 +325,8 @@ static void test_lighting_command_unit(void)
lighting_command_timer(&data, milliseconds); lighting_command_timer(&data, milliseconds);
zassert_true(data.In_Progress == BACNET_LIGHTING_TRIM_ACTIVE, NULL); zassert_true(data.In_Progress == BACNET_LIGHTING_TRIM_ACTIVE, NULL);
zassert_true(is_float_equal(Tracking_Value, data.High_Trim_Value), NULL); zassert_true(is_float_equal(Tracking_Value, data.High_Trim_Value), NULL);
data.High_Trim_Value = data.Max_Actual_Value;
zassert_true(is_float_equal(data.Last_On_Value, target_level), NULL); zassert_true(is_float_equal(data.Last_On_Value, target_level), NULL);
data.High_Trim_Value = 100.0f;
/* trim fade time */ /* trim fade time */
target_level = 80.0f; target_level = 80.0f;
milliseconds = 10; milliseconds = 10;
@@ -408,21 +416,21 @@ static void test_lighting_command_unit(void)
zassert_true(is_float_equal(target_step, 100.0f), NULL); zassert_true(is_float_equal(target_step, 100.0f), NULL);
/* physical range clamping */ /* physical range clamping */
target_level = lighting_command_physical_range_clamp(0.0f); target_level = lighting_command_normalized_range_clamp(0.0f);
zassert_true(is_float_equal(target_level, 0.0f), NULL); zassert_true(is_float_equal(target_level, 0.0f), NULL);
target_level = lighting_command_physical_range_clamp(0.5f); target_level = lighting_command_normalized_range_clamp(0.5f);
zassert_true(is_float_equal(target_level, 0.0f), NULL); zassert_true(is_float_equal(target_level, 0.0f), NULL);
target_level = lighting_command_physical_range_clamp(0.9f); target_level = lighting_command_normalized_range_clamp(0.9f);
zassert_true(is_float_equal(target_level, 0.0f), NULL); zassert_true(is_float_equal(target_level, 0.0f), NULL);
target_level = lighting_command_physical_range_clamp(1.0f); target_level = lighting_command_normalized_range_clamp(1.0f);
zassert_true(is_float_equal(target_level, 1.0f), NULL); zassert_true(is_float_equal(target_level, 1.0f), NULL);
target_level = lighting_command_physical_range_clamp(50.0f); target_level = lighting_command_normalized_range_clamp(50.0f);
zassert_true(is_float_equal(target_level, 50.0f), NULL); zassert_true(is_float_equal(target_level, 50.0f), NULL);
target_level = lighting_command_physical_range_clamp(100.0f); target_level = lighting_command_normalized_range_clamp(100.0f);
zassert_true(is_float_equal(target_level, 100.0f), NULL); zassert_true(is_float_equal(target_level, 100.0f), NULL);
target_level = lighting_command_physical_range_clamp(100.1f); target_level = lighting_command_normalized_range_clamp(100.1f);
zassert_true(is_float_equal(target_level, 100.0f), NULL); zassert_true(is_float_equal(target_level, 100.0f), NULL);
target_level = lighting_command_physical_range_clamp(150.0f); target_level = lighting_command_normalized_range_clamp(150.0f);
zassert_true(is_float_equal(target_level, 100.0f), NULL); zassert_true(is_float_equal(target_level, 100.0f), NULL);
/* step UP - inhibit ON */ /* step UP - inhibit ON */
@@ -483,7 +491,7 @@ static void test_lighting_command_unit(void)
is_float_equal(data.Last_On_Value, data.Max_Actual_Value), NULL); is_float_equal(data.Last_On_Value, data.Max_Actual_Value), NULL);
/* step DOWN, not off */ /* step DOWN, not off */
target_step = 1.0f; target_step = 1.0f;
target_level = data.Min_Actual_Value + target_step; target_level = 1.0f + target_step;
milliseconds = 10; milliseconds = 10;
lighting_command_fade_to(&data, target_level, 0); lighting_command_fade_to(&data, target_level, 0);
lighting_command_timer(&data, milliseconds); lighting_command_timer(&data, milliseconds);
@@ -492,18 +500,17 @@ static void test_lighting_command_unit(void)
lighting_command_step(&data, BACNET_LIGHTS_STEP_DOWN, target_step); lighting_command_step(&data, BACNET_LIGHTS_STEP_DOWN, target_step);
lighting_command_timer(&data, milliseconds); lighting_command_timer(&data, milliseconds);
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL); zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
zassert_true(is_float_equal(Tracking_Value, data.Min_Actual_Value), NULL); zassert_true(is_float_equal(Tracking_Value, 1.0f), NULL);
zassert_true( zassert_true(is_float_equal(data.Last_On_Value, 1.0f), NULL);
is_float_equal(data.Last_On_Value, data.Min_Actual_Value), NULL); /* clamp to min normal */
/* clamp to min */
target_step = 100.0f; target_step = 100.0f;
lighting_command_step(&data, BACNET_LIGHTS_STEP_DOWN, target_step); lighting_command_step(&data, BACNET_LIGHTS_STEP_DOWN, target_step);
lighting_command_timer(&data, milliseconds); lighting_command_timer(&data, milliseconds);
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL); zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
zassert_true(is_float_equal(Tracking_Value, data.Min_Actual_Value), NULL); zassert_true(is_float_equal(Tracking_Value, 1.0f), NULL);
/* step DOWN and off */ /* step DOWN and off */
target_step = 100.0f; target_step = 100.0f;
target_level = data.Min_Actual_Value; target_level = 1.0f;
milliseconds = 10; milliseconds = 10;
lighting_command_fade_to(&data, target_level, 0); lighting_command_fade_to(&data, target_level, 0);
lighting_command_timer(&data, milliseconds); lighting_command_timer(&data, milliseconds);
@@ -513,8 +520,7 @@ static void test_lighting_command_unit(void)
lighting_command_timer(&data, milliseconds); lighting_command_timer(&data, milliseconds);
zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL); zassert_true(data.In_Progress == BACNET_LIGHTING_IDLE, NULL);
zassert_true(is_float_equal(Tracking_Value, 0.0f), NULL); zassert_true(is_float_equal(Tracking_Value, 0.0f), NULL);
zassert_true( zassert_true(is_float_equal(data.Last_On_Value, 1.0f), NULL);
is_float_equal(data.Last_On_Value, data.Min_Actual_Value), NULL);
/* blink warn - immediate off */ /* blink warn - immediate off */
data.Blink.Interval = 0; data.Blink.Interval = 0;
data.Blink.Duration = 0; data.Blink.Duration = 0;
@@ -574,8 +580,8 @@ static void test_lighting_command_unit(void)
data.In_Progress == BACNET_LIGHTING_RAMP_ACTIVE, data.In_Progress == BACNET_LIGHTING_RAMP_ACTIVE,
"In_Progress=%d", data.In_Progress); "In_Progress=%d", data.In_Progress);
zassert_true( zassert_true(
isgreater(data.Tracking_Value, data.Min_Actual_Value), isgreater(data.Tracking_Value, 1.0f), "Tracking_Value=%f",
"Tracking_Value=%f", Tracking_Value); Tracking_Value);
zassert_true( zassert_true(
isless(data.Tracking_Value, data.Max_Actual_Value), isless(data.Tracking_Value, data.Max_Actual_Value),
"Tracking_Value=%f", Tracking_Value); "Tracking_Value=%f", Tracking_Value);
@@ -583,7 +589,7 @@ static void test_lighting_command_unit(void)
} while (data.Lighting_Operation != BACNET_LIGHTS_STOP); } while (data.Lighting_Operation != BACNET_LIGHTS_STOP);
/* slower ramp down */ /* slower ramp down */
target_level = data.Min_Actual_Value; target_level = 1.0f;
milliseconds = 33; milliseconds = 33;
ramp_rate = 0.1f; ramp_rate = 0.1f;
do { do {
@@ -594,15 +600,14 @@ static void test_lighting_command_unit(void)
data.In_Progress == BACNET_LIGHTING_RAMP_ACTIVE, data.In_Progress == BACNET_LIGHTING_RAMP_ACTIVE,
"In_Progress=%d", data.In_Progress); "In_Progress=%d", data.In_Progress);
zassert_true( zassert_true(
isgreater(data.Tracking_Value, data.Min_Actual_Value), isgreater(data.Tracking_Value, 1.0f), "Tracking_Value=%f",
"Tracking_Value=%f", Tracking_Value); Tracking_Value);
zassert_true( zassert_true(
isless(data.Tracking_Value, data.Max_Actual_Value), isless(data.Tracking_Value, data.Max_Actual_Value),
"Tracking_Value=%f", Tracking_Value); "Tracking_Value=%f", Tracking_Value);
} }
} while (data.Lighting_Operation != BACNET_LIGHTS_STOP); } while (data.Lighting_Operation != BACNET_LIGHTS_STOP);
zassert_true( zassert_true(is_float_equal(data.Last_On_Value, 1.0f), NULL);
is_float_equal(data.Last_On_Value, data.Min_Actual_Value), NULL);
/* large elapsed timer - ramp up */ /* large elapsed timer - ramp up */
target_level = data.Max_Actual_Value; target_level = data.Max_Actual_Value;
milliseconds = 2000; milliseconds = 2000;
@@ -615,8 +620,8 @@ static void test_lighting_command_unit(void)
data.In_Progress == BACNET_LIGHTING_RAMP_ACTIVE, data.In_Progress == BACNET_LIGHTING_RAMP_ACTIVE,
"In_Progress=%d", data.In_Progress); "In_Progress=%d", data.In_Progress);
zassert_true( zassert_true(
isgreater(data.Tracking_Value, data.Min_Actual_Value), isgreater(data.Tracking_Value, 1.0f), "Tracking_Value=%f",
"Tracking_Value=%f", Tracking_Value); Tracking_Value);
zassert_true( zassert_true(
isless(data.Tracking_Value, data.Max_Actual_Value), isless(data.Tracking_Value, data.Max_Actual_Value),
"Tracking_Value=%f", Tracking_Value); "Tracking_Value=%f", Tracking_Value);