diff --git a/include/Clock.h b/include/Clock.h index 87ff289..a8bcba3 100644 --- a/include/Clock.h +++ b/include/Clock.h @@ -7,9 +7,13 @@ #define CLOCK_H #include "NetworkInterface.h" +#include "mbed.h" #include "sntp.h" #include +typedef std::chrono::time_point kernel_timepoint; +std::chrono::microseconds kernel_to_real_time(kernel_timepoint time); + void clock_setup(void); SNTPError clock_sync(NetworkInterface &net); diff --git a/src/Clock.cpp b/src/Clock.cpp index acc181f..aabc005 100644 --- a/src/Clock.cpp +++ b/src/Clock.cpp @@ -8,28 +8,68 @@ using namespace std::chrono; +// The time the system started in microseconds since 1970 +microseconds boot_start; +// Always use this lock to access boot_start +Mutex boot_start_access; + +// Sets the boot_start time based on kernel uptime and real time +// in microseconds since 1970 +// This is done by removing the uptime from the real time to get the +// time the system booted +// Both kernel_time and real_time should be sampled at the same time +void set_boot_start(kernel_timepoint kernel_time, microseconds real_time) { + microseconds uptime = kernel_time.time_since_epoch(); + boot_start_access.lock(); + boot_start = real_time - uptime; + boot_start_access.unlock(); +} + +// Converts a kernel timepoint to microseconds since 1970 +// This is done by adding boot_start to the kernel time passed +microseconds kernel_to_real_time(kernel_timepoint kernel_time) { + microseconds boot_time = kernel_time.time_since_epoch(); + boot_start_access.lock(); + microseconds real_time = boot_start + boot_time; + boot_start_access.unlock(); + return real_time; +} + // Initializes the clock, run once at boot void clock_setup(void) { - // mbed reads the RTC at boot, do nothing for now + // Get RTC time + time_t rtc_time = time(NULL); + // Update boot start time + microseconds rtc_time_microsecs = seconds(rtc_time); + kernel_timepoint kernel_now = Kernel::Clock::now(); + set_boot_start(kernel_now, rtc_time_microsecs); } // Syncs the clock using SNTP, run any time SNTPError clock_sync(NetworkInterface &net) { + // Get time from SNTP struct timeval time; SNTPError err; err = sntp(net, "time.google.com", 123, &time); if (err != SNTPSuccess) { return err; } + // Set RTC time set_time(time.tv_sec); + // Convert SNTP timeval to microseconds + microseconds time_microsecs(0); + time_microsecs += seconds(time.tv_sec); + time_microsecs += microseconds(time.tv_usec); + // Update boot start time + kernel_timepoint kernel_now = Kernel::Clock::now(); + set_boot_start(kernel_now, time_microsecs); return SNTPSuccess; } // Gets the current clock time in microseconds since 1970 microseconds clock_now(void) { - time_t now_seconds = time(NULL); - microseconds microsecs = seconds(now_seconds); - return microsecs; + kernel_timepoint kernel_now = Kernel::Clock::now(); + return kernel_to_real_time(kernel_now); } // Formats a time in microseconds using strftime