TinySchema: Managing Attributes, Commands and Events in TinyOS

Wei Hong and Sam Madden
whong@intel-research.net, madden@cs.berkeley.edu

Version 1.1
September, 2003

1 Introduction

TinySchema is a collection of TinyOS components that manages a small respository of named attributes, commands and events that can be easily queried, invoked or signaled from inside or outside a mote network. A TinySchema attribute is much like a column in a traditional database system. It has a name and a type. In addition, TinySchema allows you to associate arbitrary TinyOS code to each attribute for getting and setting the attribute value. Once an attribute is created, it can be retrieved or updated through a unified interface provided by TinySchema. TinyDB (see TinyDB document), the in-network query processing system for TinyOS, is one of the applications built on top of this interface. You can also build your own application for manipulating attributes based on the interfaces provided by TinySchema. Typically, there are three classes of attributes:

A TinySchema command is much like a stored procedure in a traditional database system. It consists of a name, a list of arguments and a return type. You can associate arbitrary TinyOS code to each command. TinySchema provides a unified interface for invoking these commands. TinyDB is also built on top of the TinySchema command interfaces for its trigger actions (see TinyDB document). Typically, there are two classes of commands:

A TinySchema event is introduced to capture asynchronous events in sensor networks, e.g., detection of a bird, push of a button, etc. TinySchema provides interfaces for registering and invoking events as well as associating TinySchema commands with events as callbacks when events are signaled.

Currently all attributes and all commands must be staticly built into each mote. We plan to integrate with the virtual machines being developed for the TinyOS such as Mate and Mottle to allow dynamic creation of attributes and commands.

TinySchema is part of TinyOS1.1 release.

2 System Overview

TinySchema has three separate components in tinyos-1.x/tos/lib/Attributes/Attr.nc, tinyos-1.x/tos/lib/Commands/Command.nc and tinyos-1.x/tos/lib/Events/Event.nc. Attr provides all attributes related interfaces, Command provides all command related interfaces, and Event provides all event related interfaces.

Attr provides the following interfaces:

Command provides the following interfaces:

Event provides the following interfaces:

We will describe each of the above interfaces in details in the next section.

3 Detailed Interface Descriptions

3.1 Data Types and Error Codes

All of TinySchema's data types and error codes are defined in tinyos-1.x/tos/interfaces/SchemaTypes.h.

The following data types are supported:

Here are the error codes used in all TinySchema interfaces:

3.2 Attribute Related Interfaces

3.2.1 Attribute Data Structures

All attribute related data structures are defined in tinyos-1.x/tos/interfaces/Attr.h. The main data structure is AttrDesc which contains the definition of each attribute. AttrDescs is just an array of AttrDesc's for all the attributes defined in each mote. You must pay attention to the constants defined at the beginning of the file which defines the maximum number of attributes, maximum attribute name length, etc. Do not exceed those limits! Increase them as needed, but they cost more precious RAM space on a mote.

3.2.2 AttrRegister

command result_t registerAttr(char *name, TOSType attrType, uint8_t attrLen)

This is the command you call to register an attribute. The attrLen argument is only relevant to variable-length types such as STRING. It is ignored for fixed-length types.

event result_t getAttr(char *name, char *resultBuf, SchemaErrorNo *errorNo)

This is the TinyOS code that you must provide for getting the value of the attribute you just registered through registerAttr. name is the name of the attribute. It is mostly redundent, but may come in handy if you want to write one piece of code that supports mulitple attributes. resultBuf is a pointer to a pre-allocated buffer to hold the value of this attribute. You can assume that enough space has been allocated to hold the value of this attribute. errorNo is the return error code. You are required to do one of the following in getAttr:

event result_t setAttr(char *name, char *attrVal)

This is the TinyOS code that you must provide for setting the value of the attribute you just registered through registerAttr. name is the name of the attribute. It is mostly redundent, but may come in handy if you want to write one piece of code that supports multiple attributes. attrVal is a pointer to a value of the same type as the attribute type. NULL pointer means a null value. If the value of this attribute cannot be set, simply return FAIL.

command result_t getAttrDone(char *name, char *resultBuf, SchemaErrorNo errorNo)

This is the command you must call for split-phase attributes. In this case, the getAttr will initiate a split-phase operation, set *errorNo to SCHEMA_RESULT_PENDING then return. In the split-phase completion event (e.g. ADC.dataReady()), you must call this command with the attribute value filled in resultBuf.

