Because flash storage implementations are chip-specific, you usually find them in atos/chipsdirectory. For example, the mica family of nodes has an AT45DB-family flash chip: when you use one of the above abstractions on a mica, you use the components intos/chips/at45db.
A.6
Data structures
TinyOS has component implementations of a few commonly used data structures. All of these can be found intos/system.
A.6.1 BitVectorC
BitVectorC provides the abstraction of a bit vector. It takes a single parameter, the width of the vector. The BitVector interface has commands for getting, setting, clearing, and toggling individual bits or all of the bits at once. Because of nesC’s heavy inlining, using BitVectorC is preferable to writing your own bit vector macros within a component. BitVectorC allocates dN8e bytes for an N -bit wide vector.
generic module BitVectorC(uint16_t max_bits) {
provides interface BitVector;
}
A.6.2 QueueC
QueueC provides the abstraction of a queue of items with a fixed maximum size. It takes two parameters: the type of the items it stores and the maximum size of the queue. The Queue interface has commands for enqueuing items on the end of the queue, dequeueing the head of the queue, and commands for checking the queue size. It also allows random-access lookup: you can scan the queue.
generic module QueueC(typedef queue_t, uint8_t QUEUE_SIZE) {
provides interface Queue<queue_t>; }
QueueC is used heavily in networking protocols. A routing protocol, for example, often creates a QueueC of pointers to message buffers (message t*) for its forwarding queue, as well as a PoolC (see below) to allocate a number of buffers so it can receive packets to forward.
A.6.3 BigQueueC
The uint8 t parameter to QueueC limits its maximum size to 255. For most uses, this is sufficient and so wasting extra bytes on its internal fields to support a larger size is not worth it. However, sometimes components need a larger queue. The printf library, for example (page 134), has a queue of bytes to send, which is usually longer than 255. TinyOS therefore also has BigQueueC, which is essentially identical to QueueC except that it has a 16-bit size parameter and provides the interface BigQueue:
generic module BigQueueC(typedef queue_t, uint16_t QUEUE_SIZE) {
provides interface BigQueue<queue_t> as Queue; }
A.6.4 PoolC
PoolC is the closest thing TinyOS has to a dynamic memory allocator. It takes two parameters: the type of object to allocate, and how many. Components can then dynamically allocate and free these objects to the
133 A.7. Utilities
pool. But as the maximum pool size is set at compile time, a memory leak will cause the pool to empty, rather than cause the heap and stack to collide.
Because it does the allocation, you specify a type to PoolC, but its commands use pointers to that type. For example, if you allocate a pool ofmessage tbuffers, then calls to Pool passmessage t*.
generic configuration PoolC(typedef pool_t, uint8_t POOL_SIZE) {
provides interface Pool<pool_t>; }
You can swap data items between pools. For example, if you have two separatemessage tpools P1 and P2, it is OK to allocate M1from P1and M2from P2, yet free M1into P2and M2into P1. This behavior is critically important due to the buffer-swapping semantics of Receive. If a component receives a packet it wants to forward, it allocates a buffer from its pool and returns this new buffer to the link layer. The next packet – whose buffer came from the pool – might go to another component, which has its own pool. So the pseudocode for forwarding a packet looks something like this:
receive(m): if (!forward(m)): return m setHeaders(m) queue.put(m) m2 = pool.get() return m2 A.6.5 StateC
StateC provides an abstraction of a state machine. This is useful when multiple components need to share a global state (such as whether the subsystem is on or off).
generic configuration StateC() {
provides interface State;
}
A.7
Utilities
TinyOS provides components for several commonly-used functions and abstractions.
A.7.1 Random numbers
RandomC provide the interface Random, which components can use to generate random numbers. RandomC also provides the interfaces Init and ParameterInit, to enable a component re-initialize RandomC’s random seed. By default, RandomC’s seed is initialized to the node ID+1.
TinyOS includes two random number generators: RandomMlcgC (a multiplicative linear congruential generator) and RandomLfsrC (a linear feed shift register generator). RandomLfsrC is faster, but RandomMlcgC produces better random numbers. By default, RandomC refers to RandomMlcgC.
configuration RandomC {
provides interface Init;
provides interface ParameterInit<uint16_t> as SeedInit;
provides interface Random as Random;
A.7. Utilities 134
configuration RandomMlcgC {
provides interface Init;
provides interface ParameterInit<uint16_t> as SeedInit;
provides interface Random as Random;
}
configuration RandomLfsrC {
provides interface Init;
provides interface ParameterInit<uint16_t> as SeedInit;
provides interface Random as Random;
}
A.7.2 Leds
LedsC provides an abstraction of 3 LEDs. While some platforms have more or fewer than 3, the Leds interface has 3 for historical reasons. Also, breaking up the LEDs into 3 instances of the same interface would be a lot of extra wiring. In addition to LedsC, there is also a NoLedsC, which can be dropped in as a null replacement: calls to NoLedsC do nothing.
configuration LedsC {
provides interface Leds;
}
configuration NoLedsC {
provides interface Leds;
}
A.7.3 Cyclic redundancy checks
Cyclic redundancy checks (CRCs) are a simple way to check whether a piece of data has been corrupted. After the data, you append a CRC. Someone reading the data can recompute the CRC over the data and check that it matches the appended CRC. If the two do not match, there is a bit error either in the data or the CRC itself. Since the CRC is usually much shorter than the data, the assumption is the data has been corrupted. CRCs are heavily used in networking, to check the validity of a packet. Of course, since CRCs are shorter than the data itself, it’s possible, but unlikely, for a corrupted packet to pass a CRC check.
CRC values are distinct from cryptographic hashes. CRCs are intended to detect bursts of bit errors. Typically, an n-bit CRC can always detect a single error burst that is shorter than n bits. In contrast, cryptographically strong hashes have entropy properties that make detecting (or failing to detect) any kind of error uniformly likely.
module CrcC {
provides interface Crc;
}
The module CrcC can be found intos/system.
A.7.4 Printf
Sometimes, when debugging, it can very useful to have a mote send simple text messages. TinyOS has a printf – like the C standard library function – library for this purpose. You can use printf in your components, and the printf library will send appropriate packets over the serial port. You must start the printf library via PrintfC’s SplitControl.start.