Implementation

Integration in TinyOS

Networking is a critical part of sensor networks, and of TinyOS as a result. We detail here the networking principles of TinyOS as well as the existing components that TinyOS provides.

Link layer

TinyOS link layer relies on Active Messages (AM). They provide a unreliable one-hop datagram protocol. The implementation is provided by a set of interfaces and associated components detailed here.

For programmers to share common conventions about network interfaces, TinyOS documentation describes the choices made to design network and AM interfaces, and how upper layers should be designed to meet these conventions.

The basic interface is Packet (figure 1.1), which provides access to the field that is common to every datagram protocol : the payload. Protocols must provide a specific interface to give access to the relevant fields of their format. To avoid copy of data and memory consumption, the components of the different layers share the same packet buffer, a message_t pointer. They rely on underlying packet interfaces to know where their data begin.

Figure 1.1: The Packet interface.

interface Packet {
  command void clear(message_t* msg);
  command uint8_t payloadLength(message_t* msg);
  command void setPayLoadLength(message_t* msg, uint8_t len);
  command uint8_t maxPayloadLength();
  command void* getPayload(message_t* msg, uint8_t* len);
}

Figure 1.2: The AMPacket interface. The address command returns the address of the local node.

interface AMPacket {
  command am_addr_t address();
  command am_addr_t destination(message_t* amsg);
  command void setDestination(message_t* amsg, am_addr_t addr);
  command bool isForMe(message_t* amsg);
  command am_id_t type(message_t* amsg);
  command void setType(message_t* amsg, am_id_t t);
}

Figure 1.3: The AMSend interface.

interface AMSend {
  command error_t send(am_addr_t addr, message_t* msg, uint8_t len);
  command error_t cancel(message_t* msg);
  event void sendDone(message_t* msg, error_t error);

  command uint8_t maxPayloadLength();
  command void* getPayload(message_t* msg);
}

The AMPacket interface provides accessors to two additional fields : destination and type(figure 1.2). The type of an active message is a one-byte integer to identify the data format. Though it also provides commands to set these fields, this is solely for specific purposes beyond the scope of this document. The fields will be set during the send process by the send component, specified by AMSend (figure 1.3). We can indeed notice the addr parameter of the send command. There is no way to specify the type though. It is because AMSend implementors provide a parameterized interface, with the type as a parameter. This let co-existing protocols share a fair sending queue, managed by the sender component.

Since all layers share the same packet buffer, and all rely on a specific interface to manipulate messages, a single interface to receive packets is needed. It is named Receive, as shown on figure 1.4. The commands associated to the payload are only here for convenience.

One can notice that the receive handler is required to return a message_t buffer when a packet is received. This is a system to avoid memory leaks. Indeed, the receive component has to know when the packet is processed and the buffer available, so that it can use the buffer for another received packet. If the receive handler has to process several packets, it could keep all the buffers (which are statically allocated). This would let the receive component out of memory, and would prevent other components from receiving messages. By returning a buffer, the receive handler provides to the receive component a buffer that can be used for then next packet that is received. The receive handler can either process the packet and return the given buffer, or post a processing task and return a new buffer.

Figure 1.4: The Receive interface.

interface Receive {
  event message_t* receive(message_t* msg, void* payload, uint8_t len);
  command void* getPayload(message_t* msg, uint8_t* len);
  command uint8_t payloadLength(message_t* msg);
}

Network layer

Since TinyOS 2.0 is quite recent (released on November 6th, 2006), the default distribution does not provide many generic components to implement a routing protocol. So far, it only provides the implementation of Dissemination and Collection, two address-free protocols to transport small packets in an arborescent topology.

However, interesting work had been done for TinyOS 1.x. A modular network layer was designed to ease implementation of new protocols and code reuse. Some parts of this layer were implemented and provided with TinyOS distribution. This work gives a good basis for our design, it was therefore adapted to TinyOS 2 and our needs. This is discussed in next section.

Architecture of the implementation

This section describe the components involved in the implementation of DYMO, and how they are linked together. We will first review the general layout of the components, and give more details about each of them afterwards.