3.2.3 AttrRegisterConst

command result_t registerAttr(char *name, TOSType attrType, char *attrVal)

This command provides a simplified way to associate a constant value to an attribute without having to write the getAttr and setAttr code as described above in the AttrRegister interface. attrVal points to a value of the attrType type. The Attr component preallocates space to hold values for a fixed number (MAX_CONST_ATTRS defined in tinyos-1.x/tos/interfaces/Attr.h) of constant attributes. This command assigns a slot in the preallocated space to hold the constant value at attrVal. The AttrUse interface to be described below will automatically handle the get and set of the newly defined constant attributes just like any other attributes. Currently, a constant attribute can be at most 4 bytes long.


3.2.4 AttrUse

command AttrDescPtr getAttr(char *name)

This command returns a pointer to the attribute descriptor for the attribute with a name that matches the argument. The name is case-insensitive. NULL will be returned if the attribute does not exist. The returned attribute descriptor is NOT to be freed.

command AttrDescPtr getAttrById(uint8_t attrIdx)

This command returns a pointer to the attribute descriptor corresponding to an attribute index.

command uint8_t numAttrs()

This command returns the total number of attributes that have been registered.

command AttrDescsPtr getAttrs()

This command returns the array of attribute descriptors for all the the attributes that have been registered.

command result_t getAttrValue(char *name, char *resultBuf, SchemaErorNo *errorNo)

This is the command retrieves the value of an attribute by name. name is the name of the attribute. resultBuf is a pointer to a preallocated buffer to hold the attribute value. It must be at least as big as the attribute length. errorNo is a return parameter of the error code. It has the following cases:

command result_t setAttrValue(char *name, char *attrVal)

This command sets the value of an attribute by name. name is the attribute name. attrVal is a pointer to a value of the same type as the attribute. This command will return FAIL if the attribute cannot be set.

event result_t getAttrDone(char *name, char *resultBuf, SchemaErrorNo errorNo)

This event will be signaled after a getAttrValue command is called on a split-phase attribute when the value of the attribute is ready. By this time, the value of the attribute is already copied into resultBuf. errorNo are the same as described for getAttrValue.

command result_t startAttr(uint8_t id)

This command is called to start or restart the attribute with attribute id id. It is typically called after a mote wakes up after a sleep period for turning on the corresponding sensor associated with an attribute.

event result_t startAttrDone(uint8_t id)

This event will be signaled after a startAttr command is called when the sensor associated with the attribute is ready for use. getAttrValue must not be called before this event is signaled.

3.3 Command Related Interfaces

3.3.1 Command Data Structures

All command related data structures are defined in tinyos-1.x/tos/interfaces/Command.h. It defines the following important data structures:

You must pay attention to the constants defined at the beginning of Command.h for the current limitations such as maximum number of parameters in a command, maximum number of commands and maximum number of characters in a command name. These limits must be observed or extended at the cost of more RAM consumption.

3.3.2 CommandRegister

command result_t registerCommand(char *name, TOSType retType, uint8_t retLen, ParamList *paramList)

This NesC command registers a new TinySchema command. name is the name of the command. retType is the return type of the command. Use the VOID type if the command does not return any value. retLen is the maximum length for the return value for any variable length types such as STRING. It is ignored for fixed-length types. paramList is the list of parameter types that this command expects when invoked.

event result_t commandFunc(char *commandName, char *resultBuf, SchemaErrorNo *errorNo, ParamVals *params)

This is the TinyOS code you provide that implements the command that you just registered through registerCommand. commandName is the name of the command. It is mostly redundant, but may come in handy when you want to write one piece of code to implement multiple commands. resultBuf is a pointer to the preallocated buffer this command's return value is supposed to be copied into. errorNo is the return parameter for error code. params is the list of parameter values for the current invocation. You are required to do one of the following in commandFunc:

command result_t commandDone(char *commandName, char *resultBuf, SchemaErrorNo errorNo)

This NesC command must be called in the split-phase completion event if commandFunc returns an error code of SCHEMA_RESULT_PENDING. commandName is the command name. resultBuf is a pointer to a buffer the return value is supposed to be copied into. errorNo is the error code.

3.3.3 CommandUse

command CommandDescPtr getCommand(char *name)

This NesC command looks up a TinySchema command descriptor by name. The name is case-insensitive. NULL is returned if the command does not exist.

