『TinyOS』学习笔记 #11?

Lesson 11  TOSSIM 

Compiling TOSSIM

 

 make micaz sim

 

 

Running TOSSIM with Python

 

tos的模拟器是在python中运行

 

运行TOSSIM simulation 用到 runNextEvent function。it returns 0. This means that there was no next event to run. returns 1, there was an event to run.

 

 

Debugging Statements 

 

  • 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  

 

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, "RadioCountToLedsC", to a file. 这个channel名可以自己定义, dbg可以通过名字选择性的输出想要的信息。 比如t.addChannel("Boot", sys.stdout) 输出channel名为Boot的debug信息, 也就是执行到dbg("Boot", "Application booted.\n")这个就会输出,而dbg("my", "Application booted.\n")不会输出,因为没有加入my这个channel

 

By default, a channel has no destination and messages to it are discarded.

 

 

dbg("Boot", "Application booted.\n"); 

 

 

dbg() takes two or more parameters:

  • The first parameter ("Boot" in the above example) defines the output channel. An output channel is a string.
  • The second and subsequent parameters are the message to output and variable formatting. dbg() is identical to a sprintf statement in C++. 

debug and error functions 的唯一区别是 he string output at the beginning of a message. Debug statements print DEBUG (n), Error statements print ERROR (n).

 

If a statement has multiple channels and those channels share outputs, then TOSSIM only prints the message once. For example:

 

dbg("Boot,RadioCountToLedsC", "Application booted.\n");

 

if both the Boot channel and RadioCountToLedsC channel were connected to standard out, TOSSIM will only print one message. 

 

 

Configuring a Network

 

radio object

 

  • 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.
  • threshold(): Return the CCA threshold.
  • setThreshold(val): Set the CCA threshold value in dBm. The default is -72dbM.

 

MAC object 

 

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.

 

 

 

the radio connectivity data can be stored in a flat file, you can easily create topologies in files and then load the file using a Python script and store them into the radio object.

 

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 file specifies each link in the graph as a line with three values, the source, the destination, and the gain.

 

This script will read the file and store the data in the radio object:

>>> 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]))

 

这一章还介绍了 TOSSIM用于测试的完整的python脚本。

 

#! /usr/bin/python
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)

noise = open("meyer-heavy.txt", "r")
lines = noise.readlines()
for line in lines:
  str = line.strip()
  if (str != ""):
    val = int(str)
    for i in range(1, 4):
      t.getNode(i).addNoiseTraceReading(val)

for i in range(1, 4):
  print "Creating noise model for ",i;
  t.getNode(i).createNoiseModel()

t.getNode(1).bootAtTime(100001);
t.getNode(2).bootAtTime(800008);
t.getNode(3).bootAtTime(1800009);

for i in range(0, 100):
  t.runNextEvent()
 

还有如何生成 network topology 和相关的信噪比。 详情请见原文

 

 

Variables 

 

TOSSIM allows you to inspect variables in a running TinyOS program. Currently, you can only inspect basic types. For example, you can't look at fields of structs, but you can look at state variables.

 

用来在python中来查阅tinyos程序(nesC程序)中的变量情况, 比如变量的值,类型等。可以利用这个功能来观察程序运行的状态等情况。

 

例子

from sys import *
from random import *
from TOSSIM import *
from tinyos.tossim.TossimApp import *   #引入库

n = NescApp()  #实例化
t = Tossim(n.variables.variables()) #获取变量列表并传入Tossim对象
r = t.radio()

f = open("topo.txt", "r")
lines = f.readlines()
for line in lines:
  s = line.split()
  if (len(s) > 0):
    if (s[0] == "gain"):
      r.add(int(s[1]), int(s[2]), float(s[3]))

noise = open("meyer-heavy.txt", "r")
lines = noise.readlines()
for line in lines:
  str = line.strip()
  if (str != ""):
    val = int(str)
    for i in range(0, 4):
      t.getNode(i).addNoiseTraceReading(val)

for i in range (0, 4):
  t.getNode(i).createNoiseModel()
  t.getNode(i).bootAtTime(i * 2351217 + 23542399)

m = t.getNode(0)
v = m.getVariable("RadioCountToLedsC.counter")  #得到要观察的变量
while (v.getData() < 10):   #getData() 取得观察变量的值
  t.runNextEvent()

print "Counter variable at node 0 reached 10."
 

 

【to be cont... 】

 

 

Injecting Packets

 

TOSSIM allows you to dynamically inject packets into a network. Packets can be scheduled to arrive at any time. If a packet is scheduled to arrive in the past, then it arrives immediately. Injected packets circumvent the radio stack: it is possible for a node to receive an injected packet while it is in the midst of receiving a packet from another node over its radio.

 

可以在Tossim模拟中加入包并发送。

 

 

RadioCountMsg.py defines a packet format, but this packet is contained in the data payload of another format. If a node is sending a RadioCountMsg over AM, then the RadioCountMsg structure is put into the AM payload, and might look something like this:

AM Header RadioCountMsg AM Footer

