Time Functions
Danger
This is historical documentation, and tooling and console operations are no longer available.
Microvisor system calls include the following functions for application timekeeping operations:
Return Values and Errors
All of the functions described below return a 32-bit integer that is one of the values from the standard Microvisor enumeration MvStatus. All possible error values for a given system call are provided with each function’s description.
Success is always signaled by a return value of zero (MV_STATUS_OKAY).
mvGetMicroseconds()
Gets the current value of Microvisor’s free-running microsecond clock
Declaration
extern enum MvStatus mvGetMicroseconds(uint64_t *usec);
Parameters
Parameter  | 
Description  | 
|---|---|
  | 
A pointer to non-secure memory into which the microsecond counternvalue will be written by Microvisor  | 
Possible Errors
Error Value  | 
Description  | 
|---|---|
  | 
  | 
Description
Microvisor’s microsecond clock starts from zero when Microvisor is run, and counts up from then on. It has no relation to — and may drift with respect to — wall time.
Example
// Tick counters
uint64_t last_tick = 0;
uint64_t tick = 0;
while (true) {
enum MvStatus status = mvGetMicroseconds(&tick);
    if (status == MV_STATUS_OKAY && tick - last_tick > LED_FLASH_PERIOD_US) {
        // Toggle the USER LED's GPIO pin every LED_FLASH_PERIOD_US microseconds
        HAL_GPIO_TogglePin(LED_GPIO_BANK, LED_GPIO_PIN);
        last_tick = tick;
    }
}
mvGetWallTime()
Gets the current time in non-leap microseconds since the Unix epoch
Declaration
extern enum MvStatus mvGetWallTime(uint64_t *usec);
Parameters
Parameter  | 
Description  | 
|---|---|
  | 
A pointer to non-secure memory into which the microsecond wall time will be written by Microvisor  | 
Possible Errors
Error Value  | 
Description  | 
|---|---|
  | 
  | 
  | 
The device’s RTC has not yet been set from the server  | 
Description
This call will return MV_STATUS_TIMENOTSET on restart until the real-time clock (RTC) is synchronized with the server. Clock synchronization takes place periodically during application lifecycle: for example, it is updated regularly while the device is connected, and again when the device connects or re-connects. The value written into usec may therefore jump forward or backward in response to an updated time from the server.
Example
This example, which modifies a section of the FreeRTOS demo code logging.c file’s _write() function, shows how to use the 64-bit wall clock time to feed the standard gmtime() and strftime() functions (defined in <time.h>) to create a timestamp string to prefix any output sent to printf(). The code uses the same source to include the millisecond time:
2022-05-10 13:40:57.489 [DEBUG] Temperature: 25.31
2022-05-10 13:40:57.490 [DEBUG] Network handle: 321452355
2022-05-10 13:40:57.491 [DEBUG] HTTP channel handle: 1702803732
2022-05-10 13:40:57.492 [DEBUG] Sending HTTP request
2022-05-10 13:40:58.023 [ERROR] HTTP status code: 429
2022-05-10 13:40:58.024 [DEBUG] HTTP channel closed
Here is the code:
// Prepare and add a timestamp to log output if we can.
// If we can't, we show no time
char timestamp[64] = {0};
uint64_t usec = 0;
enum MvStatus status = mvGetWallTime(&usec);
if (status == MV_STATUS_OKAY) {
    // Get the second and millisecond times
    time_t sec = (time_t)usec / 1000000;
    time_t msec = (time_t)usec / 1000;
    // Write time string as "2022-05-10 13:30:58.XXX "
    strftime(timestamp, 64, "%F %T.XXX ", gmtime(&sec));
    // Insert the millisecond time over the XXX
    sprintf(×tamp[20], "%03u ", (unsigned)(msec % 1000));
}
// Write out the time string. Confirm that Microvisor
// has accepted the request to write data to the channel.
uint32_t time_chars = 0;
size_t len = strlen(timestamp);
if (len > 0) {
    status = mvWriteChannelStream(log_handles.channel, (const uint8_t*)timestamp, len, &time_chars);
    if (status != MV_STATUS_OKAY) {
        errno = EIO;
        return -1;
    }
}
// Write out the message string. Confirm that Microvisor
// has accepted the request to write data to the channel.
uint32_t msg_chars = 0;
status = mvWriteChannelStream(log_handles.channel, (const uint8_t*)ptr, length, &msg_chars);
if (status == MV_STATUS_OKAY) {
    // Return the number of characters written to the channel
    return time_chars + msg_chars;
} else {
    errno = EIO;
    return -1;
}