Overview

Figure 1.5: General layout of the components. To avoid complicating even more the diagram, Packet interfaces are not represented. They would have appeared each time another type of packet is used or provided.

The goal of the implementation is to provide to an application a component in order to transparently send and receive data in a multihop network. We have called this component DymoNetworkC, which is a configuration. The wiring provided by this configuration is illustrated in figure 1.5. Since DYMO is a routing protocol, the configuration must include a datagram protocol to transport data on multi-hop routes. It can be any protocol using the same address format as DYMO, a 16-bit address in this case. In this document, we refer to the transport protocol as MH (for Multi-Hop).

To be used, the network layer need to be started with the SplitControl interface. This is implemented by a dedicated module, NetControlM, which waits for all other components to start before letting the application using the network layer (ActiveMessageC implements the link layer). The application can then send and receive MHPackets, which can be manipulated with the appropriate module.

Sent and received packets are handled by the DispatcherM module, and passed to either DymoServiceC or MHServiceC, depending on their AM type. These two components inspect the packet and decide what to do with it: forwarding it, passing it to the upper layer (for MHServiceC), or dropping it.

Forwarded packets (which include sent packets) are given to AMSenderC, which manages a sendinq queue for each AM type. Service components can also generate packets, primarily to send control packets (routing and error messages for DYMO, error messages for MH). They decide what is the next hop of the packet thanks to the routing table component.

Protocol services

The DymoServiceC (figure 1.6) and MHServiceC (figure 1.7) configurations contain the components that implement the algortihms and packet format of their respective protocols. Each of them is composed of three parts: a forwarding engine, a protocol engine, and a packet implementation.

Figure 1.6: Layout of the DYMO service component.
Figure 1.7: Layout of the MH service component.

The ForwardingEngineM module has a very simple role and is identical for the two protocol services. Upon receiving a packet from the dispatcher through the forward command, it asks the routing engine for what should be done with this packet. The routing engine inspects the packet thanks to the packet module, decides what to do according to the implemented protocol, and possibly updates the packet if it has to be forwarded. It returns its decision to the forwarding engine, which performs the appropriate action.

If processing a packet is too long, the routing engine may immediately return a ``drop'' action, process the packet and forward it by itself or send an arror message, since it also has access to the AMSend interface.

Routing table

The DymoTableC component stores known routes, that is mainly a destination address, a next hop and a hop count. Routing information is retrieved from the table via RoutingTable, a generic interface for routing tables (described in section 1.3.1). The DymoEngineM module has more control thanks to the DymoTable interface, mainly to update the table and know when a route is needed, so that a route request can be issued.

New interfaces

To set the network layout provided by our implementation and let components communicate with each other, a number of new interfaces were needed in addition to those provided by TinyOS distribution. This section deals with these interfaces.


Routing Tables

Due to the fact that the routing table is shared by two protocols with different purposes, two different interfaces to manipulate the routing table were needed. The first one (figure 1.8) is a generic one, that could be used for any routing table. It provides access to the information stored in the routing table. The second one (figure 1.9) is specific to the implementation, and provides more information and control to the users.

Figure 1.8: The RoutingTable interface.

interface RoutingTable {
  /**
   * Request for a route toward a destination.
   * @param Address of the destination node
   * @return The routing information associated to the destination
   */
  command rt_info_t * getRoute(addr_t address);

  /**
   * Signal that a route has been removed from the table.
   * @param route_info Routing information associated to the evicted entry
   * @param r reason of the eviction
   */
  event void evicted(rt_info_t * route_info, reason_t r);

  command uint16_t size();
}

Figure 1.9: The DymoTable interface.

interface DymoTable {
  /**
   * Update the table with fresh information about a destination.
   * @param route_info The routing information associated to the destination
   */
  command void update(rt_info_t * route_info);

  /**
   * Signal that a component asked for an unknown route, a RREQ should
   * be generated.
   * @param destination Target node of the needed route.
   */
  event void routeNeeded(addr_t destination);
}