Overview

This tutorial will guide you to configure a timer callback, a mechanism to perform some periodic actions.

Potential use cases are:

  • Sending heartbeat messages to connected clients
  • Implementing reconnection logic for MQTT or WebSocket clients
  • Periodic upload of telemetry data
  • Periodic version checking for software updates

Our actions will be:

  • We first write the callback function, which will perform the required periodic task
  • then, after initializing an event manager, add this function to the event manager's timer list.

Our function will be called by the event manager once the specified time has elapsed.

Timer API

The timer API is tiny and consists of this key function:

struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
                              unsigned flags, void (*fn)(void *), void *arg);

This function call initializes a timer and adds it to the internal timer list within an event manager. The event manager will then call the function specified in parameter fn at the interval specified in parameter miliseconds, passing it the argument arg. The call will periodically repeat if we set the proper flag in parameter flags.

For detailed information, see documentation.

Minimal Example

This example initializes a 300 millisecond timer that simply logs a message. Note that instead of an infinite loop, it stops after some number of iterations:

#include "mongoose.h"

static void timer_fn(void *arg) {
  LOG(LL_INFO, ("Timer function called, arg %p", arg));
}

int main(void) {
  struct mg_mgr mgr;
  mg_mgr_init(&mgr);
  mg_timer_add(&mgr, 300, MG_TIMER_REPEAT, timer_fn, &mgr); // 300ms interval
  for (int i = 0; i < 500; i++) mg_mgr_poll(&mgr, 10);      // Work for 5 seconds
  mg_mgr_free(&mgr);
  return 0;
}

It is important to keep the event manager polling timeout smaller than the timer interval, because timers are checked at every polling cycle. If there are no network events, the poll function would sleep for the whole polling interval and if it is larger than the timer timeout, a timer invocation could be missed.

WebSocket broadcast

The example code in the Mongoose repository uses WebSocket to send a small periodic message to every connected client. This is of course done using the timer API.

Build the example, this will also start Mongoose:

$ make clean all

To connect to this example we'll need a WebSocket client, we can use wscat

$ wscat --connect ws://127.0.0.1:8000/websocket
Connected (press CTRL+C to quit)
< hi
< hi
< hi
< hi
< hi

or we can use a browser, as this example can also serve a small WebSocket client. Go to http://localhost:8000 in your browser:

browser

What this example mainly does is:

  • write a callback function that broadcasts a small message to all connected websocket clients:

  • initialize the event manager, add the timer callback, and call the event manager in an infinite loop:

The HTTP listener handles the upgrade to the WebSocket protocol and serving the small client instead. For more information check the WebSocket server tutorial.

Browse latest code