command CommandDescPtr getCommandById(uint8_t idx)

This NesC command looks up a TinySchema command descriptor by index.

command uint8_t numCommands()

This NesC command returns the total number of TinySchema commands currently registered.

command CommandDescsPtr getCommands()

This NesC command returns an array of command descriptors for all the currently registered TinySchema commands.

command result_t invoke(char *commandName, char *resultBuf, SchemaErrorNo *errorNo, ParamVals *params)

This NesC command is for invoking a TinySchema command. commandName is the name of the TinySchema command. resultBuf is a pointer to the buffer the return value is supposed to be copied into. errorNo is the return parameter for error code. ParamVals is the list of parameter values to be passed into this TinySchema command. See the description of getAttrValue in Section 3.2.4 for all the error codes you should handle.

command result_t invokeMsg(TOS_MsgPtr msg, char *resultBuf, SchemaErrorNo *errorNo)

This NesC command is a wrapper over invoke. It first parses the TOS_Msg into a command name and a list of parameter values then calls invoke. msg.data is expected to start with the null-terminated string for command name followed by the list of parameter values tightly packed one after the other. This NesC command is introduced for supporting remote invocation of TinySchema commands via the radio.

event result_t commandDone(char *commandName, char *resultBuf, SchemaErrorNo errorNo)

This is the event you are supposed to implement to handle split-phase command completion. See the description for getAttrDone event in Section 3.2.4.

3.4 Event Related Interfaces

3.4.1 Event Data Structures

All event related data structures are defined in tinyos-1.x/tos/interfaces/Event.h. It defines the following important data structures:

3.4.2 EventRegister

command result_t registerEvent(char *name, ParamList *paramList)

This NesC command registers a new TinySchema event. name is the name of the command. paramList is the list of parameter types that this event will be signaled with.

command result_t deleteEvent(char *name)

This NesC command deletes a registered event.

3.4.3 EventUse

command EventDescPtr getEvent(char *name)

This NesC command looks up a TinySchema event descriptor by name. The name is case-insensitive. NULL is returned if the event does not exist.

command EventDescPtr getEventById(uint8_t idx)

This NesC command looks up a TinySchema event descriptor by index.

command EventDescsPtr getEvents()

This NesC command returns an array of event descriptors for all the currently registered TinySchema events.

command result_t signalEvent(char *eventName, ParamVals *params)

This NesC command is for signaling a TinySchema event. eventName is the name of the TinySchema event. ParamVals is the list of parameter values to be passed into this TinySchema event.

command result_t signalEventMsg(TOS_MsgPtr msg)

This NesC command is a wrapper over signalEvent. It first parses the TOS_Msg into a event name and a list of parameter values then calls signalEvent. msg.data is expected to start with the null-terminated string for command name followed by the list of parameter values tightly packed one after the other. This NesC command is introduced for supporting remote signaling of TinySchema events via the radio.

command result_t registerEventCallback(char *eventName, char *cmdName)

This NesC command registers an event interest by associating a TinySchema command to a TinySchema event. The TinySchema command will be invoked when the TinySchema event is signaled. The maximum number of TinySchema commands that can be associated with each event is defined in Event.h.

event result_t eventDone(char *name, SchemaErrorNo errorNo)

This NesC event is signaled upon completion of all the commands associated with the event.

4 Examples

Directories tinyos-1.x/tos/lib/Attributes and tinyos-1.x/tos/lib/Commands contain all the ready-to-use components that implements the most common attributes and commands. These are also the attributes and commands that are built into TinyDB. They also serve as examples of TinySchema attribute and command implementations. The following is the list of files in these two directories and the corresponding attributes and commands that they implement. If you want to use any of these predefined attributes or commands in your application, simply wire the StdControl interface of these components to Main.StdControl and the attributes or commands will be automatically registered and ready to use.

About this document ...

TinySchema: Managing Attributes, Commands and Events in TinyOS

This document was generated using the LaTeX2HTML translator Version 2002-1 (1.68)

Copyright © 1993, 1994, 1995, 1996, Nikos Drakos, Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999, Ross Moore, Mathematics Department, Macquarie University, Sydney.

The command line arguments were:
latex2html -split 1 -show_section_numbers -no_navigation tinyschema.tex

The translation was initiated by Sam Madden on 2003-09-29


Sam Madden 2003-09-29