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 and app_timestamp.h, which you can use by copy/pasting both files next to your app.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 to 0 when app_timestamp_init() is called

  • app_timer_callback() is called every second

    • app_timestamp is increased by 1 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:

timestamp init

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));