One Second Timestamping#
Because Wi-SUN network changes are rare while connection times are in days or months, the underlying unit of time measurement used by the Wi-SUN Stack down to the microsecond is not necessary for long-term observability of network connection. We therefore:
Set up a 1-second timer to count seconds
Add functions to format current time and delays as dd-hh:mm:ss
To get a 1-second timestamp, do the following steps.
Note: This is all done in
app_timestamp.c
andapp_timestamp.h
, which you can use by copy/pasting both files next to yourapp.c
file.
Simplicity Studio will automatically compile any .c
file present under the project folder, so no action is required to add app_timestamp.c
to the compilation once the file is copied.
Declaration of a 64-bit app_timestamp
Variable#
sl_sleeptimer_timestamp_64_t app_timestamp;
Creation of a Callback Function to Increment the Timestamp by 1#
void app_timer_callback(sl_sleeptimer_timer_handle_t *handle, void *data) {
(void)handle;
(void)data;
app_timestamp++;
}
Protect Access to the Variable Using a Mutex#
static const osMutexAttr_t _app_timestamp_mutex_attr = {
.name = "AppTimestampMutex",
.attr_bits = osMutexRecursive,
.cb_mem = NULL,
.cb_size = 0U
};
__STATIC_INLINE void _app_timestamp_mutex_acquire(void)
{
assert(osMutexAcquire(_app_timestamp_mutex, osWaitForever) == osOK);
}
__STATIC_INLINE void _app_timestamp_mutex_release(void)
{
assert(osMutexRelease(_app_timestamp_mutex) == osOK);
}
Timestamp Init#
sl_status_t app_timestamp_init(void) {
sl_status_t status;
uint32_t app_timer_timeout;
// init mutex
_app_timestamp_mutex = osMutexNew(&_app_timestamp_mutex_attr);
assert(_app_timestamp_mutex != NULL);
app_timestamp = 0;
status = sl_sleeptimer_init();
if (status != SL_STATUS_OK) {
printf("Error initializing sleeptimer. Status %lu\n", status);
return status;
}
app_timer_timeout = (uint32_t)1.0*sl_sleeptimer_get_timer_frequency();
status = sl_sleeptimer_start_periodic_timer(&app_timer,
app_timer_timeout,
app_timer_callback,
NULL, 0, 0);
if (status != SL_STATUS_OK) {
printf("Error starting periodic timer 'app_timer'. Status %lu\n", status);
return status;
}
return status;
}
Following this:
app_timestamp
is set to0
whenapp_timestamp_init()
is calledapp_timer_callback()
is called every secondapp_timestamp
is increased by1
every second
You can retrieve it safely using the mutex
Retrieve the Current Timestamp Decimal Value#
uint64_t now_sec (void) {
sl_sleeptimer_timestamp_64_t current_sec;
_app_timestamp_mutex_acquire();
current_sec = app_timestamp;
_app_timestamp_mutex_release();
return (uint64_t)current_sec;
}
You can use now_sec()
to store the current time in decimal values:
uint64_t current_time_secs;
current_time_secs = now_sec();
Utility Functions to Process Timestamp Values#
Transform a Timestamp in days/hours/mins/secs Units#
Mainly used as a convenience function, this should rarely be used from outside this code:
sl_status_t d_h_m_s_total(sl_sleeptimer_timestamp_64_t timestamp_secs,
uint16_t* days,
uint64_t* hours,
uint64_t* mins,
uint64_t* secs
) {
*days = timestamp_secs / 60 / 60 / 24;
*hours = timestamp_secs / 60 / 60;
*mins = timestamp_secs / 60;
*secs = timestamp_secs;
return SL_STATUS_OK;
}
Transform a Timestamp as days:hours:mins:secs Decimal Values#
sl_status_t d_h_m_s (sl_sleeptimer_timestamp_64_t timestamp_secs,
uint16_t* days,
uint8_t* hours,
uint8_t* mins,
uint8_t* secs) {
uint64_t hours_total;
uint64_t mins_total;
uint64_t secs_total;
d_h_m_s_total(timestamp_secs, days, &hours_total, &mins_total, &secs_total);
*days = *days;
*hours = hours_total % 24;
*mins = mins_total % 60;
*secs = secs_total % 60;
return SL_STATUS_OK;
}
Format a Timestamp as a days:hours:mins:secs Text String#
char* dhms (sl_sleeptimer_timestamp_64_t timestamp_secs) {
uint16_t days;
uint8_t hours, mins, secs;
d_h_m_s(timestamp_secs, &days, &hours, &mins, &secs);
snprintf(time_str, TIME_STRING_LEN, "%3d:%02d:%02d:%02d", days, hours, mins, secs);
return time_str;
}
This can be used in traces as follows:
printf("Current time is %s\n", now_str());
With a Current time is 0:01:23:45
result, if the application has been running for 0 day, 1 hour, 23 minutes and 45 seconds.
Get app_timestamp
as a Text String#
char* now_str (void) {
return dhms(now_sec());
}
Trace Timestamping and Routing Macros#
A set of macros are defined to allow sending traces to the console, the RTT traces, or both:
#define printfTime(...) printf("[%s] ", now_str()); printf(__VA_ARGS__)
#define printfRTT(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#define printfTimeRTT(...) SEGGER_RTT_printf(0, "[%s] ", now_str()); SEGGER_RTT_printf(0, __VA_ARGS__)
#define printfBoth(...) SEGGER_RTT_printf(0, __VA_ARGS__); printf(__VA_ARGS__)
#define printfBothTime(...) SEGGER_RTT_printf(0, "[%s] ", now_str()); SEGGER_RTT_printf(0, __VA_ARGS__); printf("[%s] ", now_str()); printf(__VA_ARGS__)
The above makes it easy in the application to:
Select to add a timestamp or not to traces.
Print a trace to the console or the RTT traces, or both.
Use the Timestamp#
In app.c
, #include "app-timestamp.h"
to get access to the timestamping resources.
In app.c/app_task()
, initialize the one second timestamp:
It is convenient to declare variables to store various time values:
uint64_t connect_time_sec; // time stamp of Wisun connect call
uint64_t connection_time_sec; // last connection time stamp
uint64_t disconnection_time_sec; // last disconnection time stamp
These can be used as follows (example code, not part of the sample application):
printfBothTime("running since %s\n", now_str());
connect_time_sec = now_sec();
app_wisun_connect_and_wait();
/* Some time will pass until we're connected... */
connection_time_sec = now_sec();
printfBothTime("Connected in %s\n", dhms(connection_time_sec - connect_time_sec));