Feature/date time mstimer clock (#861)
* Added daylight savings time calculation module with unit testing. * Added datetime daylight savings time and clock API * Added basic datetime_local() clock using mstimer as basis and time-sync option. Integrated clock with ports/stm32f4xx example.
This commit is contained in:
@@ -527,6 +527,8 @@ add_library(${PROJECT_NAME}
|
|||||||
src/bacnet/basic/sys/days.h
|
src/bacnet/basic/sys/days.h
|
||||||
src/bacnet/basic/sys/debug.c
|
src/bacnet/basic/sys/debug.c
|
||||||
src/bacnet/basic/sys/debug.h
|
src/bacnet/basic/sys/debug.h
|
||||||
|
src/bacnet/basic/sys/dst.c
|
||||||
|
src/bacnet/basic/sys/dst.h
|
||||||
src/bacnet/basic/sys/fifo.c
|
src/bacnet/basic/sys/fifo.c
|
||||||
src/bacnet/basic/sys/fifo.h
|
src/bacnet/basic/sys/fifo.h
|
||||||
src/bacnet/basic/sys/filename.c
|
src/bacnet/basic/sys/filename.c
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ set(BACNET_PROJECT_SOURCE
|
|||||||
${LIBRARY_BACNET_BASIC}/service/h_rd.c
|
${LIBRARY_BACNET_BASIC}/service/h_rd.c
|
||||||
${LIBRARY_BACNET_BASIC}/service/h_rp.c
|
${LIBRARY_BACNET_BASIC}/service/h_rp.c
|
||||||
${LIBRARY_BACNET_BASIC}/service/h_rpm.c
|
${LIBRARY_BACNET_BASIC}/service/h_rpm.c
|
||||||
|
${LIBRARY_BACNET_BASIC}/service/h_ts.c
|
||||||
${LIBRARY_BACNET_BASIC}/service/h_whohas.c
|
${LIBRARY_BACNET_BASIC}/service/h_whohas.c
|
||||||
${LIBRARY_BACNET_BASIC}/service/h_whois.c
|
${LIBRARY_BACNET_BASIC}/service/h_whois.c
|
||||||
${LIBRARY_BACNET_BASIC}/service/h_wp.c
|
${LIBRARY_BACNET_BASIC}/service/h_wp.c
|
||||||
@@ -178,6 +179,9 @@ set(BACNET_PROJECT_SOURCE
|
|||||||
${LIBRARY_BACNET_BASIC}/service/s_ihave.c
|
${LIBRARY_BACNET_BASIC}/service/s_ihave.c
|
||||||
${LIBRARY_BACNET_BASIC}/tsm/tsm.c
|
${LIBRARY_BACNET_BASIC}/tsm/tsm.c
|
||||||
${LIBRARY_BACNET_BASIC}/sys/debug.c
|
${LIBRARY_BACNET_BASIC}/sys/debug.c
|
||||||
|
${LIBRARY_BACNET_BASIC}/sys/datetime_mstimer.c
|
||||||
|
${LIBRARY_BACNET_BASIC}/sys/days.c
|
||||||
|
${LIBRARY_BACNET_BASIC}/sys/dst.c
|
||||||
${LIBRARY_BACNET_BASIC}/sys/ringbuf.c
|
${LIBRARY_BACNET_BASIC}/sys/ringbuf.c
|
||||||
${LIBRARY_BACNET_BASIC}/sys/fifo.c
|
${LIBRARY_BACNET_BASIC}/sys/fifo.c
|
||||||
${LIBRARY_BACNET_BASIC}/sys/keylist.c
|
${LIBRARY_BACNET_BASIC}/sys/keylist.c
|
||||||
@@ -214,6 +218,7 @@ set(BACNET_PROJECT_SOURCE
|
|||||||
${LIBRARY_BACNET_CORE}/rp.c
|
${LIBRARY_BACNET_CORE}/rp.c
|
||||||
${LIBRARY_BACNET_CORE}/rpm.c
|
${LIBRARY_BACNET_CORE}/rpm.c
|
||||||
${LIBRARY_BACNET_CORE}/timestamp.c
|
${LIBRARY_BACNET_CORE}/timestamp.c
|
||||||
|
${LIBRARY_BACNET_CORE}/timesync.c
|
||||||
${LIBRARY_BACNET_CORE}/weeklyschedule.c
|
${LIBRARY_BACNET_CORE}/weeklyschedule.c
|
||||||
${LIBRARY_BACNET_CORE}/dailyschedule.c
|
${LIBRARY_BACNET_CORE}/dailyschedule.c
|
||||||
${LIBRARY_BACNET_CORE}/calendar_entry.c
|
${LIBRARY_BACNET_CORE}/calendar_entry.c
|
||||||
|
|||||||
@@ -3,15 +3,15 @@
|
|||||||
#+-------------------------------------------------------------------------------------------------+
|
#+-------------------------------------------------------------------------------------------------+
|
||||||
TARGET=bacnet
|
TARGET=bacnet
|
||||||
|
|
||||||
BACNET_DIR = ../..
|
BACNET_DIR = $(realpath ../..)
|
||||||
BACNET_SRC := $(BACNET_DIR)/src
|
BACNET_SRC := $(BACNET_DIR)/src
|
||||||
BACNET_CORE := $(BACNET_SRC)/bacnet
|
BACNET_CORE := $(BACNET_SRC)/bacnet
|
||||||
BACNET_BASIC := $(BACNET_CORE)/basic
|
BACNET_BASIC := $(BACNET_CORE)/basic
|
||||||
BACNET_INCLUDE := $(BACNET_SRC)
|
BACNET_INCLUDE := $(BACNET_SRC)
|
||||||
PLATFORM_DIR = .
|
PLATFORM_DIR = $(realpath .)
|
||||||
LIBRARY_STM32 = ./external/STM32F4xx_StdPeriph_Driver/src
|
LIBRARY_STM32 = $(realpath ./external/STM32F4xx_StdPeriph_Driver/src)
|
||||||
LIBRARY_STM32_INCLUDES = ./external/STM32F4xx_StdPeriph_Driver/inc
|
LIBRARY_STM32_INCLUDES = $(realpath ./external/STM32F4xx_StdPeriph_Driver/inc)
|
||||||
LIBRARY_CMSIS = ./external/CMSIS
|
LIBRARY_CMSIS = $(realpath ./external/CMSIS)
|
||||||
|
|
||||||
CSTACK_TOOL := $(BACNET_DIR)/tools/avstack/avstack.pl
|
CSTACK_TOOL := $(BACNET_DIR)/tools/avstack/avstack.pl
|
||||||
MEMAP_TOOL := $(BACNET_DIR)/tools/memap/memap.py
|
MEMAP_TOOL := $(BACNET_DIR)/tools/memap/memap.py
|
||||||
@@ -48,6 +48,7 @@ BASIC_SRC = \
|
|||||||
$(BACNET_BASIC)/service/h_rd.c \
|
$(BACNET_BASIC)/service/h_rd.c \
|
||||||
$(BACNET_BASIC)/service/h_rp.c \
|
$(BACNET_BASIC)/service/h_rp.c \
|
||||||
$(BACNET_BASIC)/service/h_rpm.c \
|
$(BACNET_BASIC)/service/h_rpm.c \
|
||||||
|
$(BACNET_BASIC)/service/h_ts.c \
|
||||||
$(BACNET_BASIC)/service/h_whohas.c \
|
$(BACNET_BASIC)/service/h_whohas.c \
|
||||||
$(BACNET_BASIC)/service/h_whois.c \
|
$(BACNET_BASIC)/service/h_whois.c \
|
||||||
$(BACNET_BASIC)/service/h_wp.c \
|
$(BACNET_BASIC)/service/h_wp.c \
|
||||||
@@ -55,6 +56,9 @@ BASIC_SRC = \
|
|||||||
$(BACNET_BASIC)/service/s_iam.c \
|
$(BACNET_BASIC)/service/s_iam.c \
|
||||||
$(BACNET_BASIC)/service/s_ihave.c \
|
$(BACNET_BASIC)/service/s_ihave.c \
|
||||||
$(BACNET_BASIC)/sys/debug.c \
|
$(BACNET_BASIC)/sys/debug.c \
|
||||||
|
$(BACNET_BASIC)/sys/datetime_mstimer.c \
|
||||||
|
$(BACNET_BASIC)/sys/days.c \
|
||||||
|
$(BACNET_BASIC)/sys/dst.c \
|
||||||
$(BACNET_BASIC)/sys/ringbuf.c \
|
$(BACNET_BASIC)/sys/ringbuf.c \
|
||||||
$(BACNET_BASIC)/sys/fifo.c \
|
$(BACNET_BASIC)/sys/fifo.c \
|
||||||
$(BACNET_BASIC)/sys/keylist.c \
|
$(BACNET_BASIC)/sys/keylist.c \
|
||||||
@@ -92,6 +96,7 @@ BACNET_SRC = \
|
|||||||
$(BACNET_CORE)/rpm.c \
|
$(BACNET_CORE)/rpm.c \
|
||||||
$(BACNET_CORE)/special_event.c \
|
$(BACNET_CORE)/special_event.c \
|
||||||
$(BACNET_CORE)/timestamp.c \
|
$(BACNET_CORE)/timestamp.c \
|
||||||
|
$(BACNET_CORE)/timesync.c \
|
||||||
$(BACNET_CORE)/weeklyschedule.c \
|
$(BACNET_CORE)/weeklyschedule.c \
|
||||||
$(BACNET_CORE)/whohas.c \
|
$(BACNET_CORE)/whohas.c \
|
||||||
$(BACNET_CORE)/whois.c \
|
$(BACNET_CORE)/whois.c \
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
#include "bacnet/datalink/datalink.h"
|
#include "bacnet/datalink/datalink.h"
|
||||||
#include "bacnet/npdu.h"
|
#include "bacnet/npdu.h"
|
||||||
#include "bacnet/basic/services.h"
|
#include "bacnet/basic/services.h"
|
||||||
#include "bacnet/basic/services.h"
|
|
||||||
#include "bacnet/basic/tsm/tsm.h"
|
#include "bacnet/basic/tsm/tsm.h"
|
||||||
|
#include "bacnet/datetime.h"
|
||||||
#include "bacnet/dcc.h"
|
#include "bacnet/dcc.h"
|
||||||
#include "bacnet/iam.h"
|
#include "bacnet/iam.h"
|
||||||
/* BACnet objects */
|
/* BACnet objects */
|
||||||
@@ -116,6 +116,12 @@ void bacnet_init(void)
|
|||||||
SERVICE_CONFIRMED_REINITIALIZE_DEVICE, handler_reinitialize_device);
|
SERVICE_CONFIRMED_REINITIALIZE_DEVICE, handler_reinitialize_device);
|
||||||
apdu_set_confirmed_handler(
|
apdu_set_confirmed_handler(
|
||||||
SERVICE_CONFIRMED_WRITE_PROPERTY, handler_write_property);
|
SERVICE_CONFIRMED_WRITE_PROPERTY, handler_write_property);
|
||||||
|
/* local time and date */
|
||||||
|
apdu_set_unconfirmed_handler(
|
||||||
|
SERVICE_UNCONFIRMED_TIME_SYNCHRONIZATION,
|
||||||
|
handler_timesync);
|
||||||
|
handler_timesync_set_callback_set(datetime_timesync);
|
||||||
|
datetime_init();
|
||||||
/* handle communication so we can shutup when asked */
|
/* handle communication so we can shutup when asked */
|
||||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
|
apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
|
||||||
handler_device_communication_control);
|
handler_device_communication_control);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "bacnet/bacstr.h"
|
#include "bacnet/bacstr.h"
|
||||||
#include "bacnet/bacenum.h"
|
#include "bacnet/bacenum.h"
|
||||||
#include "bacnet/apdu.h"
|
#include "bacnet/apdu.h"
|
||||||
|
#include "bacnet/datetime.h"
|
||||||
#include "bacnet/dcc.h"
|
#include "bacnet/dcc.h"
|
||||||
#include "bacnet/datalink/datalink.h"
|
#include "bacnet/datalink/datalink.h"
|
||||||
#include "bacnet/version.h"
|
#include "bacnet/version.h"
|
||||||
@@ -49,11 +50,12 @@ static struct my_object_functions {
|
|||||||
read_property_function Object_Read_Property;
|
read_property_function Object_Read_Property;
|
||||||
write_property_function Object_Write_Property;
|
write_property_function Object_Write_Property;
|
||||||
rpm_property_lists_function Object_RPM_List;
|
rpm_property_lists_function Object_RPM_List;
|
||||||
} Object_Table[] = { { OBJECT_DEVICE, NULL, /* don't init - recursive! */
|
} Object_Table[] = { { OBJECT_DEVICE, NULL,
|
||||||
Device_Count, Device_Index_To_Instance,
|
/* don't init - recursive! */
|
||||||
Device_Valid_Object_Instance_Number,
|
Device_Count, Device_Index_To_Instance,
|
||||||
Device_Object_Name, Device_Read_Property_Local,
|
Device_Valid_Object_Instance_Number,
|
||||||
Device_Write_Property_Local, Device_Property_Lists },
|
Device_Object_Name, Device_Read_Property_Local,
|
||||||
|
Device_Write_Property_Local, Device_Property_Lists },
|
||||||
{ OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count,
|
{ OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count,
|
||||||
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance,
|
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance,
|
||||||
Analog_Input_Object_Name, Analog_Input_Read_Property,
|
Analog_Input_Object_Name, Analog_Input_Read_Property,
|
||||||
@@ -116,7 +118,9 @@ static const char *BACnet_Version = BACNET_VERSION_TEXT;
|
|||||||
static uint8_t Device_UUID[16];
|
static uint8_t Device_UUID[16];
|
||||||
|
|
||||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||||
static const int Device_Properties_Required[] = { PROP_OBJECT_IDENTIFIER,
|
static const int Device_Properties_Required[] = {
|
||||||
|
/* required properties for this object */
|
||||||
|
PROP_OBJECT_IDENTIFIER,
|
||||||
PROP_OBJECT_NAME, PROP_OBJECT_TYPE, PROP_SYSTEM_STATUS, PROP_VENDOR_NAME,
|
PROP_OBJECT_NAME, PROP_OBJECT_TYPE, PROP_SYSTEM_STATUS, PROP_VENDOR_NAME,
|
||||||
PROP_VENDOR_IDENTIFIER, PROP_MODEL_NAME, PROP_FIRMWARE_REVISION,
|
PROP_VENDOR_IDENTIFIER, PROP_MODEL_NAME, PROP_FIRMWARE_REVISION,
|
||||||
PROP_APPLICATION_SOFTWARE_VERSION, PROP_PROTOCOL_VERSION,
|
PROP_APPLICATION_SOFTWARE_VERSION, PROP_PROTOCOL_VERSION,
|
||||||
@@ -126,8 +130,17 @@ static const int Device_Properties_Required[] = { PROP_OBJECT_IDENTIFIER,
|
|||||||
PROP_APDU_TIMEOUT, PROP_NUMBER_OF_APDU_RETRIES, PROP_DEVICE_ADDRESS_BINDING,
|
PROP_APDU_TIMEOUT, PROP_NUMBER_OF_APDU_RETRIES, PROP_DEVICE_ADDRESS_BINDING,
|
||||||
PROP_DATABASE_REVISION, -1 };
|
PROP_DATABASE_REVISION, -1 };
|
||||||
|
|
||||||
static const int Device_Properties_Optional[] = { PROP_DESCRIPTION,
|
static const int Device_Properties_Optional[] = {
|
||||||
PROP_LOCATION, PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, PROP_DEVICE_UUID,
|
/* optional properties for this object */
|
||||||
|
PROP_DESCRIPTION,
|
||||||
|
PROP_LOCATION,
|
||||||
|
PROP_MAX_MASTER,
|
||||||
|
PROP_MAX_INFO_FRAMES,
|
||||||
|
PROP_DEVICE_UUID,
|
||||||
|
PROP_LOCAL_DATE,
|
||||||
|
PROP_LOCAL_TIME,
|
||||||
|
PROP_UTC_OFFSET,
|
||||||
|
PROP_DAYLIGHT_SAVINGS_STATUS,
|
||||||
-1 };
|
-1 };
|
||||||
|
|
||||||
static const int Device_Properties_Proprietary[] = { -1 };
|
static const int Device_Properties_Proprietary[] = { -1 };
|
||||||
@@ -686,6 +699,10 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
|
|||||||
BACNET_BIT_STRING bit_string = { 0 };
|
BACNET_BIT_STRING bit_string = { 0 };
|
||||||
BACNET_CHARACTER_STRING char_string = { 0 };
|
BACNET_CHARACTER_STRING char_string = { 0 };
|
||||||
BACNET_OCTET_STRING octet_string = { 0 };
|
BACNET_OCTET_STRING octet_string = { 0 };
|
||||||
|
BACNET_DATE bdate;
|
||||||
|
BACNET_TIME btime;
|
||||||
|
int16_t utc_offset_minutes;
|
||||||
|
bool dst_active;
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
uint8_t *apdu = NULL;
|
uint8_t *apdu = NULL;
|
||||||
@@ -817,6 +834,23 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
|
|||||||
octetstring_init(&octet_string, Device_UUID, sizeof(Device_UUID));
|
octetstring_init(&octet_string, Device_UUID, sizeof(Device_UUID));
|
||||||
apdu_len = encode_application_octet_string(&apdu[0], &octet_string);
|
apdu_len = encode_application_octet_string(&apdu[0], &octet_string);
|
||||||
break;
|
break;
|
||||||
|
case PROP_LOCAL_TIME:
|
||||||
|
datetime_local(&bdate, &btime, &utc_offset_minutes, &dst_active);
|
||||||
|
apdu_len = encode_application_time(&apdu[0], &btime);
|
||||||
|
break;
|
||||||
|
case PROP_LOCAL_DATE:
|
||||||
|
datetime_local(&bdate, &btime, &utc_offset_minutes, &dst_active);
|
||||||
|
apdu_len = encode_application_date(&apdu[0], &bdate);
|
||||||
|
break;
|
||||||
|
case PROP_UTC_OFFSET:
|
||||||
|
datetime_local(&bdate, &btime, &utc_offset_minutes, &dst_active);
|
||||||
|
apdu_len = encode_application_signed(&apdu[0], utc_offset_minutes);
|
||||||
|
break;
|
||||||
|
case PROP_DAYLIGHT_SAVINGS_STATUS:
|
||||||
|
datetime_local(&bdate, &btime, &utc_offset_minutes, &dst_active);
|
||||||
|
apdu_len =
|
||||||
|
encode_application_boolean(&apdu[0], dst_active);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||||
@@ -1060,6 +1094,39 @@ bool Device_Write_Property_Local(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
|||||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PROP_LOCAL_TIME:
|
||||||
|
status = write_property_type_valid(
|
||||||
|
wp_data, &value, BACNET_APPLICATION_TAG_TIME);
|
||||||
|
if (status) {
|
||||||
|
status = datetime_time_is_valid(&value.type.Time);
|
||||||
|
if (status) {
|
||||||
|
datetime_timesync(NULL, &value.type.Time, false);
|
||||||
|
} else {
|
||||||
|
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||||
|
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PROP_LOCAL_DATE:
|
||||||
|
status = write_property_type_valid(
|
||||||
|
wp_data, &value, BACNET_APPLICATION_TAG_DATE);
|
||||||
|
if (status) {
|
||||||
|
status = datetime_date_is_valid(&value.type.Date);
|
||||||
|
if (status) {
|
||||||
|
datetime_timesync(&value.type.Date, NULL, false);
|
||||||
|
} else {
|
||||||
|
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||||
|
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PROP_UTC_OFFSET:
|
||||||
|
status = write_property_type_valid(
|
||||||
|
wp_data, &value, BACNET_APPLICATION_TAG_SIGNED_INT);
|
||||||
|
if (status) {
|
||||||
|
datetime_utc_offset_minutes_set(value.type.Signed_Int);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case PROP_OBJECT_TYPE:
|
case PROP_OBJECT_TYPE:
|
||||||
case PROP_VENDOR_NAME:
|
case PROP_VENDOR_NAME:
|
||||||
case PROP_VENDOR_IDENTIFIER:
|
case PROP_VENDOR_IDENTIFIER:
|
||||||
@@ -1076,6 +1143,7 @@ bool Device_Write_Property_Local(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
|||||||
case PROP_DEVICE_ADDRESS_BINDING:
|
case PROP_DEVICE_ADDRESS_BINDING:
|
||||||
case PROP_ACTIVE_COV_SUBSCRIPTIONS:
|
case PROP_ACTIVE_COV_SUBSCRIPTIONS:
|
||||||
case PROP_DATABASE_REVISION:
|
case PROP_DATABASE_REVISION:
|
||||||
|
case PROP_DAYLIGHT_SAVINGS_STATUS:
|
||||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -0,0 +1,262 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief API for Milliseconds Timer based Time-of-Day Clock
|
||||||
|
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
* @date 2024
|
||||||
|
* @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
|
||||||
|
*/
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
/* BACnet Stack defines - first */
|
||||||
|
#include "bacnet/bacdef.h"
|
||||||
|
/* BACnet Stack API */
|
||||||
|
#include "bacnet/basic/sys/dst.h"
|
||||||
|
#include "bacnet/basic/sys/mstimer.h"
|
||||||
|
#include "bacnet/datetime.h"
|
||||||
|
|
||||||
|
/* local time */
|
||||||
|
static BACNET_DATE_TIME BACnet_Date_Time;
|
||||||
|
static int16_t UTC_Offset_Minutes;
|
||||||
|
/* starting and stopping dates/times to determine DST */
|
||||||
|
static struct daylight_savings_data DST_Range;
|
||||||
|
static bool DST_Enabled;
|
||||||
|
/* local time based on mstimer */
|
||||||
|
static struct mstimer Date_Timer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Synchronize the local time from the millisecond timer
|
||||||
|
*/
|
||||||
|
static void datetime_sync(void)
|
||||||
|
{
|
||||||
|
bacnet_time_t seconds, elapsed_seconds;
|
||||||
|
unsigned long milliseconds;
|
||||||
|
|
||||||
|
milliseconds = mstimer_elapsed(&Date_Timer);
|
||||||
|
elapsed_seconds = milliseconds / 1000UL;
|
||||||
|
if (elapsed_seconds) {
|
||||||
|
mstimer_restart(&Date_Timer);
|
||||||
|
seconds = datetime_seconds_since_epoch(&BACnet_Date_Time);
|
||||||
|
seconds += elapsed_seconds;
|
||||||
|
datetime_since_epoch_seconds(&BACnet_Date_Time, seconds);
|
||||||
|
/* generate a hundredths value */
|
||||||
|
milliseconds -= (elapsed_seconds * 1000UL);
|
||||||
|
BACnet_Date_Time.time.hundredths = milliseconds / 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the local determination of daylight savings time being active
|
||||||
|
* @return true if DST is active, false otherwise
|
||||||
|
*/
|
||||||
|
static bool datetime_dst_active(
|
||||||
|
struct daylight_savings_data *dst,
|
||||||
|
BACNET_DATE_TIME *bdatetime,
|
||||||
|
bool enabled)
|
||||||
|
{
|
||||||
|
bool active = false;
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
active = dst_active(
|
||||||
|
dst, bdatetime->date.year, bdatetime->date.month,
|
||||||
|
bdatetime->date.day, bdatetime->time.hour, bdatetime->time.min,
|
||||||
|
bdatetime->time.sec);
|
||||||
|
}
|
||||||
|
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the local date and time
|
||||||
|
* @param bdate [out] The date to get
|
||||||
|
* @param btime [out] The time to get
|
||||||
|
* @param utc_offset_minutes [out] The UTC offset in minutes
|
||||||
|
* @param dst_active [out] The DST flag
|
||||||
|
* @return true if successful, false on error
|
||||||
|
*/
|
||||||
|
bool datetime_local(
|
||||||
|
BACNET_DATE *bdate,
|
||||||
|
BACNET_TIME *btime,
|
||||||
|
int16_t *utc_offset_minutes,
|
||||||
|
bool *dst_active)
|
||||||
|
{
|
||||||
|
datetime_sync();
|
||||||
|
if (bdate) {
|
||||||
|
datetime_copy_date(bdate, &BACnet_Date_Time.date);
|
||||||
|
}
|
||||||
|
if (btime) {
|
||||||
|
datetime_copy_time(btime, &BACnet_Date_Time.time);
|
||||||
|
}
|
||||||
|
if (utc_offset_minutes) {
|
||||||
|
*utc_offset_minutes = UTC_Offset_Minutes;
|
||||||
|
}
|
||||||
|
if (dst_active) {
|
||||||
|
*dst_active =
|
||||||
|
datetime_dst_active(&DST_Range, &BACnet_Date_Time, DST_Enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the UTC offset in minutes
|
||||||
|
* @return The UTC offset in minutes
|
||||||
|
*/
|
||||||
|
int16_t datetime_utc_offset_minutes(void)
|
||||||
|
{
|
||||||
|
return UTC_Offset_Minutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the UTC offset in minutes
|
||||||
|
* @param minutes [in] The UTC offset in minutes
|
||||||
|
* @return true if successful, false on error
|
||||||
|
*/
|
||||||
|
bool datetime_utc_offset_minutes_set(int16_t minutes)
|
||||||
|
{
|
||||||
|
UTC_Offset_Minutes = minutes;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the Daylight Savings Enabled flag
|
||||||
|
* @return Daylight Savings Enabled flag
|
||||||
|
*/
|
||||||
|
bool datetime_dst_enabled(void)
|
||||||
|
{
|
||||||
|
return DST_Enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Daylight Savings Enabled flag
|
||||||
|
* @param flag [in] The Daylight Savings Enabled flag
|
||||||
|
*/
|
||||||
|
void datetime_dst_enabled_set(bool flag)
|
||||||
|
{
|
||||||
|
DST_Enabled = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the local DST start and end date range
|
||||||
|
* @param dst_range [out] The DST range to get
|
||||||
|
* @return true if successful, false on error
|
||||||
|
*/
|
||||||
|
bool datetime_dst_ordinal_range(
|
||||||
|
uint8_t *start_month,
|
||||||
|
uint8_t *start_week,
|
||||||
|
uint8_t *start_day,
|
||||||
|
uint8_t *end_month,
|
||||||
|
uint8_t *end_week,
|
||||||
|
uint8_t *end_day)
|
||||||
|
{
|
||||||
|
if (!DST_Range.Ordinal) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*start_month = DST_Range.Begin_Month;
|
||||||
|
*start_week = DST_Range.Begin_Week;
|
||||||
|
*start_day = DST_Range.Begin_Day;
|
||||||
|
*end_month = DST_Range.End_Month;
|
||||||
|
*end_week = DST_Range.End_Week;
|
||||||
|
*end_day = DST_Range.End_Day;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool datetime_dst_ordinal_range_set(
|
||||||
|
uint8_t start_month,
|
||||||
|
uint8_t start_week,
|
||||||
|
BACNET_WEEKDAY start_day,
|
||||||
|
uint8_t end_month,
|
||||||
|
uint8_t end_week,
|
||||||
|
BACNET_WEEKDAY end_day)
|
||||||
|
{
|
||||||
|
DST_Range.Ordinal = true;
|
||||||
|
DST_Range.Begin_Month = start_month;
|
||||||
|
DST_Range.Begin_Week = start_week;
|
||||||
|
DST_Range.Begin_Day = start_day;
|
||||||
|
DST_Range.End_Month = end_month;
|
||||||
|
DST_Range.End_Week = end_week;
|
||||||
|
DST_Range.End_Day = end_day;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the local DST start and end date range for specific month day
|
||||||
|
* @param dst_range [in] The DST range
|
||||||
|
* @return true if the start and end month day values are returned
|
||||||
|
*/
|
||||||
|
bool datetime_dst_date_range(
|
||||||
|
uint8_t *start_month,
|
||||||
|
uint8_t *start_day,
|
||||||
|
uint8_t *end_month,
|
||||||
|
uint8_t *end_day)
|
||||||
|
{
|
||||||
|
if (DST_Range.Ordinal) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*start_month = DST_Range.Begin_Month;
|
||||||
|
*start_day = DST_Range.Begin_Day;
|
||||||
|
*end_month = DST_Range.End_Month;
|
||||||
|
*end_day = DST_Range.End_Day;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the local DST start and end date range for specific month day
|
||||||
|
* @param dst_range [in] The DST range to set
|
||||||
|
* @return true if successful, false on error
|
||||||
|
*/
|
||||||
|
bool datetime_dst_date_range_set(
|
||||||
|
uint8_t start_month, uint8_t start_day, uint8_t end_month, uint8_t end_day)
|
||||||
|
{
|
||||||
|
DST_Range.Ordinal = false;
|
||||||
|
DST_Range.Begin_Month = start_month;
|
||||||
|
DST_Range.Begin_Day = start_day;
|
||||||
|
DST_Range.End_Month = end_month;
|
||||||
|
DST_Range.End_Day = end_day;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the local date and time from a BACnet TimeSynchronization request
|
||||||
|
* @param bdate [in] The date to set
|
||||||
|
* @param btime [in] The time to set
|
||||||
|
* @param utc [in] true if originating from an UTCTimeSynchronization request
|
||||||
|
*/
|
||||||
|
void datetime_timesync(BACNET_DATE *bdate, BACNET_TIME *btime, bool utc)
|
||||||
|
{
|
||||||
|
BACNET_DATE_TIME local_time = { 0 };
|
||||||
|
const int32_t dst_adjust_minutes = 60L;
|
||||||
|
|
||||||
|
if (utc) {
|
||||||
|
if (bdate && btime) {
|
||||||
|
datetime_copy_date(&local_time.date, bdate);
|
||||||
|
datetime_copy_time(&local_time.time, btime);
|
||||||
|
datetime_add_minutes(&local_time, UTC_Offset_Minutes);
|
||||||
|
if (datetime_dst_active(&DST_Range, &local_time, DST_Enabled)) {
|
||||||
|
datetime_add_minutes(&local_time, dst_adjust_minutes);
|
||||||
|
}
|
||||||
|
datetime_copy(&BACnet_Date_Time, &local_time);
|
||||||
|
mstimer_restart(&Date_Timer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
datetime_copy_date(&BACnet_Date_Time.date, bdate);
|
||||||
|
datetime_copy_time(&BACnet_Date_Time.time, btime);
|
||||||
|
mstimer_restart(&Date_Timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the local date and time timer
|
||||||
|
*/
|
||||||
|
void datetime_init(void)
|
||||||
|
{
|
||||||
|
dst_init_defaults(&DST_Range);
|
||||||
|
mstimer_set(&Date_Timer, 0);
|
||||||
|
}
|
||||||
@@ -221,6 +221,8 @@ days_since_epoch(uint16_t epoch_year, uint16_t year, uint8_t month, uint8_t day)
|
|||||||
days += days_per_month(year, mm);
|
days += days_per_month(year, mm);
|
||||||
}
|
}
|
||||||
days += day;
|
days += day;
|
||||||
|
/* 'days since' is one less */
|
||||||
|
days -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (days);
|
return (days);
|
||||||
@@ -243,15 +245,15 @@ void days_since_epoch_to_date(
|
|||||||
uint8_t *pDay)
|
uint8_t *pDay)
|
||||||
{
|
{
|
||||||
uint8_t month = 1;
|
uint8_t month = 1;
|
||||||
uint8_t day = 0;
|
uint8_t day = 1;
|
||||||
uint16_t year;
|
uint16_t year;
|
||||||
|
|
||||||
year = epoch_year;
|
year = epoch_year;
|
||||||
while (days > days_per_year(year)) {
|
while (days >= days_per_year(year)) {
|
||||||
days -= days_per_year(year);
|
days -= days_per_year(year);
|
||||||
year++;
|
year++;
|
||||||
}
|
}
|
||||||
while (days > days_per_month(year, month)) {
|
while (days >= days_per_month(year, month)) {
|
||||||
days -= days_per_month(year, month);
|
days -= days_per_month(year, month);
|
||||||
month++;
|
month++;
|
||||||
}
|
}
|
||||||
@@ -291,3 +293,19 @@ bool days_date_is_valid(uint16_t year, uint8_t month, uint8_t day)
|
|||||||
|
|
||||||
return (valid);
|
return (valid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the day of the week value
|
||||||
|
*
|
||||||
|
* @param epoch_day - day of week for epoch day
|
||||||
|
* @param days - number of days since epoch
|
||||||
|
* @return day of week 1..7 offset by epoch day
|
||||||
|
*/
|
||||||
|
uint8_t days_of_week(uint8_t epoch_day, uint32_t days)
|
||||||
|
{
|
||||||
|
uint8_t dow = epoch_day;
|
||||||
|
|
||||||
|
dow += (days % 7);
|
||||||
|
|
||||||
|
return dow;
|
||||||
|
}
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ void days_since_epoch_to_date(
|
|||||||
uint8_t *pMonth,
|
uint8_t *pMonth,
|
||||||
uint8_t *pDay);
|
uint8_t *pDay);
|
||||||
|
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
uint8_t days_of_week(uint8_t epoch_day, uint32_t days);
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
bool days_date_is_valid(uint16_t year, uint8_t month, uint8_t day);
|
bool days_date_is_valid(uint16_t year, uint8_t month, uint8_t day);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,229 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief computes whether day is during daylight savings time
|
||||||
|
* @note Public domain algorithms from ACM
|
||||||
|
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
* @date 1997
|
||||||
|
* @copyright SPDX-License-Identifier: CC-PDDC
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "days.h"
|
||||||
|
#include "dst.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns the number of seconds after midnight
|
||||||
|
*
|
||||||
|
* @param hours - hours after midnight (0..23)
|
||||||
|
* @param minutes - minutes after hour (0..59)
|
||||||
|
* @param seconds - holds seconds after minute (0..59)
|
||||||
|
*
|
||||||
|
* @return true if date-time falls in DST. false if not.
|
||||||
|
*/
|
||||||
|
static uint32_t
|
||||||
|
time_to_seconds(uint32_t hours, uint32_t minutes, uint32_t seconds)
|
||||||
|
{
|
||||||
|
return (((hours) * 60 * 60) + ((minutes) * 60) + (seconds));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns the day of the month for starting the Nth week
|
||||||
|
*
|
||||||
|
* @param year - Year of our Lord A.D. (1900..9999)
|
||||||
|
* @param month - months of the year (1=Jan,...,12=Dec)
|
||||||
|
* @param ordinal - Ordinal Day of the Month
|
||||||
|
* 1=1st, 2=2nd, 3=3rd, 4=4th, or 5=LAST
|
||||||
|
* @return day of the month (1..31)
|
||||||
|
*/
|
||||||
|
static uint8_t
|
||||||
|
ordinal_week_month_day(uint16_t year, uint8_t month, uint8_t ordinal)
|
||||||
|
{
|
||||||
|
uint8_t day = 0;
|
||||||
|
|
||||||
|
if (ordinal == 5) {
|
||||||
|
/* last week of the month */
|
||||||
|
day = days_per_month(year, month) - 6;
|
||||||
|
} else {
|
||||||
|
if (ordinal) {
|
||||||
|
ordinal--;
|
||||||
|
day = 1 + (ordinal * 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return day;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true if the date-time is during DST
|
||||||
|
*
|
||||||
|
* @param year - Year of our Lord A.D. (2000,2001,..2099)
|
||||||
|
* @param month - months of the year (1=Jan,...,12=Dec)
|
||||||
|
* @param day - day of the month (1..31)
|
||||||
|
* @param hour - hours after midnight (0..23)
|
||||||
|
* @param minute - minutes after hour (0..59)
|
||||||
|
* @param second - holds seconds after minute (0..59)
|
||||||
|
*
|
||||||
|
* @return true if date-time falls in DST. false if not.
|
||||||
|
*/
|
||||||
|
bool dst_active(
|
||||||
|
struct daylight_savings_data *data,
|
||||||
|
uint16_t year,
|
||||||
|
uint8_t month,
|
||||||
|
uint8_t day,
|
||||||
|
uint8_t hour,
|
||||||
|
uint8_t minute,
|
||||||
|
uint8_t second)
|
||||||
|
{
|
||||||
|
bool active = false;
|
||||||
|
uint8_t i = 0;
|
||||||
|
uint32_t time_now = 0;
|
||||||
|
uint32_t time_dst = 0;
|
||||||
|
uint8_t day_of_week = 0;
|
||||||
|
uint8_t days = 0;
|
||||||
|
uint32_t days_begin = 0;
|
||||||
|
uint32_t days_now = 0;
|
||||||
|
uint32_t days_end = 0;
|
||||||
|
|
||||||
|
if (data->Ordinal) {
|
||||||
|
if ((month >= data->Begin_Month) && (month <= data->End_Month)) {
|
||||||
|
if (month == data->Begin_Month) {
|
||||||
|
days = days_per_month(year, month);
|
||||||
|
i = ordinal_week_month_day(year, month, data->Begin_Week);
|
||||||
|
for (; i <= days; i++) {
|
||||||
|
day_of_week = days_of_week(
|
||||||
|
data->Epoch_Day,
|
||||||
|
days_since_epoch(data->Epoch_Year, year, month, i));
|
||||||
|
if (day_of_week == data->Begin_Day) {
|
||||||
|
if (day == i) {
|
||||||
|
time_now = time_to_seconds(hour, minute, second);
|
||||||
|
/* begins at 2 AM Standard Time */
|
||||||
|
time_dst = time_to_seconds(2, 0, 0);
|
||||||
|
if (time_now >= time_dst) {
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
} else if (day > i) {
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (month == data->End_Month) {
|
||||||
|
days = days_per_month(year, month);
|
||||||
|
i = ordinal_week_month_day(year, month, data->End_Week);
|
||||||
|
for (; i <= days; i++) {
|
||||||
|
day_of_week = days_of_week(
|
||||||
|
data->Epoch_Day,
|
||||||
|
days_since_epoch(data->Epoch_Year, year, month, i));
|
||||||
|
if (day_of_week == data->End_Day) {
|
||||||
|
if (day == i) {
|
||||||
|
time_now = time_to_seconds(hour, minute, second);
|
||||||
|
/* ends at 2 AM Daylight time,
|
||||||
|
which is 1 AM Standard Time */
|
||||||
|
time_dst = time_to_seconds(1, 0, 0);
|
||||||
|
if (time_now < time_dst) {
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
} else if (day < i) {
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* months between the beginning and end months */
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
days_now = days_since_epoch(data->Epoch_Year, year, month, day);
|
||||||
|
days_begin = days_since_epoch(
|
||||||
|
data->Epoch_Year, year, data->Begin_Month, data->Begin_Day);
|
||||||
|
days_end = days_since_epoch(
|
||||||
|
data->Epoch_Year, year, data->End_Month, data->End_Day);
|
||||||
|
if ((days_now >= days_begin) && (days_now <= days_end)) {
|
||||||
|
if (days_now == days_begin) {
|
||||||
|
time_now = time_to_seconds(hour, minute, second);
|
||||||
|
/* begins at 2 AM Standard Time */
|
||||||
|
time_dst = time_to_seconds(2, 0, 0);
|
||||||
|
if (time_now >= time_dst) {
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
} else if (days_now == days_end) {
|
||||||
|
time_now = time_to_seconds(hour, minute, second);
|
||||||
|
/* ends at 2 AM Daylight time,
|
||||||
|
which is 1 AM Standard Time */
|
||||||
|
time_dst = time_to_seconds(1, 0, 0);
|
||||||
|
if (time_now < time_dst) {
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function sets the daylight savings time parameters
|
||||||
|
* @param data - daylight savings time data
|
||||||
|
* @param ordinal - true when ordinal day of month used, false if specific dates
|
||||||
|
* @param begin_month - month DST begins 1=Jan,...,12=Dec
|
||||||
|
* @param begin_day - day of the month DST begins
|
||||||
|
* 1..31 for specific day, or day of week 1..7 for ordinal day
|
||||||
|
* @param begin_which_day - which ordinal day of the month is used
|
||||||
|
* 1=1st, 2=2nd, 3=3rd, 4=4th, or 5=LAST
|
||||||
|
* @param end_month - month DST ends 1=Jan,...,12=Dec
|
||||||
|
* @param end_day - day of the month DST ends
|
||||||
|
* 1..31 for specific day, or day of week 1..7 for ordinal day
|
||||||
|
* @param end_which_day - which ordinal day of the month is used
|
||||||
|
* 1=1st, 2=2nd, 3=3rd, 4=4th, or 5=LAST
|
||||||
|
* @param epoch_day - day of the week for the BACnet Epoch (1=Monday..7=Sunday)
|
||||||
|
* @param epoch_year - year of the BACnet Epoch (1900..9999)
|
||||||
|
*/
|
||||||
|
void dst_init(
|
||||||
|
struct daylight_savings_data *data,
|
||||||
|
bool ordinal,
|
||||||
|
uint8_t begin_month,
|
||||||
|
uint8_t begin_day,
|
||||||
|
uint8_t begin_which_day,
|
||||||
|
uint8_t end_month,
|
||||||
|
uint8_t end_day,
|
||||||
|
uint8_t end_which_day,
|
||||||
|
uint8_t epoch_day,
|
||||||
|
uint16_t epoch_year)
|
||||||
|
{
|
||||||
|
if (data) {
|
||||||
|
data->Ordinal = ordinal;
|
||||||
|
data->Begin_Month = begin_month;
|
||||||
|
data->Begin_Day = begin_day;
|
||||||
|
data->Begin_Week = begin_which_day;
|
||||||
|
data->End_Month = end_month;
|
||||||
|
data->End_Day = end_day;
|
||||||
|
data->End_Week = end_which_day;
|
||||||
|
data->Epoch_Day = epoch_day;
|
||||||
|
data->Epoch_Year = epoch_year;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the daylight savings time parameters to their defaults.
|
||||||
|
*/
|
||||||
|
void dst_init_defaults(struct daylight_savings_data *data)
|
||||||
|
{
|
||||||
|
if (data) {
|
||||||
|
/* Starts: Second=2 Sunday=7 in March=3 */
|
||||||
|
/* Ends: First=1 Sunday=7 in November=11 */
|
||||||
|
data->Ordinal = true;
|
||||||
|
data->Begin_Month = 3;
|
||||||
|
data->Begin_Day = 7;
|
||||||
|
data->Begin_Week = 2;
|
||||||
|
data->End_Month = 11;
|
||||||
|
data->End_Day = 7;
|
||||||
|
data->End_Week = 1;
|
||||||
|
/* BACnet Epoch */
|
||||||
|
data->Epoch_Day = 1 /* Monday=1 */;
|
||||||
|
data->Epoch_Year = 1900;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief This file contains the function prototypes for for the module.
|
||||||
|
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
* @date 1997
|
||||||
|
* @note Public domain algorithms from ACM
|
||||||
|
* @copyright SPDX-License-Identifier: CC-PDDC
|
||||||
|
*/
|
||||||
|
#ifndef BACNET_BASIC_SYS_DST_H
|
||||||
|
#define BACNET_BASIC_SYS_DST_H
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
/* BACnet Stack defines - first */
|
||||||
|
#include "bacnet/bacdef.h"
|
||||||
|
|
||||||
|
struct daylight_savings_data {
|
||||||
|
bool Ordinal : 1;
|
||||||
|
uint8_t Begin_Month;
|
||||||
|
uint8_t Begin_Day;
|
||||||
|
uint8_t Begin_Week;
|
||||||
|
uint8_t End_Month;
|
||||||
|
uint8_t End_Day;
|
||||||
|
uint8_t End_Week;
|
||||||
|
uint16_t Epoch_Year;
|
||||||
|
uint8_t Epoch_Day;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
bool dst_active(
|
||||||
|
struct daylight_savings_data *dst,
|
||||||
|
uint16_t year,
|
||||||
|
uint8_t month,
|
||||||
|
uint8_t day,
|
||||||
|
uint8_t hour,
|
||||||
|
uint8_t minute,
|
||||||
|
uint8_t second);
|
||||||
|
void dst_init(
|
||||||
|
struct daylight_savings_data *data,
|
||||||
|
bool automatic,
|
||||||
|
uint8_t begin_month,
|
||||||
|
uint8_t begin_day,
|
||||||
|
uint8_t begin_which_day,
|
||||||
|
uint8_t end_month,
|
||||||
|
uint8_t end_day,
|
||||||
|
uint8_t end_which_day,
|
||||||
|
uint8_t epoch_day,
|
||||||
|
uint16_t epoch_year);
|
||||||
|
/* initialization */
|
||||||
|
void dst_init_defaults(struct daylight_savings_data *data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -884,7 +884,6 @@ void dlmstp_set_frame_rx_start_callback(dlmstp_hook_frame_rx_start_cb cb_func)
|
|||||||
void dlmstp_reset_statistics(void)
|
void dlmstp_reset_statistics(void)
|
||||||
{
|
{
|
||||||
struct dlmstp_user_data_t *user;
|
struct dlmstp_user_data_t *user;
|
||||||
struct dlmstp_statistics *stats;
|
|
||||||
|
|
||||||
if (!MSTP_Port) {
|
if (!MSTP_Port) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+5
-16
@@ -141,21 +141,12 @@ uint32_t
|
|||||||
datetime_ymd_to_days_since_epoch(uint16_t year, uint8_t month, uint8_t day)
|
datetime_ymd_to_days_since_epoch(uint16_t year, uint8_t month, uint8_t day)
|
||||||
{
|
{
|
||||||
uint32_t days = 0; /* return value */
|
uint32_t days = 0; /* return value */
|
||||||
uint16_t years = 0; /* loop counter for years */
|
|
||||||
|
|
||||||
if (datetime_ymd_is_valid(year, month, day)) {
|
if (datetime_ymd_is_valid(year, month, day)) {
|
||||||
for (years = BACNET_DATE_YEAR_EPOCH; years < year; years++) {
|
days = days_since_epoch(BACNET_DATE_YEAR_EPOCH, year, month, day);
|
||||||
days += 365;
|
|
||||||
if (days_is_leap_year(years)) {
|
|
||||||
days++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
days += datetime_ymd_day_of_year(year, month, day);
|
|
||||||
/* 'days since' is one less */
|
|
||||||
days -= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (days);
|
return days;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -248,11 +239,9 @@ void datetime_days_since_epoch_into_date(uint32_t days, BACNET_DATE *bdate)
|
|||||||
*/
|
*/
|
||||||
uint8_t datetime_day_of_week(uint16_t year, uint8_t month, uint8_t day)
|
uint8_t datetime_day_of_week(uint16_t year, uint8_t month, uint8_t day)
|
||||||
{
|
{
|
||||||
uint8_t dow = (uint8_t)BACNET_DAY_OF_WEEK_EPOCH;
|
return days_of_week(
|
||||||
|
BACNET_DAY_OF_WEEK_EPOCH,
|
||||||
dow += (datetime_ymd_to_days_since_epoch(year, month, day) % 7);
|
datetime_ymd_to_days_since_epoch(year, month, day));
|
||||||
|
|
||||||
return dow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+30
-3
@@ -318,18 +318,45 @@ bool datetime_local(
|
|||||||
BACNET_TIME *btime,
|
BACNET_TIME *btime,
|
||||||
int16_t *utc_offset_minutes,
|
int16_t *utc_offset_minutes,
|
||||||
bool *dst_active);
|
bool *dst_active);
|
||||||
|
/* UTC Offset API */
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
int16_t datetime_utc_offset_minutes(void);
|
int16_t datetime_utc_offset_minutes(void);
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
bool datetime_utc_offset_minutes_set(int16_t minutes);
|
bool datetime_utc_offset_minutes_set(int16_t minutes);
|
||||||
|
/* Daylight Savings Time API */
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
bool datetime_dst_active(void);
|
bool datetime_dst_enabled(void);
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
bool datetime_dst_range(BACNET_DATE_RANGE *dst_range);
|
void datetime_dst_enabled_set(bool flag);
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
bool datetime_dst_range_set(BACNET_DATE_RANGE *dst_range);
|
bool datetime_dst_ordinal_range(
|
||||||
|
uint8_t *start_month,
|
||||||
|
uint8_t *start_week,
|
||||||
|
uint8_t *start_day,
|
||||||
|
uint8_t *end_month,
|
||||||
|
uint8_t *end_week,
|
||||||
|
uint8_t *end_day);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
bool datetime_dst_ordinal_range_set(
|
||||||
|
uint8_t start_month,
|
||||||
|
uint8_t start_week,
|
||||||
|
BACNET_WEEKDAY start_day,
|
||||||
|
uint8_t end_month,
|
||||||
|
uint8_t end_week,
|
||||||
|
BACNET_WEEKDAY end_day);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
bool datetime_dst_date_range(
|
||||||
|
uint8_t *start_month,
|
||||||
|
uint8_t *start_day,
|
||||||
|
uint8_t *end_month,
|
||||||
|
uint8_t *end_day);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
bool datetime_dst_date_range_set(
|
||||||
|
uint8_t start_month, uint8_t start_day, uint8_t end_month, uint8_t end_day);
|
||||||
|
/* BACnet TimeSynchronization service handler API */
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void datetime_timesync(BACNET_DATE *bdate, BACNET_TIME *btime, bool utc);
|
void datetime_timesync(BACNET_DATE *bdate, BACNET_TIME *btime, bool utc);
|
||||||
|
/* Initialization for integration with a clock */
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void datetime_init(void);
|
void datetime_init(void);
|
||||||
|
|
||||||
|
|||||||
@@ -171,6 +171,7 @@ list(APPEND testdirs
|
|||||||
# basic/sys
|
# basic/sys
|
||||||
bacnet/basic/sys/color_rgb
|
bacnet/basic/sys/color_rgb
|
||||||
bacnet/basic/sys/days
|
bacnet/basic/sys/days
|
||||||
|
bacnet/basic/sys/dst
|
||||||
bacnet/basic/sys/lighting_command
|
bacnet/basic/sys/lighting_command
|
||||||
bacnet/basic/sys/fifo
|
bacnet/basic/sys/fifo
|
||||||
bacnet/basic/sys/filename
|
bacnet/basic/sys/filename
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
/* @file
|
/* @file
|
||||||
* @brief test BACnet integer encode/decode APIs
|
|
||||||
* @date June 2022
|
|
||||||
* @brief tests sRGB to and from from CIE xy and brightness API
|
* @brief tests sRGB to and from from CIE xy and brightness API
|
||||||
*
|
* @date June 2022
|
||||||
* @section LICENSE
|
* @author Steve Karg <Steve Karg <skarg@users.sourceforge.net>
|
||||||
* Copyright (c) 2022 Steve Karg <skarg@users.sourceforge.net>
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
*/
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2021 Steve Karg <skarg@users.sourceforge.net>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* @file
|
/* @file
|
||||||
* @brief test BACnet integer encode/decode APIs
|
* @brief tests day of year calculations API
|
||||||
|
* @date August 2021
|
||||||
|
* @author Steve Karg <Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <zephyr/ztest.h>
|
#include <zephyr/ztest.h>
|
||||||
#include <bacnet/basic/sys/days.h>
|
#include <bacnet/basic/sys/days.h>
|
||||||
|
|
||||||
|
/* define our epic beginnings */
|
||||||
|
#define BACNET_EPOCH_YEAR 1900
|
||||||
|
/* 1/1/1900 is a Monday */
|
||||||
|
/* Monday=1..Sunday=7 */
|
||||||
|
#define BACNET_EPOCH_DOW 1
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup bacnet_tests
|
* @addtogroup bacnet_tests
|
||||||
* @{
|
* @{
|
||||||
@@ -31,9 +33,43 @@ static void test_epoch_conversion_date(
|
|||||||
days = days_since_epoch(epoch_year, year, month, day);
|
days = days_since_epoch(epoch_year, year, month, day);
|
||||||
days_since_epoch_to_date(
|
days_since_epoch_to_date(
|
||||||
epoch_year, days, &test_year, &test_month, &test_day);
|
epoch_year, days, &test_year, &test_month, &test_day);
|
||||||
zassert_equal(year, test_year, NULL);
|
zassert_equal(
|
||||||
zassert_equal(month, test_month, NULL);
|
year, test_year, "date=%u/%u/%u year=%u test_year=%u", year, month, day,
|
||||||
zassert_equal(day, test_day, NULL);
|
year, test_year);
|
||||||
|
zassert_equal(
|
||||||
|
month, test_month, "date=%u/%u/%u month=%u test_month=%u", year, month,
|
||||||
|
day, month, test_month);
|
||||||
|
zassert_equal(
|
||||||
|
day, test_day, "date=%u/%u/%u day=%u test_day=%u", year, month, day,
|
||||||
|
day, test_day);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit Test for the day of week based on epoch year and epoch day of week
|
||||||
|
* @param epoch_year - years after Christ birth (0..9999 AD)
|
||||||
|
* @param epoch_dow - day of week (1=Monday...7=Sunday)
|
||||||
|
* @param year - years after Christ birth (0..9999 AD)
|
||||||
|
* @param month - months (1=Jan...12=Dec)
|
||||||
|
* @param day - day of month (1-31)
|
||||||
|
* @param dow - day of week (1=Monday...7=Sunday)
|
||||||
|
*/
|
||||||
|
static void test_epoch_conversion_day(
|
||||||
|
uint16_t epoch_year,
|
||||||
|
uint8_t epoch_dow,
|
||||||
|
uint16_t year,
|
||||||
|
uint8_t month,
|
||||||
|
uint8_t day,
|
||||||
|
uint8_t dow)
|
||||||
|
{
|
||||||
|
uint32_t days;
|
||||||
|
uint16_t test_dow;
|
||||||
|
|
||||||
|
/* conversions of day and date */
|
||||||
|
days = days_since_epoch(epoch_year, year, month, day);
|
||||||
|
test_dow = days_of_week(epoch_dow, days);
|
||||||
|
zassert_equal(
|
||||||
|
dow, test_dow, "date=%u/%u/%u dow=%u test_dow=%u", year, month, day,
|
||||||
|
dow, test_dow);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,13 +81,28 @@ ZTEST(days_tests, test_days_epoch_conversion)
|
|||||||
static void test_days_epoch_conversion(void)
|
static void test_days_epoch_conversion(void)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
const uint16_t epoch_year = 2000;
|
const uint16_t epoch_year = BACNET_EPOCH_YEAR;
|
||||||
|
const uint8_t epoch_day_of_week = BACNET_EPOCH_DOW;
|
||||||
|
|
||||||
test_epoch_conversion_date(epoch_year, 2000, 1, 1);
|
test_epoch_conversion_date(epoch_year, 2000, 1, 1);
|
||||||
test_epoch_conversion_date(epoch_year, 2048, 2, 28);
|
test_epoch_conversion_date(epoch_year, 2048, 2, 28);
|
||||||
test_epoch_conversion_date(epoch_year, 2048, 2, 29);
|
test_epoch_conversion_date(epoch_year, 2048, 2, 29);
|
||||||
test_epoch_conversion_date(epoch_year, 2038, 6, 15);
|
test_epoch_conversion_date(epoch_year, 2038, 6, 15);
|
||||||
test_epoch_conversion_date(epoch_year, 9999, 12, 31);
|
test_epoch_conversion_date(epoch_year, 9999, 12, 31);
|
||||||
|
|
||||||
|
test_epoch_conversion_day(
|
||||||
|
epoch_year, epoch_day_of_week, epoch_year, 1, 1, epoch_day_of_week);
|
||||||
|
/* some known day of week (1=Monday...7=Sunday) */
|
||||||
|
test_epoch_conversion_day(epoch_year, epoch_day_of_week, 2003, 1, 6, 1);
|
||||||
|
test_epoch_conversion_day(epoch_year, epoch_day_of_week, 2003, 1, 7, 2);
|
||||||
|
test_epoch_conversion_day(epoch_year, epoch_day_of_week, 2003, 1, 8, 3);
|
||||||
|
test_epoch_conversion_day(epoch_year, epoch_day_of_week, 2003, 1, 9, 4);
|
||||||
|
test_epoch_conversion_day(epoch_year, epoch_day_of_week, 2003, 1, 10, 5);
|
||||||
|
test_epoch_conversion_day(epoch_year, epoch_day_of_week, 2003, 1, 11, 6);
|
||||||
|
test_epoch_conversion_day(epoch_year, epoch_day_of_week, 2003, 1, 12, 7);
|
||||||
|
test_epoch_conversion_day(epoch_year, epoch_day_of_week, 2003, 1, 13, 1);
|
||||||
|
/* 50th wedding anniversary */
|
||||||
|
test_epoch_conversion_day(epoch_year, epoch_day_of_week, 2043, 6, 26, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -134,6 +185,42 @@ static void test_days_date_is_valid(void)
|
|||||||
zassert_equal(days_per_month(0, 0), 0, NULL);
|
zassert_equal(days_per_month(0, 0), 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit Test for the days, checking the date to see if it is a valid date
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_ZTEST_NEW_API)
|
||||||
|
ZTEST(days_tests, test_days_since_epoch)
|
||||||
|
#else
|
||||||
|
static void test_days_since_epoch(void)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
uint32_t days = 0;
|
||||||
|
uint16_t year = 0, test_year = 0;
|
||||||
|
uint8_t month = 0, test_month = 0;
|
||||||
|
uint8_t day = 0, test_day = 0;
|
||||||
|
|
||||||
|
days = days_since_epoch(BACNET_EPOCH_YEAR, BACNET_EPOCH_YEAR, 1, 1);
|
||||||
|
zassert_equal(days, 0, "days=%lu", (unsigned long)days);
|
||||||
|
days_since_epoch_to_date(BACNET_EPOCH_YEAR, days, &year, &month, &day);
|
||||||
|
zassert_equal(year, BACNET_EPOCH_YEAR, NULL);
|
||||||
|
zassert_equal(month, 1, NULL);
|
||||||
|
zassert_equal(day, 1, NULL);
|
||||||
|
|
||||||
|
for (year = BACNET_EPOCH_YEAR; year < (BACNET_EPOCH_YEAR + 0xFF); year++) {
|
||||||
|
for (month = 1; month <= 12; month++) {
|
||||||
|
for (day = 1; day <= days_per_month(year, month); day++) {
|
||||||
|
days = days_since_epoch(BACNET_EPOCH_YEAR, year, month, day);
|
||||||
|
days_since_epoch_to_date(
|
||||||
|
BACNET_EPOCH_YEAR, days, &test_year, &test_month,
|
||||||
|
&test_day);
|
||||||
|
zassert_equal(year, test_year, NULL);
|
||||||
|
zassert_equal(month, test_month, NULL);
|
||||||
|
zassert_equal(day, test_day, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit Test for days apart, checking the dates to see how many days apart
|
* Unit Test for days apart, checking the dates to see how many days apart
|
||||||
*/
|
*/
|
||||||
@@ -162,6 +249,7 @@ void test_main(void)
|
|||||||
{
|
{
|
||||||
ztest_test_suite(
|
ztest_test_suite(
|
||||||
days_tests, ztest_unit_test(test_days_epoch_conversion),
|
days_tests, ztest_unit_test(test_days_epoch_conversion),
|
||||||
|
ztest_unit_test(test_days_since_epoch),
|
||||||
ztest_unit_test(test_days_of_year_to_md),
|
ztest_unit_test(test_days_of_year_to_md),
|
||||||
ztest_unit_test(test_days_date_is_valid),
|
ztest_unit_test(test_days_date_is_valid),
|
||||||
ztest_unit_test(test_days_apart));
|
ztest_unit_test(test_days_apart));
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# 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
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${SRC_DIR}
|
||||||
|
${TST_DIR}/ztest/include
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME}
|
||||||
|
# File(s) under test
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/dst.c
|
||||||
|
# Support files and stubs (pathname alphabetical)
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/days.c
|
||||||
|
# Test and test library files
|
||||||
|
./src/main.c
|
||||||
|
${ZTST_DIR}/ztest_mock.c
|
||||||
|
${ZTST_DIR}/ztest.c
|
||||||
|
)
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
/* @file
|
||||||
|
* @brief tests daylight savings time validity API
|
||||||
|
* @date August 2021
|
||||||
|
* @author Steve Karg <Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
#include <zephyr/ztest.h>
|
||||||
|
#include <bacnet/basic/sys/dst.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup bacnet_tests
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit Test for daylight savings time
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_ZTEST_NEW_API)
|
||||||
|
ZTEST(dst_tests, dst_test_valid)
|
||||||
|
#else
|
||||||
|
static void dst_test_valid(void)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
struct daylight_savings_data data = { 0 };
|
||||||
|
uint8_t epoch_day;
|
||||||
|
uint16_t epoch_year;
|
||||||
|
/* test at 3am */
|
||||||
|
uint8_t hour = 3;
|
||||||
|
uint8_t minute = 0;
|
||||||
|
uint8_t second = 0;
|
||||||
|
bool active;
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
struct dst_test_data {
|
||||||
|
uint16_t year;
|
||||||
|
uint8_t month;
|
||||||
|
uint8_t day;
|
||||||
|
bool active;
|
||||||
|
} test_ordinal_data[] = {
|
||||||
|
/* start date boundary checking for several years */
|
||||||
|
{ 2007, 3, 10, false },
|
||||||
|
{ 2007, 3, 11, true },
|
||||||
|
{ 2008, 3, 8, false },
|
||||||
|
{ 2008, 3, 9, true },
|
||||||
|
{ 2009, 3, 7, false },
|
||||||
|
{ 2009, 3, 8, true },
|
||||||
|
{ 2010, 3, 13, false },
|
||||||
|
{ 2010, 3, 14, true },
|
||||||
|
{ 2011, 3, 12, false },
|
||||||
|
{ 2011, 3, 13, true },
|
||||||
|
{ 2012, 3, 10, false },
|
||||||
|
{ 2012, 3, 11, true },
|
||||||
|
{ 2013, 3, 9, false },
|
||||||
|
{ 2013, 3, 10, true },
|
||||||
|
{ 2014, 3, 8, false },
|
||||||
|
{ 2014, 3, 9, true },
|
||||||
|
{ 2015, 3, 7, false },
|
||||||
|
{ 2015, 3, 8, true },
|
||||||
|
/* end date boundary checking for several years */
|
||||||
|
{ 2007, 11, 3, true },
|
||||||
|
{ 2007, 11, 4, false },
|
||||||
|
{ 2008, 11, 1, true },
|
||||||
|
{ 2008, 11, 2, false },
|
||||||
|
{ 2009, 10, 31, true },
|
||||||
|
{ 2009, 11, 1, false },
|
||||||
|
{ 2010, 11, 6, true },
|
||||||
|
{ 2010, 11, 7, false },
|
||||||
|
{ 2011, 11, 5, true },
|
||||||
|
{ 2011, 11, 6, false },
|
||||||
|
{ 2012, 11, 3, true },
|
||||||
|
{ 2012, 11, 4, false },
|
||||||
|
{ 2013, 11, 2, true },
|
||||||
|
{ 2013, 11, 3, false },
|
||||||
|
{ 2014, 11, 1, true },
|
||||||
|
{ 2014, 11, 2, false },
|
||||||
|
{ 2015, 10, 31, true },
|
||||||
|
{ 2015, 11, 1, false },
|
||||||
|
/* year long check boundaries over a year */
|
||||||
|
{ 2013, 1, 1, false },
|
||||||
|
{ 2013, 3, 3, false },
|
||||||
|
{ 2013, 3, 7, false },
|
||||||
|
{ 2013, 3, 8, false },
|
||||||
|
{ 2013, 3, 9, false },
|
||||||
|
{ 2013, 3, 10, true },
|
||||||
|
{ 2013, 3, 11, true },
|
||||||
|
{ 2013, 3, 12, true },
|
||||||
|
{ 2013, 7, 10, true },
|
||||||
|
{ 2013, 11, 2, true },
|
||||||
|
{ 2013, 11, 3, false },
|
||||||
|
{ 2013, 11, 4, false },
|
||||||
|
{ 2013, 11, 7, false },
|
||||||
|
{ 2013, 11, 8, false },
|
||||||
|
{ 2013, 11, 30, false },
|
||||||
|
{ 2013, 12, 31, false },
|
||||||
|
};
|
||||||
|
struct dst_test_data *td;
|
||||||
|
|
||||||
|
dst_init_defaults(&data);
|
||||||
|
for (i = 0; i < ARRAY_SIZE(test_ordinal_data); i++) {
|
||||||
|
td = &test_ordinal_data[i];
|
||||||
|
active = dst_active(
|
||||||
|
&data, td->year, td->month, td->day, hour, minute, second);
|
||||||
|
zassert_true(active == td->active, NULL);
|
||||||
|
}
|
||||||
|
/* test the fixed dates */
|
||||||
|
epoch_day = data.Epoch_Day;
|
||||||
|
epoch_year = data.Epoch_Year;
|
||||||
|
dst_init(&data, false, 4, 1, 0, 9, 30, 0, epoch_day, epoch_year);
|
||||||
|
/* check the boundaries */
|
||||||
|
active = dst_active(&data, 2013, 3, 31, hour, minute, second);
|
||||||
|
zassert_true(active == false, NULL);
|
||||||
|
active = dst_active(&data, 2013, 4, 1, hour, minute, second);
|
||||||
|
zassert_true(active == true, NULL);
|
||||||
|
active = dst_active(&data, 2013, 4, 2, hour, minute, second);
|
||||||
|
zassert_true(active == true, NULL);
|
||||||
|
active = dst_active(&data, 2013, 9, 29, hour, minute, second);
|
||||||
|
zassert_true(active == true, NULL);
|
||||||
|
active = dst_active(&data, 2013, 9, 30, hour, minute, second);
|
||||||
|
zassert_true(active == false, NULL);
|
||||||
|
active = dst_active(&data, 2013, 10, 1, hour, minute, second);
|
||||||
|
zassert_true(active == false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(CONFIG_ZTEST_NEW_API)
|
||||||
|
ZTEST_SUITE(dst_tests, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
#else
|
||||||
|
void test_main(void)
|
||||||
|
{
|
||||||
|
ztest_test_suite(dst_tests, ztest_unit_test(dst_test_valid));
|
||||||
|
|
||||||
|
ztest_run_test_suite(dst_tests);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -22,8 +22,6 @@
|
|||||||
|
|
||||||
/* define our epic beginnings */
|
/* define our epic beginnings */
|
||||||
#define BACNET_EPOCH_YEAR 1900
|
#define BACNET_EPOCH_YEAR 1900
|
||||||
/* 1/1/1900 is a Monday */
|
|
||||||
#define BACNET_EPOCH_DOW BACNET_WEEKDAY_MONDAY
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup bacnet_tests
|
* @addtogroup bacnet_tests
|
||||||
@@ -423,35 +421,6 @@ static void testDateEpochConversion(void)
|
|||||||
BACNET_EPOCH_YEAR + 0xFF - 1, 12, 31, 23, 59, 59, 0);
|
BACNET_EPOCH_YEAR + 0xFF - 1, 12, 31, 23, 59, 59, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void testDateEpoch(void)
|
|
||||||
{
|
|
||||||
uint32_t days = 0;
|
|
||||||
uint16_t year = 0, test_year = 0;
|
|
||||||
uint8_t month = 0, test_month = 0;
|
|
||||||
uint8_t day = 0, test_day = 0;
|
|
||||||
|
|
||||||
days = days_since_epoch(BACNET_EPOCH_YEAR, BACNET_EPOCH_YEAR, 1, 1);
|
|
||||||
zassert_equal(days, 1, "days=%lu", (unsigned long)days);
|
|
||||||
days_since_epoch_to_date(BACNET_EPOCH_YEAR, days, &year, &month, &day);
|
|
||||||
zassert_equal(year, BACNET_EPOCH_YEAR, NULL);
|
|
||||||
zassert_equal(month, 1, NULL);
|
|
||||||
zassert_equal(day, 1, NULL);
|
|
||||||
|
|
||||||
for (year = BACNET_EPOCH_YEAR; year < (BACNET_EPOCH_YEAR + 0xFF); year++) {
|
|
||||||
for (month = 1; month <= 12; month++) {
|
|
||||||
for (day = 1; day <= days_per_month(year, month); day++) {
|
|
||||||
days = days_since_epoch(BACNET_EPOCH_YEAR, year, month, day);
|
|
||||||
days_since_epoch_to_date(
|
|
||||||
BACNET_EPOCH_YEAR, days, &test_year, &test_month,
|
|
||||||
&test_day);
|
|
||||||
zassert_equal(year, test_year, NULL);
|
|
||||||
zassert_equal(month, test_month, NULL);
|
|
||||||
zassert_equal(day, test_day, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(CONFIG_ZTEST_NEW_API)
|
#if defined(CONFIG_ZTEST_NEW_API)
|
||||||
ZTEST(bacnet_datetime, testBACnetDayOfWeek)
|
ZTEST(bacnet_datetime, testBACnetDayOfWeek)
|
||||||
#else
|
#else
|
||||||
@@ -641,11 +610,6 @@ ZTEST_SUITE(bacnet_datetime, NULL, NULL, NULL, NULL, NULL);
|
|||||||
#else
|
#else
|
||||||
void test_main(void)
|
void test_main(void)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
ztest_unit_test(testDateEpoch),
|
|
||||||
ztest_unit_test(testBACnetDateTimeSeconds),
|
|
||||||
ztest_unit_test(testDayOfYear),
|
|
||||||
#endif
|
|
||||||
ztest_test_suite(
|
ztest_test_suite(
|
||||||
bacnet_datetime, ztest_unit_test(testBACnetDate),
|
bacnet_datetime, ztest_unit_test(testBACnetDate),
|
||||||
ztest_unit_test(testBACnetTime), ztest_unit_test(testBACnetDateTime),
|
ztest_unit_test(testBACnetTime), ztest_unit_test(testBACnetDateTime),
|
||||||
@@ -654,7 +618,7 @@ void test_main(void)
|
|||||||
ztest_unit_test(testBACnetDateTimeAdd),
|
ztest_unit_test(testBACnetDateTimeAdd),
|
||||||
ztest_unit_test(testBACnetDateTimeWildcard),
|
ztest_unit_test(testBACnetDateTimeWildcard),
|
||||||
ztest_unit_test(testDatetimeCodec),
|
ztest_unit_test(testDatetimeCodec),
|
||||||
ztest_unit_test(testWildcardDateTime), ztest_unit_test(testDateEpoch),
|
ztest_unit_test(testWildcardDateTime),
|
||||||
ztest_unit_test(testBACnetDateTimeSeconds),
|
ztest_unit_test(testBACnetDateTimeSeconds),
|
||||||
ztest_unit_test(testDayOfYear),
|
ztest_unit_test(testDayOfYear),
|
||||||
ztest_unit_test(testDatetimeConvertUTC));
|
ztest_unit_test(testDatetimeConvertUTC));
|
||||||
|
|||||||
Reference in New Issue
Block a user