If it is sending it over a routing protocol. the packet is put in the routing payload, and might look something like this:

AM Header Routing Header RadioCountMsg AM Footer

If you want to send a RadioCountMsg to a node, then you need to decide how to deliver it. In the simple AM case, you place the RadioCountMsg structure in a basic AM packet. In the routing case, you put it in a routing packet, which you then put inside an AM packet. We'll only deal with the simple AM case here.

To get an AM packet which you can inject into TOSSIM, you call the newPacket function on a Tossim object. The returned object has the standard expected AM fields: destination, length, type, and data, as well as strength.

 

 

from RadioCountMsg import *  #include packet format

msg = RadioCountMsg()           #creates a RadioCountMsg
msg.set_counter(7);                #sets its counter to 7
pkt = t.newPacket();                #creates an AM packet
pkt.setData(msg.data)             #stores the RadioCountMsg in the AM packet
pkt.setType(msg.get_amType())     #set AM packet type
pkt.setDestination(0)                      #set AM packet destination

pkt.deliver(0, t.time() + 3)    #delivers pkt to node 0 at the current simulation time plus 3 ticks (e.g., 3ns).
 

 

 

 

 

【to be cont... 】

 

 

 

 

Using gdb

Since Driver is a C++ program, you can use gdb on it to step through your TinyOS code, inspect variables, set breakpoints, and do everything else you can normally do. Unfortunately, as gdb is designed for C and not nesC, the component model of nesC means that a single command can have multiple providers; referring to a specific command requires specifying the component, interface, and command.

 

$ gdb Driver
GNU gdb Red Hat Linux (6.0post-0.20040223.19rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) break *LedsP$Leds$led0Toggle
Breakpoint 1 at 0x804f184: file LedsP.nc, line 73.
 

 

观察程序中的变量

nesC translates component names to C names using $. $ is a legal but almost-never-used character in some versions of C, so nesC prohibits it and uses it internally. The leading * is necessary so dbg can parse the $s. With the above breakpoint set, gdb will break whenever a mote toggles led0.

Variables have similar names. For example, to inspect the packet of RadioCountToLedsC in the RadioCountToLeds application,

 

 (gdb) print RadioCountToLedsC$packet
 $1 = {{header = {{data = ""}, {data = ""}, {data = ""}, {data = ""}, {
         data = ""}}, data = {{data = ""} }, footer = {{
         data = ""}, {data = ""}}, metadata = {{data = ""}, {data = ""}, {
         data = ""}, {data = ""}, {data = ""}}} }
 

 

For those who know gdb very well, you'll recognize this as a print of an array, rather than a single variable: there are more than 1000 instances of the message_t struct. This is because TOSSIM simulates many motes; rather than there being a single RadioCountToLedsC$packet, there is one for every node. To print the packet of a specific node, you have to index into the array. This, for example, will print the variable for node 6:

 (gdb) print RadioCountToLedsC$packet[6]
 $2 = {header = {{data = ""}, {data = ""}, {data = ""}, {data = ""}, {
       data = ""}}, data = {{data = ""} }, footer = {{
       data = ""}, {data = ""}}, metadata = {{data = ""}, {data = ""}, {
       data = ""}, {data = ""}, {data = ""}}}
 

If you want to print out the variable for the node TOSSIM is currently simulating, you can do this:

(gdb) print RadioCountToLedsC$counter[sim_node()]
$4 = 0
 

设置 watchpoint

You can also set watchpoints (although, as to be expected, they are slow:

(gdb) watch CpmModelC$receiving[23]
Hardware watchpoint 2: CpmModelC$receiving[23]
 

This variable happens to be an internal variable in the packet-level network simulation, which keeps track of whether the radio thinks it is receiving a packet. So setting the above watchpoint will cause gdb to break whenever node 23 starts receiving a packet or returns to searching for packet preambles.

 

设置断点break point 

Generic components add another wrinkle. Since they use a code-copying approach, each instance of a generic has its own separate functions and variables (this is mostly due to the fact that you can pass types to them). Take, for example, AMQueueImplP, which is used in both the radio AM stack and the serial AM stack. If you use gdb on an application that uses both serial and radio communication and try to break on its Send.send, you'll see an error:

(gdb) break *AMQueueImplP$Send$send
No symbol "AMQueueImplP$Send$send" in current context.
 

nesC gives each generic a unique number. So if you have an application in which there is a single copy of AMQueueImplP, its name will actually be AMQueueImplP$0. For example, in RadioCountToLeds, this will work:

(gdb) break *AMQueueImplP$0$Send$send
Breakpoint 5 at 0x8051b29: file AMQueueImplP.nc, line 79.
 

If you have multiple instances of a generic in a program, there is unfortunately no easy way to figure out each one's name besides looking at the source code or stepping into them. E.g., if you application uses serial and radio communication, knowing which stack has AMQueueImpl$0 and which has AMQueueImplP$1 requires either stepping through their send operation or looking at their app.c files.

 

你可能感兴趣的:(TinyOS,/,NS-2,for『WSN』)