Jump to main content | Jump to Primary Navigation | Jump to Sub Navigation
| Back to main drivers page | Next tutorial |
This tutorial illustrates how to use the DevBot infrastructure to create drivers for your custom hardware. Before reading this tutorial you should read Architecture document and the tutorials on developing DevBot controllers.
There are several parts to a driver. This tutorial covers the most basic elements of a driver by examining the simple virtual device driver simple_driver.
With the exception of name and version version all of the BotDriver fields may be left blank. But since most drivers are intended to do something useful they will usually define at least a poll function and property template table and often a device initialization function.
For example, the boilerplate for the simple_driver driver (used in Tutorial 1: First steps and Tutorial 3: Creating devices programmatically) looks like this:
static const BotDriver boilerplate = { .name = "simple_driver", .description = "Demonstrates the basic features of the driver API", .version = "1.0", .initialize_device = init_device, .poll_device = poll_device, .driver_properties = driver_properties }; BOT_DRIVER_BOILERPLATE(boilerplate);
BOT_DRIVER_BOILERPLATE is a convenience macro used to export this structure.
The template structure also sets the "flags" field which is used to define access permissions. The most commonly used flags are shown in the table below.
| BOT_NO_DEFAULT | Property requires initialization -- there is no default |
| BOT_NO_READ | Property is write-only |
| BOT_NO_WRITE | Property is read-only |
This field is a bit-field, so these flags can combined using bit-wise operators. For example, the following code would indicate a mandatory, read-only property.
Finally the property table must end with the END_PROPERTY_PROTO. An example of a finished property table is:
static const BotDeviceProto driver_properties[] = { { .name = "Countdown", .description = "Value that will count down to zero.", .type = BOT_TYPE_UINT_NAME, .flags = BOT_NO_DEFAULT, }, { .name = "Message", .description = "Message to print. Limited to 256 characters.", .type = BOT_TYPE_STRING_NAME, .length = 256, }, END_PROPERTY_PROTO };
Note that it is possible for drivers to create device properties dynamically. This is covered in a later tutorial.
static bool init_device(BotDevice *device) { BotProperty *message_p; message_p = bot_device_lookup_property(device, "Message"); bot_property_add_callback(message_p, device, message_updated, CALLBACK_RELAXED); return TRUE; }
A real driver might probe a bus, or initialize internal device-specific data-structures instead.
If the user specifies a poll period that is too short for the work the poll function has to do the system will print a diagnostic error and terminate. An example poll_device() which accesses the "Countdown" property and decrements its value is given below.
static bool poll_device(BotDevice *device) { BotProperty *countdown_p; uint32_t countdown; /* Update countdown property */ countdown_p = bot_device_lookup_property(device, "Countdown"); countdown = bot_property_get_uint(countdown_p); if (countdown > 0) bot_property_set_uint(countdown_p, countdown - 1); return TRUE; }
Note that instead of looking up a property on every poll in this way, one would normally store a reference during device initialization. This is covered in a later tutorial.
The following example Makefile shows the required compiler flags for compilation.
# Makefile for compiling a DevBot driver CCROOT=/opt/devbot/armxscale-uclibc CCTARGET=$CCROOT/bin/arm-linux-uclibc-gcc CFLAGS="-Wall -shared -O2 -I$CCROOT/include -L$CCROOT/lib" drivername.so: $CCTARGET $CFLAGS $PKCFG -lbot -o drivername.so drivername.c
/****************************************************************************** * * Simple driver used for basic controller and driver tutorials. * ******************************************************************************/ #include <devbot/driver/property.h> #include <devbot/driver/driver.h> #include <devbot/driver/device.h> #include <devbot/dispatcher.h> #include <devbot/type.h> #include <devbot/bot.h> #include <stdlib.h> #include <stdio.h> static const BotDeviceProto driver_properties[] = { { .name = "Countdown", .description = "Value that will count down to zero.", .type = BOT_TYPE_UINT_NAME, .flags = BOT_NO_DEFAULT, }, { .name = "Message", .description = "Message to print. Limited to 256 characters.", .type = BOT_TYPE_STRING_NAME, .length = 256, }, END_PROPERTY_PROTO }; /* Callback attached to Message property */ static bool message_updated(BotProperty *message_p, void *user_data) { char buffer[256]; bot_property_get_string(message_p, buffer); bot_mesg("%s says, \"%s\"", bot_device_get_name(user_data), buffer); return TRUE; } /* Device initialization function */ static bool init_device(BotDevice *device) { BotProperty *message_p; message_p = bot_device_lookup_property(device, "Message"); bot_property_add_callback(message_p, device, message_updated, CALLBACK_RELAXED); return TRUE; } /* Poll function -- decrement the Countdown property */ static bool poll_device(BotDevice *device) { BotProperty *countdown_p; uint32_t countdown; /* Update countdown property */ countdown_p = bot_device_lookup_property(device, "Countdown"); countdown = bot_property_get_uint(countdown_p); if (countdown > 0) bot_property_set_uint(countdown_p, countdown - 1); return TRUE; } static const BotDriver boilerplate = { .name = "simple_driver", .description = "Demonstrates the basic features of the driver API", .version = "1.0", .initialize_device = init_device, .poll_device = poll_device, .driver_properties = driver_properties }; BOT_DRIVER_BOILERPLATE(boilerplate);
| Back to main drivers page | Next tutorial |