Jump to main content | Jump to Primary Navigation | Jump to Sub Navigation


 

Tutorial 4: Callbacks

Previous tutorial Next tutorial

This tutorial walks you though setting up a callback to monitor changes to a property's value. Callbacks are useful for writing event-driven programs.

This tutorial assumes you have already initialized a host (Tutorial 1: First steps) and configured it from a suitable XML configuration file (Tutorial 2: The XML configuration file).

The controller constructed in this tutorial uses benchmark.c which is described in Drivers 2: A more complex device driver.

Contents

  1. Obtaining a Property
  2. Writing a Callback
  3. Attaching a Callback
  4. Final Result

Obtaining a Property

A property must first be obtained to attach a callback to:

    data_p = bot_host_register_property_fail(host, "Complex/Data");

Writing a Callback

A callback function must be written to strict specifications. Ordinarily, callbacks should not block and should run in as little time as possible.

Here is a sample callback:

static bool callback(BotProperty *p, void BOT_UNUSED *user_data)
{
    uint32_t data[1];
    uint64_t time, diff;

    /* value,timestamp are paired */
    bot_property_get_uint_all(p, data);
    time = bot_property_get_timestamp(p);
    diff = time - start;

    bot_mesg("Complex->Data[0] = %d (took %lluus)", data[0],
             (unsigned long long)diff - last_diff);
    last_diff = diff;

    /* if we've been running for 10 seconds, flag the main program to quit */
    if (diff >= 10 * 1000 * 1000) {
        bot_shutdown_signal();
        return FALSE;
    }
    return TRUE;
}

The callback takes a property (which is the property you attach the callback too, since the same callback can be attached to multiple properties) and some user_data, supplied below (Attaching a Callback).

Note, the callback can return FALSE to be dequeued, and TRUE to be re-attached for subsequent calls.

Attaching a Callback

Attaching a callback is easy:

    bot_property_add_callback(data_p, NULL, callback, CALLBACK_RELAXED);

The first argument is the property to attach the callback to. The second is the user data to pass to the callback. The third is the callback function itself. CALLBACK_RELAXED works here because we don't care about dropping events.

Final Result

After taking the above steps, you should have the following program which exploits DevBot's callback mechanism (complex.c):

/* Simple DevBot application demonstrating the callback mechanism.
 */
#include <devbot/configuration.h>
#include <devbot/dispatcher.h>
#include <devbot/property.h>
#include <devbot/host.h>
#include <devbot/type.h>
#include <devbot/bot.h>

#include <unistd.h>
#include <stdio.h>

static uint64_t start, last_diff = 0;

/* callback prints out time needed to access a property */
static bool callback(BotProperty *p, void BOT_UNUSED *user_data)
{
    uint32_t data[1];
    uint64_t time, diff;

    /* value,timestamp are paired */
    bot_property_get_uint_all(p, data);
    time = bot_property_get_timestamp(p);
    diff = time - start;

    bot_mesg("Complex->Data[0] = %d (took %lluus)", data[0],
             (unsigned long long)diff - last_diff);
    last_diff = diff;

    /* if we've been running for 10 seconds, flag the main program to quit */
    if (diff >= 10 * 1000 * 1000) {
        bot_shutdown_signal();
        return FALSE;
    }
    return TRUE;
}

int main(void)
{
    /* The 'Data' property */
    BotProperty *data_p;
    /* Temporarily stores the current time */
    struct timeval tv;
    /* This host */
    BotHost *host;

    /* Initialse host */
    host = bot_host_create();
    /* Read configuration file */
    bot_configure_file(host, "complex.xml", "Default");
    /* Start DevBot on this host */
    bot_host_start(host);
    /* Register 'Data' property */
    data_p = bot_host_register_property_fail(host, "Complex/Data");

    /* initialise time variable with start time */
    gettimeofday(&tv, NULL);
    start = bot_tv_to_usec(&tv);

    /* start callback */
    bot_property_add_callback(data_p, NULL, callback, CALLBACK_RELAXED);
    /* wait to be indicated to quit */
    bot_join();
    return 0;
}

Previous tutorial Next tutorial