Added the weekly-schedule property write in basic schedule object. (#990)
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
#include "bacnet/proplist.h"
|
||||
#include "bacnet/timestamp.h"
|
||||
#include "bacnet/basic/services.h"
|
||||
#include "bacnet/basic/sys/debug.h"
|
||||
#include "bacnet/basic/object/device.h"
|
||||
#include "bacnet/basic/object/schedule.h"
|
||||
|
||||
@@ -25,6 +26,7 @@
|
||||
static SCHEDULE_DESCR Schedule_Descr[MAX_SCHEDULES];
|
||||
|
||||
static const int Schedule_Properties_Required[] = {
|
||||
/* list of required properties */
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
@@ -39,11 +41,14 @@ static const int Schedule_Properties_Required[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Schedule_Properties_Optional[] = { PROP_WEEKLY_SCHEDULE,
|
||||
static const int Schedule_Properties_Optional[] = {
|
||||
/* list of optional properties */
|
||||
PROP_WEEKLY_SCHEDULE,
|
||||
#if BACNET_EXCEPTION_SCHEDULE_SIZE
|
||||
PROP_EXCEPTION_SCHEDULE,
|
||||
PROP_EXCEPTION_SCHEDULE,
|
||||
#endif
|
||||
-1 };
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Schedule_Properties_Proprietary[] = { -1 };
|
||||
|
||||
@@ -103,7 +108,7 @@ void Schedule_Init(void)
|
||||
psched = &Schedule_Descr[i];
|
||||
datetime_copy_date(&psched->Start_Date, &start_date);
|
||||
datetime_copy_date(&psched->End_Date, &end_date);
|
||||
for (j = 0; j < 7; j++) {
|
||||
for (j = 0; j < BACNET_WEEKLY_SCHEDULE_SIZE; j++) {
|
||||
psched->Weekly_Schedule[j].TV_Count = 0;
|
||||
}
|
||||
memcpy(
|
||||
@@ -223,6 +228,50 @@ void Schedule_Out_Of_Service_Set(uint32_t object_instance, bool value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the Weekly Schedule for a given object instance
|
||||
* @param object_instance - object-instance number of the object
|
||||
* @param array_index - index of the Weekly Schedule to get 0 to 6
|
||||
* @return pointer to the Weekly Schedule, or NULL if not found
|
||||
*/
|
||||
BACNET_DAILY_SCHEDULE *
|
||||
Schedule_Weekly_Schedule(uint32_t object_instance, unsigned array_index)
|
||||
{
|
||||
SCHEDULE_DESCR *pObject;
|
||||
|
||||
pObject = Schedule_Object(object_instance);
|
||||
if (pObject && (array_index < BACNET_WEEKLY_SCHEDULE_SIZE)) {
|
||||
return &pObject->Weekly_Schedule[array_index];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the Weekly Schedule for a given object instance
|
||||
* @param object_instance - object-instance number of the object
|
||||
* @param array_index - index of the Weekly Schedule to set 0 to 6
|
||||
* @param value - pointer to the Weekly Schedule to set
|
||||
* @return true if the Weekly Schedule was set, and false if not
|
||||
*/
|
||||
bool Schedule_Weekly_Schedule_Set(
|
||||
uint32_t object_instance,
|
||||
unsigned array_index,
|
||||
const BACNET_DAILY_SCHEDULE *value)
|
||||
{
|
||||
SCHEDULE_DESCR *pObject;
|
||||
|
||||
pObject = Schedule_Object(object_instance);
|
||||
if (pObject && (array_index < BACNET_WEEKLY_SCHEDULE_SIZE)) {
|
||||
memcpy(
|
||||
&pObject->Weekly_Schedule[array_index], value,
|
||||
sizeof(BACNET_WEEKLY_SCHEDULE));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode a BACnetARRAY property element
|
||||
* @param object_instance [in] BACnet network port object instance number
|
||||
@@ -236,33 +285,19 @@ void Schedule_Out_Of_Service_Set(uint32_t object_instance, bool value)
|
||||
static int Schedule_Weekly_Schedule_Encode(
|
||||
uint32_t object_instance, BACNET_ARRAY_INDEX array_index, uint8_t *apdu)
|
||||
{
|
||||
int apdu_len = 0, len = 0;
|
||||
int apdu_len;
|
||||
SCHEDULE_DESCR *pObject;
|
||||
int day, i;
|
||||
|
||||
if (array_index >= 7) {
|
||||
if (array_index >= BACNET_WEEKLY_SCHEDULE_SIZE) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
pObject = Schedule_Object(object_instance);
|
||||
if (!pObject) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
day = array_index;
|
||||
len = encode_opening_tag(apdu, 0);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu += len;
|
||||
}
|
||||
for (i = 0; i < pObject->Weekly_Schedule[day].TV_Count; i++) {
|
||||
len = bacnet_time_value_encode(
|
||||
apdu, &pObject->Weekly_Schedule[day].Time_Values[i]);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu += len;
|
||||
}
|
||||
}
|
||||
len = encode_closing_tag(apdu, 0);
|
||||
apdu_len += len;
|
||||
|
||||
apdu_len = bacnet_dailyschedule_context_encode(
|
||||
apdu, 0, &pObject->Weekly_Schedule[array_index]);
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
@@ -346,7 +381,8 @@ int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
case PROP_WEEKLY_SCHEDULE:
|
||||
apdu_len = bacnet_array_encode(
|
||||
rpdata->object_instance, rpdata->array_index,
|
||||
Schedule_Weekly_Schedule_Encode, 7, apdu, apdu_max);
|
||||
Schedule_Weekly_Schedule_Encode, BACNET_WEEKLY_SCHEDULE_SIZE,
|
||||
apdu, apdu_max);
|
||||
if (apdu_len == BACNET_STATUS_ABORT) {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
@@ -411,6 +447,87 @@ int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a value to a BACnetARRAY property element value
|
||||
* @param object_instance [in] BACnet network port object instance number
|
||||
* @param array_index [in] array index to write:
|
||||
* 0=array size, 1 to N for individual array members
|
||||
* @param application_data [in] encoded element value
|
||||
* @param application_data_len [in] The size of the encoded element value
|
||||
* @return BACNET_ERROR_CODE value
|
||||
*/
|
||||
static BACNET_ERROR_CODE Schedule_Weekly_Schedule_Element_Write(
|
||||
uint32_t object_instance,
|
||||
BACNET_ARRAY_INDEX array_index,
|
||||
uint8_t *application_data,
|
||||
size_t application_data_len)
|
||||
{
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
BACNET_DAILY_SCHEDULE daily_schedule = { 0 };
|
||||
size_t tv, tv_size;
|
||||
int len = 0;
|
||||
SCHEDULE_DESCR *pObject;
|
||||
|
||||
pObject = Schedule_Object(object_instance);
|
||||
if (pObject) {
|
||||
if (array_index == 0) {
|
||||
error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else if (array_index <= BACNET_WEEKLY_SCHEDULE_SIZE) {
|
||||
array_index--;
|
||||
len = bacnet_dailyschedule_context_decode(
|
||||
application_data, application_data_len, 0, &daily_schedule);
|
||||
if (len > 0) {
|
||||
tv_size =
|
||||
min(daily_schedule.TV_Count,
|
||||
BACNET_DAILY_SCHEDULE_TIME_VALUES_SIZE);
|
||||
for (tv = 0; tv < tv_size; tv++) {
|
||||
/* copy the time value */
|
||||
memcpy(
|
||||
&pObject->Weekly_Schedule[array_index].Time_Values[tv],
|
||||
&daily_schedule.Time_Values[tv],
|
||||
sizeof(BACNET_TIME_VALUE));
|
||||
}
|
||||
pObject->Weekly_Schedule[array_index].TV_Count = tv_size;
|
||||
error_code = ERROR_CODE_SUCCESS;
|
||||
} else {
|
||||
error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
} else {
|
||||
error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
return error_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode one BACnetARRAY property element
|
||||
* @param object_instance [in] BACnet network port object instance number
|
||||
* @param apdu [in] Buffer in which the APDU contents are extracted
|
||||
* @param apdu_size [in] The size of the APDU buffer
|
||||
* @return The length of the decoded apdu, or BACNET_STATUS_ERROR on error
|
||||
*/
|
||||
static int Schedule_Weekly_Schedule_Element_Length(
|
||||
uint32_t object_instance, uint8_t *apdu, size_t apdu_size)
|
||||
{
|
||||
BACNET_DAILY_SCHEDULE daily_schedule = { 0 };
|
||||
int len = 0;
|
||||
SCHEDULE_DESCR *pObject;
|
||||
|
||||
pObject = Schedule_Object(object_instance);
|
||||
if (pObject) {
|
||||
len = bacnet_dailyschedule_context_decode(
|
||||
apdu, apdu_size, 0, &daily_schedule);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a property to the Schedule object
|
||||
* @param wp_data - pointer to the write property data
|
||||
* @return true if the write was successful, and false if not
|
||||
*/
|
||||
bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
unsigned object_index;
|
||||
@@ -419,9 +536,9 @@ bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
BACNET_APPLICATION_DATA_VALUE value = { 0 };
|
||||
|
||||
/* decode the some of the request */
|
||||
len = bacapp_decode_application_data(
|
||||
wp_data->application_data, wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
len = bacapp_decode_known_array_property(
|
||||
wp_data->application_data, wp_data->application_data_len, &value,
|
||||
wp_data->object_type, wp_data->object_property, wp_data->array_index);
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -441,11 +558,25 @@ bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
wp_data->object_instance, value.type.Boolean);
|
||||
}
|
||||
break;
|
||||
case PROP_WEEKLY_SCHEDULE:
|
||||
wp_data->error_code = bacnet_array_write(
|
||||
wp_data->object_instance, wp_data->array_index,
|
||||
Schedule_Weekly_Schedule_Element_Length,
|
||||
Schedule_Weekly_Schedule_Element_Write,
|
||||
BACNET_WEEKLY_SCHEDULE_SIZE, wp_data->application_data,
|
||||
wp_data->application_data_len);
|
||||
if (wp_data->error_code == ERROR_CODE_SUCCESS) {
|
||||
status = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (property_lists_member(
|
||||
Schedule_Properties_Required, Schedule_Properties_Optional,
|
||||
Schedule_Properties_Proprietary,
|
||||
wp_data->object_property)) {
|
||||
debug_printf(
|
||||
"Schedule_Write_Property: %s\n",
|
||||
bactext_property_name(wp_data->object_property));
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
|
||||
@@ -19,13 +19,9 @@
|
||||
#include "bacnet/rp.h"
|
||||
#include "bacnet/bacdevobjpropref.h"
|
||||
#include "bacnet/bactimevalue.h"
|
||||
#include "bacnet/dailyschedule.h"
|
||||
#include "bacnet/special_event.h"
|
||||
|
||||
#ifndef BACNET_WEEKLY_SCHEDULE_SIZE
|
||||
/* Maximum number of data points for each day */
|
||||
#define BACNET_WEEKLY_SCHEDULE_SIZE 8
|
||||
#endif
|
||||
|
||||
#ifndef BACNET_SCHEDULE_OBJ_PROP_REF_SIZE
|
||||
/* Maximum number of obj prop references */
|
||||
#define BACNET_SCHEDULE_OBJ_PROP_REF_SIZE 4
|
||||
@@ -40,22 +36,12 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Note:
|
||||
* This is a different struct from BACNET_DAILY_SCHEDULE used in prop value
|
||||
* encoding! The number of entries is different.
|
||||
*/
|
||||
typedef struct bacnet_obj_daily_schedule {
|
||||
BACNET_TIME_VALUE Time_Values[BACNET_WEEKLY_SCHEDULE_SIZE];
|
||||
uint16_t TV_Count; /* the number of time values actually used */
|
||||
} BACNET_OBJ_DAILY_SCHEDULE;
|
||||
|
||||
typedef struct schedule {
|
||||
/* Effective Period: Start and End Date */
|
||||
BACNET_DATE Start_Date;
|
||||
BACNET_DATE End_Date;
|
||||
/* Properties concerning Present Value */
|
||||
BACNET_OBJ_DAILY_SCHEDULE Weekly_Schedule[7];
|
||||
BACNET_DAILY_SCHEDULE Weekly_Schedule[BACNET_WEEKLY_SCHEDULE_SIZE];
|
||||
#if BACNET_EXCEPTION_SCHEDULE_SIZE
|
||||
BACNET_SPECIAL_EVENT Exception_Schedule[BACNET_EXCEPTION_SCHEDULE_SIZE];
|
||||
#endif
|
||||
@@ -94,6 +80,15 @@ void Schedule_Out_Of_Service_Set(uint32_t object_instance, bool value);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Schedule_Out_Of_Service(uint32_t object_instance);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
BACNET_DAILY_SCHEDULE *
|
||||
Schedule_Weekly_Schedule(uint32_t object_instance, unsigned array_index);
|
||||
BACNET_STACK_EXPORT
|
||||
bool Schedule_Weekly_Schedule_Set(
|
||||
uint32_t object_instance,
|
||||
unsigned array_index,
|
||||
const BACNET_DAILY_SCHEDULE *value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool Schedule_Object_Name(
|
||||
uint32_t object_instance, BACNET_CHARACTER_STRING *object_name);
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
* be enough */
|
||||
/* however we try not to boost the bacnet application value structure size, */
|
||||
/* so 7 x (this value) x sizeof(BACNET_TIME_VALUE) fits. */
|
||||
#define MAX_DAY_SCHEDULE_VALUES 40
|
||||
#ifndef BACNET_DAILY_SCHEDULE_TIME_VALUES_SIZE
|
||||
#define BACNET_DAILY_SCHEDULE_TIME_VALUES_SIZE 40
|
||||
#endif
|
||||
|
||||
/*
|
||||
BACnetDailySchedule ::= SEQUENCE {
|
||||
@@ -33,7 +35,7 @@ extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct BACnet_Daily_Schedule {
|
||||
BACNET_TIME_VALUE Time_Values[MAX_DAY_SCHEDULE_VALUES];
|
||||
BACNET_TIME_VALUE Time_Values[BACNET_DAILY_SCHEDULE_TIME_VALUES_SIZE];
|
||||
uint16_t TV_Count; /* the number of time values actually used */
|
||||
} BACNET_DAILY_SCHEDULE;
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ int bacnet_weeklyschedule_decode(
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
value->singleDay = false;
|
||||
for (wi = 0; wi < 7; wi++) {
|
||||
for (wi = 0; wi < BACNET_WEEKLY_SCHEDULE_SIZE; wi++) {
|
||||
len = bacnet_dailyschedule_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 0,
|
||||
&value->weeklySchedule[wi]);
|
||||
@@ -67,7 +67,8 @@ int bacnet_weeklyschedule_encode(
|
||||
int len = 0;
|
||||
int wi;
|
||||
|
||||
for (wi = 0; wi < (value->singleDay ? 1 : 7); wi++) {
|
||||
for (wi = 0; wi < (value->singleDay ? 1 : BACNET_WEEKLY_SCHEDULE_SIZE);
|
||||
wi++) {
|
||||
len = bacnet_dailyschedule_context_encode(
|
||||
apdu, 0, &value->weeklySchedule[wi]);
|
||||
if (len < 0) {
|
||||
@@ -176,7 +177,7 @@ bool bacnet_weeklyschedule_same(
|
||||
const BACNET_TIME_VALUE *tv1, *tv2;
|
||||
int wi, ti;
|
||||
|
||||
for (wi = 0; wi < 7; wi++) {
|
||||
for (wi = 0; wi < BACNET_WEEKLY_SCHEDULE_SIZE; wi++) {
|
||||
ds1 = &value1->weeklySchedule[wi];
|
||||
ds2 = &value2->weeklySchedule[wi];
|
||||
if (ds1->TV_Count != ds2->TV_Count) {
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define BACNET_WEEKLY_SCHEDULE_SIZE 7
|
||||
typedef struct BACnet_Weekly_Schedule {
|
||||
BACNET_DAILY_SCHEDULE weeklySchedule[7];
|
||||
BACNET_DAILY_SCHEDULE weeklySchedule[BACNET_WEEKLY_SCHEDULE_SIZE];
|
||||
bool singleDay;
|
||||
} BACNET_WEEKLY_SCHEDULE;
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ add_executable(${PROJECT_NAME}
|
||||
${SRC_DIR}/bacnet/basic/sys/bigend.c
|
||||
${SRC_DIR}/bacnet/datetime.c
|
||||
${SRC_DIR}/bacnet/basic/sys/days.c
|
||||
${SRC_DIR}/bacnet/basic/sys/debug.c
|
||||
${SRC_DIR}/bacnet/indtext.c
|
||||
${SRC_DIR}/bacnet/hostnport.c
|
||||
${SRC_DIR}/bacnet/lighting.c
|
||||
|
||||
@@ -28,11 +28,26 @@ static void testSchedule(void)
|
||||
unsigned count = 0;
|
||||
uint32_t object_instance = 0;
|
||||
const int skip_fail_property_list[] = { -1 };
|
||||
BACNET_DAILY_SCHEDULE *daily_schedule;
|
||||
size_t tv = 0, day = 0;
|
||||
|
||||
Schedule_Init();
|
||||
count = Schedule_Count();
|
||||
zassert_true(count > 0, NULL);
|
||||
object_instance = Schedule_Index_To_Instance(0);
|
||||
/* fill the weekly schedule with some data */
|
||||
for (day = 0; day < BACNET_WEEKLY_SCHEDULE_SIZE; day++) {
|
||||
daily_schedule = Schedule_Weekly_Schedule(object_instance, day);
|
||||
daily_schedule->TV_Count = BACNET_DAILY_SCHEDULE_TIME_VALUES_SIZE;
|
||||
for (tv = 0; tv < daily_schedule->TV_Count; tv++) {
|
||||
datetime_set_time(
|
||||
&daily_schedule->Time_Values[tv].Time, tv % 24, 0, 0, 0);
|
||||
daily_schedule->Time_Values[tv].Value.tag =
|
||||
BACNET_APPLICATION_TAG_REAL;
|
||||
daily_schedule->Time_Values[tv].Value.type.Real = 1.0f + tv;
|
||||
}
|
||||
}
|
||||
/* general purpose test */
|
||||
bacnet_object_properties_read_write_test(
|
||||
OBJECT_SCHEDULE, object_instance, Schedule_Property_Lists,
|
||||
Schedule_Read_Property, Schedule_Write_Property,
|
||||
|
||||
Reference in New Issue
Block a user