On Thu, 2006-02-16 at 18:09 -0700, Chad Metcalf wrote: > I've started playing with TinyOS 2.0 and got everything up and running > on Ubuntu (sort of). I did a manual of TinyOS 1.x install so keeping > backwards compatibility on a Debian based system required some > effort. > > Some things are broken like the top level Makefile for the apps. I > might have caused this with my rpm2tgz variety install (yes I know > alien but I didn't want the default installation directories of /usr > and /opt). But it seems the apps themselves are fine and its probably > the special version of make that I don't have. > > I do have several questions. > > Anyone else using a non-rpm Linux based system to work with 2.0? And > if so what work arounds have you found yourself needing? > > Is there any documentation on the 2.0 version of TOSSIM? I'm guessing > "make null sim" is the equivalent of "make pc sim" and I've found the > two examples in $TOSDIR/lib/tossim/examples but I'm lost now. I found > http://www.tinyos.net/dist-2.0.0/tinyos-2.0.0beta1/doc/ but TOSSIM > isn't part of it.
The null platform doesn't do anything; if you try to simulate it,
nothing will happen.
Currently, the only platform that TOSSIM supports is micaz. I've been
working on a tutorial, which I hope will be ready some time next week.
I've attached the draft as it is now, I hope this can help you get
started. It doesn't yet talk about some of the more advanced features,
such as injecting packets, inspecting variables, or C++. I think one of
the example scripts shows fetching a variable, though. One of the basic
goals of the variable code is so you can do something like this:
v = m.getVariable("RouterC.hasParent")
while v.getData():
t.runNextEvent()
# some code to print out connectivity, etc.
Phil
Title: Lesson T: Simulation with TOSSIM
$Id: lesson-t.html,v 1.1.2.2 2006/02/14 02:51:21 scipio Exp $
This lesson introduces the TOSSIM simulator. You will become familiar with how to compile TOSSIM and use some of its functionality. You will learn how to:
- Compile TOSSIM.
- Configure a simulation in Python and C++.
- Inject packets.
- Inspect variables.
Introduction
TOSSIM simulates entire TinyOS applications. It works by replacing components with simulation implementations. The level at which components are replaced is very flexible: for example, there is a simulation implementation of millisecond timers that replaces HilTimerMilliC, while there is also an implementation for atmega128 platforms that replaces the HPL components of the hardware clocks. The former is general and can be used for any platform, but lacks the fidelity of capturing an actual chips behavior, as the latter does. Similarly, TOSSIM can replace a packet-level communication component for packet-level simulation, or replace a low-level radio chip component for a more precise simulation of the code execution. TOSSIM is a discrete event simulator. When it runs, it pulls events of the event queue (sorted by time) and executes them. Depending on the level of simulation, simulation events can represent hardware interrupts or high-level system events (such as packet reception). Additionally, tasks are simulation events, so that posting a task causes it to run a short time (e.g., a few microseconds) in the future. TOSSIM is a library: you must write a program that configures a simulation and runs it. TOSSIM supports two programming interfaces, Python and C++. Python allows you to interact with a running simulation dynamically, like a powerful debugger. However, as the interpretation can be a performance bottleneck when obtaining results, TOSSIM also has a C++ interface. Usually, transforming code from one to the other is very simple. TOSSIM currently does not support gathering power measurements.Compiling TOSSIM
TOSSIM is a TinyOS library. Its core code lives in tos/lib/tossim. Every TinyOS source directory has an optional sim subdirectory, which contains simulation implementations of that package. For example, tos/chips/atm128/timer/sim contains TOSSIM implementations of some of the Atmega128 timer abstractions.
To compile TOSSIM, you pass the sim option to make:
$ cd apps/Blink
$ make micaz sim
Currently, the only platform TOSSIM supports is the micaz. You should see output similar to this:
mkdir -p build/micaz
placing object files in build/micaz
writing XML schema to app.xml
compiling BlinkAppC to object file sim.o
ncc -c -fPIC -o build/micaz/sim.o -g -O0 -tossim -fnesc-nido-tosnodes=1000 -fnesc-simulate -fnesc-nido-motenumber=sim_node\(\) -finline-limit=100000 -Wall -Wshadow -DDEF_TOS_AM_GROUP=0x7d -Wnesc-all -target=micaz -fnesc-cfile=build/micaz/app.c -board=micasb -Wno-nesc-data-race BlinkAppC.nc -fnesc-dump=components -fnesc-dump=variables -fnesc-dump=constants -fnesc-dump=typedefs -fnesc-dump=interfacedefs -fnesc-dump=tags -fnesc-dumpfile=app.xml
compiling Python support into pytossim.o and tossim.o
g++ -c -shared -fPIC -o build/micaz/pytossim.o -g -O0 /home/pal/src/tinyos-2.x/tos/lib/tossim/tossim_wrap.cxx -I/usr/include/python2.3 -I/home/pal/src/tinyos-2.x/tos/lib/tossim -DHAVE_CONFIG_H
g++ -c -shared -fPIC -o build/micaz/tossim.o -g -O0 /home/pal/src/tinyos-2.x/tos/lib/tossim/tossim.c -I/usr/include/python2.3 -I/home/pal/src/tinyos-2.x/tos/lib/tossim
linking into shared object ./_TOSSIMmodule.so
g++ -shared build/micaz/pytossim.o build/micaz/sim.o build/micaz/tossim.o -lstdc++ -o _TOSSIMmodule.so
copying Python script interface TOSSIM.py from lib/tossim to local directory
Compiling TOSSIM has five basic steps. Let's go through them one by one.
Writing an XML schema
writing XML schema to app.xml
The first thing the TOSSIM build process does is use nesc-dump to produce an XML document that describes the application. Among other things, this document descibes the name and type of every variable.
Compiling the TinyOS Application
Besides introducing all of these new compilation steps, the sim option changes the include paths of the application. If the application has a series of includes
-Ia -Ib -Ic
Then the sim option transforms the list to
-Ia/sim -Ib/sim -Ic/sim -I%T/lib/tossim -Ia -Ib -Ic
This means that any system-specific simulation implementations will be used first, followed by generic TOSSIM implementations, followed by standard implementations. The sim option also passes a bunch of arguments to the compiler, so it knows to compile for simulation.
The product of this step is an object file, sim.o, which lives in the platform's build directory. This object file has a set of C functions which configure the simulation and control execution.
Compiling the Programming Interface
compiling Python support into pytossim.o and tossim.o
g++ -c -shared -fPIC -o build/micaz/pytossim.o -g -O0 \
/home/pal/src/tinyos-2.x/tos/lib/tossim/tossim_wrap.cxx \
-I/usr/include/python2.3 -I/home/pal/src/tinyos-2.x/tos/lib/tossim \
-DHAVE_CONFIG_H
g++ -c -shared -fPIC -o build/micaz/tossim.o -g -O0 \
/home/pal/src/tinyos-2.x/tos/lib/tossim/tossim.c \
-I/usr/include/python2.3 -I/home/pal/src/tinyos-2.x/tos/lib/tossim
The next step compiles the support for the C++ and Python programming interfaces. The Python interface is actually built on top of the C++ interface. Calling a Python object calls a C++ object, which then calls TOSSIM through the C interface. tossim.o contains the C++ code, while pytossim.o contains the Python support. These files have to be compiled separately because C++ doesn't understand nesC, and nesC doesn't understand C++.
Building the shared object
linking into shared object ./_TOSSIMmodule.so
g++ -shared build/micaz/pytossim.o build/micaz/sim.o build/micaz/tossim.o -lstdc++ -o _TOSSIMmodule.so
The next to last step is to build a shared library that contains the TOSSIM code, the C++ support, and the Python support.
Copying Python Support
copying Python script interface TOSSIM.py from lib/tossim to local directory
Finally, there is the Python code that calls into the shared object. This code exists in lib/tossim, and the make process copies it into the local directory.
Running TOSSIM with Python
Go into the RadioCountToLeds application and build TOSSIM:
$ cd tinyos-2.x/apps/RadioCountToLeds
$ make micaz sim
We'll start with running a simulation in Python. You can either write a script and just tell Python to run it, or you can use Python interactively. We'll start with the latter. Fire up your Python interpreter:
$ python
You should see a prompt like this:
Python 2.3.4 (#1, Nov 4 2004, 14:13:38)
[GCC 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
The first thing we need to do is import TOSSIM and create a TOSSIM object. Type
>>> from TOSSIM import *
>>> t = Tossim([])
The square brackets are an optional argument that lets you access variables in the simulation. We'll get to how to use that later. In this case, we're telling TOSSIM that there are no variables that we want to look at. The way you run a TOSSIM simulation is with the runNextEvent function. For example:
>>> t.runNextEvent()
0
When you tell TOSSIM to run the next event, it returns 0. This means that there was no next event to run. The reason is simple: we haven't told any nodes to boot. This snippet of code will tell mote 32 to boot at time 45654 and run its first event (booting):
>>> m = t.getNode(32);
>>> m.bootAtTime(45654);
>>> t.runNextEVent()
1
Now, runNextEvent returns 1, because there was an event to run. But we have no way of knowing whether the node has booted or not. We can find this out in one of two ways. The first is that we can just ask it:
>>> m.isOn()
1
>>> m.turnOff()
>>> m.isOn()
0
>>> m.bootAtTime(560000)
>>> t.runNextEvent()
0
>>> t.runNextEvent()
1
Note that the first runNextEvent returned 0. This is because when we turned the mote off, there was still an event in the queue, for its next timer tick. However, since the mote was off when the event was handled in that call, runNextEvent returned 0. The second call to runNextEvent returned 1 for the second boot event, at time 560000.
Debugging Statements
The second approach to know whether a node is on is to tell it to print something out when it boots. TOSSIM has a debugging output system, called dbg. There are four dbg calls:
- dbg: print a debugging statement preceded by the node ID.
- dbg_clear: print a debugging statement which is not preceded by the node ID. This allows you to easily print out complex data types, such as packets, without interspersing node IDs through the output.
- dbgerror: print an error statement preceded by the node ID
- dbgerror_clear: print an error statement which is not preceded by the node ID
Go into RadioCountToLedsC and modify the Boot.booted event to print out a debug message when it boots, such as this:
event void Boot.booted() {
call Leds.led0On();
dbg("Boot", "Application booted.\n");
call AMControl.start();
}
Calls to the debugging calls take two or more parameters. The first parameter ("Boot" in the above example) defines the output channel. An output channel is simply a string. The second and subsequent parameters are the message to output. They are identical to a printf statement. For example RadioCountToLedsC has this call:
event message_t* Receive.receive(message_t* bufPtr, void* payload, uint8_t len) {
dbg("RadioCountToLedsC", "Received packet of length %hhu.\n", len);
...
}
which prints out the length of received packet as an 8-bit unsigned value (%hhu).
Once you have added the debugging statement to the event, recompile the application with make micaz sim and start up your Python interpreter. Load the TOSSIM module and schedule a mote to boot as before:
>>> from TOSSIM import *
>>> t = Tossim([])
>>> m = t.getNode(32);
>>> m.bootAtTime(45654);
This time, however, we want to see the debugging message that the mote has booted. TOSSIM's debugging output can be configured on a per-channel basis. So, for example, you can tell TOSSIM to send the "Boot" channel to standard output, but another channel, say "AM", to a file. Additionally, you can configureBy default, a channel has no destination, and so messages to it are discarded.
In this case, we want to send the Boot channel to standard output. To do this, we need to import the sys Python package, which lets us refer to standard out. We can then tell TOSSIM to send Boot messages to this destination:
>>> import sys
>>> t.addChannel("Boot", sys.stdout);
1
The return value shows that the channel was added successfully. Run the first
simulation event, and the mote boots:
>>> t.runNextEvent()
DEBUG (32): Application booted.
1
The only difference between debug and error functions is the string output at the beginning of a message. Debug statements print DEBUG (n), while error statements print ERROR (n).
A debugging statement can have multiple output channels. Each channel name is delimited by commas:
event void Boot.booted() {
call Leds.led0On();
dbg("Boot,RadioCountToLedsC", "Application booted.\n");
call AMControl.start();
}
If a statement has multiple channels and those channels
share outputs, then TOSSIM only prints the message once. For
example, if both the Boot channel and RadioCountToLedsC
channel were connected to standard out, TOSSIM will only
print one message. For example, this series of debug statements
event void Boot.booted() {
call Leds.led0On();
dbg("Boot,RadioCountToLedsC", "Application booted.\n");
dbg("RadioCountToLedsC", "Application booted again.\n");
dbg("Boot", "Application booted a third time.\n");
call AMControl.start();
}
when configured so
>>> import sys
>>> t.addChannel("Boot", sys.stdout)
>>> t.addChannel("RadioCountToLedsC", sys.stdout)
will print out this:
DEBUG (32): Application booted.
DEBUG (32): Application booted again.
DEBUG (32): Application booted a third time.
A channel can have multiple outputs. For example, this script will tell TOSSIM to write RadioCountToLedsC messages to standard output, but to write Boot messages to both standard output and a file named log.txt:
>>> import sys
>>> f = open("log.txt", "w")
>>> t.addChannel("Boot", f)
>>> t.addChannel("Boot", sys.stdout)
>>> t.addChannel("RadioCountToLedsC", sys.stdout)
Configuring a Network
When you start TOSSIM, no node can communicate with any other. In order to be able to simulate network behavior, you have to specify a network topology. Internally, TOSSIM is structured so that you can easily change the underlying radio simulation, but that's beyond the scope of this tutorial. The default TOSSIM radio model is signal-strength based. You provide a graph to the simulator that describes the propagation strengths. You also specify noise floor, and receiver sensitivity. There are some very early results that describe current sensor platforms (e.g., the mica2) in these terms. Because all of this is through a scripting interface, rather than provide a specific radio model, TOSSIM tries to provide a few low-level primitives that can express a wide range of radios and behavior.
You control the radio simulation through a Python Radio object:
>>> from TOSSIM import *
>>> t = Tossim([])
>>> r = t.radio()
>>> dir(r)
['__class__', '__del__', '__delattr__', '__dict__', '__doc__',
'__getattr__', '__getattribute__', '__hash__', '__init__',
'__module__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__str__', '__swig_getmethods__',
'__swig_setmethods__', '__weakref__', 'add', 'connected',
'gain', 'remove', 'setNoise', 'this', 'thisown',
]
The first set of methods (with the double underscores) are ones that you usually don't call. The important ones are at the end. They are:
- add(src, dest, gain): Add a link from src to dest with gain. When src transmits, dest will receive a packet attenuated by the gain value.
- connected(src, dest): Return whether there is a link from src to dest.
- gain(src, dest): Return the gain value of the link from src to dest.
- remove(src, dest): Remove the link from src to dest.
- setNoise(node, mean, variance): Set the noise floor at node to be a gaussian distribution with mean and variance.
- sensitivity(): Return the receive sensitivity of the nodes.
- setSensitivity(val): Set the receive sensitivity of nodes to be val. The sensitivity is how much stronger a signal must be for it to be received uncorrupted. E.g., a sensitivity of 3.0 (the default value) means that a packet must be 3dBm greater than the sum of noise and concurrent transmissions for it to be received uncorrupted.
- threshold(): Return the CCA threshold.
- setThreshold(val): Set the CCA threshold value in dBm.The default is -77.
The Radio object only deals with physical layer propagation. The MAC object deals with the data link layer, packet lengths, and radio bandwidth. The default TOSSIM MAC object is for a CSMA protocol. You get a reference to the MAC object by calling mac() on a Tossim object:
>>> mac = t.mac()
The default MAC object has a large number of functions, for
controlling backoff behavior, packet preamble length, radio
bandwidth, etc. All time values are specified in terms of
radio symbols, and you can configure the number of symbols
per second and bits per symbol. By default, the MAC object
is configured to act like the standard TinyOS 2.0 CC2420
stack: it has 4 bits per symbol and 64k symbols per second,
for 256kbps. This is a subset of the MAC functions that
could be useful for changing backoff behavior. Every
accessor function has a corresponding set function that
takes an integer as a parameter. E.g., there's int
initHigh() and void setInitHigh(int val). The
default value for each parameter is shown italicized in
parentheses.
- initHigh: The upper bound of the initial backoff range. (400)
- initLow: The lower bound of the initial backoff range. (20)
- high: The upper bound of the backoff range. This is multiplied by the exponent base to the nth power, where n is the number of previous backoffs. So if the node had its initial backoff, then the upper bound is high * base, while if it is after the second backoff then the upper bound is high * base * base. (160)
- low: The lower bound of the backoff range. This is multiplied by the exponent base to the nth power, where n is the number of previous backoffs. So if the node had its initial backoff, then the upper bound is low * base, while if it is after the second backoff then the upper bound is low * base * base. (20)
- symbolsPerSec: The number of symbols per second that the radio can transmit. (65536)
- bitsPerSymbol: The number of bits per radio symbol. Multiplying this by the symbols per second gives the radio bandwidth. (4)
- preambleLength: How long a packet preamble is. This is added to the duration of transmission for every packet. (12)
- exponentBase: The base of the exponent used to calculate backoff. Setting it to 2 provides binary exponential backoff. (0).
- maxIterations: The maximum number of times the radio will back off before signaling failure, zero signifies forever. (0).
- minFreeSamples: The number of times the radio must detect a clear channel before it will transmit. This is important for protocols like 802.15.4, whose synchonrous acknowledgments requires that this be greater than 1 (you could have sampled in the dead time when the radios are changing between RX and TX mode). (2)
- rxtxDelay: The time it takes to change the radio from RX to TX mode (or vice versa).(32)
- ackTime: The time it takes to transmit a synchonrous acknowledgment, not including the requisite RX/TX transition.(34)
Any and all of these configuration constants can be changed at compile time with #define directives. Look at tos/lib/tossim/sim_csma.h.
Because the radio connectivity graph can be scripted, you can easily store topologies in files and then load the file. Alternatively, you can store a topology as a script. For example, this script will load a file which specifies each link in the graph as a line with three values, the source, the destination, and the gain, e.g.:
1 2 -54.0
means that when 1 transmits 2 hears it at -54 dBm. Create a file topo.txt
that looks like this:
1 2 -54.0
2 1 -55.0
1 3 -60.0
3 1 -60.0
2 3 -64.0
3 2 -64.0
This script will read such a file:
>>> f = open("topo.txt", "r")
>>> lines = f.readlines()
>>> for line in lines:
... s = line.split()
... if (len(s) > 0):
... print " ", s[0], " ", s[1], " ", s[2];
... r.add(int(s[0]), int(s[1]), float(s[2]))
Now, when a node transmits a packet, other nodes will hear it. This is a complete script for simulating packet transmission with RadioCountToLedsC. Save it as a file test.py:
from TOSSIM import *
import sys
t = Tossim([])
r = t.radio()
f = open("topo.txt", "r")
lines = f.readlines()
for line in lines:
s = line.split()
if (len(s) > 0):
print " ", s[0], " ", s[1], " ", s[2];
r.add(int(s[0]), int(s[1]), float(s[2]))
t.addChannel("RadioCountToLedsC", sys.stdout)
t.addChannel("Boot", sys.stdout)
t.getNode(1).bootAtTime(100001);
t.getNode(2).bootAtTime(800008);
t.getNode(3).bootAtTime(1800009);
r.setNoise(1, -80.0, 5.0)
r.setNoise(2, -80.0, 5.0)
r.setNoise(3, -80.0, 5.0)
for i in range(0, 100):
t.runNextEvent()
Run it by typing python test.py. You should see output that looks like this:
1 2 -54.0
2 1 -55.0
1 3 -22.1
DEBUG (1): Application booted.
DEBUG (1): Application booted again.
DEBUG (1): Application booted a third time.
DEBUG (2): Application booted.
DEBUG (2): Application booted again.
DEBUG (2): Application booted a third time.
DEBUG (3): Application booted.
DEBUG (3): Application booted again.
DEBUG (3): Application booted a third time.
DEBUG (1): RadioCountToLedsC: timer fired, counter is 1.
DEBUG (1): RadioCountToLedsC: packet sent.
DEBUG (2): RadioCountToLedsC: timer fired, counter is 1.
DEBUG (2): RadioCountToLedsC: packet sent.
DEBUG (3): RadioCountToLedsC: timer fired, counter is 1.
DEBUG (3): RadioCountToLedsC: packet sent.
DEBUG (1): Received packet of length 2.
DEBUG (3): Received packet of length 2.
DEBUG (2): Received packet of length 2.
DEBUG (1): RadioCountToLedsC: timer fired, counter is 2.
DEBUG (1): RadioCountToLedsC: packet sent.
DEBUG (2): RadioCountToLedsC: timer fired, counter is 2.
DEBUG (2): RadioCountToLedsC: packet sent.
DEBUG (3): RadioCountToLedsC: timer fired, counter is 2.
DEBUG (3): RadioCountToLedsC: packet sent.
DEBUG (1): Received packet of length 2.
Variables
TOSSIM allows you to inspect variables in a running TinyOS program.
Conclusions
This lesson has introduced radio communications TinyOS 2.x.Related Documentation
_______________________________________________ Tinyos-help mailing list [email protected] https://mail.millennium.berkeley.edu/cgi-bin/mailman/listinfo/tinyos-help
