diff --git a/apps/server/main.c b/apps/server/main.c index 42e091a5..f76c43ef 100644 --- a/apps/server/main.c +++ b/apps/server/main.c @@ -47,6 +47,7 @@ #include "bacnet/basic/tsm/tsm.h" #include "bacnet/datalink/datalink.h" #include "bacnet/datalink/dlenv.h" +#include "bacnet/datetime.h" /* include the device object */ #include "bacnet/basic/object/device.h" /* objects that have tasks inside them */ @@ -369,6 +370,9 @@ int main(int argc, char *argv[]) in our device bindings list */ address_init(); Init_Service_Handlers(); + /* initialize timesync callback function. */ + handler_timesync_set_callback_set(&datetime_timesync); + #if defined(BAC_UCI) const char *uciname; ctx = ucix_init("bacnet_dev"); diff --git a/ports/bsd/datetime-init.c b/ports/bsd/datetime-init.c index 05a6e067..ec2e0aa3 100644 --- a/ports/bsd/datetime-init.c +++ b/ports/bsd/datetime-init.c @@ -15,9 +15,24 @@ #include #include #include +#include "bacnet/basic/service/h_ts.h" #include "bacport.h" #include "bacnet/datetime.h" + +/** + * @brief Set offset from the system clock. + * @param bdate BACnet Date structure to hold local time + * @param btime BACnet Time structure to hold local time + * @param utc - True for UTC sync, False for Local time + * @return True if time is set + */ +void datetime_timesync( + BACNET_DATE *bdate, BACNET_TIME *btime, bool utc) +{ + return; +} + /** * @brief Get the date, time, timezone, and UTC offset from system * @param utc_time - the BACnet Date and Time structure to hold UTC time diff --git a/ports/linux/datetime-init.c b/ports/linux/datetime-init.c index 705302a8..b32a1e75 100644 --- a/ports/linux/datetime-init.c +++ b/ports/linux/datetime-init.c @@ -15,9 +15,54 @@ #include #include #include +#include "bacnet/basic/service/h_ts.h" #include "bacport.h" #include "bacnet/datetime.h" + +static int32_t timedifference(struct timeval t0, struct timeval t1) +{ + return (t0.tv_sec - t1.tv_sec)*1000 + (t0.tv_usec - t1.tv_usec) / 1000; +} + +/** + * @brief Set offset from the system clock. + * @param bdate BACnet Date structure to hold local time + * @param btime BACnet Time structure to hold local time + * @param utc - True for UTC sync, False for Local time + * @return True if time is set + */ +void datetime_timesync( + BACNET_DATE *bdate, BACNET_TIME *btime, bool utc) +{ + struct timeval tv_inp, tv_sys; + struct tm *timeinfo; + time_t rawtime; + time( &rawtime); + timeinfo = localtime(&rawtime); + /* fixme: only set the time if off by some amount */ + timeinfo->tm_year = bdate->year-1900; + timeinfo->tm_mon = bdate->month-1; + timeinfo->tm_mday = bdate->day; + timeinfo->tm_hour = btime->hour; + timeinfo->tm_min = btime->min; + timeinfo->tm_sec = btime->sec; + tv_inp.tv_sec = mktime(timeinfo); + tv_inp.tv_usec = btime->hundredths*10000; + if (gettimeofday(&tv_sys, NULL) == 0) { + if (utc) { + handler_timesync_offset_set(timedifference(tv_inp, tv_sys) - (timezone - timeinfo->tm_isdst*3600)*1000); + + } else { + handler_timesync_offset_set(timedifference(tv_inp, tv_sys)); + } +#if PRINT_ENABLED + printf("Time offset = %d\n",handler_timesync_offset()); +#endif + } + return; +} + /** * @brief Get the date, time, timezone, and UTC offset from system * @param utc_time - the BACnet Date and Time structure to hold UTC time @@ -35,8 +80,12 @@ bool datetime_local(BACNET_DATE *bdate, bool status = false; struct tm *tblock = NULL; struct timeval tv; + int32_t to; if (gettimeofday(&tv, NULL) == 0) { + to = handler_timesync_offset(); + tv.tv_sec += (int) to/1000; + tv.tv_usec += (to%1000)*1000; tblock = (struct tm *)localtime((const time_t *)&tv.tv_sec); } if (tblock) { diff --git a/ports/win32/datetime-init.c b/ports/win32/datetime-init.c index 554f7f80..eeb418b4 100644 --- a/ports/win32/datetime-init.c +++ b/ports/win32/datetime-init.c @@ -94,6 +94,19 @@ int gettimeofday(struct timeval *tp, void *tzp) } #endif +/** + * @brief Set offset from the system clock. + * @param bdate BACnet Date structure to hold local time + * @param btime BACnet Time structure to hold local time + * @param utc - True for UTC sync, False for Local time + * @return True if time is set + */ +void datetime_timesync( + BACNET_DATE *bdate, BACNET_TIME *btime, bool utc) +{ + return; +} + /** * @brief Get the date, time, timezone, and UTC offset from system * @param utc_time - the BACnet Date and Time structure to hold UTC time diff --git a/src/bacnet/basic/service/h_ts.c b/src/bacnet/basic/service/h_ts.c index b945daf0..829c11cc 100644 --- a/src/bacnet/basic/service/h_ts.c +++ b/src/bacnet/basic/service/h_ts.c @@ -66,6 +66,21 @@ static void show_bacnet_date_time(BACNET_DATE *bdate, BACNET_TIME *btime) } #endif +/* Callback for timesync set */ +static handler_timesync_set_callback_t handler_timesync_set_callback; + +static int32_t Time_Offset; /* Time offset in ms */ + +int32_t handler_timesync_offset(void) +{ + return Time_Offset; +} + +void handler_timesync_offset_set(int32_t offset) +{ + Time_Offset = offset; +} + void handler_timesync( uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS *src) { @@ -80,12 +95,12 @@ void handler_timesync( if (len > 0) { if (datetime_is_valid(&bdate, &btime)) { /* fixme: only set the time if off by some amount */ + if (handler_timesync_set_callback) { + handler_timesync_set_callback(&bdate, &btime, false); + } #if PRINT_ENABLED - fprintf(stderr, "Received TimeSyncronization Request\r\n"); + fprintf(stderr, "Received Local TimeSyncronization Request\r\n"); show_bacnet_date_time(&bdate, &btime); -#else - /* FIXME: set the time? - Maybe only set the time if off by some amount */ #endif } } @@ -106,12 +121,13 @@ void handler_timesync_utc( service_request, service_len, &bdate, &btime); if (len > 0) { if (datetime_is_valid(&bdate, &btime)) { + if (handler_timesync_set_callback) { + handler_timesync_set_callback(&bdate, &btime, true); + } #if PRINT_ENABLED - fprintf(stderr, "Received TimeSyncronization Request\r\n"); + fprintf(stderr, "Received UTC TimeSyncronization Request\r\n"); show_bacnet_date_time(&bdate, &btime); #endif - /* FIXME: set the time? - only set the time if off by some amount */ } } @@ -276,3 +292,14 @@ void handler_timesync_init(void) } } #endif + +/** + * Configures and enables a timesync callback function + * + * @param cb - pointer to #handler_timesync_set_callback_t + */ +void handler_timesync_set_callback_set( + handler_timesync_set_callback_t cb) +{ + handler_timesync_set_callback = cb; +} diff --git a/src/bacnet/basic/service/h_ts.h b/src/bacnet/basic/service/h_ts.h index f11b1dd3..e3dae561 100644 --- a/src/bacnet/basic/service/h_ts.h +++ b/src/bacnet/basic/service/h_ts.h @@ -39,10 +39,19 @@ #include "bacnet/datetime.h" #include "bacnet/wp.h" +typedef void (*handler_timesync_set_callback_t)( + BACNET_DATE *bdate, + BACNET_TIME *btime, + bool utc); + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ + BACNET_STACK_EXPORT + int32_t handler_timesync_offset(void); + BACNET_STACK_EXPORT + void handler_timesync_offset_set(int32_t offset); /* time synchronization handlers */ BACNET_STACK_EXPORT void handler_timesync( @@ -81,7 +90,9 @@ extern "C" { bool handler_timesync_recipient_address_set( unsigned index, BACNET_ADDRESS * address); - + BACNET_STACK_EXPORT + void handler_timesync_set_callback_set( + handler_timesync_set_callback_t cb); #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/bacnet/datetime.h b/src/bacnet/datetime.h index 77ccc64a..29dd8bd6 100644 --- a/src/bacnet/datetime.h +++ b/src/bacnet/datetime.h @@ -304,6 +304,11 @@ bool datetime_local(BACNET_DATE *bdate, BACNET_TIME *btime, int16_t *utc_offset_minutes, bool *dst_active); + +BACNET_STACK_EXPORT +void datetime_timesync( + BACNET_DATE *bdate, BACNET_TIME *btime, bool utc); + BACNET_STACK_EXPORT void datetime_init(void);