Added the weekly-schedule property write in basic schedule object. (#990)

This commit is contained in:
Steve Karg
2025-05-08 08:15:16 -05:00
committed by GitHub
parent 2101748a0b
commit 1a7d823959
7 changed files with 195 additions and 49 deletions
+158 -27
View File
@@ -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 {
+11 -16
View File
@@ -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);
+4 -2
View File
@@ -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;
+4 -3
View File
@@ -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) {
+2 -1
View File
@@ -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,