Changed the load control object AbleToMeetShed to only check immediate, and added CanNowComplyWithShed function to attempt to meet the shed request while in the non-compliant state. (#1191)

This commit is contained in:
Steve Karg
2025-12-18 11:08:03 -06:00
committed by GitHub
parent df335343f3
commit 390711a604
5 changed files with 218 additions and 161 deletions
+3
View File
@@ -52,6 +52,9 @@ The git repositories are hosted at the following sites:
### Changed ### Changed
* Changed the load control object AbleToMeetShed to only check for immediate
shed ability and added CanNowComplyWithShed function to attempt to meet the
shed request while in the non-compliant state. (#1191)
* Changed the size of MAX_HEADER in BACDL_MULTIPLE because 8 is not * Changed the size of MAX_HEADER in BACDL_MULTIPLE because 8 is not
big enough for some datalinks (e.g. mstp). (#1170) big enough for some datalinks (e.g. mstp). (#1170)
* Changed printf() in many apps to use debug_printf() and friends. (#1168) * Changed printf() in many apps to use debug_printf() and friends. (#1168)
+141 -138
View File
@@ -412,7 +412,7 @@ Shed_Level_Default_Set(BACNET_SHED_LEVEL *dest, BACNET_SHED_LEVEL_TYPE type)
} }
/** /**
* @brief Determine if the object can meet the shed request * @brief Determine if the object can immediately meet the shed request
* @param pObject - object instance to get * @param pObject - object instance to get
* @return true if the object can meet the shed request * @return true if the object can meet the shed request
*/ */
@@ -429,19 +429,46 @@ static bool Able_To_Meet_Shed_Request(struct object_data *pObject)
pObject->Manipulated_Object_Instance, pObject->Manipulated_Object_Instance,
pObject->Manipulated_Object_Property, &priority, &level); pObject->Manipulated_Object_Property, &priority, &level);
requested_level = Requested_Shed_Level_Value(pObject); requested_level = Requested_Shed_Level_Value(pObject);
if (level >= requested_level) { if (level < requested_level) {
status = true; status = true;
} }
} }
if (status) {
status = false; return status;
/* can we control the output? */ }
if (priority >= pObject->Priority_For_Writing) {
/* is the level able to be lowered? */ /**
requested_level = Requested_Shed_Level_Value(pObject); * @brief Determine if the object can now comply with the shed request
if (level >= requested_level) { * @param pObject - object instance to get
status = true; * @return true if the object can comply with the shed request
} */
static bool Can_Now_Comply_With_Shed(struct object_data *pObject)
{
float level = 0.0f;
float requested_level = 0.0f;
uint8_t priority = 0;
bool status = false;
if (pObject->Manipulated_Object_Read) {
pObject->Manipulated_Object_Read(
pObject->Manipulated_Object_Type,
pObject->Manipulated_Object_Instance,
pObject->Manipulated_Object_Property, &priority, &level);
requested_level = Requested_Shed_Level_Value(pObject);
if (level <= requested_level) {
status = true;
}
}
if (!status) {
/* the object attempts to meet the shed request
until the shed is achieved. */
if (pObject->Manipulated_Object_Write) {
pObject->Manipulated_Object_Write(
pObject->Manipulated_Object_Type,
pObject->Manipulated_Object_Instance,
pObject->Manipulated_Object_Property,
pObject->Priority_For_Writing,
Requested_Shed_Level_Value(pObject));
} }
} }
@@ -547,24 +574,26 @@ void Load_Control_State_Machine(
" is after Start Time\n", " is after Start Time\n",
object_index); object_index);
/* AbleToMeetShed */ /* AbleToMeetShed */
/* If the current time is after Start_Time and the object
is able to achieve the shed request immediately,
it shall shed its loads, calculate Expected_Shed_Level
and Actual_Shed_Level, and enter the SHED_COMPLIANT state. */
if (Able_To_Meet_Shed_Request(pObject)) { if (Able_To_Meet_Shed_Request(pObject)) {
Shed_Level_Copy( Shed_Level_Copy(
&pObject->Expected_Shed_Level, &pObject->Expected_Shed_Level,
&pObject->Requested_Shed_Level); &pObject->Requested_Shed_Level);
if (pObject->Manipulated_Object_Write) {
pObject->Manipulated_Object_Write(
pObject->Manipulated_Object_Type,
pObject->Manipulated_Object_Instance,
pObject->Manipulated_Object_Property,
pObject->Priority_For_Writing,
Requested_Shed_Level_Value(pObject));
}
Shed_Level_Copy( Shed_Level_Copy(
&pObject->Actual_Shed_Level, &pObject->Actual_Shed_Level,
&pObject->Requested_Shed_Level); &pObject->Requested_Shed_Level);
pObject->Present_Value = BACNET_SHED_COMPLIANT; pObject->Present_Value = BACNET_SHED_COMPLIANT;
} else { } else {
/* CannotMeetShed */ /* CannotMeetShed */
/* If the current time is after Start_Time,
and the object is unable to meet the shed
request immediately, it shall begin shedding
its loads, calculate Expected_Shed_Level and
Actual_Shed_Level, and enter the SHED_NON_COMPLIANT
state. */
Shed_Level_Default_Set( Shed_Level_Default_Set(
&pObject->Expected_Shed_Level, &pObject->Expected_Shed_Level,
pObject->Requested_Shed_Level.type); pObject->Requested_Shed_Level.type);
@@ -576,6 +605,10 @@ void Load_Control_State_Machine(
} }
break; break;
case BACNET_SHED_NON_COMPLIANT: case BACNET_SHED_NON_COMPLIANT:
/* In the SHED_NON_COMPLIANT state, the object attempts
to meet the shed request until the shed is achieved,
the object is reconfigured, or the request has completed
unsuccessfully. */
datetime_copy(&pObject->End_Time, &pObject->Start_Time); datetime_copy(&pObject->End_Time, &pObject->Start_Time);
datetime_add_minutes(&pObject->End_Time, pObject->Shed_Duration); datetime_add_minutes(&pObject->End_Time, pObject->Shed_Duration);
diff = datetime_compare(&pObject->End_Time, bdatetime); diff = datetime_compare(&pObject->End_Time, bdatetime);
@@ -598,7 +631,7 @@ void Load_Control_State_Machine(
pObject->Present_Value = BACNET_SHED_REQUEST_PENDING; pObject->Present_Value = BACNET_SHED_REQUEST_PENDING;
break; break;
} }
if (Able_To_Meet_Shed_Request(pObject)) { if (Can_Now_Comply_With_Shed(pObject)) {
/* CanNowComplyWithShed */ /* CanNowComplyWithShed */
debug_printf( debug_printf(
"Load Control[%d]:Able to meet Shed Request\n", "Load Control[%d]:Able to meet Shed Request\n",
@@ -606,14 +639,6 @@ void Load_Control_State_Machine(
Shed_Level_Copy( Shed_Level_Copy(
&pObject->Expected_Shed_Level, &pObject->Expected_Shed_Level,
&pObject->Requested_Shed_Level); &pObject->Requested_Shed_Level);
if (pObject->Manipulated_Object_Write) {
pObject->Manipulated_Object_Write(
pObject->Manipulated_Object_Type,
pObject->Manipulated_Object_Instance,
pObject->Manipulated_Object_Property,
pObject->Priority_For_Writing,
Requested_Shed_Level_Value(pObject));
}
Shed_Level_Copy( Shed_Level_Copy(
&pObject->Actual_Shed_Level, &pObject->Actual_Shed_Level,
&pObject->Requested_Shed_Level); &pObject->Requested_Shed_Level);
@@ -869,6 +894,24 @@ bool Load_Control_Manipulated_Variable_Reference_Set(
return status; return status;
} }
/**
* @brief Return the number of shed levels in this array
* @param object_instance [in] BACnet object instance number
* @return Count of shed levels in the list.
*/
static int Load_Control_Shed_Levels_Count(uint32_t object_instance)
{
int count = 0;
struct object_data *pObject = NULL;
pObject = Object_Instance_Data(object_instance);
if (pObject) {
count = Keylist_Count(pObject->Shed_Level_List);
}
return count;
}
/** /**
* @brief Encode a BACnetARRAY property element * @brief Encode a BACnetARRAY property element
* @param object_instance [in] BACnet object instance number * @param object_instance [in] BACnet object instance number
@@ -1089,7 +1132,7 @@ int Load_Control_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
BACnet_Shed_Level_Encode(apdu, &pObject->Actual_Shed_Level); BACnet_Shed_Level_Encode(apdu, &pObject->Actual_Shed_Level);
break; break;
case PROP_SHED_LEVELS: case PROP_SHED_LEVELS:
count = Keylist_Count(pObject->Shed_Level_List); count = Load_Control_Shed_Levels_Count(rpdata->object_instance);
apdu_len = bacnet_array_encode( apdu_len = bacnet_array_encode(
rpdata->object_instance, rpdata->array_index, rpdata->object_instance, rpdata->array_index,
Load_Control_Shed_Levels_Encode, count, apdu, apdu_size); Load_Control_Shed_Levels_Encode, count, apdu, apdu_size);
@@ -1102,7 +1145,7 @@ int Load_Control_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
} }
break; break;
case PROP_SHED_LEVEL_DESCRIPTIONS: case PROP_SHED_LEVEL_DESCRIPTIONS:
count = Keylist_Count(pObject->Shed_Level_List); count = Load_Control_Shed_Levels_Count(rpdata->object_instance);
apdu_len = bacnet_array_encode( apdu_len = bacnet_array_encode(
rpdata->object_instance, rpdata->array_index, rpdata->object_instance, rpdata->array_index,
Load_Control_Shed_Level_Descriptions_Encode, count, apdu, Load_Control_Shed_Level_Descriptions_Encode, count, apdu,
@@ -1328,126 +1371,78 @@ static bool Load_Control_Duty_Window_Write(
} }
/** /**
* @brief For a given object instance-number, writes to the property value * @brief Decode a BACnetLIST property element to determine the element length
* @param wp_data - BACNET_WRITE_PROPERTY_DATA data, including * @param object_instance [in] BACnet object instance number
* requested data and space for the reply, or error response. * @param apdu [in] Buffer in which the APDU contents are extracted
* * @param apdu_size [in] The size of the APDU buffer
* @return false if an error is loaded, true if no errors * @return The length of the decoded apdu, or BACNET_STATUS_ERROR on error
*/ */
static bool Load_Control_Shed_Levels_Write(BACNET_WRITE_PROPERTY_DATA *wp_data) static int BACnet_Shed_Level_Element_Length(
uint32_t object_instance, uint8_t *apdu, size_t apdu_size)
{ {
struct object_data *pObject; (void)object_instance;
BACNET_UNSIGNED_INTEGER unsigned_value; return bacnet_shed_level_decode(apdu, apdu_size, NULL);
struct shed_level_data *entry; }
int len = 0, index = 0, count = 0, apdu_len = 0, apdu_size = 0;
KEY key;
uint8_t *apdu;
pObject = Object_Instance_Data(wp_data->object_instance); /**
if (!pObject) { * @brief Write a value to a BACnetLIST property element value
wp_data->error_class = ERROR_CLASS_OBJECT; * using a BACnetARRAY write utility function
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT; * @param object_instance [in] BACnet object instance number
return false; * @param array_index [in] array index to write:
} * 0=array size, 1 to N for individual array members
count = Keylist_Count(pObject->Shed_Level_List); * @param application_data [in] encoded element value
if (wp_data->array_index == 0) { * @param application_data_len [in] The size of the encoded element value
/* This array is not required to be resizable * @return BACNET_ERROR_CODE value
through BACnet write services */ */
wp_data->error_class = ERROR_CLASS_PROPERTY; static BACNET_ERROR_CODE BACnet_Shed_Level_Element_Write(
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED; uint32_t object_instance,
return false; BACNET_ARRAY_INDEX array_index,
} else if (wp_data->array_index == BACNET_ARRAY_ALL) { uint8_t *application_data,
/* The size of this array shall be equal to the size_t application_data_len)
size of the Shed_Level_Descriptions array.*/ {
/* will the array elements sent fit in the whole array? */ BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
apdu = wp_data->application_data; BACNET_SHED_LEVEL shed_level = { 0 };
apdu_size = wp_data->application_data_len; struct shed_level_data *entry = NULL;
while (count > 0) { int len = 0;
len = bacnet_unsigned_application_decode( struct object_data *pObject = NULL;
&apdu[apdu_len], apdu_size - apdu_len, &unsigned_value); KEY key = 0;
if (len > 0) { int count = 0;
if (unsigned_value > UINT32_MAX) {
wp_data->error_class = ERROR_CLASS_PROPERTY; pObject = Object_Instance_Data(object_instance);
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; if (pObject) {
return false;
}
apdu_len += len;
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
return false;
}
count--;
}
if (apdu_len != wp_data->application_data_len) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
/* write entire array - we know the size and values are valid */
count = Keylist_Count(pObject->Shed_Level_List); count = Keylist_Count(pObject->Shed_Level_List);
apdu = wp_data->application_data; if (array_index == 0) {
apdu_size = wp_data->application_data_len; /* This array is not required to be resizable
while (count > 0) { through BACnet write services */
len = bacnet_unsigned_application_decode( error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
&apdu[apdu_len], apdu_size - apdu_len, &unsigned_value); } else if (array_index <= count) {
len = bacnet_shed_level_decode(
application_data, application_data_len, &shed_level);
if (len > 0) { if (len > 0) {
apdu_len += len; /* represents the shed levels for the LEVEL choice */
if (unsigned_value <= UINT32_MAX) { if (shed_level.type != BACNET_SHED_TYPE_LEVEL) {
index = count - 1; error_code = ERROR_CODE_INVALID_DATA_TYPE;
entry = Keylist_Data_Delete_By_Index( } else if (shed_level.value.level <= 100) {
pObject->Shed_Level_List, index); /* our implementation uses percent of baseline */
key = (uint32_t)unsigned_value; key = array_index - 1;
index = entry = Keylist_Data(pObject->Shed_Level_List, key);
Keylist_Data_Add(pObject->Shed_Level_List, key, entry); if (entry) {
if (index < 0) { entry->Value = (float)shed_level.value.level;
wp_data->error_class = ERROR_CLASS_PROPERTY; } else {
wp_data->error_code = error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
return false;
} }
} else { } else {
wp_data->error_class = ERROR_CLASS_PROPERTY; error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
} }
}
count--;
}
} else if (wp_data->array_index <= count) {
len = bacnet_unsigned_application_decode(
wp_data->application_data, wp_data->application_data_len,
&unsigned_value);
if (len > 0) {
if (unsigned_value <= UINT32_MAX) {
index = wp_data->array_index - 1;
entry = Keylist_Data_Delete_By_Index(
pObject->Shed_Level_List, index);
key = (uint32_t)unsigned_value;
index = Keylist_Data_Add(pObject->Shed_Level_List, key, entry);
if (index < 0) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
return false;
}
} else { } else {
wp_data->error_class = ERROR_CLASS_PROPERTY; error_code = ERROR_CODE_INVALID_DATA_TYPE;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
} }
} else { } else {
wp_data->error_class = ERROR_CLASS_PROPERTY; error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
return false;
} }
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
return false;
} }
return true; return error_code;
} }
/** /**
@@ -1492,7 +1487,7 @@ static bool Load_Control_Enable_Write(
bool Load_Control_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) bool Load_Control_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
{ {
bool status = false; /* return value */ bool status = false; /* return value */
int len = 0; int len = 0, count = 0;
BACNET_APPLICATION_DATA_VALUE value = { 0 }; BACNET_APPLICATION_DATA_VALUE value = { 0 };
if (wp_data == NULL) { if (wp_data == NULL) {
@@ -1562,7 +1557,15 @@ bool Load_Control_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
break; break;
case PROP_SHED_LEVELS: case PROP_SHED_LEVELS:
status = Load_Control_Shed_Levels_Write(wp_data); count = Load_Control_Shed_Levels_Count(wp_data->object_instance);
wp_data->error_code = bacnet_array_write(
wp_data->object_instance, wp_data->array_index,
BACnet_Shed_Level_Element_Length,
BACnet_Shed_Level_Element_Write, count,
wp_data->application_data, wp_data->application_data_len);
if (wp_data->error_code == ERROR_CODE_SUCCESS) {
status = true;
}
break; break;
case PROP_ENABLE: case PROP_ENABLE:
+39
View File
@@ -257,3 +257,42 @@ bool bacnet_shed_level_from_ascii(BACNET_SHED_LEVEL *value, const char *argv)
return status; return status;
} }
/**
* @brief Initialize a BACnetShedLevel structure
* @param value - pointer to the BACNET_SHED_LEVEL structure
* @param type - type of shed level
* @param level - level value as float
* @return true on success, else false
*/
bool bacnet_shed_level_init(
BACNET_SHED_LEVEL *value, BACNET_SHED_LEVEL_TYPE type, float level)
{
if (!value) {
return false;
}
value->type = type;
switch (type) {
case BACNET_SHED_TYPE_PERCENT:
if (level < 0.0f || level > 100.0f) {
return false;
}
value->value.percent = (BACNET_UNSIGNED_INTEGER)level;
break;
case BACNET_SHED_TYPE_LEVEL:
if (level < 0.0f) {
return false;
}
value->value.level = (BACNET_UNSIGNED_INTEGER)level;
break;
case BACNET_SHED_TYPE_AMOUNT:
if (level < 0.0f) {
return false;
}
value->value.amount = level;
break;
default:
return false;
}
return true;
}
+4
View File
@@ -52,6 +52,10 @@ int bacapp_snprintf_shed_level(
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
bool bacnet_shed_level_from_ascii(BACNET_SHED_LEVEL *value, const char *argv); bool bacnet_shed_level_from_ascii(BACNET_SHED_LEVEL *value, const char *argv);
BACNET_STACK_EXPORT
bool bacnet_shed_level_init(
BACNET_SHED_LEVEL *value, BACNET_SHED_LEVEL_TYPE type, float level);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
+31 -23
View File
@@ -8,6 +8,7 @@
#include <zephyr/ztest.h> #include <zephyr/ztest.h>
#include <bacnet/bacdcode.h> #include <bacnet/bacdcode.h>
#include <bacnet/bacstr.h> #include <bacnet/bacstr.h>
#include <bacnet/bactext.h>
#include <bacnet/basic/object/ao.h> #include <bacnet/basic/object/ao.h>
#include <bacnet/basic/object/lc.h> #include <bacnet/basic/object/lc.h>
#include <property_test.h> #include <property_test.h>
@@ -40,8 +41,8 @@ static bool is_float_equal(float x1, float x2)
* @brief Test * @brief Test
*/ */
static void static void Load_Control_WriteProperty_Request_Shed_Level(
Load_Control_WriteProperty_Request_Shed_Level(int instance, unsigned level) int instance, BACNET_SHED_LEVEL_TYPE type, float level)
{ {
bool status = false; bool status = false;
BACNET_APPLICATION_DATA_VALUE value = { 0 }; BACNET_APPLICATION_DATA_VALUE value = { 0 };
@@ -52,8 +53,7 @@ Load_Control_WriteProperty_Request_Shed_Level(int instance, unsigned level)
wp_data.array_index = BACNET_ARRAY_ALL; wp_data.array_index = BACNET_ARRAY_ALL;
wp_data.priority = BACNET_NO_PRIORITY; wp_data.priority = BACNET_NO_PRIORITY;
wp_data.object_property = PROP_REQUESTED_SHED_LEVEL; wp_data.object_property = PROP_REQUESTED_SHED_LEVEL;
value.type.Shed_Level.type = BACNET_SHED_TYPE_LEVEL; bacnet_shed_level_init(&value.type.Shed_Level, type, level);
value.type.Shed_Level.value.level = level;
wp_data.application_data_len = bacapp_encode_known_property( wp_data.application_data_len = bacapp_encode_known_property(
&wp_data.application_data[0], &value, wp_data.object_type, &wp_data.application_data[0], &value, wp_data.object_type,
wp_data.object_property); wp_data.object_property);
@@ -457,7 +457,8 @@ static void testLoadControlStateMachine(void)
zassert_true(status, NULL); zassert_true(status, NULL);
status = Load_Control_Update_Interval_Set(object_instance, 0); status = Load_Control_Update_Interval_Set(object_instance, 0);
zassert_true(status, NULL); zassert_true(status, NULL);
Load_Control_WriteProperty_Request_Shed_Level(object_instance, 0); Load_Control_WriteProperty_Request_Shed_Level(
object_instance, BACNET_SHED_TYPE_LEVEL, 0.0f);
Load_Control_WriteProperty_Start_Time( Load_Control_WriteProperty_Start_Time(
object_instance, 2007, 2, 27, 15, 0, 0, 0); object_instance, 2007, 2, 27, 15, 0, 0, 0);
Load_Control_WriteProperty_Shed_Duration(object_instance, 5); Load_Control_WriteProperty_Shed_Duration(object_instance, 5);
@@ -480,7 +481,8 @@ static void testLoadControlStateMachine(void)
status = Load_Control_Update_Interval_Set(object_instance, 0); status = Load_Control_Update_Interval_Set(object_instance, 0);
zassert_true(status, NULL); zassert_true(status, NULL);
Load_Control_WriteProperty_Enable(object_instance, true); Load_Control_WriteProperty_Enable(object_instance, true);
Load_Control_WriteProperty_Request_Shed_Level(object_instance, 1); Load_Control_WriteProperty_Request_Shed_Level(
object_instance, BACNET_SHED_TYPE_LEVEL, 1.0f);
Load_Control_WriteProperty_Shed_Duration(object_instance, 5); Load_Control_WriteProperty_Shed_Duration(object_instance, 5);
Load_Control_WriteProperty_Start_Time( Load_Control_WriteProperty_Start_Time(
object_instance, 2007, 2, 27, 15, 0, 0, 0); object_instance, 2007, 2, 27, 15, 0, 0, 0);
@@ -503,7 +505,8 @@ static void testLoadControlStateMachine(void)
status = Load_Control_Update_Interval_Set(object_instance, 0); status = Load_Control_Update_Interval_Set(object_instance, 0);
zassert_true(status, NULL); zassert_true(status, NULL);
Load_Control_WriteProperty_Enable(object_instance, true); Load_Control_WriteProperty_Enable(object_instance, true);
Load_Control_WriteProperty_Request_Shed_Level(object_instance, 1); Load_Control_WriteProperty_Request_Shed_Level(
object_instance, BACNET_SHED_TYPE_LEVEL, 1.0f);
Load_Control_WriteProperty_Shed_Duration(object_instance, 5); Load_Control_WriteProperty_Shed_Duration(object_instance, 5);
Load_Control_WriteProperty_Start_Time( Load_Control_WriteProperty_Start_Time(
object_instance, 2007, 2, 27, 15, 0, 0, 0); object_instance, 2007, 2, 27, 15, 0, 0, 0);
@@ -517,7 +520,8 @@ static void testLoadControlStateMachine(void)
zassert_equal( zassert_equal(
Load_Control_Present_Value(object_instance), Load_Control_Present_Value(object_instance),
BACNET_SHED_REQUEST_PENDING, NULL); BACNET_SHED_REQUEST_PENDING, NULL);
Load_Control_WriteProperty_Request_Shed_Level(object_instance, 2); Load_Control_WriteProperty_Request_Shed_Level(
object_instance, BACNET_SHED_TYPE_LEVEL, 2.0f);
Load_Control_Timer(object_instance, 1); Load_Control_Timer(object_instance, 1);
zassert_equal( zassert_equal(
Load_Control_Present_Value(object_instance), Load_Control_Present_Value(object_instance),
@@ -556,7 +560,8 @@ static void testLoadControlStateMachine(void)
status = Load_Control_Update_Interval_Set(object_instance, 0); status = Load_Control_Update_Interval_Set(object_instance, 0);
zassert_true(status, NULL); zassert_true(status, NULL);
Load_Control_WriteProperty_Enable(object_instance, true); Load_Control_WriteProperty_Enable(object_instance, true);
Load_Control_WriteProperty_Request_Shed_Level(object_instance, 1); Load_Control_WriteProperty_Request_Shed_Level(
object_instance, BACNET_SHED_TYPE_LEVEL, 1.0f);
Load_Control_WriteProperty_Shed_Duration(object_instance, 120); Load_Control_WriteProperty_Shed_Duration(object_instance, 120);
Load_Control_WriteProperty_Start_Time( Load_Control_WriteProperty_Start_Time(
object_instance, 2007, 2, 27, 15, 0, 0, 0); object_instance, 2007, 2, 27, 15, 0, 0, 0);
@@ -570,8 +575,8 @@ static void testLoadControlStateMachine(void)
zassert_equal( zassert_equal(
Load_Control_Present_Value(object_instance), Load_Control_Present_Value(object_instance),
BACNET_SHED_REQUEST_PENDING, NULL); BACNET_SHED_REQUEST_PENDING, NULL);
/* set to lowest value so we cannot meet the shed level */ /* set to value that cannot meet the shed level immediately */
Test_Present_Value_Priority_Set(0.0f, 16); Test_Present_Value_Priority_Set(100.0f, 16);
datetime_set_values(&bdatetime, 2007, 2, 27, 16, 0, 0, 0); datetime_set_values(&bdatetime, 2007, 2, 27, 16, 0, 0, 0);
datetime_timesync(&bdatetime.date, &bdatetime.time, false); datetime_timesync(&bdatetime.date, &bdatetime.time, false);
Load_Control_Timer(object_instance, 1); Load_Control_Timer(object_instance, 1);
@@ -598,7 +603,8 @@ static void testLoadControlStateMachine(void)
status = Load_Control_Update_Interval_Set(object_instance, 0); status = Load_Control_Update_Interval_Set(object_instance, 0);
zassert_true(status, NULL); zassert_true(status, NULL);
Load_Control_WriteProperty_Enable(object_instance, true); Load_Control_WriteProperty_Enable(object_instance, true);
Load_Control_WriteProperty_Request_Shed_Level(object_instance, 1); Load_Control_WriteProperty_Request_Shed_Level(
object_instance, BACNET_SHED_TYPE_LEVEL, 1.0f);
Load_Control_WriteProperty_Shed_Duration(object_instance, 120); Load_Control_WriteProperty_Shed_Duration(object_instance, 120);
Load_Control_WriteProperty_Start_Time( Load_Control_WriteProperty_Start_Time(
object_instance, 2007, 2, 27, 15, 0, 0, 0); object_instance, 2007, 2, 27, 15, 0, 0, 0);
@@ -612,8 +618,8 @@ static void testLoadControlStateMachine(void)
zassert_equal( zassert_equal(
Load_Control_Present_Value(object_instance), Load_Control_Present_Value(object_instance),
BACNET_SHED_REQUEST_PENDING, NULL); BACNET_SHED_REQUEST_PENDING, NULL);
/* set to lowest value so we cannot meet the shed level */ /* not able to meet the shed level immediately */
Test_Present_Value_Priority_Set(0.0f, 16); Test_Present_Value_Priority_Set(100.0f, 16);
datetime_set_values(&bdatetime, 2007, 2, 27, 16, 0, 0, 0); datetime_set_values(&bdatetime, 2007, 2, 27, 16, 0, 0, 0);
datetime_timesync(&bdatetime.date, &bdatetime.time, false); datetime_timesync(&bdatetime.date, &bdatetime.time, false);
Load_Control_Timer(object_instance, 1); Load_Control_Timer(object_instance, 1);
@@ -700,11 +706,8 @@ static void testLoadControlStateMachine(void)
status = Load_Control_Update_Interval_Set(object_instance, 0); status = Load_Control_Update_Interval_Set(object_instance, 0);
zassert_true(status, NULL); zassert_true(status, NULL);
Load_Control_WriteProperty_Enable(object_instance, true); Load_Control_WriteProperty_Enable(object_instance, true);
shed_level.type = BACNET_SHED_TYPE_PERCENT; Load_Control_WriteProperty_Request_Shed_Level(
shed_level.value.percent = 20; object_instance, BACNET_SHED_TYPE_PERCENT, 20.0f);
status =
Load_Control_Requested_Shed_Level_Set(object_instance, &shed_level);
zassert_true(status, NULL);
Load_Control_WriteProperty_Start_Time( Load_Control_WriteProperty_Start_Time(
object_instance, 2007, 2, 27, 15, 0, 0, 0); object_instance, 2007, 2, 27, 15, 0, 0, 0);
Load_Control_WriteProperty_Shed_Duration(object_instance, 5); Load_Control_WriteProperty_Shed_Duration(object_instance, 5);
@@ -714,6 +717,7 @@ static void testLoadControlStateMachine(void)
shed_state = Load_Control_Present_Value(object_instance); shed_state = Load_Control_Present_Value(object_instance);
zassert_equal(shed_state, BACNET_SHED_REQUEST_PENDING, NULL); zassert_equal(shed_state, BACNET_SHED_REQUEST_PENDING, NULL);
/* configure for non-compliance */ /* configure for non-compliance */
Test_Present_Value_Priority_Set(100.0f, 16);
datetime_set_values(&bdatetime, 2007, 2, 27, 15, 0, 2, 0); datetime_set_values(&bdatetime, 2007, 2, 27, 15, 0, 2, 0);
datetime_timesync(&bdatetime.date, &bdatetime.time, false); datetime_timesync(&bdatetime.date, &bdatetime.time, false);
Load_Control_Timer(object_instance, 1); Load_Control_Timer(object_instance, 1);
@@ -721,7 +725,7 @@ static void testLoadControlStateMachine(void)
zassert_equal(shed_state, BACNET_SHED_NON_COMPLIANT, NULL); zassert_equal(shed_state, BACNET_SHED_NON_COMPLIANT, NULL);
/* configure for compliance */ /* configure for compliance */
priority = Load_Control_Priority_For_Writing(object_instance); priority = Load_Control_Priority_For_Writing(object_instance);
Test_Present_Value_Priority_Set(20.0f, priority); Test_Present_Value_Priority_Set(20.0f, 16);
datetime_set_values(&bdatetime, 2007, 2, 27, 15, 0, 3, 0); datetime_set_values(&bdatetime, 2007, 2, 27, 15, 0, 3, 0);
datetime_timesync(&bdatetime.date, &bdatetime.time, false); datetime_timesync(&bdatetime.date, &bdatetime.time, false);
Load_Control_Timer(object_instance, 1); Load_Control_Timer(object_instance, 1);
@@ -736,8 +740,8 @@ static void testLoadControlStateMachine(void)
status = Load_Control_Update_Interval_Set(object_instance, 0); status = Load_Control_Update_Interval_Set(object_instance, 0);
zassert_true(status, NULL); zassert_true(status, NULL);
Load_Control_WriteProperty_Enable(object_instance, true); Load_Control_WriteProperty_Enable(object_instance, true);
shed_level.type = BACNET_SHED_TYPE_AMOUNT; Load_Control_WriteProperty_Request_Shed_Level(
shed_level.value.amount = 0.0f; object_instance, BACNET_SHED_TYPE_AMOUNT, 0.0f);
status = status =
Load_Control_Requested_Shed_Level_Set(object_instance, &shed_level); Load_Control_Requested_Shed_Level_Set(object_instance, &shed_level);
zassert_true(status, NULL); zassert_true(status, NULL);
@@ -759,6 +763,8 @@ static void testLoadControlStateMachine(void)
zassert_true(status, NULL); zassert_true(status, NULL);
status = Load_Control_Update_Interval_Set(object_instance, 0); status = Load_Control_Update_Interval_Set(object_instance, 0);
zassert_true(status, NULL); zassert_true(status, NULL);
status = Load_Control_Full_Duty_Baseline_Set(object_instance, 100.0f);
zassert_true(status, NULL);
Load_Control_WriteProperty_Enable(object_instance, true); Load_Control_WriteProperty_Enable(object_instance, true);
shed_level.type = BACNET_SHED_TYPE_AMOUNT; shed_level.type = BACNET_SHED_TYPE_AMOUNT;
shed_level.value.amount = 10.0f; shed_level.value.amount = 10.0f;
@@ -774,6 +780,9 @@ static void testLoadControlStateMachine(void)
shed_state = Load_Control_Present_Value(object_instance); shed_state = Load_Control_Present_Value(object_instance);
zassert_equal(shed_state, BACNET_SHED_REQUEST_PENDING, NULL); zassert_equal(shed_state, BACNET_SHED_REQUEST_PENDING, NULL);
/* configure for non-compliance */ /* configure for non-compliance */
priority = Load_Control_Priority_For_Writing(object_instance);
Test_Present_Value_Priority_Set(100.0f, priority);
zassert_true(status, NULL);
datetime_set_values(&bdatetime, 2007, 2, 27, 15, 0, 2, 0); datetime_set_values(&bdatetime, 2007, 2, 27, 15, 0, 2, 0);
datetime_timesync(&bdatetime.date, &bdatetime.time, false); datetime_timesync(&bdatetime.date, &bdatetime.time, false);
Load_Control_Timer(object_instance, 1); Load_Control_Timer(object_instance, 1);
@@ -781,7 +790,6 @@ static void testLoadControlStateMachine(void)
zassert_equal(shed_state, BACNET_SHED_NON_COMPLIANT, NULL); zassert_equal(shed_state, BACNET_SHED_NON_COMPLIANT, NULL);
/* configure for compliance - amount reference full-duty-baseline */ /* configure for compliance - amount reference full-duty-baseline */
priority = Load_Control_Priority_For_Writing(object_instance); priority = Load_Control_Priority_For_Writing(object_instance);
status = Load_Control_Full_Duty_Baseline_Set(object_instance, 11.0f);
zassert_true(status, NULL); zassert_true(status, NULL);
Test_Present_Value_Priority_Set(10.0f, priority); Test_Present_Value_Priority_Set(10.0f, priority);
datetime_set_values(&bdatetime, 2007, 2, 27, 15, 0, 3, 0); datetime_set_values(&bdatetime, 2007, 2, 27, 15, 0, 3, 0);