Skip to content
Snippets Groups Projects
Commit c3ca9d22 authored by rahix's avatar rahix
Browse files

Merge 'Add monotonic clock'

parents 5773e2e1 f1251d66
No related branches found
No related tags found
No related merge requests found
......@@ -81,6 +81,8 @@ typedef _Bool bool;
#define API_RTC_SCHEDULE_ALARM 0x51
#define API_RTC_SET_MILLISECONDS 0x52
#define API_RTC_GET_MILLISECONDS 0x53
#define API_RTC_GET_MONOTONIC_SECONDS 0x54
#define API_RTC_GET_MONOTONIC_MILLISECONDS 0x55
#define API_LEDS_SET 0x60
#define API_LEDS_SET_HSV 0x61
......@@ -1733,6 +1735,24 @@ API(API_FILE_MKDIR, int epic_file_mkdir(const char *dirname));
* ===
*/
/**
* Get the monotonic time in seconds.
*
* :return: monotonic time in seconds
*/
API(API_RTC_GET_MONOTONIC_SECONDS,
uint32_t epic_rtc_get_monotonic_seconds(void)
);
/**
* Get the monotonic time in ms.
*
* :return: monotonic time in milliseconds
*/
API(API_RTC_GET_MONOTONIC_MILLISECONDS,
uint64_t epic_rtc_get_monotonic_milliseconds(void)
);
/**
* Read the current RTC value.
*
......
......@@ -9,6 +9,18 @@
#include <stdint.h>
uint64_t monotonic_offset = 0;
uint32_t epic_rtc_get_monotonic_seconds(void)
{
return epic_rtc_get_seconds() + monotonic_offset / 1000ULL;
}
uint64_t epic_rtc_get_monotonic_milliseconds(void)
{
return epic_rtc_get_milliseconds() + monotonic_offset;
}
uint32_t epic_rtc_get_seconds(void)
{
uint32_t sec, subsec;
......@@ -32,12 +44,31 @@ uint64_t epic_rtc_get_milliseconds(void)
while (RTC_GetTime(&sec, &subsec) == E_BUSY) {
vTaskDelay(pdMS_TO_TICKS(4));
}
return subsec * 1000ULL / 4096 + sec * 1000ULL;
// Without the bias of 999 (0.24 milliseconds), this decoding function is
// numerically unstable:
//
// Encoding 5 milliseconds into 20 subsecs (using the encoding function in
// epic_rtc_set_milliseconds) and decoding it without the bias of 999 yields
// 4 milliseconds.
//
// The following invariants should hold when encoding / decoding from and to
// milliseconds / subseconds:
//
// - 0 <= encode(ms) < 4096 for 0 <= ms < 1000
// - decode(encode(ms)) == ms for 0 <= ms < 1000
// - 0 <= decode(subsec) < 1000 for 0 <= subsec < 4096
//
// These invariants were proven experimentally.
return (subsec * 1000ULL + 999ULL) / 4096 + sec * 1000ULL;
}
void epic_rtc_set_milliseconds(uint64_t milliseconds)
{
uint32_t sec, subsec;
uint64_t old_milliseconds, diff;
old_milliseconds = epic_rtc_get_milliseconds();
sec = milliseconds / 1000;
subsec = (milliseconds % 1000);
......@@ -48,6 +79,9 @@ void epic_rtc_set_milliseconds(uint64_t milliseconds)
;
while (RTC_EnableRTCE(MXC_RTC) == E_BUSY)
;
diff = old_milliseconds - milliseconds;
monotonic_offset += diff;
}
void RTC_IRQHandler(void)
......
......@@ -48,6 +48,8 @@ Q(ticks_add)
Q(ticks_diff)
Q(localtime)
Q(mktime)
Q(monotonic)
Q(monotonic_ms)
Q(time)
Q(time_ms)
Q(set_time)
......
......@@ -51,6 +51,22 @@ static mp_obj_t time_time_ms(void)
}
MP_DEFINE_CONST_FUN_OBJ_0(time_time_ms_obj, time_time_ms);
static mp_obj_t time_monotonic(void)
{
mp_int_t seconds;
seconds = epic_rtc_get_monotonic_seconds();
return mp_obj_new_int(seconds);
}
MP_DEFINE_CONST_FUN_OBJ_0(time_monotonic_obj, time_monotonic);
static mp_obj_t time_monotonic_ms(void)
{
uint64_t milliseconds;
milliseconds = epic_rtc_get_monotonic_milliseconds();
return mp_obj_new_int_from_ull(milliseconds);
}
MP_DEFINE_CONST_FUN_OBJ_0(time_monotonic_ms_obj, time_monotonic_ms);
static mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args)
{
mp_int_t seconds;
......@@ -130,6 +146,9 @@ static const mp_rom_map_elem_t time_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },
{ MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) },
{ MP_ROM_QSTR(MP_QSTR_time_ms), MP_ROM_PTR(&time_time_ms_obj) },
{ MP_ROM_QSTR(MP_QSTR_monotonic), MP_ROM_PTR(&time_monotonic_obj) },
{ MP_ROM_QSTR(MP_QSTR_monotonic_ms),
MP_ROM_PTR(&time_monotonic_ms_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_time), MP_ROM_PTR(&time_set_time_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_unix_time),
MP_ROM_PTR(&time_set_unix_time_obj) },
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment