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:
Steve Karg
2024-11-24 11:20:25 -06:00
committed by GitHub
parent cdda524afc
commit fd3be47d86
19 changed files with 992 additions and 93 deletions
+5
View File
@@ -170,6 +170,7 @@ set(BACNET_PROJECT_SOURCE
${LIBRARY_BACNET_BASIC}/service/h_rd.c
${LIBRARY_BACNET_BASIC}/service/h_rp.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_whois.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}/tsm/tsm.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/fifo.c
${LIBRARY_BACNET_BASIC}/sys/keylist.c
@@ -214,6 +218,7 @@ set(BACNET_PROJECT_SOURCE
${LIBRARY_BACNET_CORE}/rp.c
${LIBRARY_BACNET_CORE}/rpm.c
${LIBRARY_BACNET_CORE}/timestamp.c
${LIBRARY_BACNET_CORE}/timesync.c
${LIBRARY_BACNET_CORE}/weeklyschedule.c
${LIBRARY_BACNET_CORE}/dailyschedule.c
${LIBRARY_BACNET_CORE}/calendar_entry.c
+10 -5
View File
@@ -3,15 +3,15 @@
#+-------------------------------------------------------------------------------------------------+
TARGET=bacnet
BACNET_DIR = ../..
BACNET_DIR = $(realpath ../..)
BACNET_SRC := $(BACNET_DIR)/src
BACNET_CORE := $(BACNET_SRC)/bacnet
BACNET_BASIC := $(BACNET_CORE)/basic
BACNET_INCLUDE := $(BACNET_SRC)
PLATFORM_DIR = .
LIBRARY_STM32 = ./external/STM32F4xx_StdPeriph_Driver/src
LIBRARY_STM32_INCLUDES = ./external/STM32F4xx_StdPeriph_Driver/inc
LIBRARY_CMSIS = ./external/CMSIS
PLATFORM_DIR = $(realpath .)
LIBRARY_STM32 = $(realpath ./external/STM32F4xx_StdPeriph_Driver/src)
LIBRARY_STM32_INCLUDES = $(realpath ./external/STM32F4xx_StdPeriph_Driver/inc)
LIBRARY_CMSIS = $(realpath ./external/CMSIS)
CSTACK_TOOL := $(BACNET_DIR)/tools/avstack/avstack.pl
MEMAP_TOOL := $(BACNET_DIR)/tools/memap/memap.py
@@ -48,6 +48,7 @@ BASIC_SRC = \
$(BACNET_BASIC)/service/h_rd.c \
$(BACNET_BASIC)/service/h_rp.c \
$(BACNET_BASIC)/service/h_rpm.c \
$(BACNET_BASIC)/service/h_ts.c \
$(BACNET_BASIC)/service/h_whohas.c \
$(BACNET_BASIC)/service/h_whois.c \
$(BACNET_BASIC)/service/h_wp.c \
@@ -55,6 +56,9 @@ BASIC_SRC = \
$(BACNET_BASIC)/service/s_iam.c \
$(BACNET_BASIC)/service/s_ihave.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/fifo.c \
$(BACNET_BASIC)/sys/keylist.c \
@@ -92,6 +96,7 @@ BACNET_SRC = \
$(BACNET_CORE)/rpm.c \
$(BACNET_CORE)/special_event.c \
$(BACNET_CORE)/timestamp.c \
$(BACNET_CORE)/timesync.c \
$(BACNET_CORE)/weeklyschedule.c \
$(BACNET_CORE)/whohas.c \
$(BACNET_CORE)/whois.c \
+7 -1
View File
@@ -14,8 +14,8 @@
#include "bacnet/datalink/datalink.h"
#include "bacnet/npdu.h"
#include "bacnet/basic/services.h"
#include "bacnet/basic/services.h"
#include "bacnet/basic/tsm/tsm.h"
#include "bacnet/datetime.h"
#include "bacnet/dcc.h"
#include "bacnet/iam.h"
/* BACnet objects */
@@ -116,6 +116,12 @@ void bacnet_init(void)
SERVICE_CONFIRMED_REINITIALIZE_DEVICE, handler_reinitialize_device);
apdu_set_confirmed_handler(
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 */
apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
handler_device_communication_control);
+76 -8
View File
@@ -18,6 +18,7 @@
#include "bacnet/bacstr.h"
#include "bacnet/bacenum.h"
#include "bacnet/apdu.h"
#include "bacnet/datetime.h"
#include "bacnet/dcc.h"
#include "bacnet/datalink/datalink.h"
#include "bacnet/version.h"
@@ -49,11 +50,12 @@ static struct my_object_functions {
read_property_function Object_Read_Property;
write_property_function Object_Write_Property;
rpm_property_lists_function Object_RPM_List;
} Object_Table[] = { { OBJECT_DEVICE, NULL, /* don't init - recursive! */
Device_Count, Device_Index_To_Instance,
Device_Valid_Object_Instance_Number,
Device_Object_Name, Device_Read_Property_Local,
Device_Write_Property_Local, Device_Property_Lists },
} Object_Table[] = { { OBJECT_DEVICE, NULL,
/* don't init - recursive! */
Device_Count, Device_Index_To_Instance,
Device_Valid_Object_Instance_Number,
Device_Object_Name, Device_Read_Property_Local,
Device_Write_Property_Local, Device_Property_Lists },
{ OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count,
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance,
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];
/* 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_VENDOR_IDENTIFIER, PROP_MODEL_NAME, PROP_FIRMWARE_REVISION,
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_DATABASE_REVISION, -1 };
static const int Device_Properties_Optional[] = { PROP_DESCRIPTION,
PROP_LOCATION, PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, PROP_DEVICE_UUID,
static const int Device_Properties_Optional[] = {
/* 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 };
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_CHARACTER_STRING char_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 count = 0;
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));
apdu_len = encode_application_octet_string(&apdu[0], &octet_string);
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:
rpdata->error_class = ERROR_CLASS_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;
}
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_VENDOR_NAME:
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_ACTIVE_COV_SUBSCRIPTIONS:
case PROP_DATABASE_REVISION:
case PROP_DAYLIGHT_SAVINGS_STATUS:
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;