Skip to content

Commit

Permalink
all: Rename absolute time-based functions to include "epoch".
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
dpgeorge committed Sep 18, 2020
1 parent bd7af61 commit 8f20cdc
Show file tree
Hide file tree
Showing 17 changed files with 67 additions and 50 deletions.
5 changes: 1 addition & 4 deletions extmod/vfs_fat.c
Original file line number Diff line number Diff line change
Expand Up @@ -311,17 +311,14 @@ 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,
(fno.ftime >> 11) & 0x1f,
(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
Expand Down
4 changes: 3 additions & 1 deletion extmod/vfs_lfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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;
Expand Down
6 changes: 2 additions & 4 deletions extmod/vfs_lfsx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
43 changes: 32 additions & 11 deletions lib/timeutils/timeutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
2 changes: 1 addition & 1 deletion ports/esp32/fatfs_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions ports/esp32/machine_rtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion ports/esp32/modutime.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
3 changes: 1 addition & 2 deletions ports/esp32/mphalport.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion ports/esp8266/esp_mphal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions ports/esp8266/fatfs_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
18 changes: 9 additions & 9 deletions ports/esp8266/machine_rtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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;
Expand All @@ -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),
Expand All @@ -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]),
Expand Down Expand Up @@ -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;

Expand All @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion ports/esp8266/modmachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions ports/esp8266/modmachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 4 additions & 4 deletions ports/esp8266/modutime.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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);

Expand Down
4 changes: 2 additions & 2 deletions ports/stm32/modutime.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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);

Expand Down
4 changes: 2 additions & 2 deletions ports/stm32/rtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion py/mphal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 8f20cdc

Please sign in to comment.