From 8f20cdc353a9d1c1e5d43484b58e1eaf81ec52e0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 14 Sep 2020 12:15:03 +1000 Subject: [PATCH] all: Rename absolute time-based functions to include "epoch". For time-based functions that work with absolute time there is the need for an Epoch, to set the zero-point at which the absolute time starts counting. Such functions include time.time() and filesystem stat return values. And different ports may use a different Epoch. To make it clearer what functions use the Epoch (whatever it may be), and make the ports more consistent with their use of the Epoch, this commit renames all Epoch related functions to include the word "epoch" in their name (and remove references to "2000"). Along with this rename, the following things have changed: - mp_hal_time_ns() is now specified to return the number of nanoseconds since the Epoch, rather than since 1970 (but since this is an internal function it doesn't change anything for the user). - littlefs timestamps on the esp8266 have been fixed (they were previously off by 30 years in nanoseconds). Otherwise, there is no functional change made by this commit. Signed-off-by: Damien George --- extmod/vfs_fat.c | 5 +---- extmod/vfs_lfs.c | 4 +++- extmod/vfs_lfsx.c | 6 ++---- lib/timeutils/timeutils.h | 43 +++++++++++++++++++++++++++---------- ports/esp32/fatfs_port.c | 2 +- ports/esp32/machine_rtc.c | 4 ++-- ports/esp32/modutime.c | 2 +- ports/esp32/mphalport.c | 3 +-- ports/esp8266/esp_mphal.c | 2 +- ports/esp8266/fatfs_port.c | 4 ++-- ports/esp8266/machine_rtc.c | 18 ++++++++-------- ports/esp8266/modmachine.c | 2 +- ports/esp8266/modmachine.h | 4 ++-- ports/esp8266/modutime.c | 8 +++---- ports/stm32/modutime.c | 4 ++-- ports/stm32/rtc.c | 4 ++-- py/mphal.h | 2 +- 17 files changed, 67 insertions(+), 50 deletions(-) diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index ace5ba5b65..95b7ad9944 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -311,7 +311,7 @@ STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { } else { mode |= MP_S_IFREG; } - mp_int_t seconds = timeutils_seconds_since_2000( + mp_int_t seconds = timeutils_seconds_since_epoch( 1980 + ((fno.fdate >> 9) & 0x7f), (fno.fdate >> 5) & 0x0f, fno.fdate & 0x1f, @@ -319,9 +319,6 @@ STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { (fno.ftime >> 5) & 0x3f, 2 * (fno.ftime & 0x1f) ); - #if MICROPY_EPOCH_IS_1970 - seconds += TIMEUTILS_SECONDS_1970_TO_2000; - #endif t->items[0] = MP_OBJ_NEW_SMALL_INT(mode); // st_mode t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev diff --git a/extmod/vfs_lfs.c b/extmod/vfs_lfs.c index a53f66f2d6..9cf3eb1108 100644 --- a/extmod/vfs_lfs.c +++ b/extmod/vfs_lfs.c @@ -26,6 +26,7 @@ #include "py/runtime.h" #include "py/mphal.h" +#include "lib/timeutils/timeutils.h" #include "extmod/vfs.h" #include "extmod/vfs_lfs.h" @@ -126,7 +127,8 @@ const char *mp_vfs_lfs2_make_path(mp_obj_vfs_lfs2_t *self, mp_obj_t path_in); mp_obj_t mp_vfs_lfs2_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in); STATIC void lfs_get_mtime(uint8_t buf[8]) { - uint64_t ns = mp_hal_time_ns(); + // On-disk storage of timestamps uses 1970 as the Epoch, so convert from host's Epoch. + uint64_t ns = timeutils_nanoseconds_since_epoch_to_nanoseconds_since_1970(mp_hal_time_ns()); // Store "ns" to "buf" in little-endian format (essentially htole64). for (size_t i = 0; i < 8; ++i) { buf[i] = ns; diff --git a/extmod/vfs_lfsx.c b/extmod/vfs_lfsx.c index d00df53104..35d5f03c59 100644 --- a/extmod/vfs_lfsx.c +++ b/extmod/vfs_lfsx.c @@ -365,10 +365,8 @@ STATIC mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) { for (size_t i = sizeof(mtime_buf); i > 0; --i) { ns = ns << 8 | mtime_buf[i - 1]; } - mtime = timeutils_seconds_since_2000_from_nanoseconds_since_1970(ns); - #if MICROPY_EPOCH_IS_1970 - mtime += TIMEUTILS_SECONDS_1970_TO_2000; - #endif + // On-disk storage of timestamps uses 1970 as the Epoch, so convert to host's Epoch. + mtime = timeutils_seconds_since_epoch_from_nanoseconds_since_1970(ns); } #endif diff --git a/lib/timeutils/timeutils.h b/lib/timeutils/timeutils.h index 08b0dc2e85..14da831dc8 100644 --- a/lib/timeutils/timeutils.h +++ b/lib/timeutils/timeutils.h @@ -42,14 +42,6 @@ typedef struct _timeutils_struct_time_t { uint16_t tm_yday; // 1..366 } timeutils_struct_time_t; -static inline uint64_t timeutils_seconds_since_2000_to_nanoseconds_since_1970(mp_uint_t s) { - return ((uint64_t)s + TIMEUTILS_SECONDS_1970_TO_2000) * 1000000000ULL; -} - -static inline mp_uint_t timeutils_seconds_since_2000_from_nanoseconds_since_1970(uint64_t ns) { - return ns / 1000000000ULL - TIMEUTILS_SECONDS_1970_TO_2000; -} - bool timeutils_is_leap_year(mp_uint_t year); mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month); mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date); @@ -63,10 +55,39 @@ mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, mp_int_t hours, mp_int_t minutes, mp_int_t seconds); -static inline uint64_t timeutils_nanoseconds_since_1970(mp_uint_t year, mp_uint_t month, +// Select the Epoch used by the port. +#if MICROPY_EPOCH_IS_1970 + +static inline uint64_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { - return timeutils_seconds_since_2000_to_nanoseconds_since_1970( - timeutils_seconds_since_2000(year, month, date, hour, minute, second)); + return timeutils_seconds_since_2000(year, month, date, hour, minute, second) + TIMEUTILS_SECONDS_1970_TO_2000; } +static inline mp_uint_t timeutils_seconds_since_epoch_from_nanoseconds_since_1970(uint64_t ns) { + return ns / 1000000000ULL; +} + +static inline uint64_t timeutils_nanoseconds_since_epoch_to_nanoseconds_since_1970(uint64_t ns) { + return ns; +} + +#else // Epoch is 2000 + +#define timeutils_seconds_since_epoch_to_struct_time timeutils_seconds_since_2000_to_struct_time +#define timeutils_seconds_since_epoch timeutils_seconds_since_2000 + +static inline uint64_t timeutils_seconds_since_epoch_to_nanoseconds_since_1970(mp_uint_t s) { + return ((uint64_t)s + TIMEUTILS_SECONDS_1970_TO_2000) * 1000000000ULL; +} + +static inline mp_uint_t timeutils_seconds_since_epoch_from_nanoseconds_since_1970(uint64_t ns) { + return ns / 1000000000ULL - TIMEUTILS_SECONDS_1970_TO_2000; +} + +static inline int64_t timeutils_nanoseconds_since_epoch_to_nanoseconds_since_1970(int64_t ns) { + return ns + TIMEUTILS_SECONDS_1970_TO_2000 * 1000000000ULL; +} + +#endif + #endif // MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H diff --git a/ports/esp32/fatfs_port.c b/ports/esp32/fatfs_port.c index 779ba1c88a..cfc52853d0 100644 --- a/ports/esp32/fatfs_port.c +++ b/ports/esp32/fatfs_port.c @@ -34,7 +34,7 @@ DWORD get_fattime(void) { struct timeval tv; gettimeofday(&tv, NULL); timeutils_struct_time_t tm; - timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm); + timeutils_seconds_since_epoch_to_struct_time(tv.tv_sec, &tm); return ((DWORD)(tm.tm_year - 1980) << 25) | ((DWORD)tm.tm_mon << 21) | ((DWORD)tm.tm_mday << 16) | ((DWORD)tm.tm_hour << 11) | ((DWORD)tm.tm_min << 5) | ((DWORD)tm.tm_sec >> 1); diff --git a/ports/esp32/machine_rtc.c b/ports/esp32/machine_rtc.c index c776eaa8d3..6902ce85fd 100644 --- a/ports/esp32/machine_rtc.c +++ b/ports/esp32/machine_rtc.c @@ -93,7 +93,7 @@ STATIC mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *ar gettimeofday(&tv, NULL); timeutils_struct_time_t tm; - timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm); + timeutils_seconds_since_epoch_to_struct_time(tv.tv_sec, &tm); mp_obj_t tuple[8] = { mp_obj_new_int(tm.tm_year), @@ -114,7 +114,7 @@ STATIC mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *ar mp_obj_get_array_fixed_n(args[1], 8, &items); struct timeval tv = {0}; - tv.tv_sec = timeutils_seconds_since_2000(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), mp_obj_get_int(items[4]), mp_obj_get_int(items[5]), mp_obj_get_int(items[6])); + tv.tv_sec = timeutils_seconds_since_epoch(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), mp_obj_get_int(items[4]), mp_obj_get_int(items[5]), mp_obj_get_int(items[6])); tv.tv_usec = mp_obj_get_int(items[7]); settimeofday(&tv, NULL); diff --git a/ports/esp32/modutime.c b/ports/esp32/modutime.c index 1f93ce6c30..ac3edb4e9b 100644 --- a/ports/esp32/modutime.c +++ b/ports/esp32/modutime.c @@ -44,7 +44,7 @@ STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { } else { seconds = mp_obj_get_int(args[0]); } - timeutils_seconds_since_2000_to_struct_time(seconds, &tm); + timeutils_seconds_since_epoch_to_struct_time(seconds, &tm); mp_obj_t tuple[8] = { tuple[0] = mp_obj_new_int(tm.tm_year), tuple[1] = mp_obj_new_int(tm.tm_mon), diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index 3a46edf1f7..ad571bf961 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -200,8 +200,7 @@ void mp_hal_delay_us(uint32_t us) { uint64_t mp_hal_time_ns(void) { struct timeval tv; gettimeofday(&tv, NULL); - // gettimeofday returns seconds since 2000/1/1 - uint64_t ns = timeutils_seconds_since_2000_to_nanoseconds_since_1970(tv.tv_sec); + uint64_t ns = tv.tv_sec * 1000000000ULL; ns += (uint64_t)tv.tv_usec * 1000ULL; return ns; } diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c index 9e1b72e438..54f9611e56 100644 --- a/ports/esp8266/esp_mphal.c +++ b/ports/esp8266/esp_mphal.c @@ -139,7 +139,7 @@ void MP_FASTCODE(mp_hal_delay_ms)(uint32_t delay) { } uint64_t mp_hal_time_ns(void) { - return pyb_rtc_get_us_since_2000() * 1000ULL; + return pyb_rtc_get_us_since_epoch() * 1000ULL; } void ets_event_poll(void) { diff --git a/ports/esp8266/fatfs_port.c b/ports/esp8266/fatfs_port.c index 8cef0acec3..bbd1051935 100644 --- a/ports/esp8266/fatfs_port.c +++ b/ports/esp8266/fatfs_port.c @@ -33,10 +33,10 @@ DWORD get_fattime(void) { // TODO: Optimize division (there's no HW division support on ESP8266, // so it's expensive). - uint32_t secs = (uint32_t)(pyb_rtc_get_us_since_2000() / 1000000); + uint32_t secs = (uint32_t)(pyb_rtc_get_us_since_epoch() / 1000000); timeutils_struct_time_t tm; - timeutils_seconds_since_2000_to_struct_time(secs, &tm); + timeutils_seconds_since_epoch_to_struct_time(secs, &tm); return ((DWORD)(tm.tm_year - 1980) << 25) | ((DWORD)tm.tm_mon << 21) | ((DWORD)tm.tm_mday << 16) | ((DWORD)tm.tm_hour << 11) | ((DWORD)tm.tm_min << 5) | ((DWORD)tm.tm_sec >> 1); diff --git a/ports/esp8266/machine_rtc.c b/ports/esp8266/machine_rtc.c index 1aa73f9b31..e7b750fd92 100644 --- a/ports/esp8266/machine_rtc.c +++ b/ports/esp8266/machine_rtc.c @@ -84,7 +84,7 @@ STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_ return (mp_obj_t)&pyb_rtc_obj; } -void pyb_rtc_set_us_since_2000(uint64_t nowus) { +void pyb_rtc_set_us_since_epoch(uint64_t nowus) { uint32_t cal = system_rtc_clock_cali_proc(); // Save RTC ticks for overflow detection. rtc_last_ticks = system_get_rtc_time(); @@ -96,7 +96,7 @@ void pyb_rtc_set_us_since_2000(uint64_t nowus) { system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); }; -uint64_t pyb_rtc_get_us_since_2000() { +uint64_t pyb_rtc_get_us_since_epoch() { uint32_t cal; int64_t delta; uint32_t rtc_ticks; @@ -120,17 +120,17 @@ uint64_t pyb_rtc_get_us_since_2000() { void rtc_prepare_deepsleep(uint64_t sleep_us) { // RTC time will reset at wake up. Let's be preared for this. - int64_t delta = pyb_rtc_get_us_since_2000() + sleep_us; + int64_t delta = pyb_rtc_get_us_since_epoch() + sleep_us; system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); } STATIC mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) { if (n_args == 1) { // Get time - uint64_t msecs = pyb_rtc_get_us_since_2000() / 1000; + uint64_t msecs = pyb_rtc_get_us_since_epoch() / 1000; timeutils_struct_time_t tm; - timeutils_seconds_since_2000_to_struct_time(msecs / 1000, &tm); + timeutils_seconds_since_epoch_to_struct_time(msecs / 1000, &tm); mp_obj_t tuple[8] = { mp_obj_new_int(tm.tm_year), @@ -149,8 +149,8 @@ STATIC mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) { mp_obj_t *items; mp_obj_get_array_fixed_n(args[1], 8, &items); - pyb_rtc_set_us_since_2000( - ((uint64_t)timeutils_seconds_since_2000( + pyb_rtc_set_us_since_epoch( + ((uint64_t)timeutils_seconds_since_epoch( mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), @@ -209,7 +209,7 @@ STATIC mp_obj_t pyb_rtc_alarm(mp_obj_t self_in, mp_obj_t alarm_id, mp_obj_t time } // set expiry time (in microseconds) - pyb_rtc_alarm0_expiry = pyb_rtc_get_us_since_2000() + (uint64_t)mp_obj_get_int(time_in) * 1000; + pyb_rtc_alarm0_expiry = pyb_rtc_get_us_since_epoch() + (uint64_t)mp_obj_get_int(time_in) * 1000; return mp_const_none; @@ -222,7 +222,7 @@ STATIC mp_obj_t pyb_rtc_alarm_left(size_t n_args, const mp_obj_t *args) { mp_raise_ValueError(MP_ERROR_TEXT("invalid alarm")); } - uint64_t now = pyb_rtc_get_us_since_2000(); + uint64_t now = pyb_rtc_get_us_since_epoch(); if (pyb_rtc_alarm0_expiry <= now) { return MP_OBJ_NEW_SMALL_INT(0); } else { diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index bc838b4206..cb28d5b144 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -132,7 +132,7 @@ STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *args) { // see if RTC.ALARM0 should wake the device if (pyb_rtc_alarm0_wake & MACHINE_WAKE_DEEPSLEEP) { - uint64_t t = pyb_rtc_get_us_since_2000(); + uint64_t t = pyb_rtc_get_us_since_epoch(); if (pyb_rtc_alarm0_expiry <= t) { sleep_us = 1; // alarm already expired so wake immediately } else { diff --git a/ports/esp8266/modmachine.h b/ports/esp8266/modmachine.h index f5cfc0fa2c..be4debd335 100644 --- a/ports/esp8266/modmachine.h +++ b/ports/esp8266/modmachine.h @@ -32,8 +32,8 @@ void pin_set(uint pin, int value); extern uint32_t pyb_rtc_alarm0_wake; extern uint64_t pyb_rtc_alarm0_expiry; -void pyb_rtc_set_us_since_2000(uint64_t nowus); -uint64_t pyb_rtc_get_us_since_2000(); +void pyb_rtc_set_us_since_epoch(uint64_t nowus); +uint64_t pyb_rtc_get_us_since_epoch(); void rtc_prepare_deepsleep(uint64_t sleep_us); #endif // MICROPY_INCLUDED_ESP8266_MODMACHINE_H diff --git a/ports/esp8266/modutime.c b/ports/esp8266/modutime.c index a951f8f8d2..86534722c7 100644 --- a/ports/esp8266/modutime.c +++ b/ports/esp8266/modutime.c @@ -58,11 +58,11 @@ STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { timeutils_struct_time_t tm; mp_int_t seconds; if (n_args == 0 || args[0] == mp_const_none) { - seconds = pyb_rtc_get_us_since_2000() / 1000 / 1000; + seconds = pyb_rtc_get_us_since_epoch() / 1000 / 1000; } else { seconds = mp_obj_get_int(args[0]); } - timeutils_seconds_since_2000_to_struct_time(seconds, &tm); + timeutils_seconds_since_epoch_to_struct_time(seconds, &tm); mp_obj_t tuple[8] = { tuple[0] = mp_obj_new_int(tm.tm_year), tuple[1] = mp_obj_new_int(tm.tm_mon), @@ -98,10 +98,10 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) { MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime); /// \function time() -/// Returns the number of seconds, as an integer, since 1/1/2000. +/// Returns the number of seconds, as an integer, since the Epoch. STATIC mp_obj_t time_time(void) { // get date and time - return mp_obj_new_int(pyb_rtc_get_us_since_2000() / 1000 / 1000); + return mp_obj_new_int(pyb_rtc_get_us_since_epoch() / 1000 / 1000); } MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); diff --git a/ports/stm32/modutime.c b/ports/stm32/modutime.c index 9641ddb473..2a37a130df 100644 --- a/ports/stm32/modutime.c +++ b/ports/stm32/modutime.c @@ -76,7 +76,7 @@ STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { } else { mp_int_t seconds = mp_obj_get_int(args[0]); timeutils_struct_time_t tm; - timeutils_seconds_since_2000_to_struct_time(seconds, &tm); + timeutils_seconds_since_epoch_to_struct_time(seconds, &tm); mp_obj_t tuple[8] = { tuple[0] = mp_obj_new_int(tm.tm_year), tuple[1] = mp_obj_new_int(tm.tm_mon), @@ -125,7 +125,7 @@ STATIC mp_obj_t time_time(void) { RTC_TimeTypeDef time; HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); - return mp_obj_new_int(timeutils_seconds_since_2000(2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds)); + return mp_obj_new_int(timeutils_seconds_since_epoch(2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds)); } MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 4f759c4bc7..18ecf77505 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -452,8 +452,8 @@ uint64_t mp_hal_time_ns(void) { RTC_DateTypeDef date; HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); - ns = timeutils_nanoseconds_since_1970( - 2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds); + ns = timeutils_seconds_since_epoch(2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds); + ns *= 1000000000ULL; uint32_t usec = ((RTC_SYNCH_PREDIV - time.SubSeconds) * (1000000 / 64)) / ((RTC_SYNCH_PREDIV + 1) / 64); ns += usec * 1000; #endif diff --git a/py/mphal.h b/py/mphal.h index 6d11f6ddc0..0d4b1224e5 100644 --- a/py/mphal.h +++ b/py/mphal.h @@ -76,7 +76,7 @@ mp_uint_t mp_hal_ticks_cpu(void); #endif #ifndef mp_hal_time_ns -// Nanoseconds since 1970/1/1. +// Nanoseconds since the Epoch. uint64_t mp_hal_time_ns(void); #endif