Schedule encoding/decoding (#319)

* schedule: add decode_daily_schedule() and encode_daily_schedule()

* schedule: encode/decode implemented + add to bacapp

* add safe encode/decode functions for timevalue, schedule function renaming

* fix unit tests build failing

* add IDEA and test temporary files to .gitignore

* try to make "deprecated" work in MSVC

* add WeeklySchedule compare function

* add bacnet_weeklyschedule_context_decode()

* Add basic test for WeeklySchedule

* Fix WeeklySchedule parsing and snprintf, decoder verified with real hardware

* try to fix windows build

* improve boolean parsing in 'bacapp_parse_application_data'

* add parse function for weekly schedule

* allow types > 16 in bacwp, show the decoded value before sending

* add bacapp binaries to gitignore

* remove bacwp logging

* Add error checking to bacapp_parse_application_data

* try to fix windows build

* fix avr build

* Fix error handling in RP Ack

* add singleDay flag

* show day name in single day weeklyschedule snprintf

* show weeklyschedule inner tag in snprintf

* improve weeklyschedule parsing and printing, supports type names now

* add weekly schedule to bacapp_decode_data

* move bacnet/bacnet_plat_compat.h to bacnet/basic/sys/platform.h

* disable tag limit also in bacwpm

* add ifdef's around strtoX helper functions in bacapp

* move strtox to BACAPP_PRINT_ENABLED ifdef in bacapp

* fix stm32 makefiles

* fix at91sam7s build

* use BACNET_UNSIGNED_INTEGER in BACnet_Short_Application_Data_Value

* fix capitalization in BACnet_Daily_Schedule

* add name to BACNET_TIME_VALUE struct

* change bacwp bacwpm to use bacapp_known_property_tag()

* fix some macros in bacdcode missing parentheses

* Remove dummy fields from BACNET_SHORT_APPLICATION_DATA_VALUE, replace remaining uses of upcasting (adds extra overhead but is maybe safer), rename short DV to Primitive

* fix new ci warnings

* more fixes for ancient C

* fix tests no longer building

* primitive value renamed to shorter name
This commit is contained in:
Ondřej Hruška
2022-09-05 16:27:15 +02:00
committed by GitHub
parent bd40c51e19
commit 7cdab61d72
66 changed files with 1800 additions and 108 deletions
+39
View File
@@ -70,3 +70,42 @@ Release/
apps/piface/libmcp23s17/
apps/piface/libpifacedigital/
/test/build/
/cmake-build-*
/.idea
/apps/abort/bacabort
/apps/ack-alarm/bacackalarm
/apps/readfile/bacarf
/apps/writefile/bacawf
/apps/dcc/bacdcc
/apps/epics/bacepics
/apps/error/bacerror
/apps/event/bacevent
/apps/getevent/bacge
/apps/iam/baciam
/apps/iamrouter/baciamr
/apps/initrouter/bacinitr
/apps/netnumis/bacnni
/apps/server-client/bacpoll
/apps/readbdt/bacrbdt
/apps/reinit/bacrd
/apps/readfdt/bacrfdt
/apps/readprop/bacrp
/apps/readpropm/bacrpm
/apps/readrange/bacrr
/apps/scov/bacscov
/apps/server/bacserv
/apps/timesync/bacts
/apps/ucov/bacucov
/apps/uevent/bacuevent
/apps/uptransfer/bacupt
/apps/writebdt/bacwbdt
/apps/whohas/bacwh
/apps/whois/bacwi
/apps/whatisnetnum/bacwinn
/apps/whoisrouter/bacwir
/apps/writeprop/bacwp
/apps/writepropm/bacwpm
/apps/mstpcap/mstpcap
/apps/mstpcrc/mstpcrc
+4
View File
@@ -124,6 +124,10 @@ add_library(${PROJECT_NAME}
src/bacnet/bactext.h
src/bacnet/bactimevalue.c
src/bacnet/bactimevalue.h
src/bacnet/dailyschedule.c
src/bacnet/dailyschedule.h
src/bacnet/weeklyschedule.c
src/bacnet/weeklyschedule.h
$<$<BOOL:${BACDL_BIP}>:src/bacnet/basic/bbmd/h_bbmd.c>
$<$<BOOL:${BACDL_BIP}>:src/bacnet/basic/bbmd/h_bbmd.h>
$<$<BOOL:${BACDL_BIP6}>:src/bacnet/basic/bbmd6/h_bbmd6.c>
+33 -7
View File
@@ -337,20 +337,46 @@ int main(int argc, char *argv[])
value_string = argv[tag_value_arg];
tag_value_arg++;
args_remaining--;
/* printf("tag[%d]=%u value[%d]=%s\n",
i, property_tag, i, value_string); */
if (property_tag >= MAX_BACNET_APPLICATION_TAG) {
if (property_tag < 0) {
property_tag = bacapp_known_property_tag(Target_Object_Type, Target_Object_Property);
} else if (property_tag >= MAX_BACNET_APPLICATION_TAG) {
fprintf(stderr, "Error: tag=%u - it must be less than %u\n",
property_tag, MAX_BACNET_APPLICATION_TAG);
return 1;
}
status = bacapp_parse_application_data(
property_tag, value_string, &Target_Object_Property_Value[i]);
if (!status) {
if (property_tag >= 0) {
status = bacapp_parse_application_data(
property_tag, value_string, &Target_Object_Property_Value[i]);
if (!status) {
/* FIXME: show the expected entry format for the tag */
fprintf(stderr, "Error: unable to parse the tag value\n");
return 1;
}
} else {
/* FIXME: show the expected entry format for the tag */
fprintf(stderr, "Error: unable to parse the tag value\n");
fprintf(stderr, "Error: unable to parse the known property"
" \"%s\"\r\n", value_string);
return 1;
}
// Print the written value (for debug)
#if 0
fprintf(stderr, "Writing: ");
BACNET_OBJECT_PROPERTY_VALUE dummy_opv = {
.value = &Target_Object_Property_Value[i],
.array_index = Target_Object_Property_Index,
};
bacapp_print_value(stderr, &dummy_opv);
fprintf(stderr, "\n");
uint8_t apdu[1000];
int len = bacapp_encode_application_data(apdu, &Target_Object_Property_Value[i]);
for(int q=0;q<len;q++) {
printf("%02x ", apdu[q]);
}
printf("\n");
#endif
Target_Object_Property_Value[i].next = NULL;
if (i > 0) {
Target_Object_Property_Value[i - 1].next =
+14 -5
View File
@@ -427,16 +427,25 @@ int main(int argc, char *argv[])
if (Verbose) {
printf("tag=%u value=%s\n", property_tag, value_string);
}
if (property_tag >= MAX_BACNET_APPLICATION_TAG) {
if (property_tag < 0) {
property_tag = bacapp_known_property_tag(wpm_object->object_type, wpm_property->propertyIdentifier);
} else if (property_tag >= MAX_BACNET_APPLICATION_TAG) {
fprintf(stderr, "Error: tag=%u - it must be less than %u\n",
property_tag, MAX_BACNET_APPLICATION_TAG);
return 1;
}
status = bacapp_parse_application_data(
property_tag, value_string, &wpm_property->value);
if (!status) {
if (property_tag >= 0) {
status = bacapp_parse_application_data(
property_tag, value_string, &wpm_property->value);
if (!status) {
/* FIXME: show the expected entry format for the tag */
fprintf(stderr, "Error: unable to parse the tag value\n");
return 1;
}
} else {
/* FIXME: show the expected entry format for the tag */
fprintf(stderr, "Error: unable to parse the tag value\n");
fprintf(stderr, "Error: unable to parse the known property"
" \"%s\"\r\n", value_string);
return 1;
}
wpm_property->value.next = NULL;
+3
View File
@@ -107,6 +107,9 @@ CORESRC = $(BACNET_CORE)/abort.c \
$(BACNET_CORE)/rp.c \
$(BACNET_CORE)/rpm.c \
$(BACNET_CORE)/timestamp.c \
$(BACNET_CORE)/weeklyschedule.c \
$(BACNET_CORE)/dailyschedule.c \
$(BACNET_CORE)/bactimevalue.c \
$(BACNET_CORE)/whohas.c \
$(BACNET_CORE)/whois.c \
$(BACNET_CORE)/wp.c
+3
View File
@@ -76,6 +76,9 @@ BACNET_SRC = \
$(BACNET_CORE)/rp.c \
$(BACNET_CORE)/rpm.c \
$(BACNET_CORE)/timestamp.c \
$(BACNET_CORE)/weeklyschedule.c \
$(BACNET_CORE)/dailyschedule.c \
$(BACNET_CORE)/bactimevalue.c \
$(BACNET_CORE)/whohas.c \
$(BACNET_CORE)/whois.c \
$(BACNET_CORE)/wp.c
+3
View File
@@ -74,6 +74,9 @@ BACNET_SRC = \
$(BACNET_CORE)/rp.c \
$(BACNET_CORE)/rpm.c \
$(BACNET_CORE)/timestamp.c \
$(BACNET_CORE)/weeklyschedule.c \
$(BACNET_CORE)/dailyschedule.c \
$(BACNET_CORE)/bactimevalue.c \
$(BACNET_CORE)/whohas.c \
$(BACNET_CORE)/whois.c \
$(BACNET_CORE)/wp.c
+575 -26
View File
@@ -37,6 +37,7 @@
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <ctype.h> /* for isalnum */
#include <errno.h>
#ifdef __STDC_ISO_10646__
#include <wchar.h>
#include <wctype.h>
@@ -52,6 +53,8 @@
#include "bacnet/bacstr.h"
#include "bacnet/lighting.h"
#include "bacnet/hostnport.h"
#include "bacnet/weeklyschedule.h"
#include "bacnet/basic/sys/platform.h"
/** @file bacapp.c Utilities for the BACnet_Application_Data_Value */
@@ -171,6 +174,11 @@ int bacapp_encode_application_data(
apdu_len = color_command_encode(
apdu, &value->type.Color_Command);
break;
case BACNET_APPLICATION_TAG_WEEKLY_SCHEDULE:
/* BACnetWeeklySchedule */
apdu_len = bacnet_weeklyschedule_encode(
apdu, &value->type.Weekly_Schedule);
break;
case BACNET_APPLICATION_TAG_HOST_N_PORT:
/* BACnetHostNPort */
apdu_len = host_n_port_encode(apdu,
@@ -318,6 +326,10 @@ int bacapp_decode_data(uint8_t *apdu,
len = color_command_decode(
apdu, len_value_type, NULL, &value->type.Color_Command);
break;
case BACNET_APPLICATION_TAG_WEEKLY_SCHEDULE:
len = bacnet_weeklyschedule_decode(
apdu, len_value_type, &value->type.Weekly_Schedule);
break;
case BACNET_APPLICATION_TAG_HOST_N_PORT:
len = host_n_port_decode(
apdu, len_value_type, NULL,
@@ -638,6 +650,11 @@ int bacapp_encode_context_data_value(uint8_t *apdu,
apdu_len = xy_color_context_encode(
apdu, context_tag_number, &value->type.XY_Color);
break;
case BACNET_APPLICATION_TAG_WEEKLY_SCHEDULE:
/* BACnetWeeklySchedule */
apdu_len = bacnet_weeklyschedule_context_encode(
apdu, context_tag_number, &value->type.Weekly_Schedule);
break;
case BACNET_APPLICATION_TAG_COLOR_COMMAND:
/* BACnetColorCommand */
apdu_len = color_command_context_encode(
@@ -1011,6 +1028,142 @@ static int decode_priority_value(uint8_t *apdu,
#endif
#if defined(BACAPP_TYPES_EXTRA)
int bacapp_known_property_tag(
BACNET_OBJECT_TYPE object_type,
BACNET_PROPERTY_ID property)
{
switch (property) {
case PROP_MEMBER_OF:
case PROP_ZONE_MEMBERS:
case PROP_DOOR_MEMBERS:
case PROP_SUBORDINATE_LIST:
case PROP_ACCESS_EVENT_CREDENTIAL:
case PROP_ACCESS_DOORS:
case PROP_ZONE_FROM:
case PROP_ZONE_TO:
case PROP_CREDENTIALS_IN_ZONE:
case PROP_LAST_CREDENTIAL_ADDED:
case PROP_LAST_CREDENTIAL_REMOVED:
case PROP_ENTRY_POINTS:
case PROP_EXIT_POINTS:
case PROP_MEMBERS:
case PROP_CREDENTIALS:
case PROP_ACCOMPANIMENT:
case PROP_BELONGS_TO:
case PROP_LAST_ACCESS_POINT:
/* Properties using BACnetDeviceObjectReference */
return BACNET_APPLICATION_TAG_DEVICE_OBJECT_REFERENCE;
case PROP_TIME_OF_ACTIVE_TIME_RESET:
case PROP_TIME_OF_STATE_COUNT_RESET:
case PROP_CHANGE_OF_STATE_TIME:
case PROP_MAXIMUM_VALUE_TIMESTAMP:
case PROP_MINIMUM_VALUE_TIMESTAMP:
case PROP_VALUE_CHANGE_TIME:
case PROP_START_TIME:
case PROP_STOP_TIME:
case PROP_MODIFICATION_DATE:
case PROP_UPDATE_TIME:
case PROP_COUNT_CHANGE_TIME:
case PROP_LAST_CREDENTIAL_ADDED_TIME:
case PROP_LAST_CREDENTIAL_REMOVED_TIME:
case PROP_ACTIVATION_TIME:
case PROP_EXPIRATION_TIME:
case PROP_LAST_USE_TIME:
/* Properties using BACnetDateTime value */
return BACNET_APPLICATION_TAG_DATETIME;
case PROP_OBJECT_PROPERTY_REFERENCE:
case PROP_LOG_DEVICE_OBJECT_PROPERTY:
case PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES:
/* Properties using BACnetDeviceObjectPropertyReference */
return BACNET_APPLICATION_TAG_DEVICE_OBJECT_PROPERTY_REFERENCE;
case PROP_MANIPULATED_VARIABLE_REFERENCE:
case PROP_CONTROLLED_VARIABLE_REFERENCE:
case PROP_INPUT_REFERENCE:
/* Properties using BACnetObjectPropertyReference */
return BACNET_APPLICATION_TAG_OBJECT_PROPERTY_REFERENCE;
case PROP_EVENT_TIME_STAMPS:
case PROP_LAST_RESTORE_TIME:
case PROP_TIME_OF_DEVICE_RESTART:
case PROP_ACCESS_EVENT_TIME:
/* Properties using BACnetTimeStamp */
return BACNET_APPLICATION_TAG_TIMESTAMP;
case PROP_DEFAULT_COLOR:
/* Properties using BACnetxyColor */
return BACNET_APPLICATION_TAG_XY_COLOR;
case PROP_TRACKING_VALUE:
case PROP_PRESENT_VALUE:
if (object_type == OBJECT_COLOR) {
/* Properties using BACnetxyColor */
return BACNET_APPLICATION_TAG_XY_COLOR;
}
return -1;
case PROP_COLOR_COMMAND:
/* Properties using BACnetColorCommand */
return BACNET_APPLICATION_TAG_COLOR_COMMAND;
case PROP_LIGHTING_COMMAND:
/* Properties using BACnetLightingCommand */
return BACNET_APPLICATION_TAG_LIGHTING_COMMAND;
case PROP_WEEKLY_SCHEDULE:
/* BACnetWeeklySchedule ([7] BACnetDailySchedule*/
return BACNET_APPLICATION_TAG_WEEKLY_SCHEDULE;
case PROP_PRIORITY_ARRAY:
/* [16] BACnetPriorityValue : 16x values (simple property) */
return -1;
case PROP_LIST_OF_GROUP_MEMBERS:
/* Properties using ReadAccessSpecification */
return -1;
case PROP_EXCEPTION_SCHEDULE:
/* BACnetSpecialEvent (Schedule) */
return -1;
case PROP_DATE_LIST:
/* FIXME: Properties using : BACnetCalendarEntry */
return -1;
case PROP_ACTIVE_COV_SUBSCRIPTIONS:
/* FIXME: BACnetCOVSubscription */
return -1;
case PROP_EFFECTIVE_PERIOD:
/* FIXME: Properties using BACnetDateRange (Schedule) */
return -1;
case PROP_RECIPIENT_LIST:
/* FIXME: Properties using BACnetDestination */
return -1;
case PROP_TIME_SYNCHRONIZATION_RECIPIENTS:
case PROP_RESTART_NOTIFICATION_RECIPIENTS:
case PROP_UTC_TIME_SYNCHRONIZATION_RECIPIENTS:
/* FIXME: Properties using BACnetRecipient */
return -1;
case PROP_DEVICE_ADDRESS_BINDING:
case PROP_MANUAL_SLAVE_ADDRESS_BINDING:
case PROP_SLAVE_ADDRESS_BINDING:
/* FIXME: BACnetAddressBinding */
return -1;
case PROP_ACTION:
return -1;
default:
return -1;
}
}
/**
* @brief Decodes a well-known, possibly complex property value
* Used to reverse operations in bacapp_encode_application_data
@@ -1028,6 +1181,15 @@ int bacapp_decode_known_property(uint8_t *apdu,
{
int len = 0;
// NOTE:
// When adding impl for a new prop, also add its tag
// to bacapp_known_property_tag()
int tag = bacapp_known_property_tag(object_type, property);
if (tag != -1) {
value->tag = tag;
}
switch (property) {
case PROP_MEMBER_OF:
case PROP_ZONE_MEMBERS:
@@ -1048,10 +1210,10 @@ int bacapp_decode_known_property(uint8_t *apdu,
case PROP_BELONGS_TO:
case PROP_LAST_ACCESS_POINT:
/* Properties using BACnetDeviceObjectReference */
value->tag = BACNET_APPLICATION_TAG_DEVICE_OBJECT_REFERENCE;
len = bacapp_decode_device_obj_ref(
apdu, &value->type.Device_Object_Reference);
break;
case PROP_TIME_OF_ACTIVE_TIME_RESET:
case PROP_TIME_OF_STATE_COUNT_RESET:
case PROP_CHANGE_OF_STATE_TIME:
@@ -1069,46 +1231,44 @@ int bacapp_decode_known_property(uint8_t *apdu,
case PROP_EXPIRATION_TIME:
case PROP_LAST_USE_TIME:
/* Properties using BACnetDateTime value */
value->tag = BACNET_APPLICATION_TAG_DATETIME;
len = bacapp_decode_datetime(apdu, &value->type.Date_Time);
break;
case PROP_OBJECT_PROPERTY_REFERENCE:
case PROP_LOG_DEVICE_OBJECT_PROPERTY:
case PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES:
/* Properties using BACnetDeviceObjectPropertyReference */
value->tag =
BACNET_APPLICATION_TAG_DEVICE_OBJECT_PROPERTY_REFERENCE;
len = bacapp_decode_device_obj_property_ref(apdu,
&value->type.Device_Object_Property_Reference);
break;
case PROP_MANIPULATED_VARIABLE_REFERENCE:
case PROP_CONTROLLED_VARIABLE_REFERENCE:
case PROP_INPUT_REFERENCE:
/* Properties using BACnetObjectPropertyReference */
value->tag = BACNET_APPLICATION_TAG_OBJECT_PROPERTY_REFERENCE;
len = bacapp_decode_obj_property_ref(
apdu, max_apdu_len,
&value->type.Object_Property_Reference);
break;
case PROP_EVENT_TIME_STAMPS:
case PROP_LAST_RESTORE_TIME:
case PROP_TIME_OF_DEVICE_RESTART:
case PROP_ACCESS_EVENT_TIME:
/* Properties using BACnetTimeStamp */
value->tag = BACNET_APPLICATION_TAG_TIMESTAMP;
len = bacapp_decode_timestamp(apdu, &value->type.Time_Stamp);
break;
case PROP_DEFAULT_COLOR:
/* Properties using BACnetxyColor */
value->tag = BACNET_APPLICATION_TAG_XY_COLOR;
len = xy_color_decode(apdu, max_apdu_len,
&value->type.XY_Color);
break;
case PROP_TRACKING_VALUE:
case PROP_PRESENT_VALUE:
if (object_type == OBJECT_COLOR) {
/* Properties using BACnetxyColor */
value->tag = BACNET_APPLICATION_TAG_XY_COLOR;
len = xy_color_decode(apdu, max_apdu_len,
&value->type.XY_Color);
} else {
@@ -1117,26 +1277,34 @@ int bacapp_decode_known_property(uint8_t *apdu,
property);
}
break;
case PROP_COLOR_COMMAND:
/* Properties using BACnetColorCommand */
value->tag = BACNET_APPLICATION_TAG_COLOR_COMMAND;
len = color_command_decode(apdu, max_apdu_len, NULL,
&value->type.Color_Command);
break;
case PROP_LIGHTING_COMMAND:
/* Properties using BACnetLightingCommand */
value->tag = BACNET_APPLICATION_TAG_LIGHTING_COMMAND;
len = lighting_command_decode(apdu, max_apdu_len,
&value->type.Lighting_Command);
break;
case PROP_PRIORITY_ARRAY:
/* [16] BACnetPriorityValue : 16x values (simple property) */
len = decode_priority_value(apdu, max_apdu_len, value, property);
break;
case PROP_WEEKLY_SCHEDULE:
/* BACnetWeeklySchedule ([7] BACnetDailySchedule*/
len = bacnet_weeklyschedule_decode(
apdu, max_apdu_len, &value->type.Weekly_Schedule);
break;
/* properties without a specific decoder - fall through to default */
case PROP_LIST_OF_GROUP_MEMBERS:
/* Properties using ReadAccessSpecification */
case PROP_WEEKLY_SCHEDULE:
/* BACnetDailySchedule[7] (Schedule) */
case PROP_EXCEPTION_SCHEDULE:
/* BACnetSpecialEvent (Schedule) */
case PROP_DATE_LIST:
@@ -1527,6 +1695,149 @@ static int bacapp_snprintf_time(char *str, size_t str_len, BACNET_TIME *btime)
}
#endif
#if defined(BACAPP_TYPES_EXTRA)
static int bacapp_snprintf_weeklyschedule(
char *str,
size_t str_len,
BACNET_WEEKLY_SCHEDULE *ws,
BACNET_ARRAY_INDEX arrayIndex)
{
int slen;
int ret_val = 0;
int wi, ti;
BACNET_OBJECT_PROPERTY_VALUE dummyPropValue;
BACNET_APPLICATION_DATA_VALUE dummyDataValue;
const char *weekdaynames[7] = {
"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
};
const int loopend = ((arrayIndex == BACNET_ARRAY_ALL) ? 7 : 1);
// Find what inner type it uses
int inner_tag = -1;
for (wi = 0; wi < loopend; wi++) {
BACNET_DAILY_SCHEDULE *ds = &ws->weeklySchedule[wi];
for (ti = 0; ti < ds->TV_Count; ti++) {
int tag = ds->Time_Values[ti].Value.tag;
if (inner_tag == -1) {
inner_tag = tag;
} else if (inner_tag != tag) {
inner_tag = -2;
}
}
}
if (inner_tag == -1) {
slen = snprintf(str, str_len, "(Null; ");
} else if (inner_tag == -2) {
slen = snprintf(str, str_len, "(MIXED_TYPES; ");
} else {
slen = snprintf(str, str_len, "(%s; ", bactext_application_tag_name(inner_tag));
}
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
for (wi = 0; wi < loopend; wi++) {
BACNET_DAILY_SCHEDULE *ds = &ws->weeklySchedule[wi];
if (arrayIndex == BACNET_ARRAY_ALL) {
slen = snprintf(str, str_len, "%s: [", weekdaynames[wi]);
} else {
slen = snprintf(
str, str_len, "%s: [",
(arrayIndex >= 1 && arrayIndex <= 7) ? weekdaynames[arrayIndex - 1] : "???"
);
}
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
for (ti = 0; ti < ds->TV_Count; ti++) {
slen = bacapp_snprintf_time(str, str_len, &ds->Time_Values[ti].Time);
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
slen = snprintf(str, str_len, " ");
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
bacnet_primitive_to_application_data_value(
&dummyDataValue, &ds->Time_Values[ti].Value);
dummyPropValue.value = &dummyDataValue;
dummyPropValue.object_property = PROP_PRESENT_VALUE;
dummyPropValue.object_type = OBJECT_SCHEDULE;
slen = bacapp_snprintf_value(str, str_len, &dummyPropValue);
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
if (ti < ds->TV_Count - 1) {
slen = snprintf(str, str_len, ", ");
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
}
}
if (wi < loopend - 1) {
slen = snprintf(str, str_len, "]; ");
ret_val += slen;
if (str) {
str += slen;
if (str_len >= slen) {
str_len -= slen;
} else {
str_len = 0;
}
}
}
}
slen = snprintf(str, str_len, "])");
ret_val += slen;
return ret_val;
}
#endif
/**
* @brief Extract the value into a text string
* @param str - the buffer to store the extracted value, or NULL for length
@@ -1939,6 +2250,11 @@ int bacapp_snprintf_value(
slen = snprintf(str, str_len, ")");
ret_val += slen;
break;
case BACNET_APPLICATION_TAG_WEEKLY_SCHEDULE:
/* BACnetWeeklySchedule */
ret_val = bacapp_snprintf_weeklyschedule(
str, str_len, &value->type.Weekly_Schedule, object_value->array_index);
break;
case BACNET_APPLICATION_TAG_HOST_N_PORT:
if (value->type.Host_Address.host_ip_address) {
octet_str = octetstring_value(
@@ -1988,6 +2304,7 @@ int bacapp_snprintf_value(
break;
#endif
default:
ret_val = snprintf(str, str_len, "UnknownType(tag=%d)", value->tag);
break;
}
}
@@ -2040,10 +2357,206 @@ bool bacapp_print_value(
#endif
#ifdef BACAPP_PRINT_ENABLED
static char* ltrim(char *str, const char *trimmedchars) {
if (str[0] == 0) {
return str;
}
while(strchr(trimmedchars, *str)) {
str++;
}
return str;
}
static char* rtrim(char *str, const char *trimmedchars) {
if (str[0] == 0) {
return str;
}
char *end = str + strlen(str) - 1;
while (strchr(trimmedchars, *end)) {
*end = 0;
if (end == str) break;
end--;
}
return str;
}
static char* trim(char *str, const char *trimmedchars) {
return ltrim(rtrim(str, trimmedchars), trimmedchars);
}
#if defined (BACAPP_TYPES_EXTRA)
static bool parse_weeklyschedule(char *str, BACNET_APPLICATION_DATA_VALUE *value)
{
char *chunk, *comma, *space, *t, *v;
int daynum = 0, tvnum = 0;
unsigned int inner_tag;
BACNET_APPLICATION_DATA_VALUE dummy_value = { 0 };
BACNET_DAILY_SCHEDULE *dsch;
/*
Format:
(1; Mon: [02:00:00.00 FALSE, 07:35:00.00 active, 07:40:00.00 inactive]; Tue: [02:00:00.00 inactive]; ...)
- the first number is the inner tag (e.g. 1 = boolean, 4 = real, 9 = enum)
- Day name prefix is optional and ignored.
- Entries are separated by semicolons.
- There can be a full week, or only one entry - when using array index to modify a single day
- time-value array can be empty: []
*/
value->tag = BACNET_APPLICATION_TAG_WEEKLY_SCHEDULE;
// Parse the inner tag
chunk = strtok(str, ";");
chunk = ltrim(chunk, "(");
if (false == bacapp_parse_application_data(BACNET_APPLICATION_TAG_UNSIGNED_INT, chunk, &dummy_value)) {
// Try searching it by name
if (false == bactext_application_tag_index(chunk, &inner_tag)) {
return false;
}
} else {
inner_tag = (int)dummy_value.type.Unsigned_Int;
}
chunk = strtok(NULL, ";");
while(chunk != NULL) {
dsch = &value->type.Weekly_Schedule.weeklySchedule[daynum];
// Strip day name prefix, if present
char *colonpos = strchr(chunk, ':');
char *sqpos = strchr(chunk, '[');
if (colonpos && colonpos < sqpos) {
chunk = colonpos + 1;
}
// Extract the inner list of time-values
chunk = rtrim(ltrim(chunk, "([ "), " ])");
// The list can be empty
if (chunk[0] != 0) {
// loop through the time value pairs
tvnum = 0;
do {
// Find the comma delimiter, replace with NUL (like strtok)
comma = strchr(chunk, ',');
if (comma) {
*comma = 0;
}
// trim the time-value pair and find the delimiter space
chunk = trim(chunk, " ");
space = strchr(chunk, ' ');
if (!space) {
// malformed time-value pair
return false;
}
*space = 0;
// Extract time and value
t = chunk;
// value starts one byte after the space, and there can be multiple spaces
chunk = ltrim(space + 1, " ");
v = chunk;
// Parse time
if (false == bacapp_parse_application_data(BACNET_APPLICATION_TAG_TIME, t, &dummy_value)) {
return false;
}
dsch->Time_Values[tvnum].Time = dummy_value.type.Time;
// Parse value
if (false == bacapp_parse_application_data(inner_tag, v, &dummy_value)) {
return false;
}
if (BACNET_STATUS_OK !=
bacnet_application_to_primitive_data_value(
&dsch->Time_Values[tvnum].Value, &dummy_value)) {
return false;
}
// Advance past the comma to the next chunk
if (comma) {
chunk = comma + 1;
}
tvnum++;
} while (comma != NULL);
}
dsch->TV_Count = tvnum;
// Find the start of the next day
chunk = strtok(NULL, ";");
daynum++;
}
if (daynum == 1) {
value->type.Weekly_Schedule.singleDay = true;
}
return true;
}
#endif
#if defined(BACAPP_SIGNED) || defined(BACAPP_BOOLEAN)
static bool strtol_checked(const char *s, long *out)
{
char *end;
errno = 0;
*out = strtol(s, &end, 0);
if (end == s) {
// Conversion was not possible
return false;
}
if (errno == ERANGE) {
// Number too large
return false;
}
return true;
}
#endif
#if defined(BACAPP_UNSIGNED) || defined(BACAPP_ENUMERATED)
static bool strtoul_checked(const char *s, unsigned long *out)
{
char *end;
errno = 0;
*out = strtoul(s, &end, 0);
if (end == s) {
// Conversion was not possible
return false;
}
if (errno == ERANGE) {
// Number too large
return false;
}
return true;
}
#endif
#if defined(BACAPP_REAL) || defined(BACAPP_DOUBLE)
static bool strtod_checked(const char *s, double *out)
{
char *end;
errno = 0;
*out = strtod(s, &end);
if (end == s) {
// Conversion was not possible
return false;
}
if (errno == ERANGE) {
// Number too large
return false;
}
return true;
}
#endif
/* used to load the app data struct with the proper data
converted from a command line argument */
converted from a command line argument.
"argv" is not const to allow using strtok internally. It MAY be modified. */
bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number,
const char *argv,
char *argv,
BACNET_APPLICATION_DATA_VALUE *value)
{
int hour, min, sec, hundredths;
@@ -2052,7 +2565,7 @@ bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number,
uint32_t instance = 0;
bool status = false;
long long_value = 0;
unsigned long unsigned_long_value = 0;
BACNET_UNSIGNED_INTEGER unsigned_long_value = 0;
double double_value = 0.0;
int count = 0;
#if defined(BACAPP_TYPES_EXTRA)
@@ -2066,34 +2579,59 @@ bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number,
switch (tag_number) {
#if defined(BACAPP_BOOLEAN)
case BACNET_APPLICATION_TAG_BOOLEAN:
long_value = strtol(argv, NULL, 0);
if (long_value)
if (strcasecmp(argv, "true") == 0 || strcasecmp(argv, "active") == 0) {
value->type.Boolean = true;
else
} else if (strcasecmp(argv, "false") == 0 || strcasecmp(argv, "inactive") == 0) {
value->type.Boolean = false;
} else {
status = strtol_checked(argv, &long_value);
if (!status) {
return false;
}
if (long_value) {
value->type.Boolean = true;
} else {
value->type.Boolean = false;
}
}
break;
#endif
#if defined(BACAPP_UNSIGNED)
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
unsigned_long_value = strtoul(argv, NULL, 0);
status = strtoul_checked(argv, &unsigned_long_value);
if (!status) {
return false;
}
if (unsigned_long_value > BACNET_UNSIGNED_INTEGER_MAX) {
return false;
}
value->type.Unsigned_Int = unsigned_long_value;
break;
#endif
#if defined(BACAPP_SIGNED)
case BACNET_APPLICATION_TAG_SIGNED_INT:
long_value = strtol(argv, NULL, 0);
value->type.Signed_Int = long_value;
status = strtol_checked(argv, &long_value);
if (!status || long_value > INT32_MAX || long_value < INT32_MIN) {
return false;
}
value->type.Signed_Int = (int32_t) long_value;
break;
#endif
#if defined(BACAPP_REAL)
case BACNET_APPLICATION_TAG_REAL:
double_value = strtod(argv, NULL);
status = strtod_checked(argv, &double_value);
if (!status) {
return false;
}
value->type.Real = (float)double_value;
break;
#endif
#if defined(BACAPP_DOUBLE)
case BACNET_APPLICATION_TAG_DOUBLE:
double_value = strtod(argv, NULL);
status = strtod_checked(argv, &double_value);
if (!status) {
return false;
}
value->type.Double = double_value;
break;
#endif
@@ -2116,8 +2654,11 @@ bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number,
#endif
#if defined(BACAPP_ENUMERATED)
case BACNET_APPLICATION_TAG_ENUMERATED:
unsigned_long_value = strtoul(argv, NULL, 0);
value->type.Enumerated = unsigned_long_value;
status = strtoul_checked(argv, &unsigned_long_value);
if (!status || unsigned_long_value > UINT32_MAX) {
return false;
}
value->type.Enumerated = (uint32_t) unsigned_long_value;
break;
#endif
#if defined(BACAPP_DATE)
@@ -2190,6 +2731,9 @@ bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number,
case BACNET_APPLICATION_TAG_COLOR_COMMAND:
/* FIXME: add parsing for BACnetColorCommand */
break;
case BACNET_APPLICATION_TAG_WEEKLY_SCHEDULE:
status = parse_weeklyschedule(argv, value);
break;
case BACNET_APPLICATION_TAG_HOST_N_PORT:
count = sscanf(argv, "%3u.%3u.%3u.%3u:%5u",
&a[0], &a[1], &a[2], &a[3], &p);
@@ -2221,7 +2765,7 @@ bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number,
return status;
}
#endif
#endif /* BACAPP_PRINT_ENABLED */
/**
* Initialize an array (or single) #BACNET_APPLICATION_DATA_VALUE
@@ -2405,6 +2949,11 @@ bool bacapp_same_value(BACNET_APPLICATION_DATA_VALUE *value,
status = color_command_same(&value->type.Color_Command,
&test_value->type.Color_Command);
break;
case BACNET_APPLICATION_TAG_WEEKLY_SCHEDULE:
/* BACnetWeeklySchedule */
status = bacnet_weeklyschedule_same(&value->type.Weekly_Schedule,
&test_value->type.Weekly_Schedule);
break;
case BACNET_APPLICATION_TAG_HOST_N_PORT:
status = host_n_port_same(&value->type.Host_Address,
&value->type.Host_Address);
+8 -1
View File
@@ -36,6 +36,7 @@
#include "bacnet/bacdevobjpropref.h"
#include "bacnet/hostnport.h"
#include "bacnet/timestamp.h"
#include "bacnet/weeklyschedule.h"
struct BACnet_Application_Data_Value;
typedef struct BACnet_Application_Data_Value {
@@ -86,6 +87,7 @@ typedef struct BACnet_Application_Data_Value {
BACNET_LIGHTING_COMMAND Lighting_Command;
BACNET_COLOR_COMMAND Color_Command;
BACNET_XY_COLOR XY_Color;
BACNET_WEEKLY_SCHEDULE Weekly_Schedule;
BACNET_HOST_N_PORT Host_Address;
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE
Device_Object_Property_Reference;
@@ -216,6 +218,11 @@ extern "C" {
BACNET_OBJECT_TYPE object_type,
BACNET_PROPERTY_ID property);
BACNET_STACK_EXPORT
int bacapp_known_property_tag(
BACNET_OBJECT_TYPE object_type,
BACNET_PROPERTY_ID property);
BACNET_STACK_EXPORT
bool bacapp_copy(
BACNET_APPLICATION_DATA_VALUE * dest_value,
@@ -260,7 +267,7 @@ extern "C" {
BACNET_STACK_EXPORT
bool bacapp_parse_application_data(
BACNET_APPLICATION_TAG tag_number,
const char *argv,
char *argv,
BACNET_APPLICATION_DATA_VALUE * value);
BACNET_STACK_EXPORT
bool bacapp_print_value(
+5 -5
View File
@@ -617,23 +617,23 @@ extern "C" {
/* from clause 20.2.1.2 Tag Number */
/* true if extended tag numbering is used */
#define IS_EXTENDED_TAG_NUMBER(x) ((x & 0xF0) == 0xF0)
#define IS_EXTENDED_TAG_NUMBER(x) (((x) & 0xF0) == 0xF0)
/* from clause 20.2.1.3.1 Primitive Data */
/* true if the extended value is used */
#define IS_EXTENDED_VALUE(x) ((x & 0x07) == 5)
#define IS_EXTENDED_VALUE(x) (((x) & 0x07) == 5)
/* from clause 20.2.1.1 Class */
/* true if the tag is context specific */
#define IS_CONTEXT_SPECIFIC(x) ((x & BIT(3)) == BIT(3))
#define IS_CONTEXT_SPECIFIC(x) (((x) & BIT(3)) == BIT(3))
/* from clause 20.2.1.3.2 Constructed Data */
/* true if the tag is an opening tag */
#define IS_OPENING_TAG(x) ((x & 0x07) == 6)
#define IS_OPENING_TAG(x) (((x) & 0x07) == 6)
/* from clause 20.2.1.3.2 Constructed Data */
/* true if the tag is a closing tag */
#define IS_CLOSING_TAG(x) ((x & 0x07) == 7)
#define IS_CLOSING_TAG(x) (((x) & 0x07) == 7)
#ifdef __cplusplus
}
+246 -36
View File
@@ -34,57 +34,195 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h> /* memcpy */
#include "bacnet/bacdcode.h"
#include "bacnet/bactimevalue.h"
#include "bacnet/bacapp.h"
int bacapp_encode_time_value(uint8_t *apdu, BACNET_TIME_VALUE *value)
static bool is_data_value_schedule_compatible(uint8_t tag) {
switch (tag) {
/* Every member of the union must be listed here to allow decoding */
case BACNET_APPLICATION_TAG_NULL:
return true;
#if defined (BACAPP_BOOLEAN)
case BACNET_APPLICATION_TAG_BOOLEAN:
return true;
#endif
#if defined (BACAPP_UNSIGNED)
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
return true;
#endif
#if defined (BACAPP_SIGNED)
case BACNET_APPLICATION_TAG_SIGNED_INT:
return true;
#endif
#if defined (BACAPP_REAL)
case BACNET_APPLICATION_TAG_REAL:
return true;
#endif
#if defined (BACAPP_DOUBLE)
case BACNET_APPLICATION_TAG_DOUBLE:
return true;
#endif
#if defined (BACAPP_ENUMERATED)
case BACNET_APPLICATION_TAG_ENUMERATED:
return true;
#endif
default:
return false;
}
}
int bacnet_time_value_encode(uint8_t *apdu, BACNET_TIME_VALUE *value)
{
int len;
int apdu_len = 0;
uint8_t *apdu_offset = NULL;
len = encode_application_time(&apdu[apdu_len], &value->Time);
if (!value || !is_data_value_schedule_compatible(value->Value.tag)) {
return BACNET_STATUS_ERROR;
}
if (apdu) {
apdu_offset = &apdu[apdu_len];
}
len = encode_application_time(apdu_offset, &value->Time);
apdu_len += len;
len = bacapp_encode_application_data(&apdu[apdu_len], &value->Value);
if (apdu) {
apdu_offset = &apdu[apdu_len];
}
BACNET_APPLICATION_DATA_VALUE adv;
bacnet_primitive_to_application_data_value(&adv, &value->Value);
len = bacapp_encode_application_data(apdu_offset, &adv);
apdu_len += len;
return apdu_len;
}
int bacapp_encode_context_time_value(
int bacapp_encode_time_value(uint8_t *apdu, BACNET_TIME_VALUE *value) {
return bacnet_time_value_encode(apdu, value);
}
int bacnet_time_value_context_encode(
uint8_t *apdu, uint8_t tag_number, BACNET_TIME_VALUE *value)
{
int len;
int apdu_len = 0;
uint8_t *apdu_offset = NULL;
len = encode_opening_tag(&apdu[apdu_len], tag_number);
if (apdu) {
apdu_offset = &apdu[apdu_len];
}
len = encode_opening_tag(apdu_offset, tag_number);
apdu_len += len;
len = bacapp_encode_time_value(&apdu[apdu_len], value);
if (apdu) {
apdu_offset = &apdu[apdu_len];
}
len = bacnet_time_value_encode(apdu_offset, value);
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], tag_number);
if (apdu) {
apdu_offset = &apdu[apdu_len];
}
len = encode_closing_tag(apdu_offset, tag_number);
apdu_len += len;
return apdu_len;
}
int bacapp_encode_context_time_value(uint8_t *apdu, uint8_t tag_number, BACNET_TIME_VALUE *value)
{
return bacnet_time_value_context_encode(apdu, tag_number, value);
}
/** returns 0 if OK, -1 on error */
int bacnet_application_to_primitive_data_value(
struct BACnet_Primitive_Data_Value *dest,
const struct BACnet_Application_Data_Value *src)
{
// make sure the value passed is valid
if (!src || !dest || !is_data_value_schedule_compatible(src->tag)) {
return BACNET_STATUS_ERROR;
}
memset(dest, 0, sizeof(struct BACnet_Primitive_Data_Value));
dest->tag = src->tag;
memcpy(&dest->type, &src->type, sizeof(dest->type));
return BACNET_STATUS_OK;
}
/** returns 0 if OK, -1 on error */
int bacnet_primitive_to_application_data_value(
struct BACnet_Application_Data_Value * dest,
const struct BACnet_Primitive_Data_Value * src)
{
// make sure the value passed is valid
if (!dest || !src) {
return BACNET_STATUS_ERROR;
}
memset(dest, 0, sizeof(struct BACnet_Application_Data_Value));
dest->tag = src->tag;
memcpy(&dest->type, &src->type, sizeof(src->type));
return BACNET_STATUS_OK; /* OK */
}
int bacnet_time_value_decode(uint8_t *apdu, int max_apdu_len, BACNET_TIME_VALUE *value)
{
int len;
int apdu_len = 0;
BACNET_APPLICATION_DATA_VALUE full_data_value = { 0 };
len = bacnet_time_application_decode(&apdu[apdu_len], max_apdu_len, &value->Time);
if (len <= 0) {
return -1;
}
apdu_len += len;
len = bacapp_decode_application_data(&apdu[apdu_len], max_apdu_len - apdu_len, &full_data_value);
if (len <= 0) {
return -1;
}
if (BACNET_STATUS_OK !=
bacnet_application_to_primitive_data_value(
&value->Value, &full_data_value)) {
return -1;
}
apdu_len += len;
return apdu_len;
}
int bacapp_decode_time_value(uint8_t *apdu, BACNET_TIME_VALUE *value)
{
return bacnet_time_value_decode(apdu, MAX_APDU, value);
}
int bacnet_time_value_context_decode(uint8_t *apdu, int max_apdu_len, uint8_t tag_number, BACNET_TIME_VALUE *value)
{
int len;
int apdu_len = 0;
len = decode_application_time(&apdu[apdu_len], &value->Time);
if (len <= 0) {
if ((max_apdu_len - apdu_len) >= 1 && decode_is_opening_tag_number(&apdu[apdu_len], tag_number)) {
apdu_len += 1;
} else {
return -1;
}
apdu_len += len;
len = bacapp_decode_application_data(&apdu[apdu_len], 2048, &value->Value);
if (len <= 0) {
len = bacnet_time_value_decode(&apdu[apdu_len], max_apdu_len - apdu_len, value);
if (len > 0) {
apdu_len += len;
} else {
return -1;
}
if ((max_apdu_len - apdu_len) >= 1 && decode_is_closing_tag_number(&apdu[apdu_len], tag_number)) {
apdu_len += 1;
} else {
return -1;
}
apdu_len += len;
return apdu_len;
}
@@ -92,27 +230,99 @@ int bacapp_decode_time_value(uint8_t *apdu, BACNET_TIME_VALUE *value)
int bacapp_decode_context_time_value(
uint8_t *apdu, uint8_t tag_number, BACNET_TIME_VALUE *value)
{
int len = 0;
int section_length;
if (decode_is_opening_tag_number(&apdu[len], tag_number)) {
len++;
} else {
return -1;
}
section_length = bacapp_decode_time_value(&apdu[len], value);
if (section_length > 0) {
len += section_length;
} else {
return -1;
}
if (decode_is_closing_tag_number(&apdu[len], tag_number)) {
len++;
} else {
return -1;
}
return len;
return bacnet_time_value_context_decode(apdu, MAX_APDU, tag_number, value);
}
int bacnet_time_values_context_decode(
uint8_t * apdu,
const int max_apdu_len,
const uint8_t tag_number,
BACNET_TIME_VALUE *time_values,
const unsigned int max_time_values,
unsigned int *out_count)
{
unsigned int j;
int len;
int apdu_len = 0;
unsigned int count_values = 0;
BACNET_TIME_VALUE dummy;
/* day-schedule [0] SEQUENCE OF BACnetTimeValue */
if (decode_is_opening_tag_number(&apdu[apdu_len], tag_number)) {
apdu_len++;
while ((apdu_len < max_apdu_len) &&
!decode_is_closing_tag_number(&apdu[apdu_len], tag_number)) {
if (count_values < max_time_values) {
len = bacnet_time_value_decode(&apdu[apdu_len],
max_apdu_len - apdu_len, &time_values[count_values++]);
} else {
len = bacnet_time_value_decode(
&apdu[apdu_len], max_apdu_len - apdu_len, &dummy);
}
if (len < 0) {
return -1;
}
apdu_len += len;
}
/* Zeroing other values */
for (j = count_values; j < max_time_values; j++) {
time_values[j].Value.tag = BACNET_APPLICATION_TAG_NULL;
time_values[j].Value.type.Unsigned_Int = 0;
time_values[j].Time.hour = 0;
time_values[j].Time.min = 0;
time_values[j].Time.sec = 0;
time_values[j].Time.hundredths = 0;
}
/* overflow ! */
if (apdu_len >= max_apdu_len) {
return -1;
}
apdu_len++; /* closing tag */
if (out_count) {
*out_count = count_values;
}
return apdu_len;
}
return -1;
}
/* Encodes a : [x] SEQUENCE OF BACnetTimeValue into a fixed-size buffer */
int bacnet_time_values_context_encode(
uint8_t * apdu,
uint8_t tag_number,
BACNET_TIME_VALUE *time_values,
unsigned int max_time_values)
{
unsigned int j;
int apdu_len = 0;
int len = 0;
BACNET_TIME t0 = { 0 };
uint8_t *apdu_offset = NULL;
/* day-schedule [x] SEQUENCE OF BACnetTimeValue */
if (apdu) {
apdu_offset = &apdu[apdu_len];
}
apdu_len += encode_opening_tag(apdu_offset, tag_number);
for (j = 0; j < max_time_values; j++)
/* Encode only non-null values (NULL,00:00:00.00) */
if (time_values[j].Value.tag != BACNET_APPLICATION_TAG_NULL ||
datetime_compare_time(&t0, &time_values[j].Time) != 0) {
if (apdu) {
apdu_offset = &apdu[apdu_len];
}
len =
bacnet_time_value_encode(apdu_offset,
&time_values[j]);
if (len < 0)
return -1;
apdu_len += len;
}
/* close tag */
if (apdu) {
apdu_offset = &apdu[apdu_len];
}
apdu_len += encode_closing_tag(apdu_offset, tag_number);
return apdu_len;
}
+109 -6
View File
@@ -29,39 +29,142 @@
#include <stdbool.h>
#include <stddef.h>
#include "bacnet/bacnet_stack_exports.h"
#include "bacnet/basic/sys/platform.h"
#include "bacnet/bacdef.h"
#include "bacnet/bacenum.h"
#include "bacnet/bacapp.h"
#include "bacnet/datetime.h"
typedef struct {
/**
* Smaller version of BACnet_Application_Data_Value used in BACnetTimeValue
*
* This must be a separate struct to avoid recursive structure.
* Keeping it small also helps keep the size of BACNET_APPLICATION_DATA_VALUE
* small. Besides, schedule can't contain complex types.
*/
typedef struct BACnet_Primitive_Data_Value {
uint8_t tag; /* application tag data type */
union {
/*
* ATTENTION! If a new type is added here, update
* `is_data_value_schedule_compatible()` in bactimevalue.c!
*/
/* NULL - not needed as it is encoded in the tag alone */
#if defined (BACAPP_BOOLEAN)
bool Boolean;
#endif
#if defined (BACAPP_UNSIGNED)
BACNET_UNSIGNED_INTEGER Unsigned_Int;
#endif
#if defined (BACAPP_SIGNED)
int32_t Signed_Int;
#endif
#if defined (BACAPP_REAL)
float Real;
#endif
#if defined (BACAPP_DOUBLE)
double Double;
#endif
#if defined (BACAPP_ENUMERATED)
uint32_t Enumerated;
#endif
} type;
} BACNET_PRIMITIVE_DATA_VALUE;
typedef struct BACnet_Time_Value {
BACNET_TIME Time;
BACNET_APPLICATION_DATA_VALUE Value;
BACNET_PRIMITIVE_DATA_VALUE Value;
} BACNET_TIME_VALUE;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct BACnet_Application_Data_Value;
/** returns 0 if OK, -1 on error */
BACNET_STACK_EXPORT
int bacnet_application_to_primitive_data_value(BACNET_PRIMITIVE_DATA_VALUE * dest,
const struct BACnet_Application_Data_Value * src);
/** returns 0 if OK, -1 on error */
BACNET_STACK_EXPORT
int bacnet_primitive_to_application_data_value(
struct BACnet_Application_Data_Value * dest,
const BACNET_PRIMITIVE_DATA_VALUE * src);
BACNET_STACK_EXPORT
int bacapp_encode_time_value(uint8_t * apdu,
int bacnet_time_value_encode(uint8_t * apdu,
BACNET_TIME_VALUE * value);
BACNET_STACK_DEPRECATED("Use bacnet_time_value_encode() instead")
BACNET_STACK_EXPORT
int bacapp_encode_context_time_value(uint8_t * apdu,
int bacapp_encode_time_value(uint8_t *apdu, BACNET_TIME_VALUE *value);
BACNET_STACK_EXPORT
int bacnet_time_value_context_encode(uint8_t * apdu,
uint8_t tag_number,
BACNET_TIME_VALUE * value);
BACNET_STACK_DEPRECATED("Use bacnet_time_value_context_encode() instead")
BACNET_STACK_EXPORT
int bacapp_encode_context_time_value(uint8_t *apdu, uint8_t tag_number, BACNET_TIME_VALUE *value);
BACNET_STACK_DEPRECATED("Use bacnet_time_value_decode() instead")
BACNET_STACK_EXPORT
int bacapp_decode_time_value(uint8_t * apdu,
BACNET_TIME_VALUE * value);
BACNET_STACK_EXPORT
int bacnet_time_value_decode(uint8_t *apdu, int max_apdu_len,
BACNET_TIME_VALUE *value);
BACNET_STACK_DEPRECATED("Use bacnet_time_value_context_decode() instead")
BACNET_STACK_EXPORT
int bacapp_decode_context_time_value(uint8_t * apdu,
uint8_t tag_number,
BACNET_TIME_VALUE * value);
BACNET_STACK_EXPORT
int bacnet_time_value_context_decode(uint8_t *apdu, int max_apdu_len,
uint8_t tag_number, BACNET_TIME_VALUE *value);
/**
* Decode array of time-values wrapped in a context tag
* @param apdu
* @param max_apdu_len
* @param tag_number - number expected in the context tag; 0 used for DailySchedule
* @param time_values
* @param max_time_values - number of time values to encode
* @param[out] out_count - actual number of time values found
* @return used bytes, <0 if decoding failed
*/
BACNET_STACK_EXPORT
int bacnet_time_values_context_decode(
uint8_t * apdu,
int max_apdu_len,
uint8_t tag_number,
BACNET_TIME_VALUE *time_values,
unsigned int max_time_values,
unsigned int *out_count);
/**
* Encode array of time-values wrapped in a context tag
* @param apdu - output buffer, NULL to just measure length
* @param max_apdu_len
* @param tag_number - number to use for the context tag; 0 used for DailySchedule
* @param time_values
* @param max_time_values - number of time values to encode
* @return used bytes, <=0 if encoding failed
*/
BACNET_STACK_EXPORT
int bacnet_time_values_context_encode(
uint8_t * apdu,
uint8_t tag_number,
BACNET_TIME_VALUE * time_values,
unsigned int max_time_values);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
#endif /* _BAC_TIME_VALUE_H_ */
+11 -11
View File
@@ -86,10 +86,10 @@ void Schedule_Init(void)
for (j = 0; j < 7; j++) {
psched->Weekly_Schedule[j].TV_Count = 0;
}
psched->Present_Value = &psched->Schedule_Default;
memcpy(&psched->Present_Value, &psched->Schedule_Default, sizeof(psched->Present_Value));
psched->Schedule_Default.context_specific = false;
psched->Schedule_Default.tag = BACNET_APPLICATION_TAG_REAL;
psched->Schedule_Default.type.Real = 21.0; /* 21 C, room temperature */
psched->Schedule_Default.type.Real = 21.0f; /* 21 C, room temperature */
psched->obj_prop_ref_cnt = 0; /* no references, add as needed */
psched->Priority_For_Writing = 16; /* lowest priority */
psched->Out_Of_Service = false;
@@ -197,7 +197,7 @@ int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_SCHEDULE);
break;
case PROP_PRESENT_VALUE:
apdu_len = bacapp_encode_data(&apdu[0], CurrentSC->Present_Value);
apdu_len = bacapp_encode_data(&apdu[0], &CurrentSC->Present_Value);
break;
case PROP_EFFECTIVE_PERIOD:
/* BACnet Testing Observed Incident oi00110
@@ -224,7 +224,7 @@ int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
for (i = 0; i < CurrentSC->Weekly_Schedule[day].TV_Count;
i++) {
apdu_len += bacapp_encode_time_value(&apdu[apdu_len],
apdu_len += bacnet_time_value_encode(&apdu[apdu_len],
&CurrentSC->Weekly_Schedule[day].Time_Values[i]);
}
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
@@ -233,7 +233,7 @@ int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
int day = rpdata->array_index - 1;
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
for (i = 0; i < CurrentSC->Weekly_Schedule[day].TV_Count; i++) {
apdu_len += bacapp_encode_time_value(&apdu[apdu_len],
apdu_len += bacnet_time_value_encode(&apdu[apdu_len],
&CurrentSC->Weekly_Schedule[day].Time_Values[i]);
}
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
@@ -396,7 +396,7 @@ void Schedule_Recalculate_PV(
SCHEDULE_DESCR *desc, BACNET_WEEKDAY wday, BACNET_TIME *time)
{
int i;
desc->Present_Value = NULL;
desc->Present_Value.tag = BACNET_APPLICATION_TAG_NULL;
/* for future development, here should be the loop for Exception Schedule */
@@ -408,19 +408,19 @@ void Schedule_Recalculate_PV(
broker an early release on a case-by-case basis. */
for (i = 0; i < desc->Weekly_Schedule[wday - 1].TV_Count &&
desc->Present_Value == NULL;
desc->Present_Value.tag == BACNET_APPLICATION_TAG_NULL;
i++) {
int diff = datetime_wildcard_compare_time(
time, &desc->Weekly_Schedule[wday - 1].Time_Values[i].Time);
if (diff >= 0 &&
desc->Weekly_Schedule[wday - 1].Time_Values[i].Value.tag !=
BACNET_APPLICATION_TAG_NULL) {
desc->Present_Value =
&desc->Weekly_Schedule[wday - 1].Time_Values[i].Value;
bacnet_primitive_to_application_data_value(&desc->Present_Value,
&desc->Weekly_Schedule[wday - 1].Time_Values[i].Value);
}
}
if (desc->Present_Value == NULL) {
desc->Present_Value = &desc->Schedule_Default;
if (desc->Present_Value.tag == BACNET_APPLICATION_TAG_NULL) {
memcpy(&desc->Present_Value, &desc->Schedule_Default, sizeof(desc->Present_Value));
}
}
+13 -4
View File
@@ -51,19 +51,28 @@
extern "C" {
#endif /* __cplusplus */
typedef struct bacnet_daily_schedule {
/*
* 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_DAILY_SCHEDULE;
} 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_DAILY_SCHEDULE Weekly_Schedule[7];
BACNET_OBJ_DAILY_SCHEDULE Weekly_Schedule[7];
BACNET_APPLICATION_DATA_VALUE Schedule_Default;
BACNET_APPLICATION_DATA_VALUE *Present_Value; /* must be set to a valid value
/*
* Caution: This is a converted to BACNET_PRIMITIVE_APPLICATION_DATA_VALUE.
* Only some data types may be used!
*/
BACNET_APPLICATION_DATA_VALUE Present_Value; /* must be set to a valid value
* default is Schedule_Default */
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE
Object_Property_References[BACNET_SCHEDULE_OBJ_PROP_REF_SIZE];
+17
View File
@@ -39,6 +39,15 @@
#include "bacnet/basic/services.h"
#include "bacnet/basic/tsm/tsm.h"
#if PRINT_ENABLED
#include <stdio.h>
#define PRINTF(...) fprintf(stdout,__VA_ARGS__)
#define PRINTF_ERR(...) fprintf(stderr,__VA_ARGS__)
#else
#define PRINTF(...)
#define PRINTF_ERR(...)
#endif
/** @file h_rp_a.c Handles Read Property Acknowledgments. */
/** For debugging...
@@ -67,6 +76,14 @@ void rp_ack_print_data(BACNET_READ_PROPERTY_DATA *data)
len = bacapp_decode_known_property(
application_data, (unsigned)application_data_len, &value,
data->object_type, data->object_property);
if (len < 0) {
PRINTF_ERR("RP Ack: unable to decode! %s:%s\n",
bactext_object_type_name(data->object_type),
bactext_property_name(data->object_property));
break;
}
if (first_value && (len < application_data_len)) {
first_value = false;
#if PRINT_ENABLED
+41
View File
@@ -0,0 +1,41 @@
/**************************************************************************
*
* Copyright (C) 2022 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*********************************************************************/
#ifndef BAC_PLATFORM_H
#define BAC_PLATFORM_H
/*
* Macros to support different compilers and platforms
*/
# ifdef _MSC_VER
# define BACNET_STACK_DEPRECATED(message) __declspec(deprecated(message))
# else
# define BACNET_STACK_DEPRECATED(message) __attribute__((deprecated(message)))
# endif
# if defined(WIN32) || defined(WIN64)
# define strcasecmp _stricmp
# endif
#endif // BAC_PLATFORM_H
+57
View File
@@ -0,0 +1,57 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2022 Steve Karg <skarg@users.sourceforge.net>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
#include <stdint.h>
#include "bacnet/dailyschedule.h"
#include "bacnet/bactimevalue.h"
int bacnet_dailyschedule_decode(
uint8_t * apdu,
int max_apdu_len,
BACNET_DAILY_SCHEDULE * day)
{
unsigned int tv_count = 0;
int retval = bacnet_time_values_context_decode(
apdu, max_apdu_len, 0, &day->Time_Values[0], MAX_DAY_SCHEDULE_VALUES, &tv_count);
day->TV_Count = (uint16_t) tv_count;
return retval;
}
int bacnet_dailyschedule_encode(
uint8_t * apdu,
BACNET_DAILY_SCHEDULE * day)
{
return bacnet_time_values_context_encode(
apdu, 0, &day->Time_Values[0], day->TV_Count);
}
+68
View File
@@ -0,0 +1,68 @@
/**************************************************************************
*
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*********************************************************************/
#ifndef DAILYSCHEDULE_H
#define DAILYSCHEDULE_H
#include <stdint.h>
#include <stdbool.h>
#include "bacnet/bacnet_stack_exports.h"
#include "bacnet/bactimevalue.h"
/* arbitrary value, shall be unlimited for B-OWS but we don't care, 640k shall 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
/*
BACnetDailySchedule ::= SEQUENCE {
day-schedule [0] SEQUENCE OF BACnetTimeValue
}
*/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct BACnet_Daily_Schedule {
BACNET_TIME_VALUE Time_Values[MAX_DAY_SCHEDULE_VALUES];
uint16_t TV_Count; /* the number of time values actually used */
} BACNET_DAILY_SCHEDULE;
/** Decode DailySchedule (sequence of times and values) */
BACNET_STACK_EXPORT
int bacnet_dailyschedule_decode(
uint8_t * apdu,
int max_apdu_len,
BACNET_DAILY_SCHEDULE * day);
/** Encode DailySchedule (sequence of times and values) */
BACNET_STACK_EXPORT
int bacnet_dailyschedule_encode(
uint8_t * apdu,
BACNET_DAILY_SCHEDULE * day);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* DAILYSCHEDULE_H */
+187
View File
@@ -0,0 +1,187 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2022 Steve Karg <skarg@users.sourceforge.net>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
#include <stdint.h>
#include "bacnet/weeklyschedule.h"
#include "bacnet/bacdcode.h"
#include "bacapp.h"
int bacnet_weeklyschedule_decode(
uint8_t * apdu,
int max_apdu_len,
BACNET_WEEKLY_SCHEDULE *value)
{
int len = 0;
int apdu_len = 0;
int wi;
value->singleDay = false;
for (wi = 0; wi < 7; wi++) {
len = bacnet_dailyschedule_decode(
&apdu[apdu_len], max_apdu_len - apdu_len, &value->weeklySchedule[wi]);
if (len < 0) {
if (wi == 1) {
value->singleDay = true;
break;
}
return -1;
}
apdu_len += len;
}
return apdu_len;
}
int bacnet_weeklyschedule_encode(
uint8_t * apdu,
BACNET_WEEKLY_SCHEDULE *value)
{
int apdu_len = 0;
int len = 0;
int wi;
uint8_t *apdu_offset = NULL;
for (wi = 0; wi < (value->singleDay ? 1 : 7); wi++) {
/* not enough room to write data */
if (apdu) {
apdu_offset = &apdu[apdu_len];
}
len =
bacnet_dailyschedule_encode(apdu_offset, &value->weeklySchedule[wi]);
if (len < 0)
return -1;
apdu_len += len;
}
return apdu_len;
}
/**
* @brief Encode a context tagged WeeklySchedule complex data type
* @param apdu - the APDU buffer
* @param tag_number - the APDU buffer size
* @param value - WeeklySchedule structure
* @return length of the APDU buffer, or 0 if not able to encode
*/
int bacnet_weeklyschedule_context_encode(
uint8_t *apdu, uint8_t tag_number, BACNET_WEEKLY_SCHEDULE *value)
{
int len = 0;
int apdu_len = 0;
uint8_t *apdu_offset = NULL;
if (value) {
apdu_offset = apdu;
len = encode_opening_tag(apdu_offset, tag_number);
apdu_len += len;
if (apdu) {
apdu_offset = &apdu[apdu_len];
}
len = bacnet_weeklyschedule_encode(apdu_offset, value);
apdu_len += len;
if (apdu) {
apdu_offset = &apdu[apdu_len];
}
len = encode_closing_tag(apdu_offset, tag_number);
apdu_len += len;
}
return apdu_len;
}
int bacnet_weeklyschedule_context_decode(
uint8_t *apdu, int max_apdu_len, uint8_t tag_number,
BACNET_WEEKLY_SCHEDULE *value)
{
int apdu_len = 0;
int len;
if ((max_apdu_len - apdu_len) >= 1 && decode_is_opening_tag_number(&apdu[apdu_len], tag_number)) {
apdu_len += 1;
} else {
return -1;
}
if (-1 == (len = bacnet_weeklyschedule_decode(&apdu[apdu_len], max_apdu_len - apdu_len, value))) {
return -1;
} else {
apdu_len += len;
}
if ((max_apdu_len - apdu_len) >= 1 && decode_is_closing_tag_number(&apdu[apdu_len], tag_number)) {
apdu_len += 1;
} else {
return -1;
}
return apdu_len;
}
/**
* @brief Compare the BACnetWeeklySchedule complex data
* @param value1 - BACNET_COLOR_COMMAND structure
* @param value2 - BACNET_COLOR_COMMAND structure
* @return true if the same
*/
bool bacnet_weeklyschedule_same(
BACNET_WEEKLY_SCHEDULE *value1, BACNET_WEEKLY_SCHEDULE *value2)
{
int wi, ti;
for (wi = 0; wi < 7; wi++) {
BACNET_DAILY_SCHEDULE *ds1 = &value1->weeklySchedule[wi];
BACNET_DAILY_SCHEDULE *ds2 = &value2->weeklySchedule[wi];
if (ds1->TV_Count != ds2->TV_Count) {
return false;
}
for (ti = 0; ti < ds1->TV_Count; ti++) {
BACNET_TIME_VALUE *tv1 = &ds1->Time_Values[ti];
BACNET_TIME_VALUE *tv2 = &ds2->Time_Values[ti];
if (0 != datetime_compare_time(&tv1->Time, &tv2->Time)) {
return false;
}
// TODO the conversion can be avoided by adding a "primitive" variant of bacapp_same_value(),
// at the cost of some code duplication
BACNET_APPLICATION_DATA_VALUE adv1, adv2;
bacnet_primitive_to_application_data_value(&adv1, &tv1->Value);
bacnet_primitive_to_application_data_value(&adv2, &tv2->Value);
if (!bacapp_same_value(&adv1, &adv2))
{
return false;
}
}
}
return true;
}
+71
View File
@@ -0,0 +1,71 @@
/**************************************************************************
*
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*********************************************************************/
#ifndef WEEKLYSCHEDULE_H
#define WEEKLYSCHEDULE_H
#include <stdint.h>
#include <stdbool.h>
#include "bacnet/bacnet_stack_exports.h"
#include "bacnet/dailyschedule.h"
#include "bacnet/bactimevalue.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct BACnet_Weekly_Schedule {
BACNET_DAILY_SCHEDULE weeklySchedule[7];
bool singleDay;
} BACNET_WEEKLY_SCHEDULE;
/** Decode WeeklySchedule */
BACNET_STACK_EXPORT
int bacnet_weeklyschedule_decode(
uint8_t * apdu,
int max_apdu_len,
BACNET_WEEKLY_SCHEDULE * value);
/** Encode WeeklySchedule */
BACNET_STACK_EXPORT
int bacnet_weeklyschedule_encode(
uint8_t * apdu,
BACNET_WEEKLY_SCHEDULE * value);
BACNET_STACK_EXPORT
int bacnet_weeklyschedule_context_encode(
uint8_t *apdu, uint8_t tag_number, BACNET_WEEKLY_SCHEDULE *value);
BACNET_STACK_EXPORT
int bacnet_weeklyschedule_context_decode(
uint8_t *apdu, int max_apdu_len, uint8_t tag_number,
BACNET_WEEKLY_SCHEDULE *value);
BACNET_STACK_EXPORT
bool bacnet_weeklyschedule_same(
BACNET_WEEKLY_SCHEDULE *value1, BACNET_WEEKLY_SCHEDULE *value2);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* WEEKLYSCHEDULE_H */
+1
View File
@@ -70,6 +70,7 @@ list(APPEND testdirs
bacnet/whohas
bacnet/whois
bacnet/wp
bacnet/weeklyschedule
)
# bacnet/basic/*
+3
View File
@@ -50,6 +50,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/indtext.c
${SRC_DIR}/bacnet/datalink/bvlc.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -48,6 +48,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/hostnport.c
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
+2
View File
@@ -49,6 +49,8 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/hostnport.c
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
+12 -7
View File
@@ -16,6 +16,7 @@
#include <ztest.h>
#include "bacnet/bactimevalue.h"
#include "bacnet/datetime.h"
#include "bacnet/bacapp.h"
/**
@@ -35,26 +36,30 @@ static void test_BACnetTimeValue(BACNET_TIME_VALUE *value)
bool status = false;
uint8_t tag_number = 0;
len = bacapp_encode_time_value(apdu, value);
apdu_len = bacapp_decode_time_value(apdu, &test_value);
len = bacnet_time_value_encode(apdu, value);
apdu_len = bacnet_time_value_decode(apdu, len, &test_value);
zassert_true(len > 0, NULL);
zassert_true(apdu_len > 0, NULL);
diff = datetime_compare_time(&test_value.Time, &value->Time);
zassert_true(diff == 0, NULL);
status = bacapp_same_value(&test_value.Value, &value->Value);
status = bacapp_same_value(
(BACNET_APPLICATION_DATA_VALUE *) &test_value.Value,
(BACNET_APPLICATION_DATA_VALUE *) &value->Value);
zassert_true(status, NULL);
len = bacapp_encode_context_time_value(apdu, tag_number, value);
apdu_len = bacapp_decode_context_time_value(apdu, tag_number, &test_value);
len = bacnet_time_value_context_encode(apdu, tag_number, value);
apdu_len = bacnet_time_value_context_decode(apdu, len, tag_number, &test_value);
zassert_true(len > 0, NULL);
zassert_true(apdu_len > 0, NULL);
diff = datetime_compare_time(&test_value.Time, &value->Time);
zassert_true(diff == 0, NULL);
status = bacapp_same_value(&test_value.Value, &value->Value);
status = bacapp_same_value(
(BACNET_APPLICATION_DATA_VALUE *) &test_value.Value,
(BACNET_APPLICATION_DATA_VALUE *) &value->Value);
zassert_true(status, NULL);
/* negative testing */
tag_number++;
apdu_len = bacapp_decode_context_time_value(apdu, tag_number, &test_value);
apdu_len = bacnet_time_value_context_decode(apdu, len, tag_number, &test_value);
zassert_true(apdu_len < 0, NULL);
}
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/hostnport.c
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -48,6 +48,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/basic/sys/days.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -52,6 +52,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -48,6 +48,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/hostnport.c
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -50,6 +50,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -53,6 +53,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -51,6 +51,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/memcopy.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
+1
View File
@@ -10,6 +10,7 @@
#include <ztest.h>
#include <bacnet/basic/object/ai.h>
#include <bacnet/bactext.h>
/**
* @addtogroup bacnet_tests
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -51,6 +51,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/memcopy.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -51,6 +51,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/memcopy.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
+1
View File
@@ -10,6 +10,7 @@
#include <ztest.h>
#include <bacnet/basic/object/bi.h>
#include <bacnet/bactext.h>
/**
* @addtogroup bacnet_tests
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -52,6 +52,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/memcopy.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
../mock/device_mock.c
@@ -52,6 +52,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/memcopy.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
../mock/device_mock.c
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -52,6 +52,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -90,6 +90,8 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/reject.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/dailyschedule.c
./stubs.c
# Test and test library files
./src/main.c
@@ -51,6 +51,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
./stubs.c
# Test and test library files
./src/main.c
@@ -51,6 +51,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -50,6 +50,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
../mock/device_mock.c
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -51,6 +51,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/memcopy.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -52,6 +52,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/proplist.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
@@ -50,6 +50,8 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
+3
View File
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/memcopy.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
+3
View File
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/indtext.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
+3
View File
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/indtext.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
+3
View File
@@ -50,6 +50,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/memcopy.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
+3
View File
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/hostnport.c
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
+3
View File
@@ -51,6 +51,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/memcopy.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
+3
View File
@@ -50,6 +50,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/hostnport.c
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
+58
View File
@@ -0,0 +1,58 @@
# SPDX-License-Identifier: MIT
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
get_filename_component(basename ${CMAKE_CURRENT_SOURCE_DIR} NAME)
project(test_${basename}
VERSION 1.0.0
LANGUAGES C)
string(REGEX REPLACE
"/test/bacnet/[a-zA-Z_/-]*$"
"/src"
SRC_DIR
${CMAKE_CURRENT_SOURCE_DIR})
string(REGEX REPLACE
"/test/bacnet/[a-zA-Z_/-]*$"
"/test"
TST_DIR
${CMAKE_CURRENT_SOURCE_DIR})
set(ZTST_DIR "${TST_DIR}/ztest/src")
add_compile_definitions(
BIG_ENDIAN=0
CONFIG_ZTEST=1
BACAPP_ALL
)
include_directories(
${SRC_DIR}
${TST_DIR}/ztest/include
)
add_executable(${PROJECT_NAME}
# File(s) under test
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Support files and stubs (pathname alphabetical)
${SRC_DIR}/bacnet/bacapp.c
${SRC_DIR}/bacnet/bacdcode.c
${SRC_DIR}/bacnet/bacint.c
${SRC_DIR}/bacnet/bacdevobjpropref.c
${SRC_DIR}/bacnet/bacreal.c
${SRC_DIR}/bacnet/bacstr.c
${SRC_DIR}/bacnet/bactext.c
${SRC_DIR}/bacnet/basic/sys/bigend.c
${SRC_DIR}/bacnet/datetime.c
${SRC_DIR}/bacnet/basic/sys/days.c
${SRC_DIR}/bacnet/indtext.c
${SRC_DIR}/bacnet/hostnport.c
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
${ZTST_DIR}/ztest.c
)
+103
View File
@@ -0,0 +1,103 @@
/**
* @file
* @brief Unit test for BACnetWeeklySchedule
* @author Ondřej Hruška <ondra@ondrovo.com>
* @date Aug 2022
*
* SPDX-License-Identifier: MIT
*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <ztest.h>
#include "bacnet/bactimevalue.h"
#include "bacnet/weeklyschedule.h"
#include "bacnet/dailyschedule.h"
#include "bacnet/datetime.h"
#include "bacnet/bacapp.h"
/**
* @addtogroup bacnet_tests
* @{
*/
/**
* @brief Test encode/decode API
*/
static void test_BACnetWeeklySchedule()
{
int len, apdu_len;
uint8_t apdu[MAX_APDU] = { 0 };
BACNET_WEEKLY_SCHEDULE empty_value = { 0 };
BACNET_WEEKLY_SCHEDULE value = { 0 };
BACNET_WEEKLY_SCHEDULE decoded = { 0 };
int diff = 0;
bool status = false;
uint8_t tag_number = 0;
value.weeklySchedule[0].TV_Count = 2;
value.weeklySchedule[0].Time_Values[0].Time = (BACNET_TIME) {
.hour = 5,
.min = 30
};
value.weeklySchedule[0].Time_Values[0].Value = (BACNET_PRIMITIVE_DATA_VALUE) {
.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT,
.type.Unsigned_Int = 123,
};
value.weeklySchedule[0].Time_Values[1].Time = (BACNET_TIME) {
.hour = 15,
.min = 0
};
value.weeklySchedule[0].Time_Values[1].Value = (BACNET_PRIMITIVE_DATA_VALUE) {
.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT,
.type.Unsigned_Int = 456,
};
value.weeklySchedule[6].TV_Count = 1;
value.weeklySchedule[6].Time_Values[0].Value = (BACNET_PRIMITIVE_DATA_VALUE) {
.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT,
.type.Unsigned_Int = 777,
};
len = bacnet_weeklyschedule_encode(apdu, &value);
apdu_len = bacnet_weeklyschedule_decode(apdu, len, &decoded);
zassert_true(len > 0, NULL);
zassert_true(apdu_len > 0, NULL);
status = bacnet_weeklyschedule_same(&value, &decoded);
zassert_true(status, NULL);
// Check that the compare function really compares:
status = bacnet_weeklyschedule_same(&empty_value, &decoded);
zassert_false(status, NULL);
len = bacnet_weeklyschedule_context_encode(apdu, tag_number, &value);
apdu_len = bacnet_weeklyschedule_context_decode(apdu, len, tag_number, &decoded);
zassert_true(len > 0, NULL);
zassert_true(apdu_len > 0, NULL);
status = bacnet_weeklyschedule_same(&value, &decoded);
zassert_true(status, NULL);
/* negative testing - the tag differs */
tag_number++;
apdu_len = bacnet_weeklyschedule_context_decode(apdu, len, tag_number, &decoded);
zassert_true(apdu_len < 0, NULL);
}
/**
* @}
*/
void test_main(void)
{
ztest_test_suite(BACnetWeeklySchedule_tests,
ztest_unit_test(test_BACnetWeeklySchedule)
);
ztest_run_test_suite(BACnetWeeklySchedule_tests);
}
+3
View File
@@ -49,6 +49,9 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/indtext.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c