Adding Load Control object state machine.

This commit is contained in:
skarg
2007-01-19 21:52:43 +00:00
parent cd01926295
commit 0a7102a79f
+101 -33
View File
@@ -61,17 +61,24 @@ typedef struct {
} BACNET_SHED_LEVEL; } BACNET_SHED_LEVEL;
/* indicates the desired load shedding */ /* indicates the desired load shedding */
static BACNET_SHED_LEVEL Requested_Shed_Level[MAX_LOAD_CONTROLS]; static BACNET_SHED_LEVEL Requested_Shed_Level[MAX_LOAD_CONTROLS];
/* Indicates the amount of power that the object expects
to be able to shed in response to a load shed request. */
static BACNET_SHED_LEVEL Expected_Shed_Level[MAX_LOAD_CONTROLS];
/* Indicates the actual amount of power being shed in response
to a load shed request. */
static BACNET_SHED_LEVEL Actual_Shed_Level[MAX_LOAD_CONTROLS];
/* indicates the start of the duty window in which the load controlled /* indicates the start of the duty window in which the load controlled
by the Load Control object must be compliant with the requested shed. */ by the Load Control object must be compliant with the requested shed. */
static BACNET_DATE_TIME Load_Control_Start_Time[MAX_LOAD_CONTROLS]; static BACNET_DATE_TIME Start_Time[MAX_LOAD_CONTROLS];
static BACNET_DATE_TIME Previous_Start_Time[MAX_LOAD_CONTROLS];
/* indicates the duration of the load shed action, /* indicates the duration of the load shed action,
starting at Start_Time */ starting at Start_Time in minutes */
static uint32_t Load_Control_Shed_Duration[MAX_LOAD_CONTROLS]; static uint32_t Shed_Duration[MAX_LOAD_CONTROLS];
/* indicates the time window used for load shed accounting */ /* indicates the time window used for load shed accounting in minutes */
static uint32_t Load_Control_Duty_Window[MAX_LOAD_CONTROLS]; static uint32_t Duty_Window[MAX_LOAD_CONTROLS];
/* indicates and controls whether the Load Control object is /* indicates and controls whether the Load Control object is
currently enabled to respond to load shed requests. */ currently enabled to respond to load shed requests. */
@@ -83,14 +90,6 @@ static bool Load_Control_Enable[MAX_LOAD_CONTROLS];
The units of Full_Duty_Baseline are kilowatts.*/ The units of Full_Duty_Baseline are kilowatts.*/
static float Full_Duty_Baseline[MAX_LOAD_CONTROLS]; static float Full_Duty_Baseline[MAX_LOAD_CONTROLS];
/* Indicates the amount of power that the object expects
to be able to shed in response to a load shed request. */
static BACNET_SHED_LEVEL Expected_Shed_Level[MAX_LOAD_CONTROLS];
/* Indicates the actual amount of power being shed in response
to a load shed request. */
static BACNET_SHED_LEVEL Actual_Shed_Level[MAX_LOAD_CONTROLS];
/* Represents the shed levels for the LEVEL choice of /* Represents the shed levels for the LEVEL choice of
BACnetShedLevel that have meaning for this particular BACnetShedLevel that have meaning for this particular
Load Control object. */ Load Control object. */
@@ -119,16 +118,10 @@ void Load_Control_Init(void)
Present_Value[i] = BACNET_SHED_INACTIVE; Present_Value[i] = BACNET_SHED_INACTIVE;
Requested_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL; Requested_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL;
Requested_Shed_Level[i].value.level = 0; Requested_Shed_Level[i].value.level = 0;
Load_Control_Start_Time[i].date.year = 2000; bacapp_set_datetime_values(
Load_Control_Start_Time[i].date.month = 1; &Start_Time[i],0,0,0,0,0,0,0,0);
Load_Control_Start_Time[i].date.day = 1; Shed_Duration[i] = 0;
Load_Control_Start_Time[i].date.wday = 1; Duty_Window[i] = 0;
Load_Control_Start_Time[i].time.hour = 0;
Load_Control_Start_Time[i].time.min = 0;
Load_Control_Start_Time[i].time.sec = 0;
Load_Control_Start_Time[i].time.hundredths = 0;
Load_Control_Shed_Duration[i] = 0;
Load_Control_Duty_Window[i] = 0;
Load_Control_Enable[i] = true; Load_Control_Enable[i] = true;
Full_Duty_Baseline[i] = 0.0; Full_Duty_Baseline[i] = 0.0;
for (j = 0; j < MAX_SHED_LEVELS; j++) { for (j = 0; j < MAX_SHED_LEVELS; j++) {
@@ -216,6 +209,80 @@ char *Load_Control_Name(uint32_t object_instance)
return NULL; return NULL;
} }
typedef enum load_control_state
{
SHED_INACTIVE,
SHED_REQUEST_PENDING,
SHED_NON_COMPLIANT,
SHED_COMPLIANT
} LOAD_CONTROL_STATE;
void Load_Control_State_Machine_Handler(int object_index)
{
static LOAD_CONTROL_STATE state[MAX_LOAD_CONTROLS];
static initialized = false;
if (!initialized) {
initialized = true;
for (i = 0; i < MAX_LOAD_CONTROLS; i++) {
state[i] = SHED_INACTIVE;
}
}
switch (state)
{
case SHED_REQUEST_PENDING:
/* CancelShed */
break;
case SHED_NON_COMPLIANT:
break;
case SHED_COMPLIANT:
break;
case SHED_INACTIVE:
default:
if (!bacapp_same_datetime(&Start_Time[object_index],
&Previous_Start_Time[object_index])) {
/* FIXME: calculate your Expected Shed Level */
/* FIXME: calculate your Actual Shed Level */
Expected_Shed_Level[object_index].type =
Requested_Shed_Level[object_index].type;
switch (Requested_Shed_Level[object_index].type)
{
case BACNET_SHED_TYPE_PERCENT:
Actual_Shed_Level[object_index].value.percent =
Expected_Shed_Level[object_index].value.percent =
Requested_Shed_Level[object_index].value.percent;
break;
case BACNET_SHED_TYPE_AMOUNT:
Actual_Shed_Level[object_index].value.amount =
Expected_Shed_Level[object_index].value.amount =
Requested_Shed_Level[object_index].value.amount;
break;
case BACNET_SHED_TYPE_LEVEL:
default:
Actual_Shed_Level[object_index].value.level =
Expected_Shed_Level[object_index].value.level =
Requested_Shed_Level[object_index].value.level;
break;
}
state = SHED_REQUEST_PENDING;
}
break;
}
return;
}
/* call every second or so */
void Load_Control_State_Machine(void)
{
for (i = 0; i < MAX_LOAD_CONTROLS; i++) {
Load_Control_State_Machine_Handler(i);
}
}
/* return apdu len, or -1 on error */ /* return apdu len, or -1 on error */
int Load_Control_Encode_Property_APDU(uint8_t * apdu, int Load_Control_Encode_Property_APDU(uint8_t * apdu,
uint32_t object_instance, uint32_t object_instance,
@@ -297,19 +364,19 @@ int Load_Control_Encode_Property_APDU(uint8_t * apdu,
break; break;
case PROP_START_TIME: case PROP_START_TIME:
len = encode_tagged_date(&apdu[0], len = encode_tagged_date(&apdu[0],
&Load_Control_Start_Time[object_index].date); &Start_Time[object_index].date);
apdu_len = len; apdu_len = len;
len = encode_tagged_time(&apdu[apdu_len], len = encode_tagged_time(&apdu[apdu_len],
&Load_Control_Start_Time[object_index].time); &Start_Time[object_index].time);
apdu_len += len; apdu_len += len;
break; break;
case PROP_SHED_DURATION: case PROP_SHED_DURATION:
apdu_len = encode_tagged_unsigned(&apdu[0], apdu_len = encode_tagged_unsigned(&apdu[0],
Load_Control_Shed_Duration[object_index]); Shed_Duration[object_index]);
break; break;
case PROP_DUTY_WINDOW: case PROP_DUTY_WINDOW:
apdu_len = encode_tagged_unsigned(&apdu[0], apdu_len = encode_tagged_unsigned(&apdu[0],
Load_Control_Duty_Window[object_index]); Duty_Window[object_index]);
break; break;
case PROP_ENABLE: case PROP_ENABLE:
state = Load_Control_Enable[object_index]; state = Load_Control_Enable[object_index];
@@ -489,7 +556,7 @@ bool Load_Control_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
break; break;
case PROP_START_TIME: case PROP_START_TIME:
if (value.tag == BACNET_APPLICATION_TAG_DATE) { if (value.tag == BACNET_APPLICATION_TAG_DATE) {
memcpy(&Load_Control_Start_Time[object_index].date, memcpy(&Start_Time[object_index].date,
&value.type.Date,sizeof(value.type.Date)); &value.type.Date,sizeof(value.type.Date));
status = true; status = true;
} else { } else {
@@ -503,17 +570,18 @@ bool Load_Control_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
wp_data->application_data_len - len, wp_data->application_data_len - len,
&value); &value);
if (len && value.tag == BACNET_APPLICATION_TAG_TIME) { if (len && value.tag == BACNET_APPLICATION_TAG_TIME) {
memcpy(&Load_Control_Start_Time[object_index].time, memcpy(&Start_Time[object_index].time,
&value.type.Time,sizeof(value.type.Time)); &value.type.Time,sizeof(value.type.Time));
status = true; status = true;
} else { } else {
status = false;
*error_class = ERROR_CLASS_PROPERTY; *error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_INVALID_DATA_TYPE; *error_code = ERROR_CODE_INVALID_DATA_TYPE;
} }
break; break;
case PROP_SHED_DURATION: case PROP_SHED_DURATION:
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
Load_Control_Shed_Duration[object_index] = Shed_Duration[object_index] =
value.type.Unsigned_Int; value.type.Unsigned_Int;
status = true; status = true;
} else { } else {
@@ -523,7 +591,7 @@ bool Load_Control_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
break; break;
case PROP_DUTY_WINDOW: case PROP_DUTY_WINDOW:
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
Load_Control_Duty_Window[object_index] = Duty_Window[object_index] =
value.type.Unsigned_Int; value.type.Unsigned_Int;
status = true; status = true;
} else { } else {
@@ -584,7 +652,7 @@ void testLoadControl(Test * pTest)
int len = 0; int len = 0;
uint32_t len_value = 0; uint32_t len_value = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_VALUE; BACNET_OBJECT_TYPE decoded_type = OBJECT_LOAD_CONTROL;
uint32_t decoded_instance = 0; uint32_t decoded_instance = 0;
uint32_t instance = 123; uint32_t instance = 123;
BACNET_ERROR_CLASS error_class; BACNET_ERROR_CLASS error_class;
@@ -600,7 +668,7 @@ void testLoadControl(Test * pTest)
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID); ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], len = decode_object_id(&apdu[len],
(int *) &decoded_type, &decoded_instance); (int *) &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == OBJECT_ANALOG_VALUE); ct_test(pTest, decoded_type == OBJECT_LOAD_CONTROL);
ct_test(pTest, decoded_instance == instance); ct_test(pTest, decoded_instance == instance);
return; return;