DSN New User Programming Tutorial
June 2007

What are Built-ins?


In order to link declarative programs to hardware such as sensors and actuators, users may specify built-in predicates. For example, the thermometer predicate may read values from the underlying temperature sensor:
! builtin(temperature, TemperatureImplementor).
someOtherPredicate(@Node,Temp) :− temperature(@Node, Temp).
Here ThermometerImplementor is an external module written in nesC implementing the thermometer predicate. Actuation is exposed similarly:
! builtin(sounder, SounderImplementor).
sounder(@Node, frequency) :− process(@Node, Object).
Here, sounder tuples result in sound as implemented by the SounderImplementor.

Built-ins also serve other important purposes permit one to easily adopt packaged functionality. Substantial system services can be incorporated into declarative programs through the use of the built-in mechanism.

The Built-in Interface


Implementing a new built-in requires implementing a handful of nesC interfaces.  The following is the full listing of provides and uses interfaces needed by a built-in:
configuration MyBuiltinTable {
provides {
        interface StdControl;
        interface TupleAccessorMutator as Tam;

        interface PushSync as LocalPush[Opnum_t operation_id];
        interface PullSync as LocalPull;
        interface PullSync as FreshPull;
        interface PushSync as RadioPush;
        interface PullSync as RadioPull;
        interface PullSync as UartPull;
        interface SystemStateNotify as NotifyFresh;
        interface SystemStateNotify as NotifyRadio;
        interface SystemStateNotify as NotifyUart;
} uses {
        interface ParamStore as getParams;
        interface GtupleAccessorMutator as Gam;
        interface GenericFunctionCall;
        interface Leds;
  }
}
implementation {
...
}
It can be quite overwhelming at first!  Fortunately, many of the interfaces are similar with only slight variations.  These break down into the following categories:
The first three categories are all variants of Push/Pull interfaces: PushSync and PullSync; as well as a helper notification interface: SystemStateNotify.  Reading tuples corresponds to pulling tuples out of the builtin whereas writing tuples corresponds to pushing tuples into the builtin.  The different instantations of these interfaces are only in what tuples are pulled or pushed or what the source of the pulling or pushing is:

While there are quite a few interfaces, it is not necessary to implement them all.  In fact, those that are not implemented can be simply wired to NoopC.nc.  The radio interfaces are rarely implemented: only do so if you're own builtin is to send and receive itself.  The uart interfaces are also only necessary for diagnostic purposes and hence are optional.  The main interfaces of concern are typically the four local interfaces (Local and Fresh).  Please see the examples of builtins included in the DSN source tree at nesc/extras/builtins.

Please note that the LocalPush interface must implement the database projection functionality.  DSN uses an table in-place project rather than a general project in order to avoid implementation of a general allocator for projections.

In addition to the push and pull interfaces, several additional support functions are required:

While there are many parts to implement, there are also several examples in the DSN source tree at at nesc/extras/builtins from which usually many parts can be borrowed liberally.

Built-in Functions

Functions are also extensible in DSN with the built-in mechanism.  The declaration of functions in snlog is similar to that of builtin predicates above.  There is only one interface necessary for functions:

configuration MyFunc {
  provides {
    interface GenericFunctionCall;
  }
}
implementation {
...
}
As functions are similar to stateless tables, the task of implementing a function is much simpler.  GenericFunctionCall receives a list of arguments and the implementation can processes these and return any result as output.  Examples of functions are available in the DSN source tree at  nesc/extras/funcs.