[Tinyos-2-commits]
CVS: tinyos-2.x/doc/html/tutorial index.html, 1.7,
1.8 lesson1.html, 1.7, 1.8 lesson10.html, 1.3,
1.4 lesson11.html, 1.14, 1.15 lesson12.html, 1.4,
1.5 lesson13.html, 1.3, 1.4 lesson15.html, 1.9,
1.10 lesson16.html, 1.2, 1.3 lesson2.html, 1.4,
1.5 lesson3.html, 1.3, 1.4 lesson4.html, 1.5, 1.6 lesson5.html,
1.5, 1.6 lesson6.html, 1.4, 1.5 lesson7.html, 1.5,
1.6 lesson8.html, 1.7, 1.8
Kevin Klues
klueska at users.sourceforge.net
Sun Jan 27 22:00:05 PST 2008
Update of /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv18117/tutorial
Modified Files:
index.html lesson1.html lesson10.html lesson11.html
lesson12.html lesson13.html lesson15.html lesson16.html
lesson2.html lesson3.html lesson4.html lesson5.html
lesson6.html lesson7.html lesson8.html
Log Message:
Update to tutorials to redirect them to the wiki now instead of directly being modified here anymore
Index: index.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/index.html,v
retrieving revision 1.7
retrieving revision 1.8
diff -C2 -d -r1.7 -r1.8
*** index.html 3 Sep 2007 22:38:41 -0000 1.7
--- index.html 28 Jan 2008 05:59:55 -0000 1.8
***************
*** 1,148 ****
! <!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
! <html>
<head>
! <title>TinyOS Tutorial</title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet" type="text/css">
</head>
!
<body>
!
! <div class="title">TinyOS 2.0 Tutorials </div>
! <div class="subtitle">Last updated 30 Aug 2007</div>
!
! <p>
! These brief tutorials are intended to get you started with TinyOS. They show
! you the basics of writing, compiling, and installing TinyOS applications.
! They introduce the basic TinyOS abstractions: computation, communication,
! sensing, and storage. The later tutorials go a little deeper into some of
! the more advanced areas of TinyOS, such as handling interrupts,
! power management, and how platforms are organized.
! </p>
!
! <h1><a href="lesson1.html">Lesson 1: TinyOS</a></h1>
!
! <dd>Lesson 1 introduces the major concepts of TinyOS: components, modules,
! configurations and interfaces. It shows you how to compile and install
! a TinyOS program on a mote.
! </dd>
!
! <h1><a href="lesson2.html">Lesson 2: Modules and the TinyOS Execution Model</a></h1>
!
! <dd>Lesson 2 explains the TinyOS execution model, looking more closely
! at modules. It explains events, commands and their relationships to
! interfaces in greater depth, introducing split-phase operations.
! It explains tasks, the basic mechanism in TinyOS for components to
! cooperatively share the processor.
! </dd>
!
! <h1><a href="lesson3.html">Lesson 3: Mote-mote radio communication</a></h1>
!
! <dd> Lesson 3 introduces the TinyOS communication model. There is an exercise that
! illustrates sending and receiving messages.
! </dd>
!
! <h1><a href="lesson4.html">Lesson 4: Mote-PC serial communication and SerialForwarder</a></h1>
!
! <dd> Lesson 4 introduces the the TinyOS toolchain for PCs
! and laptops to communicate with motes. It describes the
! concept of a packet source, the <code>mig</code> tool,
! and SerialForwarder.
! </dd>
!
! <h1><a href="lesson5.html">Lesson 5: Sensing</a></h1>
!
! <dd>Lesson 5 explains how to sample sensors in TinyOS. There is an exercise that
! periodically samples a sensor and displays the value on the leds.
! </dd>
!
! <h1><a href="lesson6.html">Lesson 6: Boot Sequence</a></h1>
!
! <dd>Lesson 6 details the boot sequence and, in doing so, answers the question, "But where is main()?".
! </dd>
!
! <h1><a href="lesson7.html">Lesson 7: Storage</a></h1>
!
! <dd> Lesson 7 introduces the TinyOS storage model. Sample
! applications illustrate the use of the Mount, ConfigStorage,
! LogRead and LogWrite interfaces.
! </dd>
!
! <h1><a href="lesson8.html">Lesson 8: Resource Arbitration and Power Management</a></h1>
!
! <dd> Lesson 8 introduces the TinyOS resource arbitration and power management model. There are two
! exercises in this tutorial. The first one illustrates how to gain access to predefined shared resources.
! The second one illustrates how to create your own shared resource. In both tutorials, the process for controlling
! the power states of the resource is presented.
! </dd>
!
! <h1>Lesson 9: Concurrency</h1>
!
! <dd> Lesson 9 introduces the TinyOS concurrency model. Tasks are revisited and async code is introduced.
! This tutorial is currently unfinished.
! </dd>
!
! <h1><a href="lesson10.html">Lesson 10: Platforms</a></h1>
!
! <dd> Lesson 10 provides a better understanding of the difference between "make
! micaz" and "make telosb," including how these commands map into underlying
! files, directories, and definitions. It is not necessary for most TinyOS
! developers, but is included as a starter's guide for people who wish to
! understand the make system better or wish to design a new platform.
! </dd>
!
! <h1><a href="lesson11.html">Lesson 11: TOSSIM</a></h1>
!
! <dd> Lesson 11 introduces TOSSIM, a TinyOS simulator. TOSSIM allows
! you to compile your TinyOS applications into a simulation
! framework, where you can perform reproducible tests and debug
! your code with standard development tools.
! </dd>
!
! <h1><a href="lesson12.html">Lesson 12: Network Protocols</a></h1>
!
! <dd> Lesson 12 introduces two basic multihop protocols,
! Dissemination and Collection. Dissemination reliably
! delivers small data items to every node in a network,
! while collection delivers small data items from every node
! in a network to designated collection roots.
! </dd>
!
! <h1><a href="lesson13.html">Lesson 13: TinyOS Toolchain</a></h1>
!
! <dd> Lesson 13 describes the details of the TinyOS toolchain, including
! the build system, how to create your own Makefile, and how to find out
! more information on the various tools included with TinyOS.
! </dd>
!
! <h1>Lesson 14: Building a simple but full-featured application</h1>
!
! <dd> Lesson 14 goes through the process of building a simple anti-theft
! application using many of the features and services of TinyOS 2. Lesson 14
! is found in the tinyos-2.x/apps/AntiTheft directory. The powerpoint slides
! found there (also available in pdf form) go over the basic principles of
! TinyOS, and show how to build the accompanying AntiTheft application. Please
! start by reading the README.txt file in the AntiTheft directory.
!
! <p>To run the AntiTheft demo you will need mica2 or micaz motes, and
! some mts310 sensor boards (you can also use mts300 boards, though you
! will lose the movement detection functionality). If you do not have this
! hardware, the slides and AntiTheft code should still provide a good
! overview of TinyOS 2.
! </dd>
! <h1><a href="lesson15.html">Lesson 15: The TinyOS printf Library</a></h1>
!
! <dd> Lesson 15 describes the details of using the TinyOS <code>printf</code> library to
! print debug messages to your PC from a TinyOS application running on a mote.
! </dd>
!
! <h1><a href="lesson16.html">Lesson 16: Writing Low Power Sensing Applications</a></h1>
! <dd>
! This lesson demonstrates how to write low power sensing applications in TinyOS. At
! any given moment, the power consumption of a wireless sensor node is a function of its
! microcontroller power state, whether the radio, flash, and sensor peripherals are on,
! and what operations active peripherals are performing. This tutorial shows you
! how to best utilize the features provided by TinyOS to keep the power consumption
! of applications that use these devices to a minumum.
! </dd>
</body>
! </html>
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
! <title>klueska.com</title>
</head>
! <frameset>
! <frame src="http://docs.tinyos.net/index.php/TinyOS_Tutorials" name="redir_frame" />
! <noframes>
<body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/TinyOS_Tutorials" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
Index: lesson1.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/lesson1.html,v
retrieving revision 1.7
retrieving revision 1.8
diff -C2 -d -r1.7 -r1.8
*** lesson1.html 31 Jul 2007 07:15:44 -0000 1.7
--- lesson1.html 28 Jan 2008 05:59:55 -0000 1.8
***************
*** 1,907 ****
! <!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
! <html>
<head>
! <title>TinyOS Tutorial Lesson 1: TinyOS Component Model</title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet" type="text/css">
</head>
!
<body>
!
! <div class="title">Lesson 1: Getting Started with TinyOS and nesC</div>
! <div class="subtitle">Last updated April 8 2007</div>
!
! <h1>Introduction</h1>
!
! <p>This lesson shows you how to compile a TinyOS program and
! install it on a mote, introduces the basic concepts and syntax of
! the TinyOS component model, and shows you how to generate
! and navigate TinyOS's source code documentation.</p>
!
! <h1>Compiling and Installing</h1>
!
! <p>As a first exercise, you'll compile and install a very simple
! TinyOS application called Blink. If you don't have mote
! hardware, you can compile it for TOSSIM, the TinyOS simulator.</p>
!
! <p>You compile TinyOS applications with the program
! <tt>make</tt>. TinyOS uses a powerful and extensible make
! system that allows you to easily add new platforms and
! compilation options. The makefile system definitions are
! located in tinyos-2.x/support/make.</p>
!
! <p>The first step is to check that your environment is set up
! correctly. Run the <code>tos-check-env</code> command:</p>
!
! <pre>
! $ tos-check-env
! </pre>
!
! <p>This script checks pretty much everything that the TinyOS
! environment needs. Most of the warnings should be somewhat
! self-explanatory, if you are at all accustomed to a UNIX
! environment. If you are having trouble with warnings, your
! best bet is to join and ask questions on the
! <A HREF="https://mail.millennium.berkeley.edu/mailman/listinfo/tinyos-help">tinyos-help</A> email list. It's almost always the
! case that if you've run into a problem, someone else has too.
! Searching the <A HREF="http://mail.millennium.berkeley.edu/pipermail/tinyos/">help archives</A> can therefore be
! useful.</p>
!
! <p>If your system says some command is not available, then
! chances are you need to install the TinyOS tools (tos-*) RPM.
! Please refer to your installation instructions. If you have
! installed the RPM, then look in /usr/bin and /usr/local/bin
! for tos-check-env. If you have downloaded from CVS rather than
! used RPMs, then you need to compile and build the tools.
! Go to <code>tinyos-2.x/tools/tinyos</code> and type:</p>
!
! <pre>
! $ configure
! $ make
! $ make install
! </pre>
!
! <p>On Linux systems, you will either need superuser abilities or
! access to <code>sudo</code> for the last command.</p>
!
!
! <p>The second thing to check is that you have the TinyOS build system
! enabled. This involves the MAKERULES environment variable. In a shell,
! type</p>
!
! <pre>
! printenv MAKERULES
! </pre>
!
! <p>You should see <tt>/opt/tinyos-2.x/support/make/Makerules</tt>. If
! your TinyOS tree is installed somewhere besides the standard place,
! you might not see <tt>/opt</tt>, but rather a different initial path.
! If MAKERULES is not set (printenv prints nothing), you need to set it.
! Depending on your shell, this involves using either <tt>export</tt> (bash)
! or <tt>setenv</tt> (csh, tcsh). If you don't know about shell environment
! variables, this
! <A HREF="http://www.ee.surrey.ac.uk/Teaching/Unix/unix8.html">tutorial</A>
! should help.</p>
!
! <p>The make command to compile a TinyOS application is
! <code>make</code> <i>[platform]</i>, executed from the
! application's directory. To compile Blink, go the <code>apps/Blink</code>
! directory and depending on which hardware you have, type <tt>make micaz</tt>,
! <tt>make mica2</tt>, <tt>make telosb</tt>, or, for simulation, type
! <tt>make micaz sim</tt>.</p> You should see output such as this:
!
! <pre>
! dark /root/src/tinyos-2.x/apps/Blink -4-> make telosb
! mkdir -p build/telosb
! compiling BlinkAppC to a telosb binary
! ncc -o build/telosb/main.exe -Os -O -mdisable-hwmul -Wall -Wshadow
! -DDEF_TOS_AM_GROUP=0x7d -Wnesc-all -target=telosb -fnesc-cfile=build/telosb/app.c
! -board= BlinkAppC.nc -lm
! compiled BlinkAppC to build/telosb/main.exe
! 2782 bytes in ROM
! 61 bytes in RAM
! msp430-objcopy --output-target=ihex build/telosb/main.exe build/telosb/main.ihex
! writing TOS image
! </pre>
!
! <p>If you compile for TOSSIM, you will see a much longer message,
! as building TOSSIM requires several steps, such as building shared
! libraries and scripting support.</p>
!
! <p>If you are running Cygwin and see the error message "The procedure entry point basename could not be located in the dynamic link library cygwin1.dll" then you need to install the other Cygwin nesC RPM (step 4 of the <A HREF="../install-tinyos.html">install instructions</A> or step 2 of the <A HREF="../upgrade-tinyos.html">upgrade instructions</A>)</p>
!
! <h2>Making sure you're invoking the right version of the nesC compiler</h2>
!
! <p>If you see an error message along the lines of this:</p>
!
! <pre>
! BlinkAppC.nc:46: syntax error before `new'
! make: *** [exe0] Error 1
! </pre>
!
! <p>Then you are invoking an older version of the nesc compiler.
! Check by typing <tt>ncc --version</tt>. You should see:</p>
!
! <pre>
! ncc: 1.2.1
! nescc: 1.2.6
! </pre>
!
!
! <p>Followed by some information on what version of the C compiler
! is being used. If you see different versions than those above,
! your compilation problems are most probably due to the fact that
! make is invoking the wrong version. This can easily happen if
! you are upgrading from TinyOS 1.x. You might have passed the
! tos-check-env because you have the right compiler on your system,
! but for some reason make is invoking the wrong one.</p>
!
! <p><tt>ncc</tt> is a script that invokes the full compiler,
! <tt>nescc</tt>. It lives in <tt>tinyos-2.x/tools/tinyos/ncc</tt>.
! If you've installed from an RPM, then the RPM put the new
! version of <tt>ncc</tt> in <tt>/usr/bin</tt>. You can see which
! version make is invoking by typing <tt>which ncc</tt>:
!
! <pre>
! $ which ncc
! /usr/local/bin/ncc
! $ /usr/local/bin/ncc --version
! Unknown target mica
! Known targets for TinyOS directory /opt/tinyos-2.x/tos
! and the specified include directories are:
! none.
! </pre>
!
! <p>In this case, the version of ncc is so old that it doesn't even
! respond to the <tt>--version</tt> flag. In contrast,</p>
!
! <pre>
! $ /usr/bin/ncc --version
! ncc: 1.2.1
! nescc: 1.2.5
! </pre>
!
! <p>The best solution to this problem is to move the old ncc to
! a different name (keep in around in case you need to go back
! to your old setup):</p>
!
! <pre>
! $ mv /usr/local/bin/ncc /usr/local/bin/ncc.old
! $ which ncc
! /usr/bin/ncc
! </pre>
!
! <p>You can apply the same process for <tt>nescc</tt>:</p>
!
! <pre>
! $ nescc --version
! ncc: 1.1.2
! $ which nescc
! /usr/local/bin/nescc
! $ /usr/bin/nescc --version
! nescc: 1.2.5
! $ mv /usr/local/bin/nescc /usr/local/bin/nescc.old
! $ which nescc
! /usr/bin/nescc
! </pre>
!
! <p>Now that we've compiled the application it's time to program the
! mote and run it. The next step depends on what family of mote you
! are programming.</p>
!
! <ul>
! <li><A HREF="#mica">Installing on a mica-family mote</A></li>
! <li><A HREF="#telos">Installing on a telos-family mote</A></li>
! <li><A HREF="#tinynode">Installing on a tinynode mote</A></li>
! <li><A HREF="#eyes">Installing on an eyesIFX-family mote</A></li>
! <li><A HREF="#intel">Installing on an IntelMote2</A></li>
! </ul>
!
! <h2><A NAME="mica">Installing on a mica-family mote (micaz, mica2, mica2dot)</A></h2>
!
! <p>This example uses a Mica2 mote and the
! serial-based programming board (<span
! style="font-family: monospace;">mib510</span>). Instructions on how to
! use other programming boards are <a href="programmers.html">here</a>.
! To download your program onto the mote, place the mote board (or mote
! and sensor stack) into the bay on the programming board, as shown
! below. You can either supply a 3 or 5 volt supply to the connector on the
! programming board or power the node directly. The green LED (labeled PWR)
! on the programming board will be on when power is supplied. If you are
! using batteries to power the mote, be sure the mote is switched on (the
! power switch should be towards the connector). The ON/OFF switch on the
! mib510 board should normally be left in the OFF position. Only switch it
! to ON if you have problems programming the mote and when you are done
! programming, switch it back to OFF (when the switch is ON the mote
! cannot send data to the PC). </p>
!
! <p>Plug the 9-pin connector into the serial port of a computer
! configured with the TinyOS tools, using a pass-through (not null-modem!)
! DB9 serial cable. If your computer does not have a serial port, you can
! easily obtain DB9-serial-to-USB cables. </p>
!
! <center>
! <table border="0" cellspacing="2" cellpadding="3" hspace="4">
! <tbody>
! <tr>
! <td><img src="img/mica-offboard.jpg" height="240" width="320"></td>
! <td><img src="img/mica-onboard.jpg" height="240" width="320"></td>
! </tr>
! <tr>
! <td><i>Mica2 mote next to the programming board</i></td>
! <td><i>Mica2 mote connected to the programming board</i></td>
! </tr>
! </tbody>
! </table>
! </center>
!
! <p>Type:
! <pre>make mica2 reinstall mib510,<i>serialport</i></pre>
! where <i>serialport</i> is the serial port device name. Under Windows, if
! your serial port is <tt>COM<i>n</i>:</tt>, you must use
! <tt>/dev/ttyS<i>n-1</i></tt> as the device name. On Linux, the device name
! is typically <tt>/dev/ttyS</tt><i>n</i> for a regular serial port and
! <tt>/dev/ttyUSB<i>n</i></tt> or <tt>/dev/usb/tts/<i>n</i></tt> for a
! USB-serial cable (the name depends on the Linux distribution). Additionally,
! on Linux, you will typically need to make this serial port world writeable.
! As superuser, execute the following command:
! <pre>chmod 666 <i>serialport</i></pre>
! <p>
! If the installation is successful you should see something like the
! following (if you don't, try repeating the <tt>make</tt> command): </p>
!
! <pre>
! cp build/mica2/main.srec build/mica2/main.srec.out
! installing mica2 binary using mib510
! uisp -dprog=mib510 -dserial=/dev/ttyUSB1 --wr_fuse_h=0xd9 -dpart=ATmega128
! --wr_fuse_e=ff --erase --upload if=build/mica2/main.srec.out
! Firmware Version: 2.1
! Atmel AVR ATmega128 is found.
! Uploading: flash
!
! Fuse High Byte set to 0xd9
!
! Fuse Extended Byte set to 0xff
! rm -f build/mica2/main.exe.out build/mica2/main.srec.out
! </pre>
!
!
! <A name="#telos"><h2>Installing on telos-family mote (telosa, telosb)</h2></A>
! <p>Telos motes are USB devices, and can be plugged into any USB port:
! <center>
! <table border="0" cellspacing="2" cellpadding="3" hspace="4">
! <tbody>
! <tr>
! <td><img src="img/telos.jpg" height="240" width="320"></td>
! <td><img src="img/telos2.jpg" height="240" width="320"></td>
! </tr>
! <tr>
! <td><i>Telos mote</i></td>
! <td><i>Telos mote plugged into a USB port</i></td>
! </tr>
! </tbody>
! </table>
! </center>
!
! <p>Because Telos motes are USB devices, they register with
! your OS when you plug them in. Typing <code>motelist</code>
! will display which nodes are currently plugged in:</p>
! <pre>
! $ motelist
! Reference CommPort Description
! ---------- ---------- ----------------------------------------
! UCC89MXV COM4 Telos (Rev B 2004-09-27)
! </pre>
!
! <p><i>motelist</i> tells you which ports have motes attached. Under
! Windows, it displays the mote's COM port (in this case 4), under Linux it
! displays just the USB serial port number (e.g., 2). Confusingly, the
! Windows version of the code installer (<tt>tos-bsl</tt>) takes the COM port
! number - 1 as it's argument (in this case 3); under Linux it takes the USB
! device name (e.g., /dev/ttyUSB2 or /dev/tts/usb/2 if motelist reports that
! the mote is device 2). On Linux, as with the mica programmers, you will
! typically need to make the USB serial port world writeable. As superuser,
! execute the following command:
! <pre>chmod 666 <i>usb-device-name</i></pre>
!
! Now you can install the application using one of:</p>
!
! <pre>
! make telosb reinstall bsl,3 # Windows example
! make telosb reinstall bsl,/dev/ttyUSB2 # Linux example
! </pre>
!
! <p>This would compile an image suitable for the telosb platform and install
! it with a mote ID of 2 on a mote connected to COM4 on Windows or
! /dev/ttyUSB2 on Linux. If you have a single mote installed, you can skip
! the bsl and device name/number arguments. Again, see the Getting Started
! Guide for your chosen platform for the exact make parameters.</p>
!
! <p>You should see something like this scroll by:</p>
!
! <pre>
! installing telosb binary using bsl
! tos-bsl --telosb -c 16 -r -e -I -p build/telosb/main.ihex.out
! MSP430 Bootstrap Loader Version: 1.39-telos-8
! Mass Erase...
! Transmit default password ...
! Invoking BSL...
! Transmit default password ...
! Current bootstrap loader version: 1.61 (Device ID: f16c)
! Changing baudrate to 38400 ...
! Program ...
! 2782 bytes programmed.
! Reset device ...
! rm -f build/telosb/main.exe.out-2 build/telosb/main.ihex.out
! </pre>
!
!
! <A name="tinynode"><h2>Installing on a TinyNode mote</h2></A>
! <p>There are different ways to program a TinyNode mote depending on how
! it is connected to your computer. The most common case is to connect
! it to a serial port using either the standard extension board (SEB) or
! the MamaBoard. <i>(The other possible methods are to use a Mamaboard with a Digi
! Connect ethernet adaptor and program a node over the network, or to
! use a JTAG adaptor. These are not covered in this tutorial; please
! refer to the Tinynode documentation for further details.)</i>
!
! <p>To install an application on a TinyNode mote using the
! serial port, enter the following command, taking care to
! replace <tt>/dev/ttyXXX</tt> with the file device corresponding to the
! serial port that the tinynode is plugged into.</p>
!
! <pre>
! make tinynode reinstall bsl,/dev/XXX
! </pre>
!
! As with the telos and eyesIFX platforms, this command will reprogram your
! mote using the <tt>tos-bsl</tt> utility, and you will see similar
! output on your screen as given above for telos.
!
! <A NAME="eyes"><h2>Installing on an eyesIFX-family mote</h2></A>
!
! <p>The eyesIFX motes have a mini-B USB connector, allowing easy
! programming and data exchange over the USB. The on-board serial-to-USB
! chip exports two separate serial devices: a lower-numbered one used
! exclusively for serial data communication, and a higher-numbered one
! used for programming of the microcontroller.</p>
!
! <center>
! <table border="0" cellspacing="2" cellpadding="3" hspace="4">
! <tbody>
! <tr>
! <td><img src="img/eyesIFX.jpg" height="140" width="320"></td>
! <td><img src="img/eyesIFX_usb.jpg" height="240" width="320"></td>
! </tr>
! <tr>
! <td><i>eyesIFXv2 mote</i></td>
! <td><i>eyesIFXv2 mote attached to a USB cable</i></td>
! </tr>
! </tbody>
! </table>
! </center>
!
!
!
! <p>The actual programming is performed by the <i>msp430-bsl</i> script,
! conveniently invoked using the same <i>make</i> rules as for the telos
! motes. In the most basic form:</p>
!
! <pre>
! make eyesIFX install bsl
! </pre>
!
! <p>the install script defaults to programming using the /dev/ttyUSB1
! device on Linux and COM1 on Windows, giving output similar to this:</p>
!
! <pre>
! installing eyesIFXv2 binary using bsl
! msp430-bsl --invert-test --invert-reset --f1x -c /dev/ttyUSB1 -r -e -I -p build/eyesIFXv2/main.ihex.out
! MSP430 Bootstrap Loader Version: 2.0
! Mass Erase...
! Transmit default password ...
! Invoking BSL...
! Transmit default password ...
! Current bootstrap loader version: 1.61 (Device ID: f16c)
! Program ...
! 2720 bytes programmed.
! Reset device ...
! rm -f build/eyesIFXv2/main.exe.out build/eyesIFXv2/main.ihex.out
! </pre>
!
! <p> The programming device can also be explicitly set as a parameter
! of the <i>bsl</i> command using shorthand or full notation:</p>
!
! <pre>
! make eyesIFX install bsl,USB3
! make eyesIFX install bsl,/dev/ttyUSB3
! </pre>
!
! <p>The eyesIFX motes can be programmed over the provided JTAG interface
! with the help of the msp430-jtag script:</p>
!
! <pre>
! make eyesIFX install jtag
! </pre>
!
! <p>producing output as in the following:</p>
!
! <pre>
! installing eyesIFXv2 binary using the parallel port jtag adapter
! msp430-jtag -Iepr build/eyesIFXv2/main.ihex.out
! MSP430 parallel JTAG programmer Version: 2.0
! Mass Erase...
! Program...
! 2720 bytes programmed.
! Reset device...
! Reset and release device...
! </pre>
!
!
! <A NAME="intel"><h2>Installing on an IntelMote2</h2></A>
!
!
! <h1>Installation options</h1>
!
! <p>You can now test the program by unplugging the mote from the
! programming board and turning on the power switch (if it's not already
! on). With any luck the three LEDs should be displaying a counter
! incrementing at 4Hz.</p>
!
! <p>The <tt>reinstall</tt> command told the make system to
! install the currently compiled binary: it skips the
! compilation process. Type <tt>make clean</tt> to clean up all
! of the compiled binary files, then type, e.g., <tt>make telosb install</tt>
! This will recompile Blink and install it on one action.</p>
!
! <p>Networking almost always requires motes to have unique identifiers.
! When you compile a TinyOS application, it has a default unique
! identifier of 1. To give a node a different identifier, you can specify
! it at installation. For example, if you type <tt>make telosb install.5</tt>
! or <tt>make telosb reinstall.5</tt>, you will install the application
! on a node and give it 5 as its identifier.</b></p>
!
! <p>For more information on the build system, please see <a
! href="lesson13.html">Lesson 13</a>.
!
! <h1>Components and Interfaces</h1>
!
! <p>Now that you've installed Blink, let's look at how
! it works. Blink, like all TinyOS code, is written
! in nesC, which is C with some additional language
! features for components and concurrency.</p>
!
! <p>A nesC application consists of one or more <i>components</i>
! assembled, or <i>wired</i>, to form an application executable.
! Components define two scopes: one for their specification which
! contains the names of their <i>interfaces</i>, and a second scope for their
! implementation. A component <i>provides</i> and <i>uses</i>
! interfaces. The provided interfaces are intended to represent
! the functionality that the component provides to its user in its
! specification; the used interfaces represent the functionality the
! component needs to perform its job in its implementation.</p>
!
! <p>Interfaces are bidirectional: they specify a set of
! <i>commands</i>, which are functions to be implemented by the
! interface's provider, and a set of <i>events</i>, which are functions
! to be implemented by the interface's user. For a component to call the
! commands in an interface, it must implement the events of that
! interface. A single component may use or provide multiple interfaces
! and multiple instances of the same interface.</p>
!
! <p>The set of interfaces which a component provides together with the
! set of interfaces that a component uses is considered that component's
! <i>signature</i>.</p>
!
! <h2>Configurations and Modules</h2>
!
! <p>There are two types of components in nesC: <i>modules</i> and
! <i>configurations</i>. Modules provide the implementations of one or more
! interfaces. Configurations are used to assemble other components
! together, connecting interfaces used by components to interfaces
! provided by others. Every nesC
! application is described by a top-level configuration that wires
! together the components inside.</p>
!
! <h1>Blink: An Example Application</h1>
!
! <p>Let's look at a concrete example:
! <tt><a href="../../../apps/Blink">Blink</a></tt> in the TinyOS
! tree. As you saw, this application displays a counter on the
! three mote LEDs. In actuality, it simply causes the LED0 to to turn on and off at
! .25Hz, LED1 to turn on and off at .5Hz, and LED2 to turn on and off at
! 1Hz. The effect is as if the three
! LEDs were displaying a binary count of one to seven every two
! seconds. </p>
!
! <p>Blink is composed of two <b>components</b>: a <b>module</b>, called
! "<tt>BlinkC.nc</tt>", and a <b>configuration</b>, called
! "<tt>BlinkAppC.nc</tt>". Remember that all applications require a
! top-level configuration file, which is typically named after the
! application itself. In this case <tt>BlinkAppC.nc</tt> is the
! configuration for the Blink application and the source file that the
! nesC compiler uses to generate an executable file. <tt>BlinkC.nc</tt>,
! on the other hand, actually provides the <i>implementation</i> of the
! Blink application. As you might guess, <tt>BlinkAppC.nc</tt> is used
! to wire the <tt>BlinkC.nc</tt> module to other components that the
! Blink application requires. </p>
!
! <p>The reason for the distinction between modules and configurations
! is to allow a system designer to build applications out of existing
! implementations. For example, a designer could provide a configuration
! that simply wires together one or more modules, none of which she
! actually designed. Likewise, another developer can provide a new set
! of library modules that can be used in a range of applications. </p>
!
! <p>Sometimes (as is the case with <tt>BlinkAppC</tt> and
! <tt>BlinkC</tt>) you will have a configuration and a module that go
! together. When this is the case, the convention used in the TinyOS
! source tree is:</p>
!
!
! <CENTER>
! <table border="1" cellspacing="1" cellpadding="1">
! <tbody>
!
! <tr>
! <td>File Name </td>
! <td>File Type </td>
! </tr>
!
! <tr>
! <td><tt>Foo.nc</tt></td>
! <td>Interface </td>
! </tr>
!
! <tr>
! <td><tt>Foo.h</tt></td>
! <td>Header File</td>
! </tr>
!
! <tr>
! <td><tt>FooC.nc </tt></td>
! <td>Public Module</td>
! </tr>
!
! <tr>
! <td><tt>FooP.nc</tt></td>
! <td>Private Module</td>
! </tr>
!
!
! </tbody>
! </table>
! </CENTER>
!
! <p>While you could
! name an application's implementation module and associated top-level
! configuration anything, to keep things simple we suggest that you
! adopt this convention in your own code. There are several other
! conventions used in TinyOS;
! <a href="../tep3.html">TEP 3</a>
! specifies the coding standards and best current practices.
!
! <h1>The BlinkAppC.nc Configuration</h1>
!
! <p>The nesC compiler compiles a nesC application when given the file
! containing the top-level configuration. Typical TinyOS applications
! come with a standard Makefile that allows platform selection and
! invokes ncc with appropriate options on the application's top-level
! configuration.
!
! <p>Let's look at <tt>BlinkAppC.nc</tt>, the configuration for this
! application first:
!
! <pre></pre>
! <prehead>apps/Blink/BlinkAppC.nc:</prehead>
! <pre>
! configuration BlinkAppC {
! }
! implementation {
! components MainC, BlinkC, LedsC;
! components new TimerMilliC() as Timer0;
! components new TimerMilliC() as Timer1;
! components new TimerMilliC() as Timer2;
!
! BlinkC -> MainC.Boot;
! BlinkC.Timer0 -> Timer0;
! BlinkC.Timer1 -> Timer1;
! BlinkC.Timer2 -> Timer2;
! BlinkC.Leds -> LedsC;
! }
! </pre>
!
! <p>The first thing to notice is the key word <tt>configuration</tt>,
! which indicates that this is a configuration file. The first two
! lines,
!
! <pre></pre>
! <prehead>apps/Blink/BlinkAppC.nc:</prehead>
! <pre>
! configuration BlinkAppC {
! }
! </pre>
!
! simply state that this is a configuration called <tt>BlinkAppC</tt>.
! Within the empty braces here it is possible to specify <tt>uses</tt>
! and <tt>provides</tt> clauses, as with a module. This is important to
! keep in mind: a configuration can use and provide interfaces. Said
! another way, not all configurations are top-level applications.
!
! <p>The actual configuration is implemented within the pair of curly
! brackets following the key word <tt>implementation </tt>. The
! <tt>components</tt> lines specify the set of components that this
! configuration references. In this case those components are
! <tt>Main</tt>, <tt>BlinkC</tt>,
! <tt>LedsC</tt>, and three instances of a timer component called
! <tt>TimerMilliC</tt> which will be referenced as Timer0, Timer1,
! and Timer2<a href="#timermillic_footnote">(1)</a>. This is accomplished
! via the <i>as</i> keyword which is simply an alias<a href="#hint10">(2)</a>.
!
! <p>As we continue reviewing the BlinkAppC application, keep in mind that the
! BlinkAppC component is not the same as the BlinkC component. Rather,
! the BlinkAppC component is composed of the BlinkC component along with
! MainC, LedsC and the three timers.
!
! <p>The remainder of the BlinkAppC configuration consists of connecting
! interfaces used by components to interfaces provided by others. The
! <tt>MainC.Boot</tt> and <tt>MainC.SoftwareInit</tt> interfaces are
! part of TinyOS's boot sequence and will be covered in detail in Lesson
! 3. Suffice it to say that these wirings enable the LEDs and Timers to
! be initialized.
!
! <p>The last four lines wire interfaces that the BlinkC component
! <i>uses</i> to interfaces that the TimerMilliC and LedsC
! components <i>provide</i>. To fully understand the semantics of these
! wirings, it is helpful to look at the BlinkC module's definition and
! implementation.
!
! <h1>The BlinkC.nc Module</h1>
!
! <pre></pre>
! <prehead>apps/Blink/BlinkC.nc:</prehead>
! <pre>
! module BlinkC {
! uses interface Timer<TMilli> as Timer0;
! uses interface Timer<TMilli> as Timer1;
! uses interface Timer<TMilli> as Timer2;
! uses interface Leds;
! uses interface Boot;
! }
! implementation
! {
! // implementation code omitted
! }
! </pre>
!
! <p>The first part of the module code states that this is a module
! called <tt>BlinkC</tt>and declares the interfaces it provides and
! uses. The <tt>BlinkC</tt> module <b>uses</b> three
! instances of the interface <tt>Timer<TMilli></tt> using the
! names Timer0, Timer1 and Timer2 (the <tt><TMilli></tt> syntax
! simply supplies the generic Timer interface with the required timer
! precision). Lastly, the <tt>BlinkC</tt>
! module also uses the Leds and Boot interfaces. This means that BlinkC
! may call any command declared in the interfaces it uses and must also
! implement any events declared in those interfaces.
!
! <p>After reviewing the interfaces used by the <tt>BlinkC</tt>
! component, the semantics of the last four lines in
! <tt>BlinkAppC.nc</tt> should become clearer. The line
! <tt>BlinkC.Timer0 -> Timer0</tt> wires the three
! <tt>Timer<TMilli></tt> interface used by <tt>BlinkC</tt> to the
! <tt>Timer<TMilli></tt> interface provided the three
! <tt>TimerMilliC</tt> component. The <tt>BlinkC.Leds ->
! LedsC</tt> line wires the <tt>Leds</tt> interface used by the
! <tt>BlinkC</tt> component to the <tt>Leds</tt> interface provided by
! the <tt>LedsC</tt> component.
!
! <p>nesC uses arrows to bind interfaces to one another. The right arrow
! (<tt>A->B</tt>) as "A wires to B". The left side of the arrow (A)
! is a user of the interface, while the right side of the arrow (B) is
! the provider. A full wiring is <tt>A.a->B.b</tt>, which means
! "interface a of component A wires to interface b of component B."
! Naming the interface is important when a component uses or provides multiple
! instances of the same interface. For example, BlinkC uses three instances of
! Timer: Timer0, Timer1 and Timer2.
!
! When a component only has one instance
! of an interface, you can elide the interface name. For example, returning
! to BlinkAppC:
!
! <pre></pre>
! <prehead>apps/Blink/BlinkAppC.nc:</prehead>
! <pre>
! configuration BlinkAppC {
! }
! implementation {
! components MainC, BlinkC, LedsC;
! components new TimerMilliC() as Timer0;
! components new TimerMilliC() as Timer1;
! components new TimerMilliC() as Timer2;
!
! BlinkC -> MainC.Boot;
! BlinkC.Timer0 -> Timer0;
! BlinkC.Timer1 -> Timer1;
! BlinkC.Timer2 -> Timer2;
! BlinkC.Leds -> LedsC;
! }
! </pre>
!
! <p>The interface name Leds does not have to be included in LedsC:</p>
!
! <pre>
! BlinkC.Leds -> LedsC; // Same as BlinkC.Leds -> LedsC.Leds
! </pre>
!
! <p>Because BlinkC only uses one instance of the Leds interface, this
! line would also work:</p>
!
! <pre>
! BlinkC -> LedsC.Leds; // Same as BlinkC.Leds -> LedsC.Leds
! </pre>
!
! <p>As the TimerMilliC components each provide a single instance of Timer,
! it does not have to be included in the wirings:</p>
!
! <pre>
! BlinkC.Timer0 -> Timer0;
! BlinkC.Timer1 -> Timer1;
! BlinkC.Timer2 -> Timer2;
! </pre>
!
! <p>However, as BlinkC has three instances of Timer, eliding the name
! on the user side would be a compile-time error, as the compiler would
! not know which instance of Timer was being wired:</p>
!
! <pre>
! BlinkC -> Timer0.Timer; // Compile error!
! </pre
!
! <p>The direction of a wiring arrow is always from a user to a
! provider. If the provider is on the left side, you can also
! use a left arrow:</p>
!
! <pre>
! Timer0 <- BlinkC.Timer0; // Same as BlinkC.Timer0 -> Timer0;
! </pre>
!
! <p>For ease of reading, however, most wirings are left-to-right.</p>
!
! <h1>Visualizing a Component Graph</h1>
!
! <p>Carefully engineered TinyOS systems often have many layers of configurations,
! each of which refines the abstraction in simple way, building something robust
! with very little executable code. Getting to the modules underneath
! -- or just navigating the layers -- with a text editor can be laborious.
! To aid in this process, TinyOS and nesC have a documentation feature called
! nesdoc, which generates documentation automatically from source code. In
! addition to comments, nesdoc displays the structure and composition of
! configurations.</p>
!
! <p>To generate documentation for an application, type</p>
!
! <pre>
! make <i>platform</i> docs
! </pre>
!
! <p>You should see a long list of interfaces and components stream by. If you
! see the error message</p>
!
! <pre>sh: dot: command not found</pre>
!
! <p>then you need to <A HREF="http://www.graphviz.org/Download..php">install
! graphviz</A>, which is the program that draws the component graphs.</p>
!
! <p>Once you've generated the documentation, go to <tt>tinyos-2.x/doc/nesdoc</tt>. You
! should see a directory for your platform: open its <tt>index.html</tt>, and
! you'll see a list of the components and interfaces for which you've
! generated documentation. For example, if you generated documentation
! for Blink on the telosb platform, you'll see documentation for interfaces
! such as Boot, Leds, and Timer, as well as some from the underlying hardware
! implementations, such as Msp430TimerEvent and HplMsp430GeneralIO.</p>
!
! <p>In the navigation panel on the left, components are below interfaces.
! Click on BlinkAppC, and you should a figure like this: </p>
!
! <CENTER>
! <IMG SRC="img/BlinkAppC.gif">
! </CENTER>
!
! <p>In nesdoc diagrams, a single box is a module and a double box is a
! configuration. Dashed border lines denote that a component is a generic:</p>
! <CENTER>
! <TABLE CELLPADDING=6 BORDER=1>
! <TR>
! <td></td>
! <td><b>Singleton</b></td>
! <td><b>Generic</b></td>
! </TR>
! <TR>
! <td>Module</td>
! <td><IMG SRC="img/singleton-module.gif"></td>
! <td><IMG SRC="img/generic-module.gif"></td>
! </TR>
! <TR>
! <td>Configuration</td>
! <td><IMG SRC="img/singleton-configuration.gif"></td>
! <td><IMG SRC="img/generic-configuration.gif"></td>
! </TR>
! </TABLE>
! </CENTER>
! <p>Lines denote wirings, and shaded ovals denote interfaces
! that a component provides or uses. You can click on the components
! in the graph to examine their internals. Click on MainC, which shows
! the wirings for the boot sequence:</p>
!
! <CENTER>
! <IMG SRC="img/tos.system.MainC.gif">
! </CENTER>
!
! <p>Shaded ovals denote wireable interfaces.
! Because MainC provides the Boot interface and uses the Init (as
! SoftwareInit) interface, it has two shaded ovals. Note the direction
! of the arrows: because it uses SoftwareInit, the wire goes out from
! RealMainP to SoftwareInit, while because it provides Boot, the wire
! goes from Boot into RealMainP. The details of MainC aren't too important
! here, and we'll be looking at it in greater depth in
! <A HREF="lesson3.html">lesson 3</A>
! (you can also read <A HREF="../tep107.html">TEP 107</A> for details),
! but looking at the components you can get a sense of what it does: it
! controls the scheduler, initializes the hardware platform, and
! initializes software components.</p>
!
! <h1>Conclusion</h1>
!
! <p>This lesson has introduced the concepts of the TinyOS component
! model: configurations, modules, interfaces and wiring. It showed
! how applications are built by wiring components together. The next
! lesson continues with Blink, looking more closely at modules,
! including the TinyOS concurrency model and executable code.
!
! <p>
! <a name=#related_docs>
! <h1>Related Documentation</h1>
! </a>
! <ul>
! <li> mica mote Getting Started Guide at <a href="http://www.xbow.com">Crossbow</a>
! <li> telos mote Getting Started Guide for <a href="http://www.moteiv.com">Moteiv</a>
! <li> <a href="https://sourceforge.net/projects/nescc">nesc at sourceforge</a>
! <li> <a href="http://nescc.sourceforge.net/papers/nesc-ref.pdf">nesC reference manual</a>
! <li> <a href="http://csl.stanford.edu/~pal/pubs/tinyos-programming-1-0.pdf">TinyOS Programming Guide</a>
! <li> <a href="../tep3.html">TEP 3: TinyOS Coding Conventions</a>
! <li> <a href="../tep102.html">TEP 102: Timers</a>
! <li> <a href="../tep106.html">TEP 106: Schedulers and Tasks</a>
! <li> <a href="../tep107.html">TEP 106: TinyOS 2.x Boot Sequence</a>
! </ul>
!
! <p>
! <hr>
!
! <p><a name="timermillic_footnote">(1)</a> The TimerMilliC component is a
! <i>generic component</i> which means that, unlike non-generic components,
! it can be instantiated more than once. Generic components can take types
! and constants as arguments, though in this case TimerMilliC takes
! none. There are also <i>generic interafces</i>, which take type arguments
! only. The Timer interface provided by TimerMilliC is a generic interface;
! its type argument defines the timer's required precision (this prevents
! programmer from wiring, e.g., microsecond timer users to millisecond timer
! providers). A full explanation of generic components is outside this
! document's scope, but you can read about them in <!-- TODO: Need to update
! this link to a real file><a href="../../nesc/user/generics-1.2.txt"> -->the
! nesc generic component documentation</a>.
!
! <p><a name="hint10">(2)</a>
! <b>Programming Hint 10:</b> Use the <i>as</i> keyword liberally. From
! <a href="http://csl.stanford.edu/~pal/pubs/tinyos-programming-1-0.pdf"><i>TinyOS Programming</i></a>
!
!
! <!-- Begin footer -->
! <br>
! <hr>
! <center>
! <p>< <b><a href="index.html">Top</a></b>
! | <b><a href="lesson2.html">Next Lesson </a> ></b>
! </center>
!
</body>
! </html>
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
! <title>klueska.com</title>
</head>
! <frameset>
! <frame src="http://docs.tinyos.net/index.php/Getting_Started_with_TinyOS" name="redir_frame" />
! <noframes>
<body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/Getting_Started_with_TinyOS" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
Index: lesson10.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/lesson10.html,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** lesson10.html 12 Dec 2006 18:22:53 -0000 1.3
--- lesson10.html 28 Jan 2008 05:59:55 -0000 1.4
***************
*** 1,560 ****
! <!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
! <html>
<head>
! <title>TinyOS Tutorial Lesson 10: Platforms</title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet" type="text/css">
</head>
!
<body>
!
! <div class="title">Lesson 10: Platforms</div>
! <div class="subtitle">Last updated October 23 2006</div>
!
! <h1>Introduction</h1>
!
! <p>Many different hardware platforms (e.g micaZ, telos, eyesIFX) can be
! used with TinyOS. This lesson shows you what a platform port consists
! of, and how TinyOS reuses as much code as possible between different
! platforms.
! The lesson will proceed by showing how to do the port for an imaginary
! mote called "yamp", which has a MSP430 microcontroller and a CC2420
! radio transceiver.
!
! <p>
! The <b>target audience</b> of this lesson consists of those people that want
! to better understand what the difference between e.g "make micaz" and "make
! telosb" is, and how these differences concretely map into the underlying
! files, definitions, etc.
!
! <p> Note that the material covered in this tutorial is <b>not</b>
! strictly necessary for regular tinyos developpers, and you can safely skip
! it if you have no intention of working down to the lowest level or
! developping new platforms.
!
! </p>
!
! <h1>Chips vs Platforms</h1>
!
! <p>
! Two key building blocks for any mote are the microcontroller and
! radio transceiver.
! Of course, both a microcontroller and a radio can be used on
! more than one platform. This is indeed the case for the MSP430 and CC2420
! that our yamp mote uses (telos, eyes, and tinynode use the MSP430; telos
! and micaz use the CC2420).
! </p>
!
! <p>
! Given this multiplicity of platforms, it would be vasly redundant if each
! platform developper had to rewrite the software support for each chip
! from scratch. While a chip may be physically wired in a different way on
! different platforms (e.g., a radio is connected to a different digital
! pins on the microcontroller), by far the largest part of the logic to
! deal with a chip is platform-independent.
! </p>
!
! <p>
! Thus, platform-independent code to support a chip is placed in a
! chip-specific directory. Writing a platform port for a platform is then
! (essentially) a matter of <b>pulling in the code for each of the
! platform's chips, and "gluing" things together</b>.
! For example, the modules and components that support the CC2420 are in
! tos/chips/cc2420. This radio is used on both the telos and micaZ motes; the
! "gluing" is done by the modules in the tos/platforms/telosa/chips/cc2420 and
! tos/platforms/micaz/chips/cc2420/ directories.
! </p>
!
! <p>
! Note that in general there may
! be more to a platform port than pulling in existing code for different
! chips, in particular when a new platform uses a chip that is not yet
! supported. Developping drivers for a new chip can be a non-trivial
! undertaking (especially for radios and microcontrollers); these aspects
! are not covered here.
! </p>
!
! <h1>Initial platform bring-up</h1>
!
! <p>
! As a first step to bring up the platform, we will stick to the bare minimum in
! order to compile and install the Null application on our yamp mote.
! </p>
!
! <p>
! All platform-specific code goes in tos/platforms/<platformname>.
! For example, we have tos/platforms/micaz or tos/platforms/tinynode.
! Our first step is to create a directory for the yamp platform:
! <pre>
! $ cd tinyos-2.x/tos/platforms
! $ mkdir yamp
! </pre>
! </p>
!
! <h2>The .platform file</h2>
!
! Each platform directory (such as tos/platforms/yamp) should contain a
! file named ".platform", that contains basic compiler parameters
! information for each platform. So, create the file
! "tos/platforms/yamp/.platform" (note the <b>.</b> in "<b>.</b>platform" !!!), that contains the following:
!
! <pre>
! push( @includes, qw(
!
! %T/chips/cc2420
! %T/chips/msp430
! %T/chips/msp430/adc12
! %T/chips/msp430/dma
! %T/chips/msp430/pins
! %T/chips/msp430/timer
! %T/chips/msp430/usart
! %T/chips/msp430/sensors
! %T/lib/timer
! %T/lib/serial
! %T/lib/power
! ) );
!
! @opts = qw(
!
! -gcc=msp430-gcc
! -mmcu=msp430x1611
! -fnesc-target=msp430
! -fnesc-no-debug
! -fnesc-scheduler=TinySchedulerC,TinySchedulerC.TaskBasic,TaskBasic,TaskBasic,runTask,postTask
!
! );
!
! </pre>
!
! <p>
! This file contains perl snippets that are intepreted by the ncc compiler.
! The first statement simply adds some directories to the include path that
! is used when compiling an application for the yamp platform (the %T gets
! expanded to the full location of tinyos-2.x/tos, using the TOS2DIR
! environment variable). Note that we have included the CC2420 and MSP430
! directories, as well as some libraries.
! </p>
!
! <p>
! The second statement defines the @opts list, that contains various parameters
! passed to nesc. Please consult the nesc documentation for information on the
! meaning of these parameters.
! </p>
!
! <h2>The hardware.h file</h2>
!
! <p>
! Each platform directory also has a file named "hardware.h" that is included by
! default when compiling an application for that platform. This can define
! platform-specific constants, pin names, or also include other "external"
! header files (e.g. msp430hardware.h in our case, or atm128hardware.h for
! platforms using the atm128 MCU).<br>
!
! So, create the file "tos/platforms/yamp/hardware.h" with the following contents:
! </p>
!
! <pre>
! #ifndef _H_hardware_h
! #define _H_hardware_h
!
! #include "msp430hardware.h"
!
! // LEDs
! TOSH_ASSIGN_PIN(RED_LED, 5, 4);
! TOSH_ASSIGN_PIN(GREEN_LED, 5, 5);
! TOSH_ASSIGN_PIN(YELLOW_LED, 5, 6);
!
! // UART pins
! TOSH_ASSIGN_PIN(SOMI0, 3, 2);
! TOSH_ASSIGN_PIN(SIMO0, 3, 1);
! TOSH_ASSIGN_PIN(UCLK0, 3, 3);
! TOSH_ASSIGN_PIN(UTXD0, 3, 4);
! TOSH_ASSIGN_PIN(URXD0, 3, 5);
! TOSH_ASSIGN_PIN(UTXD1, 3, 6);
! TOSH_ASSIGN_PIN(URXD1, 3, 7);
! TOSH_ASSIGN_PIN(UCLK1, 5, 3);
! TOSH_ASSIGN_PIN(SOMI1, 5, 2);
! TOSH_ASSIGN_PIN(SIMO1, 5, 1);
!
!
! #endif // _H_hardware_h
! </pre>
!
! <p>
! This file simply pulls in msp430hardware.h from tos/chips/msp430 (the compiler
! will find it because we have added this directory to our search path in the
! .platform created previously) and defines some physical pins using macros from
! msp430hardware.h. For example, on our yamp mote, the red led is physically
! connected to the general purpose I/O (GPIO) pin 5.4.
! </p>
!
! <p>
! Some other very important functions (that are defined in msp430hardware.h
! and so pulled in indirectly via this hardware.h)
! concern the disabling of interrupts for atomic sections (atomic blocks in nesc
! code essentially get converted into __nesc_atomic_start() and
! __nesc_atomic_end()). How interrupts are disabled is of course microcontroller
! specific; the same applies to putting the microcontroller to sleep (as is done
! by the scheduler when there are no more tasks to run, using the McuSleep
! interface). These functions must be somehow defined for each platform,
! typically by means of an <tt>#include</tt>'d MCU-specific file.<br>
! <i> As an exercise, try finding the definitions of</i> __nesc_atomic_start() <i>and
! </i> __nesc_atomic_end()<i> for the micaZ and intelmote2 platforms.</i>
!
! </p>
!
! <h1>Setting up the build environment and building the "null" app</h1>
! Before pulling in existing chip drivers or writing any code, we must set up
! the build environment so that it is aware of and supports our platform.
!
! Once this is done, we will define the basic TinyOS module for our platform,
! and use the Null app (in tinyos-2.x/apps/null) in order to test that our
! platform is properly configured. As per it's description in its README file,
! Null is an empty skeleton application. It is useful to test that the
! build environment is functional in its most minimal sense, i.e., you
! can correctly compile an application. So, let's go ahead and try to compile
! Null for the yamp platform:
!
! <!-- <h2> Defining a make target</h3> -->
!
! <!-- At this point we have created all the necessary files in tos/platforms/yamp/ -->
! <!-- in order to run the Null application. But how do we compile it and install it -->
! <!-- on our yamp mote? -->
!
! <!-- We would like to enter "make yamp" in any application directory and have a -->
! <!-- yamp binary be built, just as e.g. "make micaz" builds us a micaz -->
! <!-- binary. But if we try it at this point we get an error message listing all the -->
! <!-- valid targets and telling us that yamp is not a valid target: -->
!
! <pre>
! $ cd tinyos-2.x/apps/Null
! $ make yamp
! /home/henridf/work/tinyos-2.x/support/make/Makerules:166: ***
!
! Usage: make <target> <extras>
! make <target> help
!
! Valid targets: all btnode3 clean eyesIFX eyesIFXv1 eyesIFXv2 intelmote2 mica2 mica2dot micaz null telos telosa telosb tinynode tmote
! Valid extras: docs ident_flags nescDecls nowiring rpc sim sim-cygwin sim-fast tos_image verbose wiring
!
! Welcome to the TinyOS make system!
!
! You must specify one of the valid targets and possibly some combination of
! the extra options. Many targets have custom extras and extended help, so be
! sure to try "make <target> help" to learn of all the available features.
!
! Global extras:
!
! docs : compile additional nescdoc documentation
! tinysec : compile with TinySec secure communication
!
! ERROR, "yamp tos-ident-flags tos_image" does not specify a valid target. Stop.
!
! </pre>
!
! <p>
! The problem is that we need to define the platform in the <i>TinyOS build
! system</i>, so that the make invocation above recognizes the yamp platform.
! The TinyOS build system is a Makefile-based set of rules and definitions
! that has a very rich functionality. This includes invoking
! necessary compilation commands as with any build system, but goes much
! further and includes support for other important aspects such as
! device reprogramming or supporting multiple platforms and targets.
! </p>
!
! <p>
! A full description of the inner workings of the TinyOS build system is beyond
! the scope of this tutorial. For now, we will simply see how to define the
! yamp platform so that the "make yamp" command does what it should. (For those
! that want to delve deeper, start with "tinyos-2.x/support/make/Makerules".)
! </p>
!
! <h2> Defining a make target</h2>
!
! The TinyOS build system resides in "tinyos-2.x/support/make". The strict
! minimum for a platform to be recognized by the build system (i.e., for the
! build system to understand that "yamp" is a legal platform when we enter "make
! yamp") is the existence of a <i>platformname</i>.target file in the
! aforementioned make directory.<br>
! So, create the file "tinyos-2.x/support/make/yamp.target" with the following
! contents:
!
! <pre>
!
! PLATFORM = yamp
!
! $(call TOSMake_include_platform,msp)
!
! yamp: $(BUILD_DEPS)
! @:
! </pre>
!
! This sets the PLATFORM variable to yamp, includes the msp platform
! ("make/msp/msp.rules") file, and provides in the last two lines a make rule
! for building a yamp application using standard Makefile syntax.
!
! Now, let's go back and try to compile the Null app as before. This time we get:
!
! <pre>
! [18:23 henridf at tinyblue: ~/work/tinyos-2.x/apps/Null] make yamp
! mkdir -p build/yamp
! compiling NullAppC to a yamp binary
! ncc -o build/yamp/main.exe -Os -Wall -Wshadow -DDEF_TOS_AM_GROUP=0x7d -Wnesc-all -target=yamp -fnesc-cfile=build/yamp/app.c -board= NullAppC.nc -lm
! In file included from NullAppC.nc:42:
! In component `MainC':
! /home/henridf/work/tinyos-2.x/tos/system/MainC.nc:50: component PlatformC not found
! /home/henridf/work/tinyos-2.x/tos/system/MainC.nc:53: no match
! make: *** [exe0] Error 1
! </pre>
!
! So there's progress of sorts, since now we're getting a "real" compilation
! error as opposed to not even making it past the build system. Let's take a
! closer look at the output. The ncc compiler is unhappy about not finding a
! "PlatformC" component.
!
! The "PlatformC" component must be defined for each platform. Its role and
! placement in the system is described in more detail in TEP107. For now,
! suffice to cite from that TEP that:
! <i>A port of TinyOS to a new plaform MUST include a component PlatformC which
! provides one and only one instance of the Init interface.</i>.
!
!
! Create the file "tos/platforms/yamp/PlatformP.nc" with the following contents:
!
! <pre>
! #include "hardware.h"
!
! module PlatformP{
! provides interface Init;
! uses interface Init as Msp430ClockInit;
! uses interface Init as LedsInit;
! }
! implementation {
! command error_t Init.init() {
! call Msp430ClockInit.init();
! call LedsInit.init();
! return SUCCESS;
! }
!
! default command error_t LedsInit.init() { return SUCCESS; }
!
! }
! </pre>
!
! , and create the file "tos/platforms/yamp/PlatformC.nc" as:
!
! <pre>
! #include "hardware.h"
!
! configuration PlatformC
! {
! provides interface Init;
! }
! implementation
! {
! components PlatformP
! , Msp430ClockC
! ;
!
! Init = PlatformP;
! PlatformP.Msp430ClockInit -> Msp430ClockC.Init;
! }
! </pre>
!
! Now, compilation of the Null application finally works for the yamp platform:
!
! <pre>
! [19:47 henridf at tinyblue: ~/work/tinyos-2.x/apps/Null] make yamp
! mkdir -p build/yamp
! compiling NullAppC to a yamp binary
! ncc -o build/yamp/main.exe -Os -Wall -Wshadow -DDEF_TOS_AM_GROUP=0x7d -Wnesc-all -target=yamp -fnesc-cfile=build/yamp/app.c -board= NullAppC.nc -lm
! compiled NullAppC to build/yamp/main.exe
! 1216 bytes in ROM
! 6 bytes in RAM
! msp430-objcopy --output-target=ihex build/yamp/main.exe build/yamp/main.ihex
! writing TOS image
! </pre>
!
!
! <h1>Getting Blink to work</h1>
!
! With the previous steps, we now have the basic foundation to start working on
! our yamp platform: the basic platform definitions are in place, and the build
! system recognizes and correctly acts upon the "make yamp" target. We haven't
! yet actually <i>programmed</i> our mote yet.
! <p>
! The next step in the bring-up of a platform, that we will cover in this part,
! is to program a node with an application and verify that it actually
! works. We'll do this with Blink, because it is simple, and easy to verify that
! it works. As a bonus, we'll also have validated basic timer functionality once
! we see those Leds turning on and off.
! <p>
! As a first step, let's go to the Blink application directory and try to
! compile the application:
! <pre>
! [19:06 henridf at tinyblue: ~/work/tinyos-2.x/apps/Blink] make yamp
! mkdir -p build/yamp
! compiling BlinkAppC to a yamp binary
! ncc -o build/yamp/main.exe -Os -Wall -Wshadow -DDEF_TOS_AM_GROUP=0x7d -Wnesc-all -target=yamp -fnesc-cfile=build/yamp/app.c -board= BlinkAppC.nc -lm
! In file included from BlinkAppC.nc:45:
! In component `LedsC':
! /home/henridf/work/tinyos-2.x/tos/system/LedsC.nc:38: component PlatformLedsC not found
! /home/henridf/work/tinyos-2.x/tos/system/LedsC.nc:42: cannot find `Init'
! /home/henridf/work/tinyos-2.x/tos/system/LedsC.nc:43: cannot find `Led0'
! /home/henridf/work/tinyos-2.x/tos/system/LedsC.nc:44: cannot find `Led1'
! /home/henridf/work/tinyos-2.x/tos/system/LedsC.nc:45: cannot find `Led2'
! make: *** [exe0] Error 1
! </pre>
!
! The compiler cannot find the component "PlatformLedsC" that is referred to in
! the file tos/system/LedsC.nc. As the name indicates, "PlatformLedsC" is a
! platform-specific component, and thus we will need to define this component
! for the yamp platform.
! <p>
! Why should there be such a platform-specific component for accessing Leds? This is because at
! the lowest level, i.e in hardware, Leds are implemented differently on
! different platforms. Typically, a Led is connected to a microcontroller I/O pin,
! and the Led is turned on/off by setting the appropriate output 0/1 on that
! pin. This is in fact the model used on all current TinyOS platforms.
! But even in this simple and uniform model, (and disregarding
! the fact that future platforms may use different hardware implementations
! and not connect each Led directly to an I/O pin), we have that the
! lowest-level to turn on/off a Led must be defined on a per-platform basis.
! <p>
! Now, consider Leds from another perspective, namely that of the Leds.nc
! interface (defined in tos/interfaces/Leds.nc). In this interface, we have
! commands such as <tt>get();</tt> in principle such a command does not need to be
! platform-dependent: the code that maintains the current state of a Led and
! returns it via the get() call does not need to be re-written each time a Led
! is connected to a different pin (of course re-writing get() for each
! platform would not be much overhead given its simplicity; this argument
! clearly becomes far stronger in more complex situations involving entire chips
! rather than individual GPIOs).
! <p> The key notion that the above example is simply that there is a boundary
! above which software components are platform-independent, and below which
! components are specifically written with one hardware platform in mind.
! This is at heart a very simple concept; its complete instantiation in TinyOS is of
! course richer than the above example, and is the topic of TEP2 (Hardware
! Abstraction Architecture).
! <p> Let's now return to the task at hand, which is to make Blink work on our
! platform. If we take a closer look at the file "tos/system/LedsC.nc", we see
! that it contains a configuration that wires the module LedsP with modules
! Init, Leds0, Leds1, and Leds2, all of which are to be provided by the
! (still missing) PlatformLedsC. Taking a closer look at
! "tos/system/LedsP.nc", we see that the Leds0,1,2 modules used by LedsP are
! GeneralIO interfaces. The GeneralIO interface (see
! "tos/interfaces/GeneralIO.nc" and TEP 117) simply encapsulates a digital I/O pin and
! provides functions to control its direction and get/set its input/output
! values.
! <p> So, we need to create a PlatformLedsC configuration that shall provide
! three GeneralIO interfaces and an Init. This is done by creating the file
! "tos/platforms/yamp/PlatformLedsC.nc" with the following contents:
!
! <pre>
! #include "hardware.h"
!
! configuration PlatformLedsC {
! provides interface GeneralIO as Led0;
! provides interface GeneralIO as Led1;
! provides interface GeneralIO as Led2;
! uses interface Init;
! }
! implementation
! {
! components
! HplMsp430GeneralIOC as GeneralIOC
! , new Msp430GpioC() as Led0Impl
! , new Msp430GpioC() as Led1Impl
! , new Msp430GpioC() as Led2Impl
! ;
! components PlatformP;
!
! Init = PlatformP.LedsInit;
!
! Led0 = Led0Impl;
! Led0Impl -> GeneralIOC.Port54;
!
! Led1 = Led1Impl;
! Led1Impl -> GeneralIOC.Port55;
!
! Led2 = Led2Impl;
! Led2Impl -> GeneralIOC.Port56;
!
! }
! </pre>
!
! We refer the reader to the TinyOS Programming Guide cited below for more
! explanations on how the above confiuration uses generics (ie with the "new"
! keyword). For the purpose of this lesson, the key point is that we are wiring
! to ports 5.4, 5.5, and 5.6 -- we shall suppose that these are the MSP430
! microcontroller pins to which the three Leds are connected on the yamp
! platform. <p>
!
! With the above file in place, we can now compile Blink for the yamp platform.
! How do we test that the application actually works? We have thus far presented
! yamp as an imaginary platform, but it turns out that the above application
! should work on any platform with the MSP430x1611 microcontroller and where the
! Leds are connected to microcontroller ports 5.4-5.6.
! Not entirely coincidentally, these are exactly the Led wirings used by the
! telos/tmote platforms. So those readers that have a telos/tmote at hand can
! test this application on it. (Testing on a tinynode or eyes mote is also easy and only
! requires changing the pin wirings in PlatformLedsC to follow those of that
! platform; running this application on mica-family motes will require more
! changes since they use a different microcontroller).
!
! <p>
! Now, enter the following command (where you have suitably replaced /dev/ttyXXX by the appropriate serial port),
! <pre>
! make yamp install bsl,/dev/ttyXXX
! </pre>
! and you will see the Leds of your impersonated (by a telos) yamp node Blinking!
!
! <h1>Conclusion</h1>
!
! <p>This lesson has introduced the notion of per-platform support in TinyOS
! using as a guiding example the development of a platform port to an
! imaginary "yamp" platform. We have seen how introducing support for a new
! platform requires touching not only nesc code but also adding some rules to
! the build system. This tutorial also touched upon the notions of Hardware
! Abstraction Architecture (HAA) that is central to the clean and modular
! support of different platforms and chips in TinyOS.
! <p>
! The steps outlined here did not cover what is the hardest part of
! a platform port: developping the components to drive a radio transceiver or
! MCU (which are necessary if the platform uses chips that are not currently
! supported in TinyOS). Developping such drivers is an advanced topic that is
! beyond the scope of the tutorials; for those curious to gain some insight we
! recommend perusing the code for a chip (e.g the CC2420 radio in
! tos/chips/cc2420 or the xe1205 radio in tos/chips/xe1205) armed with that
! chips datasheet and the platform schematics.
! <p>
! <a name=#related_docs>
! <h1>Related Documentation</h1>
! </a>
! <ul>
! <li> <a href="https://sourceforge.net/projects/nescc">nesc at sourceforge</a>
! <li> <a href="http://nescc.sourceforge.net/papers/nesc-ref.pdf">nesC reference manual</a>
! <li> <a href="http://csl.stanford.edu/~pal/pubs/tinyos-programming-1-0.pdf">TinyOS Programming Guide</a>
! <li> <a href="../tep102.html">TEP 2: Hardware Abstraction Architecture</a>
! <li> <a href="../tep106.html">TEP 106: Schedulers and Tasks</a>
! <li> <a href="../tep107.html">TEP 107: TinyOS 2.x Boot Sequence</a>
! <li> <a href="../tep117.html">TEP 117: Low-level I/O</a>
! </ul>
!
! <p>
! <hr>
!
!
! <!-- Begin footer -->
! <br>
! <hr>
! <center>
! <p>< <b><a href="lesson8.html">Previous Lesson</a></b> | <b><a
! href="index.html">Top</a></b> | <b><a href="lesson11.html">Next
! Lesson </a> ></b>
! </p>
!
! </b>
! </center>
!
</body>
! </html>
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
! <title>klueska.com</title>
</head>
! <frameset>
! <frame src="http://docs.tinyos.net/index.php/Platforms" name="redir_frame" />
! <noframes>
<body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/Platforms" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
Index: lesson11.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/lesson11.html,v
retrieving revision 1.14
retrieving revision 1.15
diff -C2 -d -r1.14 -r1.15
*** lesson11.html 20 Oct 2007 00:14:19 -0000 1.14
--- lesson11.html 28 Jan 2008 05:59:55 -0000 1.15
***************
*** 1,1684 ****
! <!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
! <html>
<head>
! <title>Lesson 11: Simulation with TOSSIM</title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet" type="text/css">
</head>
<body>
!
! <div class="title">Lesson 11: Simulation with TOSSIM</div>
! <div class="subtitle">Last Modified: 20 April 2007</div>
[...1670 lines suppressed...]
! </center>
!
</body>
! </html>
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
! <title>klueska.com</title>
</head>
+ <frameset>
+ <frame src="http://docs.tinyos.net/index.php/TOSSIM" name="redir_frame" />
+ <noframes>
<body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/TOSSIM" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
Index: lesson12.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/lesson12.html,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** lesson12.html 26 Oct 2007 15:21:19 -0000 1.4
--- lesson12.html 28 Jan 2008 05:59:55 -0000 1.5
***************
*** 1,206 ****
! <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
! <html>
<head>
! <title>TinyOS Tutorial Lesson 12: Network Protocols</title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet"
! type="text/css">
</head>
<body>
! <div class="title">Lesson 12: Network Protocols<br>
! </div>
! <div class="subtitle">Last updated Nov 3 2006</div>
! <p>This lesson introduces the two basic network primitives of Tinyos-2:
! Dissemination and Collection.<br>
! </p>
! <h1>Dissemination<br>
! </h1>
! <p>The goal of a dissemination protocol is to reliably deliver a piece of data to every
! node in the network. It allows administrators
! to reconfigure, query, and reprogram a network. Reliability is
! important because it makes the operation robust to temporary
! disconnections or high packet loss. Dissemination is fully
! explained in TEP 118.<br>
! </p>
! <p>In TinyOS 2.x, dissemination provides two interfaces: DisseminationValue and
! DisseminationUpdate. Let's take a look at these two interfaces:<br>
! </p>
!
! <p>tos/lib/net/DisseminationUpdate.nc:<br>
! </p>
! <pre>interface DisseminationUpdate<t> {<br> command void change(t* newVal);<br>}</pre>
!
! <p>tos/lib/net/DisseminationValue.nc:<br>
! </p>
! <pre>interface DisseminationValue<t> {<br> command const t* get();<br> event void changed();<br>}</pre>
! <span style="font-family: monospace;"></span>
!
! <p>DisseminationUpdate is used by producers. The command <span
! style="font-weight: bold; font-style: italic;">DisseminationUpdate.change()</span> should be
! called each time the producer wants to disseminate a new value, passing this
! new value as a parameter.<br>
! DisseminationValue is for consumers. The event <span
! style="font-weight: bold; font-style: italic;">DisseminationValue.changed()</span> is
! signalled each time the disseminated value is changed (the producer has
! called <span style="font-weight: bold; font-style: italic;">change</span>),
! and the command<span style="font-style: italic;"> <span
! style="font-weight: bold;">get</span></span> allows to obtain this new
! value. <br>
! </p>
! We build now a simple application (EasyDissemination) where one node
! (the producer) periodically disseminates the value of a counter to rest
! of the nodes in the network (consumers).
! As a first step, c<code></code>reate a new directory in <tt>apps</tt>
! named <span style="font-family: monospace;">EasyDissemination</span>:
! <pre>$ cd tinyos-2.x/apps<br>$ mkdir EasyDissemination<br></pre>
! Inside this directory, create a file <code>EasyDisseminationC.nc</code>,
! which
! has this code:
! <pre>#include <Timer.h><br><br>module EasyDisseminationC {<br> uses interface Boot;<br> uses interface DisseminationValue<uint16_t> as Value;<br> uses interface DisseminationUpdate<uint16_t> as Update;<br> uses interface Leds;<br> uses interface Timer<TMilli>;<br>}<br><br>implementation {<br><br> uint16_t counter;<br><br> task void ShowCounter() {<br> if (counter & 0x1) <br> call Leds.led0On();<br> else <br> call Leds.led0Off();<br> if (counter & 0x2) <br> call Leds.led1On();<br> else <br> call Leds.led1Off();<br> if (counter & 0x4) <br> call Leds.led2On();<br> else<br> call Leds.led2Off();<br> }<br> <br> event void Boot.booted() {<br> counter = 0;<br> if ( TOS_NODE_ID == 1 ) <br> call Timer.startPeriodic(2000);<br> }<br><br> event void Timer.fired() {<br> counter = counter + 1;<br> // show counter in leds<br> post ShowCounter();<br> // disseminate counter value<br> call Update.change(&counter);<br> }<br><br> event void Value.changed() {<br> const uint16_t* newVal = call Value.get();<br> // show new counter in leds<br> counter = *newVal;<br> post ShowCounter();<br> }<br>}<br></pre>
! We assume that the base station is the node with ID = 1. First
! note that the base station will periodically (every 2 seconds)
! increment a 3-bit counter, display the counter using its three leds, and disseminate it
! through the network. This is done using the change command provided in
! the DisseminationUpdate interface:<br>
! <pre> call Update.change(&counter);</pre>
! Second, note that when a node receives a change notification, it
! updates its counter value and shows it on the leds:<br>
! <pre> event void Value.changed() {<br> const uint16_t* newVal = call Value.get();<br> // show new counter in leds<br> counter = *newVal;<br> post ShowCounter();<br> }<br></pre>
! The <code>EasyDisseminationAppC.nc</code>
! provides the needed wiring:
! <pre>configuration EasyDisseminationAppC {}<br>implementation {<br> components EasyDisseminationC;<br><br> components MainC;<br> EasyDisseminationC.Boot -> MainC;<br><br> components new DisseminatorC(uint16_t, 0x1234) as Diss16C;<br> EasyDisseminationC.Value -> Diss16C;<br> EasyDisseminationC.Update -> Diss16C;<br><br> components LedsC;<br> EasyDisseminationC.Leds -> LedsC;<br><br> components new TimerMilliC();<br> EasyDisseminationC.Timer -> TimerMilliC;<br>}<br></pre>
! <p>Note that both Dissemination interfaces we use are provided by the
! module DisseminatorC. <br>
! This module provides the Dissemination service:<br>
! </p>
! <p>tos/lib/net/Dissemination/DisseminationC.nc:</p>
! <prehead></prehead>
! <pre> generic configuration DisseminatorC(typedef t, uint16_t key) {<br> provides interface DisseminationValue<t>;<br> provides interface DisseminationUpdate<t>;<br>}<br></pre>
! Note that we need to specify to the Disseminartor module a type t and a
! key. In our case, the value we want to disseminate is
! just an unsigned two-byte counter. The key allows to have
! different instances of DisseminatroC. <br>
! <br>
! To compile this program we use create the following Makefile:<br>
! <pre>COMPONENT=EasyDisseminationAppC<br>CFLAGS += -I$(TOSDIR)/lib/net<br><br>include $(MAKERULES)<br></pre>
! Now install this program into several nodes (make sure you have one
! base station, that is, one node whose ID is 1) and see how the counter
! displayed in the base station is "disseminated" to all the nodes
! belonging to the network. You will also notice that dissemination works across
! resets, i.e., if you reset a node it will rapidly re-'synchronize' and display
! the correct value after it reboots.
! <br>
! <br>
! For more information, read TEP118 [Dissemination].<br>
! <br>
! <h1>Collection<br>
! </h1>
! <p>Collection is the complementary operation to disseminating and it
! consists in "collecting" the data generated in the network into a base
! stations. The general approach used is to build one
! or more collection <em>trees</em>, each of which is rooted at a base
! station. When a node has data which needs to be collected, it
! sends the data up the tree, and it forwards collection data that
! other nodes send to it. <br>
! </p>
! <p>We build now a simple application (EasyCollection) where nodes
! periodically send information to a base station which collects all the
! data.<br>
! As a first step, c<code></code>reate a new directory in <tt>apps</tt>
! named <span style="font-family: monospace;">EasyCollection</span>:
! </p>
! <pre>$ cd tinyos-2.x/apps<br>$ mkdir EasyCollection<br></pre>
! Inside this directory, create a file <code>EasyCollectionC.nc</code>,
! which
! has the following code:
! <pre>#include <Timer.h><br><br>module EasyCollectionC {<br> uses interface Boot;<br> uses interface SplitControl as RadioControl;<br> uses interface StdControl as RoutingControl;<br> uses interface Send;<br> uses interface Leds;<br> uses interface Timer<TMilli>;<br> uses interface RootControl;<br> uses interface Receive;<br>}<br>implementation {<br> message_t packet;<br> bool sendBusy = FALSE;<br><br> typedef nx_struct EasyCollectionMsg {<br> nx_uint16_t data;<br> } EasyCollectionMsg;<br><br> event void Boot.booted() {<br> call RadioControl.start();<br> }<br> <br> event void RadioControl.startDone(error_t err) {<br> if (err != SUCCESS)<br> call RadioControl.start();<br> else {<br> call RoutingControl.start();<br> if (TOS_NODE_ID == 1) <br> call RootControl.setRoot();<br> else<br> call Timer.startPeriodic(2000);<br> }<br> }<br><br> event void RadioControl.stopDone(error_t err) {}<br><br> void sendMessage() {<br> EasyCollectionMsg* msg = (EasyCollectionMsg*)call Send.getPayload(&packet);<br> msg->data = 0xAAAA;<br> <br> if (call Send.send(&packet, sizeof(EasyCollectionMsg)) != SUCCESS) <br> call Leds.led0On();<br> else <br> sendBusy = TRUE;<br> }<br> event void Timer.fired() {<br> call Leds.led2Toggle();<br> if (!sendBusy)<br> sendMessage();<br> }<br> <br> event void Send.sendDone(message_t* m, error_t err) {<br> if (err != SUCCESS) <br> call Leds.led0On();<br> sendBusy = FALSE;<br> }<br> <br> event message_t* <br> Receive.receive(message_t* msg, void* payload, uint8_t len) {<br> call Leds.led1Toggle(); <br> return msg;<br> }<br>}<br></pre>
! <p> Lets take a look at this program. First note that all nodes
! turn on the radio into the Boot sequence:<br>
! </p>
! <p></p>
! <pre> event void Boot.booted() {<br> call RadioControl.start();<br> }</pre>
! <p>Once we are sure that the radio is on, we start the routing sub-system
! (that
! is, to generate the collection <span style="font-style: italic;">tree</span>):<br>
! </p>
! <pre>call RoutingControl.start();</pre>
! Next we need need to specify the root of the collection tree, that is,
! the node that will receive all the data packets. For this, we use the
! interface RootControl:<br>
! tos/lib/net/RootControl.nc<br>
! <pre>interface RootControl {<br> command error_t setRoot();<br> command error_t unsetRoot();<br> command bool isRoot();<br>}<br></pre>
! <p>This interface controls whether the current node is a root of the
! tree. Using the setRoot() command and assuming that the base station ID
! is 1, we select the root of the collection <span
! style="font-style: italic;">tree</span> as follows:<br>
! </p>
! <pre>if (TOS_NODE_ID == 1) <br> call RootControl.setRoot(); <br>else<br> call Timer.startPeriodic(2000);</pre>
! <p>The remaining nodes in the network periodically generate some data
! and send it to the base station. To send and receive data we use
! two interfaces that will be wired to the collection tree. That is, when
! we call the send command, the data packet will be sent through the
! collection tree. Similarly, the receive event will be only called
! in the root of the tree, that is, in the base station. When the base
! station receives a "collected" packet it just toggle a led. Now
! we will see how to wire these interfaces .<br>
! The <code>EasyCollectionAppC.nc</code>
! provides the needed wiring:<br>
! </p>
! <pre>configuration EasyCollectionAppC {}<br>implementation {<br> components EasyCollectionC, MainC, LedsC, ActiveMessageC;<br> components CollectionC as Collector;<br> components new CollectionSenderC(0xee);<br> components new TimerMilliC();<br><br> EasyCollectionC.Boot -> MainC;<br> EasyCollectionC.RadioControl -> ActiveMessageC;<br> EasyCollectionC.RoutingControl -> Collector;<br> EasyCollectionC.Leds -> LedsC;<br> EasyCollectionC.Timer -> TimerMilliC;<br> EasyCollectionC.Send -> CollectionSenderC;<br> EasyCollectionC.RootControl -> Collector;<br> EasyCollectionC.Receive -> Collector.Receive[0xee];<br>}<br></pre>
! <p>Most of the collection interfaces (RoutingControl, RootControl and
! Receive) are provided by the CollectionC module. The send
! interface is provided by CollectionSenderC which is
! a virtualized collection sender abstraction module.<br>
! This is an extract of the signature of the CollectionC module and
! CollectionSenderC:<br>
! tos/lib/net/ctp/CollectionC.nc<br>
! </p>
! <pre>configuration CollectionC {<br> provides {<br> interface StdControl;<br> interface Send[uint8_t client];<br> interface Receive[collection_id_t id];<br> interface Receive as Snoop[collection_id_t];<br> interface Intercept[collection_id_t id];<br><br> interface Packet;<br> interface CollectionPacket;<br> interface CtpPacket;<br><br> interface CtpInfo;<br> interface CtpCongestion;<br> interface RootControl; <br> }<br></pre>
! <p>tos/lib/net/ctp/CollectionSenderC:<br>
! </p>
! <pre> generic configuration CollectionSenderC(collection_id_t collectid) {<br> provides {<br> interface Send;<br> interface Packet;<br> }</pre>
! <p>Note that the sender and receive interfaces requires a
! collection_id_t to differentiate different possible collections trees. <br>
! Note also that the CollectionC module provides some other
! interfaces in addition to the ones used in this example. As we explained
! previously, the CollectionC module generates a collection tree that
! will be using for
! the routing. These interfaces can be used get information or modify
! this routing tree. For instance, if we want to obtain information about
! this tree we use
! the CtpInfo interface (see tos/lib/net/ctp/CtpInfo.nc) and if we
! want to indicate/query if any node/sink is congested we use the
! CtpCongestion interface (see tos/lib/net/ctp/CtpCongestion.nc)<br>
! </p>
! <p>Finally, to compile this program we create the following
! Makefile:<br>
! </p>
! <pre>COMPONENT=EasyCollectionAppC<br>CFLAGS += -I$(TOSDIR)/lib/net \<br> -I$(TOSDIR)/lib/net/4bitle \<br> -I$(TOSDIR)/lib/net/ctp<br>include $(MAKERULES)<br></pre>
! Now install this program into several nodes (make sure you have one
! base station, that is, one node whose ID is 1) and see how all the
! packets generated in the nodes are collected in the base station.<br>
! <br>
! For more information, read TEP119 [Collection].<br>
! <br>
! <h1>To experiment further <br>
! </h1>
! If you want to experiment with a more complex application take a look
! at apps/test/TestNetwork/ which combines dissemination and collection
! into a single application.<br>
! <br>
! <h1>Related Documentation</h1>
! <ul>
! <li><a href="../tep108.html">TEP 118: Dissemination</a></li>
! <li><a href="../tep119.html">TEP 119: Collection</a><br>
! </li>
! </ul>
! <p>
! </p>
! <hr><br>
! <center>
! <p>< <b><a href="lesson11.html">Previous Lesson</a></b> | <b><a
! href="index.html">Top</a></b> | <b><a href="lesson13.html">Next
! Lesson </a> ></b>
! </p>
! </center>
</body>
! </html>
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
! <title>klueska.com</title>
</head>
+ <frameset>
+ <frame src="http://docs.tinyos.net/index.php/Network_Protocols" name="redir_frame" />
+ <noframes>
<body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/Network_Protocols" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
Index: lesson13.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/lesson13.html,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** lesson13.html 20 Aug 2007 06:37:44 -0000 1.3
--- lesson13.html 28 Jan 2008 05:59:55 -0000 1.4
***************
*** 1,377 ****
! <!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
! <html>
<head>
! <title>TinyOS Tutorial Lesson 13: TinyOS Toolchain</title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet" type="text/css">
</head>
!
<body>
!
! <div class="title">Lesson 13: TinyOS Toolchain</div>
! <div class="subtitle">Last updated October 29 2006</div>
!
! <p> This lesson describes the details of the TinyOS toolchain, including
! the build system, how to create your own Makefile, and how to find out
! more information on the various tools included with TinyOS.
!
! <h1>TinyOS Build System</h1>
!
! As you saw in <a href="lesson1.html">Lesson 1</a>, TinyOS applications
! are built using a somewhat unconventional application of the
! <i>make</i> tool. For instance, in the <code>apps/Blink</code> directory,
!
! <pre>$ make mica2
! </pre>
!
! compiles Blink for the mica2 platform,
!
! <pre>$ make mica2 install
! </pre>
!
! compiles and installs (using the default parallel port programmer) Blink
! for the mica2, and
!
! <pre>$ make mica2 reinstall mib510,/dev/ttyS0
! </pre>
!
! installs the previously compiled mica2 version of Blink using the MIB510
! serial port programmer connected to serial port /dev/ttyS0.
!
! <p>
! As these examples show, the TinyOS build system is controlled by passing
! arguments to make that specify the target platform, the desired action,
! and various options. These arguments can be categorised as follows:
!
! <ul>
! <li>Target platform: one of the supported TinyOS platforms, e.g., <b>mica2</b>,
! <b>telosb</b>, <b>tinynode</b>. A target platform is always required,
! except when using the <b>clean</b> action.<p>
!
! <li>Action: the action to perform. By default, the action is to compile
! the application in the current directory, but you can also specify:
!
! <ul>
! <li> <b>help</b>: display a help message for the target platform.
! <li> <b>install,<i>N</i></b>: compile and install. The <i>N</i> argument
! is optional and specifies the mote id (default 1).
! <li> <b>reinstall,<i>N</i></b>: install only (fails if the application wasn't previously compiled). <i>N</i> is as for <b>install</b>.
! <li> <b>clean</b>: remove compiled application for all platforms.
! <li> <b>sim</b>: compile for the simulation environment for the specified platform (see <a href="lesson11.html">Lesson 11</a> for details).
! </ul>
!
! Example: to compile for simulation for the micaz:
! <pre>$ make micaz sim</pre>
!
! <li>Compilation option: you can change the way compilation proceeds by
! specifying:
! <ul>
! <li> <b>debug</b>: compile for debugging. This enables debugging, and
! turns off optimisations (e.g., inlining) that make debugging
! difficult.
! <li> <b>debugopt</b>: compile for debugging, but leave optimisations
! enabled. This can be necessary if compiling with <b>debug</b>
! gives code that is too slow, or if the bug only shows up when
! optimisation is enabled.
! <li> <b>verbose</b>: enable a lot of extra output, showing all commands
! executed by <i>make</i> and the details of the nesC compilation
! including the full path of all files loaded. This can be helpful
! in tracking down problems (e.g., when the wrong version of a
! component is loaded).
! <li> <b>wiring</b>, <b>nowiring</b>: enable or disable the use of
! the nescc-wiring to check the wiring annotations in a nesC
! program. See the nescc-wiring man page for more details.
! </ul>
!
! Example: to do a verbose compilation with debugging on the telosb:
! <pre>$ make debug verbose telosb</pre>
!
! <p>Additionally, you can pass additional compilation options by
! setting the CFLAGS environment variable when you invoke make. For instance,
! to compile <code>apps/RadioCountoToLeds</code> for a mica2 with
! a 900MHz radio set to ~916.5MHz, you would do:
!
! <pre>$ env CFLAGS="-DCC1K_DEF_FREQ=916534800" make mica2 </pre>
!
! Note that this will not work with applications whose Makefile
! defines CFLAGS (but this practice is discouraged, see the section
! on <a href="#makefile">writing Makefiles</a> below).<p>
!
! <li>Installation option: some platforms have multiple programmers, and
! some programmers require options (e.g., to specify which serial port
! to use). The programmer is specified by including its name amongst the
! <i>make</i> arguments. Known programmers include <b>bsl</b> for
! msp430-based platforms and <b>avrisp</b> (STK500), <b>dapa</b> (MIB500
! and earlier), <b>mib510</b> (MIB510) and <b>eprb</b> (MIB600) for mica
! family motes.
!
! <p>Arguments to the programmer are specified with a comma after the
! programmer name, e.g.,
!
! <pre>$ make mica2dot reinstall mib510,/dev/ttyUSB1 </pre>
! <pre>$ make telosb reinstall bsl,/dev/ttyUSB1 </pre>
!
! to specify that the programmer is connected to serial port /dev/ttyUSB1.
!
! <p>More details on the programmers and their options can be found in
! your mote documentation.
!
! </ul>
!
! <h1>Customising the Build System</h1>
!
! You may find that you are often specifying the same options, e.g., that
! your mib510 programmer is always connected to /dev/ttyS1 or that you
! want to use channel 12 of the CC2420 radio rather than the default
! TinyOS 2 channel (26). To do this, put the following lines
!
! <pre>
! MIB510 ?= /dev/ttyS1
! PFLAGS = -DCC2420_DEF_CHANNEL=12
! </pre>
! in a file called <code>Makelocal</code> in the <code>support/make</code>
! directory. If you now compile in <code>apps/RadioCountToLeds</code>, you
! will see:
! <pre>
! $ make micaz install mib510
! compiling RadioCountToLedsAppC to a micaz binary
! ncc -o build/micaz/main.exe -Os <b>-DCC2420_DEF_CHANNEL=12</b> ... RadioCountToLedsAppC.nc -lm
! compiled RadioCountToLedsAppC to build/micaz/main.exe
! ...
! installing micaz binary using mib510
! uisp -dprog=mib510 <b>-dserial=/dev/ttyS1</b> ...
! </pre>
!
! The definition of <code>PFLAGS</code> passes an option to the nesC
! compiler telling it to define the C preprocessor symbol
! <code>CC2420_DEF_CHANNEL</code> to 12. The CC2420 radio stack checks
! the value of this symbol when setting its default channel.
!
! <p>The definition of <code>MIB510</code> sets the value of the
! argument to the <b>mib510</b> installation option, i.e.,
! <pre>$ make micaz install mib510 </pre>
! is now equivalent to
! <pre>$ make micaz install mib510,/dev/ttyS1 </pre>
!
! Note that the assignment to MIB510 was written using the <code>?=</code>
! operator. If you just use regular assignment (<code>=</code>), then the
! value in <code>Makelocal</code> will override any value you specify
! on the command line (which is probably not what you want...).
!
! <p><code>Makelocal</code> can contain definitions for any <i>make</i>
! variables used by the build system. Unless you understand the details of
! how this works, we recommend you restrict yourselves to defining:
!
! <ul>
! <li> <code>PFLAGS</code>: extra options to pass to the nesC compiler. Most
! often used to define preprocessor symbols as seen above.
! <li> <code><i>X</i></code>: set the argument for <i>make</i> argument <i>
! x</i>, e.g., <code>MIB510</code> as seen above. You can, e.g., set the
! default mote id to 12 by adding <code>INSTALL ?= 12</code> and
! <code>REINSTALL ?= 12</code> to <code>Makelocal</code>.
! </ul>
!
! <p>Some useful preprocessor symbols that you can define with
! <code>PFLAGS</code> include:
! <ul>
! <li> DEFINED_TOS_AM_ADDRESS: the motes group id (default is 0x22).
! <li> CC2420_DEF_CHANNEL: CC2420 channel (default is 26).
! <li> CC1K_DEF_FREQ: CC1000 frequency (default is 434.845MHz).
! <li> TOSH_DATA_LENGTH: radio packet payload length (default 28).
! </ul>
! <p>
!
! <a name="makefile">
! <h1>Application Makefiles</h1>
! </a>
!
! To use the build system with your application, you must create a makefile
! (a file called <code>Makefile</code>) which contains at the minimum:
!
! <pre>
! COMPONENT=<i>TopLevelComponent</i>
! include $(MAKERULES)
! </pre>
! where <i>TopLevelComponent</i> is the name of the top-level component
! of your application.
!
! <p>TinyOS applications commonly also need to specify some options to the
! nesC compiler, and build some extra files alongside the TinyOS
! application. We will see examples of both, by looking at, and making a
! small change to, the <code>apps/RadioCountToLeds</code> application.
!
! <p>The RadioCountToLeds Makefile uses <code>mig</code> (see <a
! href="lesson4.html">Lesson 4</a>) to build files describing the layout
! of its messages, for use with python and Java tools:
!
! <pre>
! COMPONENT=RadioCountToLedsAppC
! <b>BUILD_EXTRA_DEPS = RadioCountMsg.py RadioCountMsg.class</b>
!
! RadioCountMsg.py: RadioCountToLeds.h
! mig python -target=$(PLATFORM) $(CFLAGS) -python-classname=RadioCountMsg RadioCountToLeds.h RadioCountMsg -o $@
!
! RadioCountMsg.class: RadioCountMsg.java
! javac RadioCountMsg.java
!
! RadioCountMsg.java: RadioCountToLeds.h
! mig java -target=$(PLATFORM) $(CFLAGS) -java-classname=RadioCountMsg RadioCountToLeds.h RadioCountMsg -o $@
!
! include $(MAKERULES)
! </pre>
!
! The first and last line of this Makefile are the basic lines present in
! all TinyOS Makefiles; the line in bold defining BUILD_EXTRA_DEPS
! specifies some additional <i>make</i> targets to build alongside the
! main TinyOS application (if you are not familiar with make, this may be a
! good time to read a make tutorial, e.g., <a
! href="http://oucsace.cs.ohiou.edu/~bhumphre/makefile.html">this
! one</a>).
!
! <p>When you compile RadioCountToLeds for the first time, you will see that
! the two extra targets, <code>RadioCountMsg.py</code> and
! <code>RadioCountMsg.class</code>, are automatically created:
! <pre>
! $ make mica2
! mkdir -p build/mica2
! mig python -target=mica2 -python-classname=RadioCountMsg RadioCountToLeds.h RadioCountMsg -o RadioCountMsg.py
! mig java -target=mica2 -java-classname=RadioCountMsg RadioCountToLeds.h RadioCountMsg -o RadioCountMsg.java
! javac RadioCountMsg.java
! compiling RadioCountToLedsAppC to a mica2 binary
! ...
! </pre>
!
! As this Makefile is written, these generated files are not deleted when
! you execute <code>make clean</code>. Fix this by adding the following line:
! <pre>
! CLEAN_EXTRA = $(BUILD_EXTRA_DEPS) RadioCountMsg.java
! </pre>
! to <code>apps/RadioCountToLeds/Makefile</code>. This defines the CLEAN_EXTRA
! make variable to be the same as BUILD_EXTRA_DEPS, with RadioCountMsg.java
! added to the end. The build system's <b>clean</b> target deletes all files
! in CLEAN_EXTRA:
! <pre>
! $ make clean
! rm -rf build RadioCountMsg.py RadioCountMsg.class RadioCountMsg.java
! rm -rf _TOSSIMmodule.so TOSSIM.pyc TOSSIM.py
! </pre>
!
! Finally, to see how to pass options to the nesC compiler, we will change
! RadioCountToLeds's source code to set the message sending period based
! on the preprocessor symbol <code>SEND_PERIOD</code>. Change the line in
! <code>RadioCountToLedsC.nc</code> that reads
! <pre> call MilliTimer.startPeriodic(1000);</pre>
! to
! <pre> call MilliTimer.startPeriodic(SEND_PERIOD);</pre>
! and add the following line to RadioCountToLeds's Makefile:
! <pre>
! CFLAGS += -DSEND_PERIOD=2000
! </pre>
! Note the use of <code>+=</code> when defining CFLAGS: this allows the user
! to also pass options to nesC when invoking make as we saw above (<code>env CFLAGS=x make ...</code>).
!
! <p>Now compiling RadioCountToLeds gives:
! <pre>
! $ make mica2
! ...
! compiling RadioCountToLedsAppC to a mica2 binary
! ncc -o build/mica2/main.exe ... <b>-DSEND_PERIOD=2000</b> ... RadioCountToLedsAppC.nc -lm
! compiled RadioCountToLedsAppC to build/mica2/main.exe
! ...
! </pre>
!
! <h1>TinyOS Tools</h1>
!
! The TinyOS build system is designed to make it easier to write Makefiles
! for applications that support multiple platforms, programmers, etc in
! a uniform way. However, it's use is not compulsory, and all the tools it
! is built on can be used in your own build system (e.g., your own Makefile
! or simple build script). Below we show how to build and install the
! RadioCountToLeds application for a micaz with the mib510 programmer
! using just a few commands.
!
! <p>First, we compile RadioCountToLedsAppC.nc (the main component of
! the application) using the nesC compiler, ncc:
! <pre>
! $ ncc -target=micaz -o rcl.exe -Os -finline-limit=100000 -Wnesc-all -Wall RadioCountToLedsAppC.nc
! </pre>
!
! This generates an executable file, <code>rcl.exe</code>. Next, we want
! to install this program on a mote with mote id 15. First, we create a
! new executable, <code>rcl.exe-15</code>, where the variables storing the
! mote's identity are changed to 15, using the
! <code>tos-set-symbols</code> command:
! <pre>
! $ tos-set-symbols rcl.exe rcl.exe-15 TOS_NODE_ID=15 ActiveMessageAddressC\$addr=15
! </pre>
!
! Finally, we install this executable on the micaz using <code>uisp</code>,
! to a mib510 programmer connected to port /dev/ttyUSB1:
! <pre>$ uisp -dpart=ATmega128 -dprog=mib510 -dserial=/dev/ttyUSB1 --erase --upload if=rcl.exe-15
! Firmware Version: 2.1
! Atmel AVR ATmega128 is found.
! Uploading: flash
! </pre>
!
! If you wish to follow this route, note two things: first, you can find out
! what commands the build system is executing by passing the <code>-n</code>
! option to make, which tells it to print rather than execute commands:
! <pre>
! $ make -n micaz install.15 mib510
! mkdir -p build/micaz
! echo " compiling RadioCountToLedsAppC to a micaz binary"
! ncc -o build/micaz/main.exe -Os -finline-limit=100000 -Wall -Wshadow -Wnesc-all -target=micaz -fnesc-cfile=build/micaz/app.c -board=micasb -fnesc-dump=wiring -fnesc-dump='interfaces(!abstract())' -fnesc-dump='referenced(interfacedefs, components)' -fnesc-dumpfile=build/micaz/wiring-check.xml RadioCountToLedsAppC.nc -lm
! nescc-wiring build/micaz/wiring-check.xml
! ...
! </pre>
!
! Second, all the commands invoked by the build system should have man pages
! describing their behaviour and options. For instance, try the following
! commands:
! <pre>
! $ man tos-set-symbols
! $ man ncc
! $ man nescc
! </pre>
!
! <h1>Related Documentation</h1>
! </a>
! <ul>
! <li> mica mote Getting Started Guide at <a href="http://www.xbow.com">Crossbow</a>
! <li> telos mote Getting Started Guide for <a href="http://www.moteiv.com">Moteiv</a>
! <li> <a href="lesson1.html">Lesson 1</a> introduced the build system.
! <li> <a href="lesson10.html">Lesson 10</a> describes how to add a new platform
! to the build system.
! <li> GNU make man page.
! <li> man pages for the nesC compiler (man ncc, man nescc) and the various
! TinyOS tools.
! </ul>
!
! <!-- Begin footer -->
! <br>
! <hr>
! <center>
! <p>< <b><a href="lesson12.html">Previous Lesson</a></b> | <b><a
! href="index.html">Top</a></b> | <b><a href="lesson15.html">Next Lesson </a> ></b>
! </center>
!
</body>
! </html>
!
! <!-- LocalWords: toolchain mib telosb tinynode sim micaz inlining debugopt nc
! -->
! <!-- LocalWords: nowiring nescc CFLAGS env DCC practice bsl msp avrisp STK lm
! -->
! <!-- LocalWords: dapa eprb PFLAGS RadioCountToLedsAppC ncc uisp dprog dserial
! -->
! <!-- LocalWords: TOS TOSH TopLevelComponent MAKERULES RadioCountToLeds DEPS
! -->
! <!-- LocalWords: RadioCountMsg py mig classname java javac mkdir rf TOSSIM
! -->
! <!-- LocalWords: TOSSIMmodule pyc RadioCountToLeds's MilliTimer startPeriodic
! -->
! <!-- LocalWords: DSEND rcl exe finline Wnesc tos ActiveMessageAddressC addr
! -->
! <!-- LocalWords: dpart ATmega Atmel AVR Wshadow fnesc cfile micasb dumpfile
! -->
! <!-- LocalWords: interfacedefs telos Moteiv
! -->
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
! <title>klueska.com</title>
</head>
! <frameset>
! <frame src="http://docs.tinyos.net/index.php/TinyOS_Toolchain" name="redir_frame" />
! <noframes>
<body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/TinyOS_Toolchain" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
Index: lesson15.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/lesson15.html,v
retrieving revision 1.9
retrieving revision 1.10
diff -C2 -d -r1.9 -r1.10
*** lesson15.html 4 Sep 2007 22:51:38 -0000 1.9
--- lesson15.html 28 Jan 2008 05:59:55 -0000 1.10
***************
*** 1,381 ****
! <html>
! <head>
! <title>TinyOS Tutorial Lesson 15: The TinyOS printf Library</title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet" Type="text/css">
! </head>
! <body>
!
! <div class="title">Lesson 15: The TinyOS <code><font size=6>printf</font></code> Library</div>
! <div class="subtitle">Last updated August 19th, 2007</div>
!
! <p>This lesson demonstrates how to use the <code>printf</code> library located in
! <code>tos/lib/printf</code> to debug TinyOS applications by printing messages over
! the serial port.</p>
!
! <h1>Overview</h1>
! <p>
! Anyone familiar with TinyOS knows that debugging applications has
! traditionally been a very arduous, if not stressful process. While simulators
! like TOSSIM can be used to help verify the logical correctness of a program,
! unforseen problems inevitably arise once that program is deployed on
! real hardware. Debugging such a program typically involves flashing the
! three available LEDs in some intricate sequence or resorting to line by line
! analysis of a running program through the use of a JTAG.
! </p>
! <p>
! It is common practice when developing desktop applications to print output
! to the terminal screen for debugging purposes. While tools such as
! <code>gdb</code> provide means of stepping though a program line by line,
! often times developers simply want to quickly print something to the screen
! to verify that the value of a variable has been set correctly, or determine
! that some sequence of events is being run in the proper order. It would be
! absurd to suggest that they only be allowed three bits of information in order
! to do so.
! </p>
! <p>
! The TinyOS <code>printf</code> library provides this terminal printing functionality
! to TinyOS applications through motes connected to a pc via their serial interface.
! Messages are printed by calling
! <code>printf</code> commands using a familiar syntax borrowed from the C programming
! language. In order to use this functionality, developers simply need to include
! a single component in their top level configuration file (<code>PrintfC</code>),
! and include a <code>"printf.h"</code> header file in any components that actually call
! <code>printf()</code>.
! </p>
! <p>
! Currently, the <code>printf</code> library is only supported on msp430 and atmega128x
! based platforms (e.g. mica2, micaZ, telos, eyesIFX). In the future we hope to add
! support for other platforms as well.
! </p>
! <h1>The TinyOS <code>printf</code> Library</h1>
! This section provides a basic overview of the TinyOS <code>printf</code> library,
! including the components that make it up and the interfaces they provide.
! In the following section we walk you through the process of actually using these components
! to print messages from a mote to your pc. If you dont care how <code>printf</code>
! works and only want to know how to use it, feel free to skip ahead to the next section.
! <hr></hr>
! The entire <code>printf</code> library consists of only 4 files located
! in the <code>tos/lib/printf</code> directory: one module,
! one configuration, one interface file, and one header file.
! <br><br>
! <ul>
! <li><b>PrintfC.nc</b> -- Configuration file providing printf functionality to TinyOS applications
! <li><b>PrintfP.nc</b> -- Module implementing the printf functionality
! <li><b>PrintfFlush.nc</b> -- Interface for flushing printf messages over the serial port to a pc
! <li><b>printf.h</b> -- Header file specifying the printf message format and size of the flush buffer</pre>
! </ul>
! <p>
! The <code>PrintfC</code> configuration is the only component an application needs to wire
! in order to use the functionality provided by the TinyOS <code>printf</code>
! library. Below is the component graph of the <code>PrintfC</code> configuration:
! </p>
! <center><img src=img/printf_components.png></img><p><b>Figure 1: The component
! graph of the PrintfC configuration.</b></p></center>
! <p>
! Conceptually, the operation of the TinyOS <code>printf</code> library is very
! simple. Developers supply strings to <code>printf()</code> commands in a
! distributed fashion throughout any of the components that make up a complete
! TinyOS application. These strings are buffered in a central location inside
! the <code>PrintfP</code> component and flushed out to a PC in the form of
! TinyOS SerialMessages upon calling the <code>flush()</code> command of the
! <code>PrintfFlush</code> interface.
! </p>
! <p>
! By encapsulating the strings produced by calls to <code>printf()</code> inside
! standard TinyOS SerialMessages, applications that use the serial stack for
! other purposes can share the use of the serial port. Alternate
! implementations were considered in which <code>printf</code> would have
! had exclusive access to the serial port, and explicit flushing would not have
! been necessary. In the end, we felt it was better to give developers the
! freedom to decide exactly when messages should be printed, as well as allow them
! to send multiple types of SerialMessages in a single application.
! </p>
! <p>
! Currently, only a single buffer is used to store the strings supplied to
! calls to <code>printf</code> before flushing them. This means that while
! the buffer is being flushed, any calls to <code>printf</code> will fail.
! In the future, we plan to implement a double buffered approach so that
! strings can continue to be buffered at the same time they are being printed.
! </p>
! <p>
! There are also plans to provide a means of flushing messages out to a PC
! without requiring developers to make an explicit <code>flush()</code> call.
! This would allow developers to simply wire in the <code>PrintfC</code> component
! without having to make any calls to any interfaces it provides. In fact,
! the <code>PrintfC</code> component would not need to provide any interfaces
! at all. It would start itself up and then run in a loop, periodically
! flushing the contents of the <code>printf</code> buffer.
! Such functionality is useful in applications that do not really care when
! messages are printed or how long a delay the process of printing introduces
! to other sections of code. Explicit flushing would still be recommended in
! applications where the sections of code under examinatation are very timing
! sensitive (e.g. inside the CC2420 radio stack).
! </p>
! <h1>Using the TinyOS <code>printf</code> Library</h1>
!
! <p>
! To help guide the process of using the <code>printf</code> library, a
! <code>TestPrintf</code> application has been created.
! At present, this application is not included in
! the official TinyOS distribution (<= 2.0.2). If you are using TinyOS
! from a cvs checkout, you will find it located under
! <code>apps/tutorials/Printf</code>. Otherwise, you can obtain it from
! cvs by running the following set of commands from a terminal window:
! </p>
!
! <pre>
! cd $TOSROOT/apps/tutorials
! cvs -d:pserver:anonymous at tinyos.cvs.sourceforge.net:/cvsroot/tinyos login
! cvs -z3 -d:pserver:anonymous at tinyos.cvs.sourceforge.net:/cvsroot/tinyos co -P -d Printf tinyos-2.x/apps/tutorials/Printf</pre>
! <p>
! Just hit enter when prompted for a CVS password. You do not need to enter one.
! </p>
!
! <p>
! If you are not using cvs, you will also have to apply the patch
! found <a href=http://sing.stanford.edu/klueska/tinyos-2.0-printf.patch>here</a>
! in order to allow the <code>printf</code> library to compile correctly for
! atmega128x based platforms (i.e. mica2, micaz):
! </p>
! <pre>
! cp tinyos-2.0-printf.patch $TOSROOT/..
! cd $TOSROOT/..
! patch -p0 < tinyos-2.0-printf.patch</pre>
! <p>
! Note that you may have to use 'sudo' when applying the patch if you run into
! permission problems.
! </p>
!
! <hr></hr>
!
! <p>
! The <code>TestPrintf</code> application demonstrates everything necessary
! to use the <code>printf</code> library. Go ahead and open the
! <code>TestPrintfAppC</code> configuration to see how the various interfaces
! provided by the <code>PrintfC</code> component have been wired in. You will
! want to do something similar in your own applications.
!
! <pre>
! configuration TestPrintfAppC{
! }
! implementation {
! components MainC, TestPrintfC, LedsC;
! components PrintfC;
!
! TestPrintfC.Boot -> MainC;
! TestPrintfC.Leds -> LedsC;
! TestPrintfC.PrintfControl -> PrintfC;
! TestPrintfC.PrintfFlush -> PrintfC;
! }</pre>
!
! <p>
! First, the <code>PrintfControl</code> interface has been wired in to enable turning on and
! off the service providing <code>printf</code> functionality. Turning on
! the <code>Printf</code> service implicity
! turns on the serial port for sending messages. Second, the <code>PrintfFlush</code>
! interface has been wired in to allow the application to control when
! <code>printf</code> messages should be flushed out over the serial line. In this
! application, all <code>printf()</code> commands are called directly within the
! <code>TestPrintfC</code> component. In general, <code>printf()</code> commands can be
! called from any component as long as they have included the <code>"printf.h"</code>
! header file.
! </p>
! <hr></hr>
! <p>
! Before examining the <code>TestPrintfC</code> component, first install the
! application on a mote and see what kind of output it produces.
! Note that the instructions here are only valid for installation on a telosb mote
! on a linux based TinyOS distribution.
! For installation on other systems or for other mote platforms, please refer to
! <a href="lesson1.html"> lesson 1</a> for detailed instructions.
! </p>
! <p>
! To install the application on the mote, run the following set of commands.
! </p>
! <pre>
! cd $TOSROOT\apps\tests\TestPrintf
! make telosb install bsl,/dev/ttyUSBXXX</pre>
! <p>
! You will notice during the installation process that a pair of java files are
! compiled along with the TinyOS application. The first java file,
! <code>PrintfMsg.java</code>, is generated by <code>mig</code>
! to encapsulate a TinyOS <code>printf</code> message received over the serial
! line (for more information on mig and how it generates these files, please refer
! to the section entitled "MIG: generating packet objects" in
! <a href=lesson4.html>lesson 4</a>). The second file, <code>PrintfClient.java</code>
! is used to read <code>printf</code> messages received from a mote and print
! them to your screen.
! </p>
! <p>
! To see the output generated by <code>TestPrintf</code> you need to start the
! <code>PrintfClient</code> by running the following command:
! </p>
! <pre>
! cd $TOSROOT\apps\tests\TestPrintf
! java PrintfClient -comm serial@/dev/ttyUSBXXX:telosb</pre>
!
! <p>
! After resetting the mote, the following output should be printed to your screen:
! </p>
! <pre>
! Hi I am writing to you from my TinyOS application!!
! Here is a uint8: 123
! Here is a uint16: 12345
! Here is a uint32: 1234567890
! I am now iterating: 0
! I am now iterating: 1
! I am now iterating: 2
! I am now iterating: 3
! I am now iterating: 4
! This is a really short string...
! I am generating this string to have just less than 250
! characters since that is the limit of the size I put on my
! maximum buffer when I instantiated the PrintfC component.
! Only part of this line should get printed bec</pre>
!
! <p>
! Note that the 'tty' device (i.e. COM port) specified when starting the PrintfClient
! MUST be the one used for communicating with a mote over the serial line. On telos
! and mica motes this is the same port that the mote is programmed from. Other motes,
! such as eyesIFX, have one port dedicated to programming and another for
! communication. Just make sure you use the correct one.
! </p>
! <p>
! If for some reason you do not receive the output shown above, please refer
! to <a href=lesson4.html>lesson 4</a> to verify you have done everything
! necessary to allow serial communication between your pc and the mote. Remember
! that when using the MIB510 programming board that the switch on the very front
! of the board must be set to the <font style=bold>OFF</font> position in order to send
! messages from the mote to the pc.
! </p>
! <hr></hr>
! <p>
! Go ahead and open up <code>TestPrintfC</code> to see how this output is being generated.
! </p>
! <p>
! Upon receiving the booted event, the <code>Printf</code> service is started via a call to
! <code>PrintfControl.start()</code>
! </p>
! <pre>
! event void Boot.booted() {
! call PrintfControl.start();
! }</pre>
! <p>
! Once the <code>Printf</code> service has been started, a
! <code>PrintfControl.startDone()</code> event is generated. In the body of this event
! the first four
! lines of output are generated by making successive calls to <code>printf</code>
! and then flushing the buffer they are stored in.
! </p>
! <pre>
! event void PrintfControl.startDone(error_t error) {
! printf("Hi I am writing to you from my TinyOS application!!\n");
! printf("Here is a uint8: %u\n", dummyVar1);
! printf("Here is a uint16: %u\n", dummyVar2);
! printf("Here is a uint32: %ld\n", dummyVar3);
! call PrintfFlush.flush();
! }</pre>
! <p>
! Once these first four lines have been flushed out, the <code>PrintfFlush.flushDone()</code>
! event is signaled. The body of this event first prints the next 5 lines in a loop,
! followed by the last five lines. Finally, once all lines have been printed, the
! <code>Printf</code> service is stopped via a call to <code>PrintfControl.stop()</code>.
! </p>
! <pre>
! event void PrintfFlush.flushDone(error_t error) {
! if(counter < NUM_TIMES_TO_PRINT) {
! printf("I am now iterating: %d\n", counter);
! call PrintfFlush.flush();
! }
! else if(counter == NUM_TIMES_TO_PRINT) {
! printf("This is a really short string...\n");
! printf("I am generating this string to have just less <font color=red>...</font>
! printf("Only part of this line should get printed bec <font color=red>...</font>
! call PrintfFlush.flush();
! }
! else call PrintfControl.stop();
! counter++;
! }</pre>
! <p>
! Notice that the last line of output is cut short before being fully printed.
! If you actually read the line printed above it you can see why. The buffer
! used to store TinyOS <code>printf</code> messages before they are flushed
! is by default limited to 250 bytes. If you try and print more characters than
! this before flushing, then only the first 250 characters will actually be printed.
! This buffer size is configurable, however, by specifying the proper CFLAGS option
! in your Makefile.
! </p>
! <pre>
! CFLAGS += -DPRINTF_BUFFER_SIZE=XXX</pre>
! <p>
! Once the the <code>Printf</code> service has been stopped, the
! <code>PrintfControl.stopDone()</code> event is signaled and Led 2 is turned
! on to signify that the application has terminated.
! </p>
! <pre>
! event void PrintfControl.stopDone(error_t error) {
! counter = 0;
! call Leds.led2Toggle();
! printf("This should not be printed...");
! call PrintfFlush.flush();
! }
! </pre>
! <p>
! Notice that the call to <code>printf()</code> inside the body of the
! <code>PrintfControl.stopDone()</code> event never produces any output.
! This is because the <code>Printf</code> service has been stopped before
! this command is called.
! </p>
! <h1>Conclusion</h1>
! <p>
! A few points are worthy of note before jumping in and writing your own applications that
! use the functionality provided by the <code>printf</code> library.
! </p>
! <ol>
! <li>In order to use the <code>printf</code> library, the <code>tos/lib/printf</code>
! directory must be in your include path. The easiest way to include it is
! by adding the following line directly within the Makefile of your top
! level application:
! <pre>
! CFLAGS += -I$(TOSDIR)/lib/printf</pre>
! Remember that changing the <code>printf</code> buffer size is done similarly:
! <pre>
! CFLAGS += -DPRINTF_BUFFER_SIZE=XXX</pre>
! </li>
! <li>You MUST be sure to #include <code>"printf.h"</code> header file in
! every component in which you would like to call the <code>printf()</code>
! command. Failure
! to do so will result in obscure error messages making it difficult to identify
! the problem.</li>
! </ol>
!
! <p>
! Hopefully you now have everything you need to get going with the TinyOS <code>printf</code>
! library. All questions (or comments) about the use of this library should be directed to
! <a href=mailto:tinyos-help at millennium.berkeley.edu>tinyos-help</a> mailing list.
! </p>
!
! <p>
! Enjoy!!
! </p>
!
! <!--
! <a name=#related_docs>
! <h1>Related Documentation</h1>
! </a>
! <ul>
! <li> <a href="../tep102.html">TEP 102: Timers</a>
! <li> <a href="../tep106.html">TEP 106: Schedulers and Tasks</a>
! </ul>
! -->
!
! <!-- Begin footer -->
! <br>
! <hr>
! <center>
! <p>< <b><a href="lesson13.html">Previous Lesson</a></b> | <b><a
! href="index.html">Top</a></b> | <b><a href="lesson16.html">Next Lesson </a> ></b>
! </center>
!
</body>
! </html>
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
! <head>
! <title>klueska.com</title>
! </head>
! <frameset>
! <frame src="http://docs.tinyos.net/index.php/The_TinyOS_printf_Library" name="redir_frame" />
! <noframes>
! <body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/The_TinyOS_printf_Library" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
Index: lesson16.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/lesson16.html,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** lesson16.html 4 Sep 2007 22:51:38 -0000 1.2
--- lesson16.html 28 Jan 2008 05:59:55 -0000 1.3
***************
*** 1,465 ****
! <html>
! <head>
! <title>TinyOS Tutorial Lesson 16: Writing Low Power Sensing Applications</title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet" Type="text/css">
! </head>
! <body>
!
! <div class="title">Lesson 16: Writing Low Power Sensing Applications</div>
! <div class="subtitle">Last updated August 31st, 2007</div>
!
! <p>
! This lesson demonstrates how to write low power sensing applications in TinyOS. At
! any given moment, the power consumption of a wireless sensor node is a function of its
! microcontroller power state, whether the radio, flash, and sensor peripherals are on,
! and what operations active peripherals are performing. This tutorial shows you
! how to best utilize the features provided by TinyOS to keep the power consumption
! of applications that use these devices to a minumum.
! </p>
!
! <h1>Overview</h1>
! <p>
! Energy management is a critical concern in wireless sensor networks. Without it,
! the lifetime of a wireless sensor node is limited to just a few short weeks or even
! days, depending on the type of application it is running and the size of batteries
! it is using. With proper energy management, the same node, running the
! same application, can be made to last for months or years on the same set of batteries.
! </p>
! <p>
! Ideally, one would want all energy management to be handled transparently by the
! operating system, relieving application developers from having to deal with this
! burden themselves. While attempts have been made in the past to provide such
! capabilities, most operating systems today still just provide the necessary primitives for
! performing energy management -- the logic of when and how to do so is left completely up
! to the application.
! </p>
! <p>
! TinyOS provides a novel method of performing energy management directly
! within the OS. The method it uses is as efficient as it is elegant. Developers
! no longer have to struggle with code that explicitly manages the power state for any of the
! peripheral devices that it uses. To get a better idea of the complexity involved in
! doing something as simple as periodically taking a set of sensor readings
! and logging them to flash in the most energy efficient manner possible, take a look
! at the pseudo code found below.
! </p>
! <pre>
! Every Sample Period:
! Turn on SPI bus
! Turn on flash chip
! Turn on voltage reference
! Turn on I2C bus
! Log prior readings
! Start humidity sample
! Wait 5ms for log
! Turn off flash chip
! Turn off SPI bus
! Wait 12ms for vref
! Turn on ADC
! Start total solar sample
! Wait 2ms for total solar
! Start photo active sample
! Wait 2ms for photo active
! Turn off ADC
! Turn off vref
! Wait 34ms for humidity
! Start temperature sample
! Wait 220ms for temperature
! Turn off I2C bus
! </pre>
! <p>
! With the methods provided by TinyOS, hand-tuned application code that looks like that
! can be transformed into this:
! </p>
! <pre>
! Every Sample Period:
! Log prior readings
! Sample photo active
! Sample total solar
! Sample temperature
! Sample humidity
! </pre>
! <p>
! The pseudo code shown above is for concurrently sampling all of the
! the onboard sensors found on the latest revision of the tmote sky sensor nodes.
! Experiments have shown that using the methods provided by TinyOS, this application
! comes within 1.6% of the energy efficiency of the hand-tuned implementation --
! even at sampling rates as fast as 1 sample per second. For more information
! on these experiments and the method TinyOS uses to actually manage energy
! so efficiently, please refer to the paper found
! <a href="http://sing.stanford.edu/klueska/Black_Site/Publications_files/klues07icem.pdf">
! here.</a>
! </p>
! <!---
! <center>
! <img src="img/tmote_current.png" width=66% ></img>
! </center>
! -->
! <p>
! The rest of this tutorial is dedicated to teaching you how to write applications
! that allow TinyOS to manage energy for you in the most efficient manner possible.
! As a rule, TinyOS can manage energy more efficiently when I/O requests are submitted
! by an application in parallel. Submitting them serially may result in energy
! wasted by unnecessarily turning devices on and off more frequently than required.
! </p>
! <h1>
! Peripheral Energy Management
! </h1>
! <p>
! Compare the following two code snippets:
! </p>
! <table>
! <tr><td><b>Parallel</b></td><td width=10></td><td><b>Serial</b></td></tr>
! <tr><td valign=top>
! <pre>
! event void Boot.booted() {
! call Timer.startPeriodic(SAMPLE_PERIOD);
! }
!
! event void Timer.fired() {
! call LogWrite.append(current_entry, sizeof(log_entry_t));
!
! current_entry_num = !current_entry_num;
! current_entry = &(entry[current_entry_num]);
! current_entry->entry_num = ++log_entry_num;
!
! call Humidity.read();
! call Temperature.read();
! call Photo.read();
! call Radiation.read();
! }
!
! event void Humidity.readDone(error_t result, uint16_t val) {
! if(result == SUCCESS) {
! current_entry->hum = val;
! }
! else current_entry->hum = 0xFFFF;
! }
!
! event void Temperature.readDone(error_t result, uint16_t val) {
! if(result == SUCCESS) {
! current_entry->temp = val;
! }
! else current_entry->temp = 0xFFFF;
! }
!
! event void Photo.readDone(error_t result, uint16_t val) {
! if(result == SUCCESS) {
! current_entry->photo = val;
! }
! else current_entry->photo = 0xFFFF;
! }
!
! event void Radiation.readDone(error_t result, uint16_t val) {
! if(result == SUCCESS) {
! current_entry->rad = val;
! }
! else current_entry->rad = 0xFFFF;
! }
!
! event void LogWrite.appendDone(void* buf,
! storage_len_t len,
! bool recordsLost,
! error_t error) {
! if (error == SUCCESS)
! call Leds.led2Toggle();
! }
! </pre>
! </td>
! <td></td>
! <td valign=top>
! <pre>
! event void Boot.booted() {
! call Timer.startPeriodic(SAMPLE_PERIOD);
! }
!
! event void Timer.fired() {
! call Humidity.read();
! }
!
! event void Humidity.readDone(error_t result, uint16_t val) {
! if(result == SUCCESS) {
! entry->rad = val;
! }
! else current_entry->rad = 0xFFFF;
! call Temperature.read();
! }
!
! event void Temperature.readDone(error_t result, uint16_t val) {
! if(result == SUCCESS) {
! entry->rad = val;
! }
! else current_entry->rad = 0xFFFF;
! call Photo.read();
! }
!
! event void Photo.readDone(error_t result, uint16_t val) {
! if(result == SUCCESS) {
! entry->rad = val;
! }
! else current_entry->rad = 0xFFFF;
! call Radiation.read();
! }
!
! event void Radiation.readDone(error_t result, uint16_t val) {
! if(result == SUCCESS) {
! entry->rad = val;
! }
! else current_entry->rad = 0xFFFF;
! call LogWrite.append(entry, sizeof(log_entry_t));
! }
!
! event void LogWrite.appendDone(void* buf,
! storage_len_t len,
! bool recordsLost,
! error_t error) {
! if (error == SUCCESS)
! call Leds.led2Toggle();
! }
!
!
!
!
!
! </pre>
! </td>
! </tr>
! </table>
! <p>
! In the parallel case, logging to flash and requesting samples from each sensor is
! all done within the body of the <code>Timer.fired()</code> event. In the serial case,
! a chain of events is triggered by first calling <code>Humidity.read()</code> in
! <code>Timer.fired()</code>, sampling each subsequent sensor in the body of the previous
! <code>readDone()</code> event, and ending with all sensor readings
! being logged to flash.
! </p>
! <p>
! By logging to flash and sampling all sensors within the body of a single event, the OS
! has the opportunity to schedule each operation as it sees fit. Performing each operation
! after the completion of the previous one gives the OS no such opportunity. The only
! downside of the parallel approach is that the application must manually manage a double
! buffer so that the values written to flash are not overwritten before they are logged. To save
! the most energy, however, the parallel version should always be used.
! Keep in mind that in both cases, the developer must also make sure that the sampling
! interval is longer than the time it takes to gather all sensor readings. If it is not,
! data corruption will inevitably occur.
! </p>
! <h1>
! Radio Power Management
! </h1>
! <p>
! By default, TinyOS provides low power radio operation through a technique known as
! <i>Low-Power Listening</i>. In low-power listening, a node turns on
! its radio just long enough to detect a carrier on the channel.
! If it detects a carrier, then it keeps the radio on long enough to detect a packet.
! Because the LPL check period is much longer than a packet, a transmitter must send
! its first packet enough times for a receiver to have a chance to hear it. The
! transmitter stops sending once it receives a link-layer acknowledgment or a timeout
! of twice the check period. When a node receives a packet, it stays awake long
! enough to receive a second packet. Therefore, a packet burst amortizes the wakeup
! cost of the first packet over the follow-up packets. It is therefore more energy
! efficient to send packets in bursts when using low-power listening than sending individual
! packets at some fixed constant rate. Keep this in mind when developing applications
! that require low power operation.
! </p>
! <p>
! Controlling the operation of low-power listening in TinyOS is provided through the
! use of the <code>LowPowerListening</code> interface. Currently, this interface
! is only supported for the cc1000 and cc2420 radios. In the future we hope to
! support other radio platforms as well.
! </p>
! <pre>
! interface LowPowerListening {
! /**
! * Set this this node's radio sleep interval, in milliseconds.
! * Once every interval, the node will sleep and perform an Rx check
! * on the radio. Setting the sleep interval to 0 will keep the radio
! * always on.
! *
! * This is the equivalent of setting the local duty cycle rate.
! *
! * @param sleepIntervalMs the length of this node's Rx check interval, in [ms]
! */
! command void setLocalSleepInterval(uint16_t sleepIntervalMs);
!
! /**
! * @return the local node's sleep interval, in [ms]
! */
! command uint16_t getLocalSleepInterval();
!
! /**
! * Set this node's radio duty cycle rate, in units of [percentage*100].
! * For example, to get a 0.05% duty cycle,
! * call LowPowerListening.setDutyCycle(5);
! *
! * For a 100% duty cycle (always on),
! * call LowPowerListening.setDutyCycle(10000);
! *
! * This is the equivalent of setting the local sleep interval explicitly.
! *
! * @param dutyCycle The duty cycle percentage, in units of [percentage*100]
! */
! command void setLocalDutyCycle(uint16_t dutyCycle);
!
! /**
! * @return this node's radio duty cycle rate, in units of [percentage*100]
! */
! command uint16_t getLocalDutyCycle();
!
! /**
! * Configure this outgoing message so it can be transmitted to a neighbor mote
! * with the specified Rx sleep interval.
! * @param msg Pointer to the message that will be sent
! * @param sleepInterval The receiving node's sleep interval, in [ms]
! */
! command void setRxSleepInterval(message_t *msg, uint16_t sleepIntervalMs);
!
! /**
! * @return the destination node's sleep interval configured in this message
! */
! command uint16_t getRxSleepInterval(message_t *msg);
!
! /**
! * Configure this outgoing message so it can be transmitted to a neighbor mote
! * with the specified Rx duty cycle rate.
! * Duty cycle is in units of [percentage*100], i.e. 0.25% duty cycle = 25.
! *
! * @param msg Pointer to the message that will be sent
! * @param dutyCycle The duty cycle of the receiving mote, in units of
! * [percentage*100]
! */
! command void setRxDutyCycle(message_t *msg, uint16_t dutyCycle);
!
! /**
! * @return the destination node's duty cycle configured in this message
! * in units of [percentage*100]
! */
! command uint16_t getRxDutyCycle(message_t *msg);
!
! /**
! * Convert a duty cycle, in units of [percentage*100], to
! * the sleep interval of the mote in milliseconds
! * @param dutyCycle The duty cycle in units of [percentage*100]
! * @return The equivalent sleep interval, in units of [ms]
! */
! command uint16_t dutyCycleToSleepInterval(uint16_t dutyCycle);
!
! /**
! * Convert a sleep interval, in units of [ms], to a duty cycle
! * in units of [percentage*100]
! * @param sleepInterval The sleep interval in units of [ms]
! * @return The duty cycle in units of [percentage*100]
! */
! command uint16_t sleepIntervalToDutyCycle(uint16_t sleepInterval);
!
! }</pre>
! <p>
! This interface is located in <code>tos/interfaces</code> in the standard TinyOS tree. Take a
! look at the comments for each command to familiarize yourself with how this interface can be used.
! </p>
! <p>
! Using this interface typically involves first setting a nodes local duty cycle within the
! <code>Boot.booted()</code> event of the top level application. For each packet the application
! wishes to send, the duty cycle of its destination is then specified as metadata so that the
! correct number of preambles can be prepended to it. The code snippet found below demonstrates
! this usage pattern:
! </p>
! <pre>
! event void Boot.booted() {
! call LPL.setLocalSleepInterval(LPL_INTERVAL);
! call AMControl.start();
! }
!
! event void AMControl.startDone(error_t e) {
! if(e != SUCCESS)
! call AMControl.start();
! }
!
! ...
!
! void sendMsg() {
! call LPL.setRxSleepInterval(&msg, LPL_INTERVAL);
! if(call Send.send(dest_addr, &msg, sizeof(my_msg_t)) != SUCCESS)
! post retrySendTask();
! }</pre>
!
! The <code>AMControl</code> interface is provided by <code>ActiveMessageC</code>, and is
! used, among other things, to enable the operation of low-power listening for the radio.
! Once <code>AMControl.start()</code> has completed successfully, the radio begins to duty cycle
! itself as specified by the parameter to the <code>setLocalSleepInterval()</code> command. Calling
! <code>setRxSleepInterval()</code> with a specific sleep interval then allows the correct number of preambles to be sent
! for the message specified in its parameter list.
!
! <h1>
! Microcontroller Power Management
! </h1>
! <p>
! Microcontrollers often have several power states, with varying power draws,
! wakeup latencies, and peripheral support. The microcontroller should always be
! in the lowest possible power state that can satisfy application requirements.
! Determining this state accurately requires knowing a great deal about the power
! state of many subsystems and their peripherals. Additionally, state transitions
! are common. Every time a microcontroller handles an interrupt, it moves from a low
! power state to an active state, and whenever the TinyOS scheduler finds the task
! queue empty it returns the microcontroller to a low power state. TinyOS uses
! three mechanisms to decide what low power state it puts a microcontroller into:
! status and control registers, a dirty bit, and a power state override.
! Please refer to <a href=../tep112.html>TEP 112</a> for more information.
! </p>
! </p>
! As a developer, you will not have to worry about MCU power managment at all in
! most situations. TinyOS handles everything for you automatically. At times,
! however, you may want to use the provided power state override functionality.
! Take a look at <code>tos/chips/atm128/timer/HplAtm128Timer0AsyncP.nc</code> if
! you are interested in seeing an example of where this override functionality is used.
! </p>
!
! <h1>
! Low Power Sensing Application
! </h1>
! <p>
! A fully functional low-power sensing application has been created that combines each
! of the techniques found in this tutorial. At present, this application is not included
! in the official TinyOS distribution (<= 2.0.2). If you are using TinyOS from a cvs
! checkout, you will find it located under <code>apps/tutorials/LowPowerSensing</code>.
! Otherwise, you can obtain it from
! cvs by running the following set of commands from a terminal window:
! </p>
!
! <pre>
! cd $TOSROOT/apps/tutorials
! cvs -d:pserver:anonymous at tinyos.cvs.sourceforge.net:/cvsroot/tinyos login
! cvs -z3 -d:pserver:anonymous at tinyos.cvs.sourceforge.net:/cvsroot/tinyos co -P -d LowPowerSensing tinyos-2.x/apps/tutorials/LowPowerSensing</pre>
! <p>
! Just hit enter when prompted for a CVS password. You do not need to enter one.
! </p>
!
! This
! application has been tested on telosb and mica2 platforms, but should be usable
! on others without modification. Take a look at the README file found in the top level directory
! for more information.
! </p>
! <a name=#related_docs>
! <h1>Related Documentation</h1>
! </a>
! <ul>
! <li> <a href="../tep103.html">TEP 103: Permanent Data Storage (Flash)</a>
! <li> <a href="../tep105.html">TEP 105: Low Power Listening</a>
! <li> <a href="../tep108.html">TEP 108: Resource Arbitration</a>
! <li> <a href="../tep109.html">TEP 109: Sensors and Sensor Boards</a>
! <li> <a href="../tep112.html">TEP 112: Microcontroller Power Management</a>
! <li> <a href="../tep114.html">TEP 114: SIDs: Source and Sink Independent Drivers</a>
! <li> <a href="../tep115.html">TEP 115: Power Management of Non-Virtualised Devices</a>
! <li> <a href="http://sing.stanford.edu/klueska/Black_Site/Publications_files/klues07icem.pdf">
! Integrating Concurrency Control and Energy Management in Device Drivers</a>
! </ul>
!
! <!-- Begin footer -->
! <br>
! <hr>
! <center>
! <p>< <b><a href="lesson15.html">Previous Lesson</a></b> | <b><a
! href="index.html">Top</a></b> |
! </center>
!
</body>
! </html>
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
! <head>
! <title>klueska.com</title>
! </head>
! <frameset>
! <frame src="http://docs.tinyos.net/index.php/Writing_Low-Power_Applications" name="redir_frame" />
! <noframes>
! <body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/Writing_Low-Power_Applications" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
Index: lesson2.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/lesson2.html,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** lesson2.html 16 Jul 2007 21:03:07 -0000 1.4
--- lesson2.html 28 Jan 2008 05:59:55 -0000 1.5
***************
*** 1,779 ****
! <html>
! <head>
! <title>TinyOS Tutorial Lesson 2: Modules and the TinyOS Execution Model</title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet" type="text/css">
! </head>
! <body>
!
! <div class="title">Lesson 2: Modules and the TinyOS Execution Model</div>
! <div class="subtitle">Last updated June 27 2006</div>
!
! <p>This lesson introduces nesC modules, commands, events, and
! tasks. It explains the TinyOS execution model.</p>
!
! <h1>Modules and State</h1>
!
! <p>Compiling TinyOS applications produces a single binary image that assumes
! it has complete control of the hardware. Therefore, a mote only
! runs one TinyOS image at a time. An image consists of the
! components needed for a single application. As most more platforms
! do not have hardware-based memory protection, there is
! no seperation between a "user" address space and a "system"
! address space; there is only one address space that all
! components share. This is why many TinyOS components try to keep
! their state private and avoid passing pointers: since there is
! no hardware protection, the best way to keep memory uncorrupted
! is to share it as little as possible.</p>
!
! <p>Recall from lesson 1 that the set of interfaces a component uses
! and provides
! define its signature. Both kinds of components -- configurations and
! modules -- provide and use interfaces. The difference between the
! two lies in their implementation: configurations are implemented
! in terms of other components, which they wire, while modules
! are executable code. After unwrapping all of the layers of abstraction
! that configurations introduce, modules always lie within. Module
! implementations are for the most part written in C, with
! some extra constructions for nesC abstractions.</p>
!
! <p>Modules can declare state variables. Any state a component declares
! is private: no
! other component can name it or directly access it. The only
! way two components can directly interact is through interfaces.
! Let's revisit the Blink application.
! Here is the Blink module BlinkC's implementation in
! its entirety:</p>
!
! <pre></pre>
! <prehead>apps/Blink/BlinkC.nc:</prehead>
! <pre>
! module BlinkC {
! uses interface Timer<TMilli> as Timer0;
! uses interface Timer<TMilli> as Timer1;
! uses interface Timer<TMilli> as Timer2;
! uses interface Leds;
! uses interface Boot;
! }
! implementation
! {
! event void Boot.booted()
! {
! call Timer0.startPeriodic( 250 );
! call Timer1.startPeriodic( 500 );
! call Timer2.startPeriodic( 1000 );
! }
!
! event void Timer0.fired()
! {
! call Leds.led0Toggle();
! }
!
! event void Timer1.fired()
! {
! call Leds.led1Toggle();
! }
!
! event void Timer2.fired()
! {
! call Leds.led2Toggle();
! }
! }
! </pre>
!
! <p>BlinkC does not allocate any state. Let's change it so that its
! logic is a little different: rather than blink the LEDs from three
! different timers, we'll blink them with a single timer and keep
! some state to know which ones to toggle. Make a copy of the Blink
! application, <tt>BlinkSingle</tt>, and go into its directory.</p>
!
! <pre>
! $ cd tinyos-2.x/apps
! $ cp -R Blink BlinkSingle
! $ cd BlinkSingle
! </pre>
!
! <p>Open the BlinkC module in an editor.
! The first step is to comment out the LED toggles in Timer1 and
! Timer2:</p>
!
! <pre>
! event void Timer1.fired()
! {
! // call Leds.led1Toggle();
! }
!
! event void Timer2.fired()
! {
! // call Leds.led2Toggle();
! }
! </pre>
!
! <p>The next step is to add some state to BlinkC, a single byte. Just
! like in C, variables and functions must be declared before they are
! used, so put it at the beginning of the implementation:</p>
!
! <pre>
! implementation
! {
!
! uint8_t counter = 0;
!
! event void Boot.booted()
! {
! call Timer0.startPeriodic( 250 );
! call Timer1.startPeriodic( 500 );
! call Timer2.startPeriodic( 1000 );
! }
! </pre>
!
! <p>Rather than the standard C names of <tt>int</tt>, <tt>long</tt>,
! or <tt>char</tt>, TinyOS code uses more explicit types, which
! declare their size. In reality, these map to the basic C types, but
! do so differently for different platforms. TinyOS code avoids using
! <tt>int</tt>, for example, because it is platform-specific. For example,
! on mica and Telos motes, <tt>int</tt> is 16 bits, while on the
! IntelMote2, it is 32 bits. Additionally, TinyOS code often
! uses unsigned values heavily, as wrap-arounds to negative numbers
! can often lead to very unintended consequences. The commonly used
! types are:</p>
!
! <CENTER>
! <table border=1 cellpadding=6>
! <tr>
! <td></td><td>8 bits</td><td>16 bits</td><td>32 bits</td><td>64 bits</td>
! </tr>
! <tr>
! <td>signed</td><td><tt>int8_t</tt></td><td><tt>int16_t</tt></td><td><tt>int32_t</tt></td><td><tt>int64_t</tt></td>
! </tr>
! <tr>
! <td>unsigned</td><td><tt>uint8_t</td><td><tt>uint16_t</td><td><tt>uint32_t</td><td><tt>uint64_t</tt></td>
! </tr>
! </table>
! </CENTER>
! <p>There is also a <tt>bool</tt> type. You can use the standard C
! types, but doing so might raise cross-platform issues. Also,
! <tt>uint32_t</tt> is often easier to write than <tt>unsigned
! long</tt>. Most platforms support floating point numbers
! (<tt>float</tt> almost always, <tt>double</tt> sometimes),
! although their arithmetic is in software rather than hardware.</p>
!
! <p>Returning to our modified BlinkC, we've allocated a single unsigned
! byte, <tt>counter</tt>. When the mote boots, the <tt>counter</tt>
! will be initialized to zero. The next step is to make it that
! when Timer0 fires, it increments <tt>counter</tt> and displays the
! result:</p>
!
! <pre>
! event void Timer0.fired()
! {
! counter++;
! if (counter & 0x1) {
! call Leds.led0On();
! }
! else {
! call Leds.led0Off();
! }
! if (counter & 0x2) {
! call Leds.led2On();
! }
! else {
! call Leds.led2Off();
! }
! if (counter & 0x4) {
! call Leds.led2On();
! }
! else {
! call Leds.led2Off();
! }
! }
! </pre>
!
! <p>Another, more succinct way to do it is to use the <tt>set</tt>
! command:</p>
!
! <pre>
! event void Timer0.fired()
! {
! counter++;
! call Leds.set(counter);
! }
! </pre>
!
! <p>Compile your program and install it on a mote. You'll see
! that it behaves just as before, except that now the LEDs
! are being driven by a single, rather than three, timers.</p>
!
! <p>As only one timer is being used, this means that you don't need
! Timer1 and Timer2: they waste CPU resources and memory. Open
! BlinkC again and remove them from its signature and implementation.
! You should have something that looks like this:</p>
!
! <pre>
! module BlinkC {
! uses interface Timer<TMilli> as Timer0;
! uses interface Leds;
! users interface Boot;
! }
! implementation
! {
! uint8_t counter = 0;
!
! event void Boot.booted()
! {
! call Timer0.startPeriodic( 250 );
! }
!
! event void Timer0.fired()
! {
! counter++;
! call Leds.set(counter);
! }
!
! }
! </pre>
!
! <p>Try to compile the application: nesC will throw an error, because
! the configuration BlinkAppC is wiring to interfaces on BlinkC
! that no longer exist (Timer1 and Timer2):</p>
!
! <pre>
! dark /root/src/tinyos-2.x/apps/BlinkSingle -5-> make micaz
! mkdir -p build/micaz
! compiling BlinkAppC to a micaz binary
! ncc -o build/micaz/main.exe -Os -finline-limit=100000 -Wall -Wshadow -DDEF_TOS_AM_GROUP=0x7d -Wnesc-all -target=micaz -fnesc-cfile=build/micaz/app.c -board=micasb -fnesc-dump=wiring -fnesc-dump='interfaces(!abstract())' -fnesc-dump='referenced(interfacedefs, components)' -fnesc-dumpfile=build/micaz/wiring-check.xml BlinkAppC.nc -lm
! In component `BlinkAppC':
! BlinkAppC.nc:54: cannot find `Timer1'
! BlinkAppC.nc:55: cannot find `Timer2'
! make: *** [exe0] Error 1
! </pre>
!
! <p>Open BlinkAppC and remove the two Timers and their wirings. Compile
! the application:</p>
!
! <pre>
! mkdir -p build/micaz
! compiling BlinkAppC to a micaz binary
! ncc -o build/micaz/main.exe -Os -finline-limit=100000 -Wall -Wshadow -DDEF_TOS_AM_GROUP=0x7d -Wnesc-all -target=micaz -fnesc-cfile=build/micaz/app.c -board=micasb -fnesc-dump=wiring -fnesc-dump='interfaces(!abstract())' -fnesc-dump='referenced(interfacedefs, components)' -fnesc-dumpfile=build/micaz/wiring-check.xml BlinkAppC.nc -lm
! compiled BlinkAppC to build/micaz/main.exe
! 2428 bytes in ROM
! 39 bytes in RAM
! avr-objcopy --output-target=srec build/micaz/main.exe build/micaz/main.srec
! avr-objcopy --output-target=ihex build/micaz/main.exe build/micaz/main.ihex
! writing TOS image
! </pre>
!
! <p>If you compare the ROM and RAM sizes with the unmodified Blink
! application, you should see that they are a bit smaller: TinyOS
! is only allocating state for a single timer, and there is
! event code for only one timer.</p>
!
! <h1>Interfaces, Commands, and Events</h1>
!
! <p>Go back to <tt>tinyos-2.x/apps/Blink</tt>.
! In lesson 1 we learned that if a component uses an interface, it can
! call the interface's commands and must implement handlers for its
! events. We also saw that the BlinkC component uses the Timer, Leds,
! and Boot interfaces.
! Let's take a look at those interfaces:</p>
!
! <pre></pre>
! <prehead>tos/interfaces/Boot.nc:</prehead>
! <pre>
! interface Boot {
! event void booted();
! }
! </pre>
!
! <prehead>tos/interfaces/Leds.nc:</prehead>
! <pre>
! interface Leds {
!
! /**
! * Turn LED n on, off, or toggle its present state.
! */
! async command void led0On();
! async command void led0Off();
! async command void led0Toggle();
!
! async command void led1On();
! async command void led1Off();
! async command void led1Toggle();
!
! async command void led2On();
! async command void led2Off();
! async command void led2Toggle();
!
! /**
! * Get/Set the current LED settings as a bitmask. Each bit corresponds to
! * whether an LED is on; bit 0 is LED 0, bit 1 is LED 1, etc.
! */
! async command uint8_t get();
! async command void set(uint8_t val);
!
! }
! </pre>
!
! <prehead>tos/interfaces/Timer.nc:</prehead>
! <pre>
! interface Timer<precision_tag>
! {
! // basic interface
! command void startPeriodic( uint32_t dt );
! command void startOneShot( uint32_t dt );
! command void stop();
! event void fired();
!
! // extended interface omitted (all commands)
! }
! </pre>
!
! <p>Looking over the interfaces for <code>Boot</code>,
! <code>Leds</code>, and
! <code>Timer</code>, we can see that since <code>BlinkC</code> uses
! those interfaces it must implement handlers for the
! <code>Boot.booted()</code> event, and the <code>Timer.fired()</code>
! event. The <code>Leds</code> interface signature does not include any
! events, so <code>BlinkC</code> need not implement any in order
! to call the Leds commands. Here, again, is <code>BlinkC</code>'s
! implementation of <code>Boot.booted()</code>:</p>
!
! <pre></pre>
! <prehead>apps/Blink/BlinkC.nc:</prehead>
! <pre>
! event void Boot.booted()
! {
! call Timer0.startPeriodic( 250 );
! call Timer1.startPeriodic( 500 );
! call Timer2.startPeriodic( 1000 );
! }
! </pre>
!
! <p><code>BlinkC</code> uses 3 instances of the TimerMilliC component,
! wired to the interfaces <code>Timer0</code>, <code>Timer1</code>, and
! <code>Timer2</code>. The <code>Boot.booted()</code> event handler
! starts each instance. The parameter to
! <code>startPeriodic()</code> specifies the period in milliseconds after
! which the timer will fire (it's millseconds because of the
! <tt><TMilli></tt> in the interface).
! Because the timer is started using
! the <code>startPeriodic()</code>
! command, the timer will be reset after firing such that the
! <code>fired()</code> event is
! triggered every n milliseconds.</p>
!
! <p>Invoking an interface command requires the <tt>call</tt> keyword,
! and invoking an interface event requires the <tt>signal</tt> keyword.
! BlinkC does not provide any interfaces, so its code
! does not have any signal statements: in a later lesson,
! we'll look at the boot sequence, which signals the Boot.booted()
! event.</p>
!
! <p>Next, look at the implementation of the <code>Timer.fired()</code>:</p>
!
! <pre></pre>
! <prehead>apps/Blink/BlinkC.nc:</prehead>
! <pre>
! event void Timer0.fired()
! {
! call Leds.led0Toggle();
! }
!
! event void Timer1.fired()
! {
! call Leds.led1Toggle();
! }
!
! event void Timer2.fired()
! {
! call Leds.led2Toggle();
! }
! }
! </pre>
!
! <p>Because it uses three instances of the Timer interface,
! <code>BlinkC</code>
! must implement three instances of <code>Timer.fired()</code>
! event. When implementing or invoking an interface function, the
! function name is always <i>interface</i>.<i>function</i>. As
! BlinkC's three Timer instances are named <tt>Timer0</tt>,
! <tt>Timer1</tt>, and <tt>Timer2</tt>, it implements the three
! functions <tt>Timer0.fired</tt>, <tt>Timer1.fired</tt>, and
! <tt>Timer2.fired</tt>.</p>
!
!
!
! <h1>TinyOS Execution Model: Tasks</h1>
!
! <p>All of the code we've looked at so far is <i>synchronous</i>.
! It runs in a single execution context and does not have
! any kind of pre-emption. That is, when synchronous (sync) code
! starts running, it does not relinquish the CPU to other
! sync code until it completes. This simple mechanism allows
! the TinyOS scheduler to minimize its RAM consumption and
! keeps sync code very simple. However, it means that if one
! piece of sync code runs for a long time, it prevents other
! sync code from running, which can adversely affect system
! responsiveness. For example, a long-running piece of code
! can increase the time it takes for a mote to respond to a
! packet.</p>
!
! <p>So far, all of the examples we've looked at have been
! direct function calls. System components, such as the
! boot sequence or timers, signal events to a component,
! which takes some action (perhaps calling a command) and
! returns. In most cases, this programming approach works
! well. Because sync code is non-preemptive, however,
! this approach does not work well for large computations.
! A component needs to be able to split a large computation
! into smaller parts, which can be executed one at a time.
! Also, there are times when a component needs to do something,
! but it's fine to do it a little later. Giving TinyOS the
! ability to defer the computation until later can let it
! deal with everything else that's waiting first.</p>
!
! <p><b>Tasks</b> enable components to perform general-purpose
! "background" processing in an application. A task is a function
! which a component tells TinyOS to run later, rather than now.
! The closest analogies in traditonal operating systems are
! <A HREF="http://www.tldp.org/LDP/tlk/kernel/kernel.html">interrupt
! bottom halves</A> and <A HREF="http://opensource.adobe.com/twiki/bin/view/AdobeSource/DeferredProcSystem">deferred
! procedure calls</A>.</p>
!
! <p>Make a copy of the Blink application, and call it BlinkTask:</p>
!
! <pre>
! $ cd tinyos-2.x/apps
! $ cp -R Blink BlinkTask
! $ cd BlinkTask
! </pre>
!
! <p>Open <code>BlinkC.nc</code>. Currently, the event handler
! for <code>Timer0.fired()</code> is:</p>
!
! <pre>
! event void Timer0.fired() {
! dbg("BlinkC", "Timer 0 fired @ %s\n", sim_time_string());
! call Leds.led0Toggle();
! }
! </pre>
!
! <p>Let's change it so that it does a bit of work, enough that
! we'll be able to see how long it runs. In terms of a mote,
! the rate at which we can see things (about 24 Hz, or 40 ms)
! is <u>slow</u>: the micaZ and Telos can send about 20 packets
! in that time. So this example is really exaggerated, but it's
! also simple enough that you can observe it with the naked eye.
! Change the handler to be this:</p>
!
! <pre>
! event void Timer0.fired() {
! uint32_t i;
! dbg("BlinkC", "Timer 0 fired @ %s\n", sim_time_string());
! for (i = 0; i < 400001; i++) {
! call Leds.led0Toggle();
! }
! }
! </pre>
!
! <p>This will cause the timer to toggle 400,001 times, rather
! than once. Because the number is odd, it will have the end
! result of a single toggle, with a bit of flickering in-between.
! Compile and install the program. You'll see that
! Led 0 introduces so much latency in the Led 1 and Led 2
! toggles that you never see a situation where only one is on.
! On TelosB motes, this long running task can cause the Timer stack
! to completely skip events (try setting the count to 200,001 or 100,001).
! </p>
!
! <p>The problem is that this computation is interfering with the timer's
! operation. What we'd like to do is tell TinyOS to execute the computation
! later. We can accomplish this with a <b>task</b>.</p>
!
! <p>A task is declared in your implementation module using the syntax
! <pre> task void taskname() { ... }</pre> where
! <tt>taskname()</tt> is whatever symbolic name you want to assign to the
! task. Tasks must return <tt>void</tt> and may not take any
! arguments. To dispatch a task for (later) execution, use the syntax
! <pre> post taskname();</pre> A component can post a task in a
! command, an event, or a task. Because they are the root of a call
! graph, a tasks can safely both call commands and signal events. We will
! see later that, by convention, commands do not signal events to avoid
! creating recursive loops across component boundaries (e.g., if command
! X in component 1 signals event Y in component 2, which itself calls
! command X in component 1). These loops would be hard for the programmer to
! detect (as they depend on how the application is wired) and would lead to
! large stack usage.</p>
!
!
! <p>Modify BlinkC to perform the loop in a task:</p>
!
! <pre>
! task void computeTask() {
! uint32_t i;
! for (i = 0; i < 400001; i++) {}
! }
!
! event void Timer0.fired() {
! call Leds.led0Toggle();
! post computeTask();
! }
! </pre>
!
! <p>Telos platforms will still struggle, but mica platforms will
! operate OK.</p>
!
!
! <p>The <tt>post</tt> operation places the task on an internal
! <b>task queue</b> which is processed in FIFO order. When a
! task is executed, it runs to completion
! before the next task is run. Therefore, and as the above examples
! showed, a task should not run for long periods of time.
! Tasks do not preempt each
! other, but a task can be preempted by a hardware interrupts (which
! we haven't seen yet).
! If you need to run a series of long operations,
! you should dispatch a separate task for each operation, rather
! than using one big task. The <tt>post</tt> operation returns
! an <tt>error_t</tt>, whose value is either <tt>SUCCESS</tt>
! or <tt>FAIL</tt>. A post fails if and only if the task is
! already pending to run (it has been posted successfully and has not been invoked yet).(<A HREF="#task_footnote">1</A>)</p>
!
! <p>For example, try this:</p>
!
! <pre>
! uint32_t i;
!
! task void computeTask() {
! uint32_t start = i;
! for (;i < start + 10000 && i < 400001; i++) {}
! if (i >= 400000) {
! i = 0;
! }
! else {
! post computeTask();
! }
! }
! </pre>
!
! <p>This code breaks the compute task up into many smaller tasks.
! Each invocation of computeTask runs through 10,000 iterations of
! the loop. If it hasn't completed all 400,001 iterations, it reposts
! itself. Compile this code and run it; it will run fine on both
! Telos and mica-family motes.</p>
!
! <p>Note that using a task in this way required including another
! variable (<tt>i</tt>) in the component. Because computeTask()
! returns after 10,000 iterations, it needs somewhere to store
! its state for the next invocation. In this situation, <tt>i</tt>
! is acting as a static function variable often does in C. However,
! as nesC component state is completely private, using the
! <tt>static</tt> keyword to limit naming scope is not as useful.
! This code, for example, is equivalent:</p>
! <pre>
! task void computeTask() {
! static uint32_t i;
! uint32_t start = i;
! for (;i < start + 10000 && i < 400001; i++) {}
! if (i >= 400000) {
! i = 0;
! }
! else {
! post computeTask();
! }
! }
! </pre>
!
! <h1>Internal Functions</h1>
!
! <p>Commands and events are the only way that a function in a component
! can be made callable by another component. There are situations
! when a component wants private functions for its own internal
! use. A component can define standard C functions, which other
! components cannot name and therefore cannot invoke directly.
! While these functions do not have the <tt>command</tt> or <tt>event</tt>
! modifier, they can freely call commands or signal events. For example,
! this is perfectly reasonable nesC code:</p>
!
! <pre>
! module BlinkC {
! uses interface Timer<TMilli> as Timer0;
! uses interface Timer<TMilli> as Timer1;
! uses interface Timer<TMilli> as Timer2;
! uses interface Leds;
! uses interface Boot;
! }
! implementation
! {
!
! void startTimers() {
! call Timer0.startPeriodic( 250 );
! call Timer1.startPeriodic( 500 );
! call Timer2.startPeriodic( 1000 );
! }
!
! event void Boot.booted()
! {
! startTimers();
! }
!
! event void Timer0.fired()
! {
! call Leds.led0Toggle();
! }
!
! event void Timer1.fired()
! {
! call Leds.led1Toggle();
! }
!
! event void Timer2.fired()
! {
! call Leds.led2Toggle();
! }
! }
! </pre>
!
! <p>Internal functions act just like C functions: they don't need the <tt>
! call</tt> or <tt>signal</tt> keywords.</p>
!
! <h1>Split-Phase Operations</h1>
!
! <p>Because nesC interfaces are wired at compile time,
! callbacks (events) in TinyOS are very efficient. In most
! C-like languages, callbacks have to be registered at run-time
! with a function pointer. This can prevent the compiler from
! being able to optimize code across callback call paths. Since
! they are wired statically in nesC, the compiler knows exactly
! what functions are called where and can optimize heavily.</p>
!
! <p>The ability to optimize across component boundaries is
! very important in TinyOS, because it has no blocking operations.
! Instead, every long-running operation is <b>split-phase</b>.
! In a blocking system, when a program calls a long-running operation,
! the call does not return until the operation is complete: the program
! blocks. In a split-phase system, when a program calls a long-running
! operation, the call returns immediately, and the called abstraction
! issues a callback when it completes. This approach is called
! split-phase because it splits invocation and completion into two
! separate phases of execution. Here is a simple example of the
! difference between the two:</p>
!
! <center>
! <table>
! <tr><td align=center>Blocking</td> <td align=center>Split-Phase</td></tr>
! <tr>
! <td valign=top>
! <pre>
! if (send() == SUCCESS) {
! sendCount++;
! }
! </pre>
! </td>
! <td valign=top>
! <pre>
! // start phase
! send();
!
! //completion phase
! void sendDone(error_t err) {
! if (err == SUCCESS) {
! sendCount++;
! }
! }
! </pre>
! </td>
! </tr>
! </table>
! </center>
!
! <p>Split-phase code is often a bit more verbose and complex than
! sequential code. But it has several advantages. First, split-phase
! calls do not tie up stack memory while they are executing. Second,
! they keep the system reponsive: there is never a situation when
! an application needs to take an action but all of its threads are
! tied up in blocking calls. Third, it tends to reduce stack
! utilization, as creating large variables on the stack is rarely
! necessary.</p>
!
! <p>Split-phase interfaces enable a TinyOS component to easily start
! several operations at once and have them execute in parallel.
! Also, split-phase operations can save memory. This is because
! when a program calls a blocking operation, all of the state it
! has stored on the call stack (e.g., variables declared in functions)
! have to be saved. As determining the exact size of the stack is
! difficult, operating systems often choose a very conservative
! and therefore large size. Of course, if there is data that
! has to be kept across the
! call, split-phase operations still need to save it.</p>
!
! <p>The command <tt>Timer.startOneShot</tt> is an example of
! a split-phase call. The user of the Timer inteface calls the command,
! which returns immediately. Some time later (specified by the
! argument), the component providing Timer signals <tt>Timer.fired</tt>.
! In a system with blocking calls, a program might use <tt>sleep()</tt>:
!
! <center>
! <table>
! <tr>
! <td align=center>Blocking</td><td align=center>Split-phase</td>
! </tr>
! <tr>
! <td valign=top>
! <pre>
! state = WAITING;
! op1();
! sleep(500);
! op2();
! state = RUNNING
! </pre>
! </td>
! <td valign=top>
! <pre>
! state = WAITING;
! op1();
! call Timer.startOneShot(500);
!
! event void Timer.fired() {
! op2();
! state = RUNNING;
! }
! </pre>
! </td>
! </tr>
! </table>
! </center>
!
! <p>In the next lesson, we'll look at one of the most basic
! split-phase operations: sending packets.</p>
!
! <a name=#related_docs>
! <h1>Related Documentation</h1>
! </a>
! <ul>
! <li> <a href="../tep102.html">TEP 102: Timers</a>
! <li> <a href="../tep106.html">TEP 106: Schedulers and Tasks</a>
! </ul>
!
! <p>
! <hr>
!
! <p><a name="task_footnote">(1)</a> The task semantics have changed
! significantly from tinyos-2.x. In 1.x, a task could be posted more
! than once and a post could fail if the task queue were full. In 2.x, a
! basic post will only fail if that task has already been posted and has
! not started execution. So a task can always run, but can only have one
! outstanding post at any time. If a component needs to post task
! several times, then the end of the task logic can repost itself as
! need be.
!
!
! <!-- Begin footer -->
! <br>
! <hr>
! <center>
! <p>< <b><a href="lesson1.html">Previous Lesson</a></b> | <b><a
! href="index.html">Top</a></b> | <b><a href="lesson3.html">Next Lesson </a> ></b>
! </center>
!
</body>
! </html>
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
! <head>
! <title>klueska.com</title>
! </head>
! <frameset>
! <frame src="http://docs.tinyos.net/index.php/Modules_and_the_TinyOS_Execution_Model" name="redir_frame" />
! <noframes>
! <body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/Modules_and_the_TinyOS_Execution_Model" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
Index: lesson3.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/lesson3.html,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** lesson3.html 17 Jan 2007 20:26:08 -0000 1.3
--- lesson3.html 28 Jan 2008 05:59:56 -0000 1.4
***************
*** 1,981 ****
! <!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
! <html>
<head>
! <title>Lesson 3: Mote-mote radio communication</title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet" type="text/css">
</head>
<body>
!
! <div class="title">Lesson 3: Mote-mote radio communication</div>
! <div class="subtitle">Last Modified: June 27 2006</div>
[...967 lines suppressed...]
! </center>
!
</body>
! </html>
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
! <title>klueska.com</title>
</head>
+ <frameset>
+ <frame src="http://docs.tinyos.net/index.php/Mote-mote_radio_communication" name="redir_frame" />
+ <noframes>
<body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/Mote-mote_radio_communication" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
Index: lesson4.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/lesson4.html,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** lesson4.html 20 Oct 2007 00:14:19 -0000 1.5
--- lesson4.html 28 Jan 2008 05:59:56 -0000 1.6
***************
*** 1,758 ****
! <!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
! <html>
<head>
! <title>Lesson 4: Mote-PC serial communication and SerialForwarder</title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet" type="text/css">
</head>
<body>
! <div class="title">Lesson 4: Mote-PC serial communication and SerialForwarder</div>
! <div class="subtitle">Last updated June 27 2006</div>
!
! <p>To goal of this lesson is to show you how to communicate with a
! mote from a PC. This will allow you to collect data from the network,
! send commands to motes, and monitor network traffic.</p>
!
! <p>This tutorial presents the Java-based infrastructure for communicating
! with motes. There is also a C-based infrastructure, found in support/sdk/c.
! Please see the documentation found there, and the <code>mig</code> and
! <code>ncg</code> man pages for more details.
!
!
! <h1>Packet sources and TestSerial</h1>
!
! <p>The first step is to check that you are able to get your PC to
! communicate with a mote. Most motes have a serial port or similar
! interface. For example, the mica family can directly control a serial
! port: programming boards basically connect the mote's serial port
! pins to the actual serial port on the board. Telos motes also have
! a serial interface, but it talks to their USB hardware, which
! is similar in functionality but very different in terms of cables and
! connectors.</p>
!
! <p>The basic abstraction for mote-PC communication is a <b>packet
! source</b>. A packet source is exactly that: a communication medium
! over which an application can receive packets from and send packets to
! a mote. Examples of packet sources include serial ports, TCP sockets,
! and the SerialForwarder tool. Most TinyOS communication tools take
! an optional <code>-comm</code> parameter, which allows you to
! specify the packet source as a string. For example:</p>
!
! <pre>
! $ java net.tinyos.tools.Listen -comm serial at COM1:telos
! </pre>
!
! <p>tells the Listen tool to use the COM1 serial port (on a Windows
! machine) at the correct speed for a telos mote, while</p>
!
! <pre>
! $ java net.tinyos.tools.Listen -comm serial@/dev/ttyS0:micaz
! </pre>
!
! <p>tells Listen to use the serial port <code>/dev/ttyS0</code> (on
! a UNIX machine) at the correct speed for a micaz mote.</p>
!
! <p>The first step to testing your serial port is to install
! the <code>apps/tests/TestSerial</code> application on a mote. This
! application sends a packet to the serial port every second,
! and when it receives a packet over the serial port it displays
! the packet's sequence number on the LEDs.</p>
!
! <p>Once you have installed <code>TestSerial</code>, you need
! to run the corresponding Java application that communicates with
! it over the serial port. This is built when you build the TinyOS
! application. From in the application directory, type:</p>
!
! <pre>
! $ java TestSerial
! </pre>
!
! If you get a message like
! <pre>
! The java class is not found: TestSerial
! </pre>
! it means that you either haven't compiled the Java code (try running <code>
! make <i>platform</i></code> again) or you don't have <code>.</code> (the
! current directory) in your Java <code>CLASSPATH</code>.
!
! <p>Because you haven't specified a packet source, TestSerial
! will fall back to a default, which is a SerialForwarder. Since
! you don't have a SerialForwarder running, TestSerial will
! exit, complaining that it can't connect to one. So let's specify
! the serial port as the source. The syntax for a serial port
! source is as follows:</p>
!
! <pre>
! serial@<PORT>:<SPEED>
! </pre>
!
! <p>PORT depends on your platform and where you have plugged the mote in.
! For Windows/Cygwin platforms, it is COM<i>N</i>, where <i>N</i> is the port
! number. For Linux/UNIX machines, it is <code>/dev/ttyS</code><i>N</i> for a
! built-in serial port, or one of <code>/dev/ttyUSB<i>N</I></code> or
! <code>/dev/usb/tts/<i>N</I></code> for a serial-over-USB port. Additionally
! as we saw in <a href="lesson1.html">lesson 1</a>, on Linux you will
! typically need to make this serial port world writeable. As superuser,
! execute the following command:
! <pre>chmod 666 <i>serialport</i></pre>
! <p>
!
! <p>The SPEED
! can either be a numeric value, or the name of a platform. Specifying a
! platform name tells the serial packet source to use the default speed for
! the platform. Valid platforms are:</p>
!
! <CENTER>
! <table>
! <tr><td>Platform</td><td>Speed (baud)</td></tr>
! <tr><td colspan=2><hr></td></tr>
! <tr><td>telos</td><td>115200</td></tr>
! <tr><td>telosb</td><td>115200</td></tr>
! <tr><td>tmote</td><td>115200</td></tr>
! <tr><td>micaz</td><td>57600</td></tr>
! <tr><td>mica2</td><td>57600</td></tr>
! <tr><td>mica2dot</td><td>19200</td></tr>
! <tr><td>eyes</td><td>115200</td></tr>
! <tr><td>intelmote2</td><td>115200</td></tr>
! </table>
! </center>
! <br>
!
! <p>The Java file <tt>support/sdk/java/net/tinyos/packet/BaudRate.java</tt>
! determines these mappings. Unlike in TinyOS 1.x, all platforms have a common
! serial packet format. Following the table, these two serial
! specfications are identical:</p>
!
! <pre>
! serial at COM1:micaz
! serial at COM1:57600
! </pre>
!
! <p>If you run <code>TestSerial</code> with the proper PORT and SPEED
! settings, you should see output like this:</p>
!
! <pre>
! Sending packet 1
! Received packet sequence number 4
! Sending packet 2
! Received packet sequence number 5
! Sending packet 3
! Received packet sequence number 6
! Sending packet 4
! Received packet sequence number 7
! Received packet sequence number 8
! Sending packet 5
! Received packet sequence number 9
! Sending packet 6
! </pre>
!
! <p>and the mote LEDs will blink.</p>
!
! <h2>Cannot find JNI error</h2>
!
! <p>If you try to run TestSerial and receive an error that Java cannot find
! TOSComm JNI support, this means the Java Native Interface (JNI) files that
! control the serial port haven't been correctly installed. Run the command
! <code>tos-install-jni</code> (on Linux, do this as the superuser). If this
! command does not exist, then you have either not installed the tinyos-tools
! RPM or it was installed incorrectly. The <tt>tos-</tt> commands are typically
! installed in /usr/bin. If you still cannot find the script, email <tt>tinyos-help</tt>.</p>
!
! <h3>Installing <tt>tos-install-jre</tt> from CVS sources</h3>
! <p>If you have not installed the tools RPM and are working directly from the
! TinyOS CVS repository, you can manually install the tos-locate-jre script.
! Go to <code>tinyos-2.x/tools/tinyos/java</code>. If
! the directory has a <code>Makefile</code> in it, type <code>make</code>
! and (again, on Linux, as superuser) <code>make
! install</code>. If the directory does not have a <code>Makefile</code>, go
! to <code>tinyos-2.x/tools</code> and type:</p>
!
! <pre>
! $ ./Bootstrap
! $ ./configure
! $ ./make
! $ ./make install
! </pre>
!
! <p>Then type <code>tos-install-jni</code>. This should install
! serial support in your system.</p>
!
! <h2>MOTECOM</h2>
!
! <p>If you do not pass a
! <code>-comm</code> parameter, then tools will check the
! <code>MOTECOM</code> environment variable for a packet source,
! and if there is no <code>MOTECOM</code>, they default to a
! SerialForwarder. This means that if you're always communicating
! with a mote over your serial port, you can just set <code>MOTECOM</code>
! and no longer have to specify the <code>-comm</code> parameter.
! For example:</p>
!
! <pre>
! export MOTECOM=serial at COM1:19200 # mica baud rate
! export MOTECOM=serial at COM1:mica # mica baud rate, again
! export MOTECOM=serial at COM2:mica2 # the mica2 baud rate, on a different serial port
! export MOTECOM=serial at COM3:57600 # explicit mica2 baud rate
! </pre>
!
! <p>Try setting your MOTECOM variable and running TestSerial without
! a <code>-comm</code> parameter.</p>
!
!
! <h1>BaseStation and net.tinyos.tools.Listen</h1>
!
! <p><code>BaseStation</code> is a basic TinyOS utility application.
! It acts as a bridge between the serial port and radio network.
! When it receives a packet from the serial port,
! it transmits it on the radio; when it receives a packets over
! the radio, it transmits it to the serial port. Because TinyOS
! has a toolchain for generating and sending packets to a mote
! over a serial port, using a BaseStation allows PC tools to
! communicate directly with mote networks.</p>
!
! <p>Take one of the two nodes that had BlinkToRadio (from <a href="lesson3.html">lesson 3</a>) installed
! and install BaseStation on it. If you turn on the node that still
! has BlinkToRadio installed, you should see LED 1 on the BaseStation
! blinking. BaseStation toggles LED 0 whenever it sends a packet
! to the radio and LED 1 whenever it sends a packet to the
! serial port. It toggles LED 2 whenever it has to drop a packet:
! this can happen when one of the two receives packets faster
! than the other can send them (e.g., receiving micaZ radio packets
! at 256kbps but sending serial packets at 57.6kbps).</p>
!
! <p>BaseStation is receiving your BlinkToRadio packets and sending
! them to the serial port, so if it is plugged into a PC we can
! view these packets. The Java tool Listen is a basic packet
! sniffer: it prints out the binary contents of any packet it hears.
! Run Listen, using either MOTECOM or a -comm parameter:</p>
!
! <pre>
! $ java net.tinyos.tools.Listen
! </pre>
!
! <p>Listen creates a packet source and just prints out every
! packet it sees. Your output should look something like this:</p>
!
! <pre>
! 00 FF FF 00 00 04 22 06 00 02 00 01
! 00 FF FF 00 00 04 22 06 00 02 00 02
! 00 FF FF 00 00 04 22 06 00 02 00 03
! 00 FF FF 00 00 04 22 06 00 02 00 04
! 00 FF FF 00 00 04 22 06 00 02 00 05
! 00 FF FF 00 00 04 22 06 00 02 00 06
! 00 FF FF 00 00 04 22 06 00 02 00 07
! 00 FF FF 00 00 04 22 06 00 02 00 08
! 00 FF FF 00 00 04 22 06 00 02 00 09
! 00 FF FF 00 00 04 22 06 00 02 00 0A
! 00 FF FF 00 00 04 22 06 00 02 00 0B
! </pre>
!
!
! <p>Listen is simply printing out the packets that are coming from the
! mote. Each data packet that comes out of the mote contains several fields
! of data. The first byte (00) indicates that this is packet is an AM
! packet. The next fields are the generic Active Message fields, defined in
! <tt>tinyos-2.x/tos/serial/Serial.h</tt>. Finally, the remaining fields are
! the data payload of the message, which was defined in BlinkToRadio.h as:</p>
!
! <pre>
! typedef nx_struct BlinkToRadioMsg {
! nx_uint16_t nodeid;
! nx_uint16_t counter;
! } BlinkToRadioMsg;
! </pre>
!
! The overall message format for the BlinkToRadioC application is
! therefore (ignoring the first 00 byte): </p>
! <ul>
! <li> <b>Destination address</b> (2 bytes)</li>
! <li> <b>Source address</b> (2 bytes)</li>
! <li> <b>Message length</b> (1 byte)</li>
! <li> <b>Group ID</b> (1 byte)</li>
! <li> <b>Active Message handler type</b> (1 byte)</li>
! <li> <b>Payload</b> (up to 28 bytes):</li>
! <ul>
! <li> <b>source mote ID</b> (2 bytes)</li>
! <li> <b>sample counter</b> (2 bytes)</li>
! </ul>
! </ul>
! So we can interpret the data packet as follows:
! <table hspace="0" cellpadding="0" cellspacing="10" border="0">
! <tbody>
! <tr bgcolor="#d0d0d0">
! <td><b>dest addr</b></td>
! <td><b>src addr</b></td>
! <td><b>msg len</b></td>
! <td><b>groupID</b></td>
! <td><b>handlerID</b></td>
! <td><b>hop addr</b></td>
! <td><b>counter</b></td>
! </tr> <tr>
! <td bgcolor="#d0d0ff">ff ff</td>
! <td bgcolor="#d0d0ff">00 00</td>
! <td bgcolor="#d0d0ff">04</td>
! <td bgcolor="#d0d0ff">22</td>
! <td bgcolor="#d0d0ff">06</td>
! <td bgcolor="#d0ffd0">00 02</td>
! <td bgcolor="#d0ffd0">00 0B</td>
! </tr>
! </tbody>
! </table>
!
! <p>The hop address depends on what mote ID you installed your
! BlinkToRadio application with. The default (if you do not specify
! and ID) is <code>00 01</code>.
! Note that the data is sent by the mote in <i>big-endian</i>
! format; for example, <code>01 02</code> means 258 (256*1 + 2).
! This format is independent of the endian-ness of the processor,
! because the packet format is an <code>nx_struct</code>, which is
! a network format, that is, big-endian and byte-aligned. Using
! <code>nx_struct</code> (rather than a standard C <code>struct</code>)
! for a message payload ensures that it will work across platforms.</p>
!
! <p>TinyOS serial stacks do not fill in the source address as the
! address of the sending mote. The assumption is that the serial connection
! can identify the node, and setting the source address prevents
! applications such as BaseStation from working properly. This is
! because BaseStation just forwards radio packets to the serial port:
! it needs to fill in the <i>radio source</i> address as the source
! address of the serial packet.</p>
! <p>As you watch the packets scroll by, you should see the counter
! field increase as the BlinkToRadio app increments its counter.</p>
!
! <h1>MIG: generating packet objects</h1>
!
! <p>The <tt>Listen</tt> program is the most basic way of communicating
! with the mote; it just prints binary packets to the screen. Obviously
! it is not easy to visualize the sensor data
! using this program. What we'd really like is a better way of retrieving
! and observing data coming from the sensor network. Of course, exactly
! what data to display and how to visualize it can be very application
! specific. For this reason, TinyOS only
! has a few applications for visualizing simple
! sensor data (in the next lesson, you'll use the Oscilloscope application),
! but it provides support for building new visualization or logging systems.
! </p>
!
! <p>One problem with Listen is that it just dumps binary data: a user has
! to be able to read the bytes and parse them into a given packet format.
! The TinyOS toolchain makes this process easier by providing tools for
! automatically generating message objects from packet descriptions.
! Rather than parse packet formats manually, you can use the <code>mig</code>
! (Message Interface Generator) tool to build a Java, Python, or C interface
! to the message structure. Given a sequence of bytes, the MIG-generated
! code will automatically parse each of the fields in the packet, and it
! provides a set of standard accessors and mutators for printing out
! received packets or generating new ones.</p>
!
! <p>The mig tool takes three basic arguments: what programming language
! to generate code for (Java, Python, or C), which file in which to find
! the structure, and the name of the structure. The tool also takes standard
! C options, such as -I for includes and -D for defines. The TestSerial
! application, for example, uses mig so that it can easily create
! and parse the packets over the serial port. If you go back to TestSerial
! and type <code>make clean;make</code>, you should see this:</p>
!
! <pre>
! rm -rf build *.class TestSerialMsg.java
! rm -rf _TOSSIMmodule.so TOSSIM.pyc TOSSIM.py
! mkdir -p build/telosb
! mig java -target=telosb -I%T/lib/oski -java-classname=TestSerialMsg TestSerial.h TestSerialMsg -o TestSerialMsg.java
! javac *.java
! compiling TestSerialAppC to a telosb binary
! ncc -o build/telosb/main.exe -Os -O -mdisable-hwmul -Wall -Wshadow -DDEF_TOS_AM_GROUP=0x66 -Wnesc-all -DCC2420_DEF_CHANNEL=19 -target=telosb -fnesc-cfile=build/telosb/app.c -board= -I%T/lib/oski TestSerialAppC.nc -lm
! compiled TestSerialAppC to build/telosb/main.exe
! 6300 bytes in ROM
! 281 bytes in RAM
! msp430-objcopy --output-target=ihex build/telosb/main.exe build/telosb/main.ihex
! writing TOS image
! </pre>
!
! <p>Before building the TinyOS application, the Makefile has a rule
! for generating <code>TestSerialMsg.java</code>. It then compiles
! TestSerialMsg.java as well as TestSerial.java, and finally
! compiles the TinyOS application. Looking at the Makefile, we can see
! that it has a few more rules than the one for BlinkToRadio:</p>
!
! <pre>
! COMPONENT=TestSerialAppC
! BUILD_EXTRA_DEPS += TestSerial.class
! CLEAN_EXTRA = *.class TestSerialMsg.java
!
! TestSerial.class: $(wildcard *.java) TestSerialMsg.java
! javac *.java
!
! TestSerialMsg.java:
! mig java -target=null -java-classname=TestSerialMsg TestSerial.h TestSerialMsg -o $@
!
! include $(MAKERULES)
! </pre>
!
! <p>The <code>BUILD_EXTRA_DEPS</code> line tells the TinyOS make system
! that the TinyOS application has additional dependencies that must
! be satisfied before it can be built. The Makefile tells the make system
! that <code>TestSerial.class</code>, the Java application that we ran
! to test serial communication. The <code>CLEAN_EXTRA</code> line tells
! the make system extra things that need to be done when a user types
! <code>make clean</code> to clean up.</p>
!
! <p>The <code>BUILD_EXTRA_DEPS</code> line tells make to compile
! TestSerial.class before the application; the line</p>
!
! <pre>
! TestSerial.class: $(wildcard *.java) TestSerialMsg.java
! javac *.java
! </pre>
!
! <p>tells it that TestSerial.class depends on all of the .java files
! in the directory as well as TestSerialMsg.java. Once all of these
! dependencies are resolved, the make system will call <code>javac
! *.java</code>, which creates TestSerial.class. The final line,</p>
!
! <pre>
! TestSerialMsg.java:
! mig java -target=null -java-classname=TestSerialMsg TestSerial.h TestSerialMsg -o $@
! </pre>
!
! <p>tells the make system how to create TestSerialMsg.java, the
! Java class representing the packet sent between the mote and PC.
! Because TestSerialMsg.java is a dependency for TestSerial.class,
! make will create it if it is needed. To create TestSerialMsg.java,
! the Makefile invokes the mig tool. Let's step through the parameters
! one by one:</p>
!
! <table>
! <tr> <td>mig</td> <td width=60></td> <td>Invoke mig</td> </tr>
! <tr> <td>java</td> <td></td> <td>Build a Java class</td> </tr>
! <tr> <td>-target=null</td> <td></td> <td>For the <code>null</code>platform</td></tr>
! <tr> <td>-java-classname=TestSerialMsg</td><td></td> <td>Name the Java class TestSerialMsg</td> </tr>
! <tr> <td>TestSerial.h</td> <td></td> <td>The structure is in TestSerial.h</td> </tr>
! <tr> <td>TestSerialMsg</td> <td></td> <td>The structure is named TestSerialMsg</td></tr>
! <tr> <td>-o $@</td> <td></td> <td>Write the file to $@, which is TestSerialMsg.java</tr></tr>
! </table>
!
! <p>The <code>null</code> platform is a special platform which is convenient to use
! as the target when using <code>mig</code>. It includes all the standard
! system components, but with dummy do-nothing implementations. Building an
! application for the <code>null</code> platform is useless, but it allows
! <code>mig</code> to extract the layout of packets.
!
! <p>Let's build a Java packet object for BlinkToRadio. Open the Makefile for
! BlinkToRadio and add a dependency:</p>
!
! <pre>
! BUILD_EXTRA_DEPS=BlinkToRadioMsg.class
! </pre>
!
! <p>Then add a step which explains how to compile a .java to a .class:</p>
!
! <pre>
! BlinkToRadioMsg.class: BlinkToRadioMsg.java
! javac BlinkToRadioMsg.java
! </pre>
!
! <p><b>Note that there must be a tab before javac, and not just spaces.</b>
! Finally, add the line which explains how to create BlinkToRadioMsg.java:</p>
!
! <pre>
! BlinkToRadioMsg.java:
! mig java -target=null -java-classname=BlinkToRadioMsg BlinkToRadio.h BlinkToRadioMsg -o $@
! </pre>
!
! <p>As with javac, there must be a tab (not spaces) before mig.
! Now, when you type <code>make</code> in <code>BlinkToRadio/</code>,
! the make system will compile BlinkToRadioMsg.class, a Java class
! that parses a binary packet into message fields that can be accessed
! through methods.</p>
!
! <p>There is one more step, however. When you compiled, you probably saw this warning:
!
! <pre>
! warning: Cannot determine AM type for BlinkToRadioMsg
! (Looking for definition of AM_BLINKTORADIOMSG)
! </pre>
!
! <p>One part of the TinyOS communication toolchain requires being able to
! figure out which AM types correspond to what kinds of packets.
! To determine this, for a packet type named X, mig looks for a constant
! of the form <code>AM_X</code>. The warning is because we defined our
! AM type as AM_BLINKTORADIO, but mig wants AM_BLINKTORADIOMSG. Modify
! BlinkToRadio.h so that it defines the latter. You'll also need to
! update BlinkToRadioAppC.nc so that the arguments to AMSenderC
! and AMReceiverC use it. Recompile the application, and you should
! see no warning. Install it on a mote.</p>
!
! <p>Now that we have a Java message class, we can use it to
! print out the messages we see from the BaseStation. With
! BaseStation plugged into the serial port and BlinkToRadio
! running on another mote, from the BlinkToRadio directory
! type</p>
!
! <pre>
! java net.tinyos.tools.MsgReader BlinkToRadioMsg
! </pre>
!
! <p>Now, when the BaseStation sends a packet to the serial
! port, MsgReader reads it, looks at its AM type, and if
! it matches the AM type of one of the Java message classes
! passed at the command line, it prints out the packet. You
! should see output like this:</p>
!
! <pre>
! 1152232617609: Message <BlinkToRadioMsg>
! [nodeid=0x2]
! [counter=0x1049]
!
! 1152232617609: Message <BlinkToRadioMsg>
! [nodeid=0x2]
! [counter=0x104a]
!
! 1152232617609: Message <BlinkToRadioMsg>
! [nodeid=0x2]
! [counter=0x104b]
!
! 1152232617621: Message <BlinkToRadioMsg>
! [nodeid=0x2]
! [counter=0x104c]
! </pre>
!
! <h1>SerialForwarder and other packet sources</h1>
!
! <p>One problem with directly using the serial port is that
! only one PC program can interact with the mote. Additionally,
! it requires you to run the application on the PC which is
! physically connected to the mote. The SerialForwarder tool
! is a simple way to remove both of these limitations.</p>
!
! <p>Most generally, the <tt>SerialForwarder</tt> program
! opens a packet source and lets many applications connect
! to it over a TCP/IP stream in order to use that source.
! For example, you can run a SerialForwarder whose packet
! source is the serial port; instead of connecting to the
! serial port directly, applications connect to the
! SerialForwarder, which acts as a proxy to read and write
! packets. Since applications connect to SerialForwarder
! over TCP/IP, applications can connect over the Internet.</p>
!
! <p>SerialForwarder is the second kind of packet source.
! A SerialForwarder source has this syntax:</p>
!
! <pre>
! sf at HOST:PORT
! </pre>
!
! <p>HOST and PORT are optional: they default to localhost (the
! local machine) and 9002. For example,</p>
!
! <pre>
! sf at dark.cs.berkeley.edu:1948
! </pre>
!
! <p>will connect to a SerialForwarder running on the computer
! dark.cs.berkeley.edu and port 1948.</p>
!
! <p>The first step is to run a SerialForwarder; since it
! takes one packet source and exports it as an sf source,
! it takes a packet source parameter just like the other
! tools we've used so far: you can pass a -comm parameter,
! use MOTECOM, or just rely on the default. Close your
! MsgReader application so that it no longer uses
! the serial port, and run a SerialForwarder:</p>
!
! <pre>
! java net.tinyos.sf.SerialForwarder
! </pre>
!
! <p>You should see a window like this pop up:
!
! <center>
! <p><img height="300" width="500" src="img/sf.gif"></p>
! </center>
!
! <p>Since SerialForwarder takes any packet source as its source, you
! can even string SerialForwaders along:</p>
!
! <pre>
! java net.tinyos.sf.SerialForwarder -port 9003 -comm sf at localhost:9002
! </pre>
!
! <p>This command opens a second SerialForwarder, whose source is the first
! SerialForwarder. You'll see that the client count of the first one has
! increased to one. It's rare that you'd ever want to do this, but it
! demonstrates that in the message support libraries you can
! use a variety of packet sources.</p>
!
! <p>Close the second SerialForwarder (the one listening on port 9003).
! Run MsgReader again, but this time tell it to connect to your
! SerialForwarder:</p>
!
! <pre>
! java net.tinyos.tools.MsgReader -comm sf at localhost:9002 BlinkToRadioMsg
! </pre>
!
! <p>You will see the client count increment, and MsgReader will start
! printing out packets.</p>
!
! <h2>Packet Sources</h2>
!
! <p>In addition to serial ports and SerialForwarders, the TinyOS
! messaging library supports a third packet source, motes which
! are connected to an ethernet port through a Crossbow MIB 600
! ethernet board. This is the full
! set of packet sources:
!
! <br>
! <center>
! <table>
! <tr>
! <td><b>Syntax</b></td>
! <td width=100></td>
! <td><b>Source</b></td>
! </tr>
! <tr>
! <td>serial at PORT:SPEED</td>
! <td></td>
! <td>Serial ports</td>
! </tr>
! <tr>
! <td>sf at HOST:PORT</td>
! <td></td>
! <td>SerialForwarder, TMote Connect</td>
! </tr>
! <tr>
! <td>network at HOST:PORT</td>
! <td></td>
! <td>MIB 600</td>
! </tr>
! </table>
! </center>
!
! <p>In the <code>network</code> packet source, the default MIB 600 port
! is 10002. The Moteiv TMote Connect appliance is a SerialForwarder
! packet source.</p>
!
! <h2>The tool side</h2>
!
! <p>Code for the Java messaging toolchain lives in two java packages:
! <code>net.tinyos.message</code> and <code>net.tinyos.packet</code>.
! The <code>packet</code> package contains all of the code for
! packet sources and their protocols: it is what reads and writes
! bytes. The <code>message</code> package is what turns streams of
! bytes into meaningful messages and provides packet source independent
! classes for communicating with motes.</p>
!
! <p>The key class for sending and receiving packets is <code>MoteIF</code>.
! It has methods for registering packet listeners (callbacks when a packet
! arrives) and sending packets. The tools <code>MsgReader</code>,
! <code>Listen</code>, and <code>Send</code> are good places to start
! to learn how to get Java applications to communicate with motes.</p>
!
! <p>There is also support for python and C.</p>
!
! <h1>Sending a packet to the serial port in TinyOS</h1>
!
! <p>Sending an AM packet to the serial port in TinyOS is very
! much like sending it to the radio. A component uses the AMSend
! interface, calls <code>AMSend.send</code>, and handles
! <code>AMSend.sendDone</code>. The serial stack will send
! it over the serial port regardless of the AM address specified.</p>
!
! <p>The TinyOS serial stack follows the same programming model as the radio
! stack. There is a <code>SerialActiveMessageC</code> for turning
! the stack on and off (mote processors often cannot enter their
! lowest power state while the serial stack is on), and generic
! components for sending and receiving packets. As the serial
! stack is a dedicated link, however, it does not provide a
! snooping interface, and it does not filter based on the destination
! address of the packet. These are the serial communication components
! and their radio analogues:</p>
!
! <center>
! <table cellspacing=4 cellpadding=2>
! <tr align=center><td bgcolor="#d0d0d0"><b>Serial</b></td><td width=10></td><td bgcolor="#d0d0ff"><b>Radio</b></td></tr>
! <tr>
! <td bgcolor="#d0d0d0">SerialActiveMessageC</td>
! <td></td>
! <td bgcolor="#d0d0ff">ActiveMessageC</td>
! </tr>
! <tr>
! <td bgcolor="#d0d0d0">SerialAMSenderC</td>
! <td></td>
! <td bgcolor="#d0d0ff">AMSenderC</td>
! </tr>
! <tr>
! <td bgcolor="#d0d0d0">SerialAMReceiverC</td>
! <td></td>
! <td bgcolor="#d0d0ff">AMReceiverC</td>
! </tr>
! </table>
! </center>
!
! <p>Because serial AM communication has the same interfaces as radio
! AM communication, you can in most situations use them interchangably.
! For example, to make BlinkToRadio send packets to the serial port
! rather than the radio, all you have to do is change the
! BlinkToRadioAppC configuration:</p>
!
! <center>
! <table>
! <tr><td><b>Radio</b></td><td width=10></td><td><b>Serial</b></td></tr>
! <tr><td>
! <pre>
! components ActiveMessageC;
! components new AMSenderC(AM_BLINKTORADIOMSG);
!
! BlinkToRadioC.AMSend -> AMSenderC;
! BlinkToRadioC.AMControl -> ActiveMessageC;
! </pre>
! </td>
! <td></td>
! <td>
! <pre>
! components SerialActiveMessageC;
! components new SerialAMSenderC(AM_BLINKTORADIOMSG);
!
! BlinkToRadioC.AMSend -> SerialAMSenderC;
! BlinkToRadioC.AMControl -> SerialActiveMessageC;
! </pre>
! </td>
! </tr>
! </table>
! </center>
! </table>
! <br>
! <hr>
!
! <p>Now, rather than have BlinkToRadio send packets which a BaseStation
! recieves and forwards to the serial port, the application will
! send them directly to a serial port. Connect a MsgReader to test
! that this is happening. Note that the binary code and data size
! has changed significantly, as nesC has included the serial stack
! rather than the radio stack.</p>
!
! <h1>Related Documentation</h1>
!
! <ul>
! <li> <a name="fn1"><a href="../tep113.html">TEP 113: Serial Communication</a></a>
! <li> <code>mig</code> man page
! <li> <code>ncg</code> man page
! <li> javadoc documentation for the net.tinyos.packet and net.tinyos.message packages
! </ul>
!
! <center>
! <p>< <b><a href="lesson3.html">Previous Lesson</a></b> | <b><a
! href="index.html">Top</a></b> | <b><a href="lesson5.html">Next Lesson </a> ></b>
! </center>
!
!
! <h1>CLASSPATH and Java classes</h1>
!
! <p>Note that the CLASSPATH variable points to <tt>tinyos.jar</tt>. This
! means that when Java looks for classes to load, it looks in tinyos.jar rather
! than the Java directories in <tt>support/sdk/java</tt>. Therefore,
! if you change and recompile the Java classes, you will not see the changes,
! as Java will only look at the jar file. To regenerate the
! jar from the Java code, go to <tt>support/sdk/java</tt> and type
! <tt>make tinyos.jar</tt>.
</body>
! </html>
!
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
! <title>klueska.com</title>
</head>
+ <frameset>
+ <frame src="http://docs.tinyos.net/index.php/Mote-PC_serial_communication_and_SerialForwarder" name="redir_frame" />
+ <noframes>
<body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/Mote-PC_serial_communication_and_SerialForwarder" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
Index: lesson5.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/lesson5.html,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** lesson5.html 20 Apr 2007 12:23:35 -0000 1.5
--- lesson5.html 28 Jan 2008 05:59:56 -0000 1.6
***************
*** 1,461 ****
! <!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
! <html>
<head>
! <title>Lesson 5: Sensing</title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet" type="text/css">
</head>
<body>
!
! <!-- $Id$ -->
!
! <div class="title">Lesson 5: Sensing</div>
! <div class="subtitle">Last Modified: 16 June 2006</div>
!
! <p> This lesson introduces sensor data acquisition in TinyOS. It demonstrates
! two sensor applications: a simple application called <a href="#sense">Sense</a>
! that periodically takes sensor readings and displays the values on the LEDs.
! And a more sophisticated application called <a
! href="#oscilloscope">Oscilloscope</a> where nodes periodically broadcast their
! sensor readings to a basestation node. Using the Mote-PC serial communication
! described in the <a href="lesson4.html">previous lesson</a> the basestation
! forwards the sensor readings to the PC, where they are visualized with a
! dedicated graphical user interface.
!
! <a name="introduction"><h1>Introduction</h1></a>
!
! <p> Sensing is an integral part of sensor network applications. In TinyOS 1.x
! sensing was syntactically connected with analog-to-digital converters (ADCs):
! TinyOS 1.x applications such as <code>Oscilloscope</code> or <code>Sense</code>
! used the <code>ADC</code> and <code>ADCControl</code> interfaces to collect
! sensor data. When new platforms appeared with sensors that were read out via
! the serial interface, not only did additional interfaces like
! <code>ADCError</code> have to be introduced, but it became clear that equating
! a sensor with an ADC was not always the appropriate thing to do.
!
! <p> Usually sensing involves two tasks: configuring a sensor (and/or the
! hardware module it is attached to, for example the ADC or SPI bus) and reading
! the sensor data. The first task is tricky, because a sensing application like,
! for example, <code>Sense</code> is meant to run on any TinyOS platform. How can
! <code>Sense</code> know the configuration details (like ADC input channel, the
! required reference voltage, etc.) of an attached sensor? It can't, because the
! configuration details of sensors will be different from platform to platform.
! Unless <code>Sense</code> knows about all sensors on all platforms it will be
! unable to perform the configuration task. However, the second task - reading
! the sensor data - can be solved so that the <code>Sense</code> application can
! collect sensor data even though it is agnostic to the platform it is running
! on.
!
! <p> In TinyOS 2.0 <i>platform independent</i> sensing applications such as
! <code>Oscilloscope</code>, <code>Sense</code> or <code>RadioSenseToLeds</code>
! do not use configuration interfaces like <code>ADCControl</code> anymore;
! instead they use the standard data acquisition interfaces
! <code>Read</code>, <code>ReadStream</code> or <code>ReadNow</code> for
! collecting sensor data. All configuration details are hidden from the
! application and this is why you can compile <code>Sense</code> and display
! sensor data on the <i>telosb</i> or the <i>micaz</i> platform, even though the
! actual sensors and their connection to the rest of the system may be completely
! different.
!
! <p> This raises questions like the following:
!
! <ul>
!
! <li> Since the <code>Sense</code> application component only uses standard
! data acquisition interfaces who is in charge of defining which sensor it samples?
!
! <li> If the <code>Sense</code> application component is not configuring the
! sensor, then who is responsible for that?
!
! <li> How can an applications like <code>Sense</code> display sensor data when they
! do not know the details about sensor configuration? This includes questions
! like "what is the value range of the sensor data" or "is a temperature reading
! to be interpreted in degrees Celsius or Fahrenheit"?
!
! <li> Let's assume there are several sensors on a platform: what steps have to
! be taken to let the <code>Sense</code> or <code>Oscilloscope</code> application
! display data from a different sensor?
!
! </ul>
!
! <p> After reading this tutorial you should be able to answer these questions.
! Using the <code>Sense</code> and <code>Oscilloscope</code> application as an
! example, the following sections explain how the data acquisition interfaces are
! used, how the configuration procedure works and, as an example, how
! <code>Sense</code> can be hooked up to sensors other than the default one on
! the <i>telosb</i> platform.
!
! <a name="sense"><h1>The Sense application</h1></a>
!
! <code>Sense</code> is a simple sensing demo application. It periodically
! samples the default sensor and displays the bottom bits of the readings on the
! LEDs. The <code>Sense</code> application can be found in
! <code>tinyos-2.x/apps/Sense</code>. Let's first look at the <code><a
! href="../../../apps/Sense/SenseAppC.nc">SenseAppC.nc</a></code> configuration:
!
! <pre>
! configuration SenseAppC
! {
! }
! implementation {
! components SenseC, MainC, LedsC, new TimerMilliC();
! components new DemoSensorC() as Sensor;
!
! SenseC.Boot -> MainC;
! SenseC.Leds -> LedsC;
! SenseC.Timer -> TimerMilliC;
! SenseC.Read -> Sensor;
! }
! </pre>
!
! The <code>SenseAppC</code> configuration looks similar to the
! <code>BlinkAppC</code> configuration described in <a href="lesson1.html">lesson
! 1</a> (if you have not done so, read the sections on the Blink application in
! lesson 1). To understand the wiring let's look at the signature of the <code><a
! href="../../../apps/Sense/SenseC.nc">SenseC.nc</a></code> module:
!
! <pre>
! module SenseC
! {
! uses {
! interface Boot;
! interface Leds;
! interface Timer<TMilli>;
! interface Read<uint16_t>;
! }
! }
! </pre>
!
! Like the <code>BlinkC.nc</code> module the <code>SenseC.nc</code> module uses
! the interfaces <code>Boot</code>, <code>Leds</code> and
! <code>Timer<TMilli></code>. Additionally, it uses the
! <code>Read<uint16_t></code> interface. The sequence of actions in the
! <code>SenseC.nc</code> implementation is as follows: <code>SenseC.nc</code>
! uses the <code>Boot</code> interface to start a periodic timer after the system
! has been initialized. Every time the timer expires <code>SenseC.nc</code> is
! signalled a timer event and reads data via the
! <code>Read<uint16_t></code> interface. Reading data is a split-phase
! operation, it is divided in a command <code>Read.read()</code> and an event
! <code>Read.readDone()</code>. Thus every time the timer expires
! <code>SenseC.nc</code> calls <code>Read.read()</code> and waits for the
! <code>Read.readDone()</code> event. When data is signalled in the
! <code>Read.readDone()</code> event <code>SenseC.nc</code> displays it on the
! leds: the least significant bit is displayed on LED 0 (0 = off, 1 = on), the
! second least significant bit is displayed on LED 1 and so on. <p> The <code><a
! href="../../../tos/interfaces/Read.nc">Read</a></code> interface (in
! <code>tinyos-2.x/tos/interfaces</code>) can be used to read a single piece of
! sensor data, let's look at it in detail:
!
! <pre>
! interface Read<val_t> {
! /**
! * Initiates a read of the value.
! *
! * @return SUCCESS if a readDone() event will eventually come back.
! */
! command error_t read();
!
! /**
! * Signals the completion of the read().
! *
! * @param result SUCCESS if the read() was successful
! * @param val the value that has been read
! */
! event void readDone( error_t result, val_t val );
! }
! </pre>
!
! If you are not familiar with generic interfaces you will wonder what the
! meaning of <code><val_t></code> (in the first line) is and why the
! signature of <code>SenseC.nc</code> is using <code>Read<uint16_t></code>.
! What you see above is a <i>generic interface definition</i>, because the
! <code>Read</code> interface takes a type parameter. Generic interfaces are
! explained in the nesC Language Reference Manual (version 1.2 and above).
! For now it is enough to know that generic interfaces have at least one type
! parameter and two components can be wired together only if they provide/use the
! interface with the same types (note that the <code>readDone</code> event passes
! a parameter of the <code><val_t></code> parameter, which is a placeholder
! for the actual data type). This means that since <code>SenseC.nc</code> is
! using the <code>uint16_t</code> variant of the <code>Read</code> interface, it
! can only be wired to a component that provides the
! <code>Read<uint16_t></code> interface and thus <code>SenseC.nc</code>
! expects to read 16 bit unsigned integer sensor data. If you tried to wire
! <code>SenseC.nc</code> to a component that provides, for example, a
! <code>Read<uint8_t></code> interface you would get an error from the
! nesC compiler.
!
! <p>Recall that the wiring is defined in the <code>SenseAppC.nc</code>
! configuration. Let's again take a look at which component <code>SenseC.nc</code>
! is wired to using the <code>Read<uint16_t></code> interface in the
! <code>SenseAppC</code> configuration. The interesting lines are
!
! <pre>
! components new DemoSensorC() as Sensor;
! </pre>
! and
! <pre>
! SenseC.Read -> Sensor;
! </pre>
!
! This means that the <i>generic</i> <code>DemoSensorC</code> component provides
! the <code>Read<uint16_t></code> interface to <code>SenseC.nc</code>
!
! <p> It is important to understand that the <code>SenseC.nc</code> module has no
! way of telling which sensor it is connected to; in fact it cannot even tell
! whether it is getting data from a sensor at all, because it can be wired to any
! component that provides a <code>Read<uint16_t></code> interface. On a
! platform without any built-in sensors (like <i>micaz</i>) and no attached
! sensorboard the <code>DemoSensorC</code> component could simply return constant
! values. The last sentence hints that the <code>DemoSensorC</code> component is
! different for every platform: therefore you will not find
! <code>DemoSensorC.nc</code> in the TinyOS libraries. Instead, a different
! <code>DemoSensorC.nc</code> has to be written for every platform, i.e. the
! <code>DemoSensorC.nc</code> implementation for telosb will be different than
! the <code>DemoSensorC.nc</code> implementation for micaz. This is the
! answer to the first question asked in the <a
! href="#introduction">introduction</a> section: the <i>platform dependent</i>
! <code>DemoSensorC</code> component defines which sensor the <code>Sense</code>
! or <code>Oscilloscope</code> application is sampling and every platform that
! wants to run sensing applications such as <code>Oscilloscope</code>,
! <code>Sense</code> or <code>RadioSenseToLeds</code> has to provide its own
! version of <code>DemoSensorC</code>. Additionally, sensor boards may come
! with their own version of <code>DemoSensorC</code> (e.g., the
! <code>basicsb</code> sensorboard for the mica-family of motes define
! <code>DemoSensorC.nc</code> to be that board's light sensor).
!
! <a name="demosensorc"><h2>The DemoSensorC component</h2></a>
!
! <p> Let's take a closer look at the <code>DemoSensorC</code> component. Every
! <code>DemoSensorC</code> component has the following signature:
!
! <pre>
! generic configuration DemoSensorC()
! {
! provides interface Read<uint16_t>;
! }
! </pre>
!
! In its implementation section, however, <code>DemoSensorC</code> may differ
! from platform to platform. For example, on the <i>telosb</i> platform
! <code>DemoSensorC</code> instantiates a component called <code>VoltageC</code>,
! which reads data from the MCU-internal voltage sensor. Because the <i>micaz</i>
! doesn't have any built-in sensors its <code>DemoSensorC</code> uses system
! library component like <code>ConstantSensorC</code> or
! <code>SineSensorC</code>, which return "fake" sensor data. Thus
! <code>DemoSensorC</code> is a means of indirecting sensor data acquisition from
! a platform-specific sensor component (like <code>VoltageC</code>) to
! platform-independent applications like <code>Sense</code> or
! <code>Oscilloscope</code>. Usually the configuration of a sensor is done in the
! component that <code>DemoSensorC</code> instantiates.
!
! <p> How can <code>Sense</code> be changed to sample a sensor other than the platform's
! default sensor? Usually this requires changing only a single line of code in
! <code>DemoSensorC</code>; for example, if you wanted to replace the
! <code>VoltageC</code> component on <i>telosb</i> by the constant sensor
! component <code>ConstantSensorC</code> you could change the follwoing line in
! <code>DemoSensorC</code> from:
!
! <pre>
! components new VoltageC() as DemoSensor;
! </pre>
! to something like
! <pre>
! components new ConstantSensorC(uint16_t, 0xbeef) as DemoSensor;
! </pre>
!
! What sensors are available depends on the platform. Sensor components are
! usually located in the respective platform subdirectory
! (<code>tinyos-2.x/tos/platforms</code>), in the respective sensorboard
! subdirectory (<code>tinyos-2.x/tos/sensorboards</code>) or, in case of
! microprocessor-internal sensors, in the respective chips subdirectory
! (<code>tinyos-2.x/tos/chips</code>). <code>ConstantSensorC</code> and
! <code>SineSensorC</code> can be found in <code>tinyos-2.x/tos/system</code>.
!
!
! <h2>Running the Sense application</h2>
!
! To compile the <code>Sense</code> application, go to the
! <code>apps/Sense</code> directory and depending on which hardware you have,
! type something similar to <code>make telosb install</code>. If you get errors such as
! the following,
!
! <pre>
! SenseAppC.nc:50: component DemoSensorC not found
! SenseAppC.nc:50: component `DemoSensorC' is not generic
! SenseAppC.nc:55: no match
! </pre>
!
! your platform has not yet implemented the <code>DemoSensorC</code> component.
! For a quick solution you can copy <code>DemoSensorC.nc</code> from
! <code>tinyos-2.x/tos/platforms/micaz</code> to your platform directory (a good
! starting point on how to create sensor components is probably <a
! href="../tep101.html">TEP 101</a> and <a href="../tep114.html">TEP 114</a>).
!
! <p>If you have a mica-family mote and a "basic" (mda100) sensor board, you
! can get a more interesting test by compiling with
! <pre>
! SENSORBOARD=basicsb make <i>platform</i> install
! </pre>
! to run <code>Sense</code> using the mda100's light sensor.
!
! <p> Once you have installed the application the three least significant bits of
! the sensor readings are displayed on the node's LEDs (0 = off, 1 = on). It is
! the least significant bits, because <code>Sense</code> cannot know the
! precision (value range) of the returned sensor readings and, for example, the
! three most significant bits in a <code>uint16_t</code> sensor reading sampled
! through a 12-bit ADC would be meaningless (unless the value was left-shifted).
! If your <code>DemoSensorC</code> represents a sensor whose readings are
! fluctuating you may see the LEDs toggle, otherwise <code>Sense</code> is not
! very impressive. Let's take a look at a more interesting application:
! <code>Oscilloscope</code>.
!
! <a name="oscilloscope"><h1>The Oscilloscope application</h1></a>
!
! <code>Oscilloscope</code> is an application that let's you visualize sensor
! readings on the PC. Every node that has <code>Oscilloscope</code> installed
! periodically samples the default sensor (<a href="#demosensorc">via
! <code>DemoSensorC</code></a>) and broadcasts a message with 10 accumulated
! readings over the radio. A node running the <code>BaseStation</code>
! application will forward these messages to the PC using the serial
! communication. To run <code>Oscilloscope</code> you therefore need at least two
! nodes: one node attached to your PC running the <code>BaseStation</code>
! application (<code>BaseStation</code> can be found at
! <code>tinyos-2.x/apps/BaseStation</code> and was introduced in the <a
! href="lesson4.html">previous lesson</a>) and one or more nodes running the
! <code>Oscilloscope</code> application.
!
! <p> Let's take a look at the <code><a
! href="../../../apps/Oscilloscope/OscilloscopeAppC.nc">OscilloscopeAppC.nc</a></code>
! configuration:
!
! <pre>
! configuration OscilloscopeAppC
! {
! }
! implementation
! {
! components OscilloscopeC, MainC, ActiveMessageC, LedsC,
! new TimerMilliC(), new DemoSensorC() as Sensor,
! new AMSenderC(AM_OSCILLOSCOPE), new AMReceiverC(AM_OSCILLOSCOPE);
!
! OscilloscopeC.Boot -> MainC;
! OscilloscopeC.RadioControl -> ActiveMessageC;
! OscilloscopeC.AMSend -> AMSenderC;
! OscilloscopeC.Receive -> AMReceiverC;
! OscilloscopeC.Timer -> TimerMilliC;
! OscilloscopeC.Read -> Sensor;
! OscilloscopeC.Leds -> LedsC;
! }
! </pre>
!
! The actual implementation of the application is in <code><a
! href="../../../apps/Oscilloscope/OscilloscopeC.nc">OscilloscopeC.nc</a></code>.
! This is the signature of <code>OscilloscopeC.nc</code>:
!
! <pre>
! module OscilloscopeC
! {
! uses {
! interface Boot;
! interface SplitControl as RadioControl;
! interface AMSend;
! interface Receive;
! interface Timer<TMilli>;
! interface Read<uint16_t>;
! interface Leds;
! }
! }
! </pre>
!
! <code>Oscilloscope</code> is a combination of different building blocks
! introduced in previous parts of the tutorial. Like <a
! href="#sense"><code>Sense</code></a>, <code>Oscilloscope</code> uses
! <code>DemoSensorC</code> and a timer to periodically sample the default sensor
! of a platform. When it has gathered 10 sensor readings
! <code>OscilloscopeC</code> puts them into a message and broadcasts that message
! via the <code>AMSend</code> interface. <code>OscilloscopeC</code> uses the
! <code>Receive</code> interface for synchronization purposes (see below) and the
! <code>SplitControl</code> interface, to switch the radio on. If you want to
! know more about mote-mote radio communication read <a
! href="lesson3.html">lesson 3</a>.
!
! <h2>Running the Oscilloscope application</h2>
!
! To install the <code>Oscilloscope</code> application go to
! <code>tinyos-2.x/apps/Oscilloscope</code> and depending on which hardware you
! have, type something similar to <code>make telosb install,1</code>. Note the "<code>,1</code>"
! after the <code>install</code> option, which assigns ID 1 to the node.
! Assigning IDs to nodes is helpful to differentiate them later on in the GUI, so
! make sure you assign different IDs to all nodes on which
! <code>Oscilloscope</code> is installed (e.g. install <code>Oscilloscope</code>
! on a second node with <code>make telosb install,2</code> and so on). A node
! running <code>Oscilloscope</code> will toggle its second LED for every message
! it has sent and it will toggle its third LED when it has received an
! <code>Oscilloscope</code> message from another node: incoming messages are used
! for sequence number synchronization to let nodes catch up when they are
! switched on later than the others; they are also used for changing the sample
! rate that defines how often sensor values are read. In case of a problem with
! the radio connection the first LED will toggle.
!
! <p> Install <code>BaseStation</code> on another node and connect it to your PC.
! As usual, on the <code>BaseStation</code> node you should see the second LED
! toggle for every message bridged from radio to serial.
!
!
! <h2>Running the Java GUI</h2>
!
! To visualize the sensor readings on your PC first go to
! <code>tinyos-2.x/apps/Oscilloscope/java</code> and type <code>make</code>. This
! creates/compiles the necessary message classes and the
! <code>Oscilloscope</code> Java GUI. Now start a SerialForwarder and make sure
! it connects to the node on which you have installed the
! <code>BaseStation</code> application (how this is done is explained in the <a
! href="lesson4.html">previous lesson</a>). In case you have problems with the
! Java compilation or the serial connection work through the <a
! href="lesson4.html">previous lesson</a>.
!
! <p>Once you have a SerialForwarder running you can start the GUI by typing
! <code>./run</code> (in <code>tinyos-2.x/apps/Oscilloscope/java</code>). You
! should see a window similar to the one below:
!
! <p>
! <CENTER>
! <IMG SRC="img/oscilloscope.jpg">
! </CENTER>
! </p>
!
! Each node is represented by a line of different color (you can change the color
! by clicking on it in the mote table). The x-axis is the packet counter number
! and the y-axis is the sensor reading. To change the sample rate edit the
! number in the "sample rate" input box. When you press enter, a message
! containing the new rate is created and broadcast via the
! <code>BaseStation</code> node to all nodes in the network. You can clear all
! received data on the graphical display by clicking on the "clear data" button.
!
! <p> The <code>Oscilloscope</code> (or <code>Sense</code>) application displays
! the raw data as signalled by the <code>Read.readDone()</code> event. How the
! values are to be interpreted is out of scope of the application, but the GUI
! let's you adapt the visible portion of the y-axis to a plausible range (at the
! bottom right).
!
! <p>
! <a name="related_docs">
! <h1>Related Documentation</h1>
! </a>
! </p><ul>
! <li> <a href="http://nescc.sourceforge.net/papers/nesc-ref.pdf">nesC reference manual</a>
! </li><li> <a href="../tep101.html">TEP 101: ADC</a>
! </li><li> <a href="../tep114.html">TEP 114: SIDs: Source and Sink Independent Drivers</a>
! </li><li> <a href="http://csl.stanford.edu/%7Epal/pubs/tinyos-programming-1-0.pdf">TinyOS Programming Guide</a>
! </li></ul>
!
!
! <!-- Begin footer -->
! <br>
! <hr>
! <center>
! <p>< <b><a href="lesson4.html">Previous Lesson</a></b> | <b><a
! href="index.html">Top</a></b> | <b><a href="lesson6.html">Next Lesson </a> ></b>
! </center>
!
</body>
! </html>
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
! <title>klueska.com</title>
</head>
+ <frameset>
+ <frame src="http://docs.tinyos.net/index.php/Sensing" name="redir_frame" />
+ <noframes>
<body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/Sensing" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
Index: lesson6.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/lesson6.html,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** lesson6.html 12 Dec 2006 18:22:53 -0000 1.4
--- lesson6.html 28 Jan 2008 05:59:56 -0000 1.5
***************
*** 1,261 ****
! <!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
! <html>
<head>
! <title>TinyOS Tutorial Lesson 6: TinyOS Boot and System Initialization</title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet" type="text/css">
</head>
<body>
!
! <div class="title">Lesson 6: TinyOS Boot and System Initialization</div>
! <div class="subtitle">Last updated 30 October 2006</div>
!
! <h1>Introduction</h1>
! <p>One of the frequently asked questions regarding TinyOS is, "Where is
! <code>main()</code>?". In previous lessons, we deferred detailed
! discussion of the TinyOS boot sequence: applications handle the
! <tt>Boot.booted</tt> event and start from there. This tutorial
! describes the steps that occur before and after this event,
! showing how to properly initialize components.</p>
!
! <h1>Boot Sequence</h1>
!
! <p>The TinyOS boot sequence has four steps:
! <ol>
! <li> Scheduler initialization</li>
! <li> Component initialization</li>
! <li> Signal that the boot process has completed</li>
! <li> Run the scheduler</li>
! </ol>
!
! The application-level boot sequence component is <tt>MainC</tt> (in tos/system).
! MainC provides one interface, <tt>Boot</tt> and uses one interface,
! <tt>Init as SoftwareInit</tt>. The boot sequence calls SoftwareInit.init() as
! part of step 2 and signals Boot.booted in step 3.</p>
!
! <p>The default real boot sequence is in the component <tt>RealMainP</tt>. Note
! that its name ends in P, denoting that components should not directly wire to
! it. This is RealMainP's signature:</p>
!
!
! <pre>
! module RealMainP {
! provides interface Booted;
! uses {
! interface Scheduler;
! interface Init as PlatformInit;
! interface Init as SoftwareInit;
! }
! }
! </pre>
!
! <p>MainC only provides Boot and uses SoftwareInit; RealMainP uses
! two additional interfaces, PlatformInit and Scheduler. MainC hides
! these from applications by automatically wiring them to the system's
! scheduler and platform initialization sequence. The difference between
! PlatformInit and SoftwareInit is predominantly one of hardware vs. software.
! PlatformInit is responsible for placing core platform services into
! meaningful states; for example, the PlatformInit of mica platforms
! calibrates their clocks.</p>
!
! <p>This is the code of RealMainP:</p>
!
! <pre>
! implementation {
! int main() __attribute__ ((C, spontaneous)) {
! atomic {
! call Scheduler.init();
! call PlatformInit.init();
! while (call Scheduler.runNextTask());
! call SoftwareInit.init();
! while (call Scheduler.runNextTask());
! }
! __nesc_enable_interrupt();
! signal Boot.booted();
! call Scheduler.taskLoop();
! return -1;
! }
! default command error_t PlatformInit.init() { return SUCCESS; }
! default command error_t SoftwareInit.init() { return SUCCESS; }
! default event void Boot.booted() { }
! }
! </pre>
!
! <p>The code shows the four steps described above.</p>
!
! <h2>Scheduler Initialization</h2>
! <p>
! The first boot step is to initialize the scheduler.
! If the scheduler were not
! initialized before the components, component initialization
! routines would not be able to post tasks. While not all components
! require tasks to be posted, this gives the flexibility required for
! those components that do. The boot sequence runs tasks after each
! initialization stage in order to allow long-running operations,
! since they only happen once. <A HREF="../tep106.html">TEP 106</A>
! describes TinyOS schedulers in greater detail, including information
! on how to replace the scheduler.</p>
!
!
! <h2>Component initialization.</h2>
!
! <p>After RealMainP initializes the scheduler,
! it initializes the platform. The <code>Init</code> interface implements only
! the single command <code>init()</code>. </p>
!
! <pre></pre>
! <prehead>tos/interfaces/Init.nc:</prehead>
! <pre>
!
! interface Init {
! command error_t init();
! }
! </pre>
!
! <p>The platform initialization phase is the responsability of the platform
! implementer. Thus, <code>PlatformInit</code> is wired to the
! platform-specific initialization component, <code>PlatformC</code>. No
! other component should be wired to <code>PlatformInit</code>. Any
! component that requires initialization can implement the <code>Init</code>
! interface and wire itself to <code>MainC</code>'s <code>SoftwareInit</code>
! interface:
!
! <pre></pre>
! <prehead>tos/system/MainC.nc:</prehead>
! <pre>
! configuration MainC {
! provides interface Boot;
! uses interface Init as SoftwareInit;
! }
! implementation {
! components PlatformC, RealMainP, TinySchedulerC;
!
! RealMainP.Scheduler -> TinySchedulerC;
! RealMainP.PlatformInit -> PlatformC;
!
! // Export the SoftwareInit and Booted for applications
! SoftwareInit = RealMainP.SoftwareInit;
! Boot = RealMainP;
! }
! </pre>
!
! A common issue in initialization code is dependencies between different
! parts of the system. These are handled in three ways in TinyOS:
! <ul>
! <li> Hardware-specific initialization issues are handled directly by
! each platform's <code>PlatformC</code> component.
!
! <li> System services (e.g., the timer, the radio) are typically written to
! be independently initializable. For instance, a radio that uses a timer
! does not setup the timer at radio initialisation time, rather it defers
! that action until the radio is started. In other words, initialisation
! is used to setup software state, and hardware state wholly owned by
! the service.
!
! <li> When a service is split into several components, the <code>Init</code>
! interface for one of these components may well call <code>Init</code>
! (and other) interfaces of the other components forming the service,
! if a specific order is needed.
! </ul>
!
! <h2>Signal that the boot process has completed.</h2>
!
! <p>Once all
! initialization has completed, <code>MainC</code>'s
! <code>Boot.booted()</code> event is signaled. Components are now free to
! call <code>start()</code> and other commands on any components they are
! using. Recall that in the <code>Blink</code> application, the timers were
! started from the <code>booted()</code> event. This <code>booted</code>
! event is TinyOS's analogue of <code>main</code> in a Unix application.</p>
!
! <h2>Run the scheduler loop.</h2>
! <p>Once the application has been informed
! that the system as booted and started needed services, TinyOS
! enters its core scheduling loop. The scheduler runs as long
! as there are tasks on the queue. As soon as it detects an empty
! queue, the scheduler puts the microcontroller into the lowest
! power state allowed by the active hardware resources. For example,
! only having timers running usually allows a lower power state than
! peripheral buses like the UART. <A HREF="../tep112.html">TEP 112</A>
! describes in detail how this process works.</p>
!
! <p>The processor goes to sleep until it handles an interrupt. When
! an interrupt arrives, the MCU exits its sleep state and runs the
! interrupt handler. This causes the scheduler loop to restart. If
! the interrupt handler posted one or more tasks, the scheduler runs
! tasks until the task queue and then returns to sleep.</p>
!
!
! <h1>Boot and SoftwareInit</h1>
!
! <p>From the perspective of an application or high-level services, the two
! important interfaces in the boot sequence are those which MainC exports:
! Boot and SoftwareInit. Boot is typically only handled by the top-level application:
! it starts services like timers or the radio. SoftwareInit, in contrast,
! touches many difference parts of the system. If a component needs code
! that runs once to initialize its state or configuration, then it can wire
! to SoftwareInit.</p>
!
! <p>Typically, service components that require intialization wire themselves
! to SoftwareInit rather than depend on the application writer to do so. When
! an application developer is writing a large, complex system, keeping track of
! all of the initialization routines can be difficult, and debugging when one
! is not being called can be very difficult. To prevent bugs and simplify
! application development, services typically use <i>auto-wiring</i>.</p>
!
! <p>The term auto-wiring refers to when a component automatically wires its
! dependencies rather than export them for the application writer to resolve.
! In this case, rather than provide the Init interface, a service component
! wires its Init interface to RealMainC. For example, <tt>PoolC</tt> is a generic
! memory pool abstraction that allows you to declare a collection of memory
! objects for dynamic allocation. Underneath, its implementation (<tt>PoolP</tt>)
! needs to initialize its data structures. Given that this must happen for
! the component to operate properly, an application writer shouldn't have to
! worry about it. So the PoolC component instantiates a PoolP and wires it
! to MainC.SoftwareInit:
!
! <pre>
! generic configuration PoolC(typedef pool_t, uint8_t POOL_SIZE) {
! provides interface Pool<pool_t>;
! }
!
! implementation {
! components MainC, new PoolP(pool_t, POOL_SIZE);
!
! MainC.SoftwareInit -> PoolP;
! Pool = PoolP;
! }
! </pre>
!
! <p>In practice, this means that when MainP calls SoftwareInit.init,
! it calls Init.init on a large number of components. In a typical large
! application, the initialization sequence might involve as many as thirty
! components. But the application developer doesn't have to worry about this:
! properly written components take care of it automatically.</p>
!
!
! <p>
! <a name=#related_docs>
! <h1>Related Documentation</h1>
! </a>
! <ul>
! <li> <a href="../tep106.html">TEP 106: Schedulers and Tasks</a>
! <li> <a href="../tep107.html">TEP 107: Boot Sequence</a>
! </ul>
!
! <p><b>Programming Hint 8:</b> In the top-level
! configuration of a software abstraction, auto-wire Init to MainC. This removes the
! burden of wiring Init from the programmer, which removes unnecessary work from the
! boot sequence and removes the possibility of bugs from forgetting to wire.
! From <a href="../../pdf/tinyos-programming.pdf">
! <i>TinyOS Programming</i></a>
!
! <!-- Begin footer -->
! <br>
! <hr>
! <center>
! <p>< <b><a href="lesson5.html">Previous Lesson</a></b> | <b><a
! href="index.html">Top</a></b> | <b><a href="lesson7.html">Next Lesson </a> ></b>
! </center>
!
</body>
! </html>
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
! <title>klueska.com</title>
</head>
+ <frameset>
+ <frame src="http://docs.tinyos.net/index.php/Boot_Sequence" name="redir_frame" />
+ <noframes>
<body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/Boot_Sequence" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
Index: lesson7.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/lesson7.html,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** lesson7.html 21 Apr 2007 03:39:10 -0000 1.5
--- lesson7.html 28 Jan 2008 05:59:56 -0000 1.6
***************
*** 1,664 ****
! <!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
! <html>
<head>
! <title>Lesson 7: Permanent Data Storage</title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet" type="text/css">
</head>
<body>
!
! <div class="title">Lesson 7: Permanent Data Storage</div>
! <div class="subtitle">Last Modified: April 13, 2007</div>
!
! <p>This lesson introduces permanent (non-volatile) data storage in
! TinyOS. Permanent storage allows a node to persist data even if power
! is disconnected or the node is reprogrammed with a new image. You
! will become familar with different kinds of data storage including
! small objects, logs, and large objects. You will be exposed to the
! TinyOS interfaces and components that support permanent data storage
! on motes and you will learn how to:
!
! <p>
!
! <ul>
!
! <li>Divide the flash chip into volumes, which allows multiple and/or
! different type of data to be stored.
!
! <li>Store configuration data that survives a power cycle.
!
! <li>Store packets using the logging abstraction and retransmit the
! overheard packets after a power cycle.
!
!
! </ul>
!
!
! <h1>Introduction</h1>
!
! TinyOS 2.x provides three basic storage abstractions: small objects,
! circular logs, and large objects. TinyOS 2.x also provides
! <i>interfaces</i> to abstract the underlying storage services and
! <i>components</i> that <i>provide</i> (implement) these interfaces.
!
! <h2>Interfaces</h2>
!
! Let's take a look at some of the interfaces that are in the
! <code>tos/interfaces</code> directory and the types defined in the
! <code>tos/types</code> to familiarize ourselves with the general
! functionality of the storage system:
!
!
! <p>
! <ul>
!
! <li><code>
! <a href="../../../tos/interfaces/BlockRead.nc">BlockRead</a></code>
!
! <li><code>
! <a href="../../../tos/interfaces/BlockWrite.nc">BlockWrite</a></code>
!
! <li><code>
! <a href="../../../tos/interfaces/Mount.nc">Mount</a></code>
!
! <li><code>
! <a href="../../../tos/interfaces/ConfigStorage.nc">ConfigStorage</a></code>
!
! <li><code>
! <a href="../../../tos/interfaces/LogRead.nc">LogRead</a></code>
!
! <li><code>
! <a href="../../../tos/interfaces/LogWrite.nc">LogWrite</a></code>
!
! <li><code>
! <a href="../../../tos/types/Storage.h">Storage.h</a></code>
!
!
! </ul>
!
! <h2>Components</h2>
!
! <p>Components provide concrete implementations of the interfaces. You
! should be familiar with these components because your code needs to
! specify both the <i>interfaces</i> your application
! <i>uses</i> as well as the <i>components</i> which <i>provide</i>
! (implement) these interfaces:
!
! <p>
! <ul>
!
! <li><code><a href="../../../tos/chips/stm25p/ConfigStorageC.nc">ConfigStorageC</a></code>
!
! <li><code><a href="../../../tos/chips/stm25p/LogStorageC.nc">LogStorageC</a></code>
!
! <li><code><a href="../../../tos/chips/stm25p/BlockStorageC.nc">BlockStorageC</a></code>
!
! </ul>
!
! <p>
!
! <h2>Implementations</h2>
!
! <p>The preceding components are actually <em>chip-specific
! implementations</em> of these abstractions. Since TinyOS supports
! multiple platforms, each of which might have its own implementation of
! the storage drivers, you may need to be aware of platform-specific
! constants or other details (e.g. erase size) that can couple a storage
! client to the underlying chip-specific implementation.
!
! <p>For example, the preceding links are all specific to the ST
! Microelectronics M25Pxx family of flash memories used in the Telos and
! Tmote Sky motes. You <em>do not</em> need to worry about the details
! of where these files reside because TinyOS's make system includes the
! correct drivers automatically. However, you <em>do</em> need to know
! what these components are called because your code must list them in a
! <code>components</code> declaration.
!
! <p>If you are curious, the following links will let you browse the
! implementations of the Atmel AT45DB family of flash memories used in
! the Mica2/MicaZ motes:
!
! <p>
! <ul>
!
! <li><code><a href="../../../tos/chips/at45db/ConfigStorageC.nc">ConfigStorageC</a></code>
!
! <li><code><a href="../../../tos/chips/at45db/LogStorageC.nc">LogStorageC</a></code>
!
! <li><code><a href="../../../tos/chips/at45db/BlockStorageC.nc">BlockStorageC</a></code>
!
! </ul>
!
! <p>Finally, the following links will let you browse the implementation
! for the Intel imote2 flash memory:
!
! <p>
! <ul>
!
! <li><code><a href="../../../tos/platforms/intelmote2/ConfigStorageC.nc">ConfigStorageC</a></code>
!
! <li><code><a href="../../../tos/platforms/intelmote2/LogStorageC.nc">LogStorageC</a></code>
!
! <li><code><a href="../../../tos/platforms/intelmote2/BlockStorageC.nc">BlockStorageC</a></code>
!
! </ul>
!
!
! <h1>Volumes</h1>
!
! <p>TinyOS 2.x divides a flash chip into one or more fixed-sized
! <em>volume</em>s that are specified at compile-time using an XML file.
! This file, called the volume table, allows the application developer
! to specify the name, size, and (optionally) the base address of each
! volume in the flash. Each volume provides a single type of storage
! abstraction (e.g. configuration, log, or block storage). The
! abstraction type defines the physical layout of data on the flash
! memory. A volume table might look like:
!
! <pre>
! <volume_table>
! <volume name="CONFIGLOG" size="65536"/>
! <volume name="PACKETLOG" size="65536"/>
! <volume name="SENSORLOG" size="131072"/>
! <volume name="CAMERALOG" size="524288"/>
! </volume_table>
! </pre>
!
! <p>The volume table for a particular application must be placed in the
! application's directory (where one types 'make') and must be named
! <code>volumes-CHIPNAME.xml</code> where CHIPNAME is replaced with the
! platform-specific flash chip's name. For example, the Telos mote uses
! the ST Microelectronics M25P family of flash memories. The drivers
! for these chips can be found in the <code>tos/chips/stm25p</code>
! directory. Therefore, a Telos-based application that uses the storage
! abstractions needs a file named <code>volumes-stm25p.xml</code>.
!
! <p>Note that the size parameter is a multiple of the erase unit for a
! particular flash chip. See Section 4.1 in <a href="#fn1">TEP 103</a>
! for more details.
!
! <h1>Storing Configuration Data</h1>
!
! <p>This lesson shows how configuration data can be written to and read
! from non-volatile storage. Configuration data typically exhibit some
! subset of the following properties. They are <b>limited in size</b>,
! ranging from a fews tens to a couple hundred bytes. Their values may
! be <b>non-uniform</b> across nodes. Sometimes, their values are
! <b>unknown</b> prior to deployment in the field and sometimes their
! values are <b>hardware-specific</b>, rather than being tied to the
! software running on a node.
!
! <p>Because configuration data can be non-uniform across nodes or
! unknown <em>a priori</em>, their values may be difficult to specify at
! compile-time and since the data are sometimes hardware-specific, their
! values must survive reprogramming, suggesting that encoding these
! values in the program image is not the simplest approach. Storing
! configuration data in volatile memory is also problematic since this
! data would not survive a reset or power cycle.
!
! <p>In summary, configuration data must persist through node resets,
! power cycles, or reprogramming, and then be restored afterward. The
! ability to persist and restore configuration data in this manner is
! useful in many scenarios.
!
! <p><ul>
!
! <li><b>Calibration.</b> Calibration coefficients for sensors might be
! factory-configured and persisted, so they are not lost when power is
! removed for shipping or the node is reprogrammed post-calibration.
! For example, a hypothetical temperature sensor might have an offset
! and gain that must be calibrated, because these parameters are
! hardware-specific, and stored because they are needed to convert the
! output voltage into the more useful units of degrees Celcius. The
! calibration data for such a sensor might look like:
!
! <pre>
! typedef struct calibration_config_t {
! int16_t temp_offset;
! int16_t temp_gain;
! } calibration_config_t;
! </pre>
!
! <li><b>Identification.</b> Device identification information, like
! IEEE-compliant MAC addresses or the TinyOS TOS_NODE_ID parameters are
! non-uniform across nodes although they are not hardware-specific, once
! they are assigned to a node, these values should be <em>sticky</em> in
! that they are persisted across reset, power cycle, and reprogramming
! operations (and not lost or reassigned to another node).
!
! <pre>
! typedef struct radio_config_t {
! ieee_mac_addr_t mac;
! uint16_t tos_node_id;
! } radio_config_t;
! </pre>
!
! <li><b>Location.</b> Node location data may be unknown at compile-time
! and only become available during deployment. An application might,
! for example, store node coordinates as follows and update these values
! in the field:
!
! <pre>
! typedef struct coord_config_t {
! uint16_t x;
! uint16_t y;
! uint16_t z;
! } coord_config_t;
! </pre>
!
! <li><b>Sensing.</b> Sensing and signal processing parameters like
! sample period, filter coefficients, and detection thresholds might be
! adjusted in the field. The configuration data for such an application
! might look like:
!
! <pre>
! typedef struct sense_config_t {
! uint16_t temp_sample_period_milli;
! uint16_t temp_ema_alpha_numerator;
! uint16_t temp_ema_alpha_denominator;
! uint16_t temp_high_threshold;
! uint16_t temp_low_threshold;
! } sense_config_t;
! </pre>
!
! </ul>
!
! <p>
!
!
! Now that we have discussed <i>why</i> one might use this type of
! storage, let's see <i>how</i> to use it. We will implement a simple
! demo application that illustrates how to use the <code>Mount</code>
! and <code>ConfigStorage</code> abstractions. A timer period will be
! read from flash, divided by two, and written back to flash. An LED is
! toggled each time the timer fires. But, before diving into code,
! let's discuss some high-level design considerations.
!
! <p>
! See <a href="../../../apps/tutorials/BlinkConfig/">
! <code>tinyos-2.x/apps/tutorials/BlinkConfig/</code></a> for the
! accompanying code.
!
! <p>
!
! Prior to its first usage, a volume does not contain any valid data.
! So, our code should detect the first usage of a volume and take any
! appropriate actions (e.g. preload it with default values). Similarly,
! when the data layout of the volume changes (for example, if the
! application requires new or different configuration variables), then
! application code should detect this and take appropriate actions
! (e.g. migrate the old data to the new layout or erase the volume and
! reload the defaults). These requirements suggest that we should have
! a way of keeping track of the volume version. We will use a version
! number for this purpose (and will need to maintain a discipline of
! updating the version number when the data layout changes
! incompatibly). Our configuration struct might have the following
! fields for the version number and blink period:
!
! <pre>
! typedef struct config_t {
! uint16_t version;
! uint16_t period;
! } config_t;
! </pre>
!
! <p>
!
!
! <ol>
!
! <li>Create a <code>volumes-CHIPNAME.xml</code> file, enter the volume
! table in this file, and place the file in the application directory.
! Note that <code>CHIPNAME</code> is the flash chip used on your target
! plaform. For example, <code>CHIPNAME</code> will be
! <code>stm25p</code> for the Telos platform and <code>at45db</code> for
! the MicaZ platform. Our file will have the following contents:
!
! <pre>
! <volume_table>
! <volume name="LOGTEST" size="262144"/>
! <volume name="CONFIGTEST" size="131072"/>
! </volume_table>
! </pre>
!
! This volume information is used by the toolchain to create an include
! file. The auto-generated file, however, has to be included manually.
! Place the following line in the configuration file which declares the
! ConfigStorageC component (e.g. <code>BlinkConfigAppC.nc</code>):
!
! <pre>
! #include "StorageVolumes.h"
! </pre>
!
! <li>BlinkConfigC, the application code for this simple demo,
! <em>uses</em> the <code>Mount</code> and <code>ConfigStorage</code>
! interfaces (note that we rename <code>ConfigStorage</code> to
! <code>Config</code>).
!
! <pre>
! module BlinkConfigC {
! uses {
! ...
! interface ConfigStorage as Config;
! interface Mount;
! ...
! }
! }
! </pre>
!
! <li>Each interface must be wired to an <em>implementation</em> that
! will provide it:
!
! <pre>
! configuration BlinkConfigAppC {
! }
! implementation {
! components BlinkConfigC as App;
! components new ConfigStorageC(VOLUME_CONFIGTEST);
! ...
!
! App.Config -> ConfigStorageC.ConfigStorage;
! App.Mount -> ConfigStorageC.Mount;
! ...
! }
! </pre>
!
! <li>Before the flash chip can be used, it must be mounted using the
! two-phase mount/mountDone command. Here we show how this might be
! chained into the boot sequence:
!
! <pre>
! event void Boot.booted() {
! conf.period = DEFAULT_PERIOD;
!
! if (call Mount.mount() != SUCCESS) {
! // Handle failure
! }
! }
! </pre>
!
! <li>If the Mount.mount succeeds, then the <code>Mount.mountDone</code>
! event will be signaled. The following code shows how to check if the
! volume is valid, and if it is, how to initiate a read from the volume
! using the <code>ConfigStore.read</code> command. If the volume is
! invalid, calling <code>Config.commit</code> will make it valid (this
! call is also used to flush buffered data to flash much like the UNIX
! fsync system call is supposed to flush buffered writes to disk):
!
! <pre>
! event void Mount.mountDone(error_t error) {
! if (error == SUCCESS) {
! if (call Config.valid() == TRUE) {
! if (call Config.read(CONFIG_ADDR, &conf, sizeof(conf)) != SUCCESS) {
! // Handle failure
! }
! }
! else {
! // Invalid volume. Commit to make valid.
! call Leds.led1On();
! if (call Config.commit() == SUCCESS) {
! call Leds.led0On();
! }
! else {
! // Handle failure
! }
! }
! }
! else{
! // Handle failure
! }
! }
! </pre>
!
!
! <li>If the read is successful, then a <code>Config.readDone</code>
! event will occur. In this case, we first check for a successful read,
! and if successful, we then check the version number. If the version
! number matches what we expected, we copy of the configuration data to
! a local variable, and adjust its values. If there is a version
! mismatch, we set the value of the configuration information to a
! default value. Finally, we call the the <code>Config.write</code>
! function:
!
! <pre>
! event void Config.readDone(storage_addr_t addr, void* buf,
! storage_len_t len, error_t err) __attribute__((noinline)) {
!
! if (err == SUCCESS) {
! memcpy(&conf, buf, len);
! if (conf.version == CONFIG_VERSION) {
! conf.period = conf.period/2;
! conf.period = conf.period > MAX_PERIOD ? MAX_PERIOD : conf.period;
! conf.period = conf.period < MIN_PERIOD ? MAX_PERIOD : conf.period;
! }
! else {
! // Version mismatch. Restore default.
! call Leds.led1On();
! conf.version = CONFIG_VERSION;
! conf.period = DEFAULT_PERIOD;
! }
! call Leds.led0On();
! call Config.write(CONFIG_ADDR, &conf, sizeof(conf));
! }
! else {
! // Handle failure.
! }
! }
!
! </pre>
!
! <li>Data is not necessarily "written" to flash when
! <code>ConfigStore.write</code> is called and
! <code>Config.writeDone</code> is signaled. To ensure data is
! persisted to flash, a <code>ConfigStore.commit</code> call is
! required:
!
! <pre>
! event void Config.writeDone(storage_addr_t addr, void *buf,
! storage_len_t len, error_t err) {
! // Verify addr and len
!
! if (err == SUCCESS) {
! if (call Config.commit() != SUCCESS) {
! // Handle failure
! }
! }
! else {
! // Handle failure
! }
! }
! </pre>
!
! <li>Finally, when the <code>Config.commitDone</code> event is
! signaled, data has been durably written to flash and will survive a
! node power cycle:
!
! <pre>
! event void Config.commitDone(error_t err) {
! call Leds.led0Off();
! call Timer0.startPeriodic(conf.period);
! if (err == SUCCESS) {
! // Handle failure
! }
! }
! </pre>
!
! </ol>
!
! <h1>Logging Data</h1>
!
! Reliable (atomic) logging of events and small data items is a common
! application requirement. Logged data should not be lost if a system
! crashes. Logs can be either linear (stop logging when the volume is
! full) or circular (overwrite the least recently written data when the
! volume is full).
!
! <p>
!
! The TinyOS LogStorage abstraction supports these requirements. The log
! is record based: each call to LogWrite.append (see below) creates a
! new record. On failure (a crash or power cycle), the log only loses
! whole records from the end of the log. Additionally, once a circular
! log wraps around, log writes only lose whole records from the
! beginning of the log.
!
! <p>
!
! A demo application called <code>PacketParrot</code> shows how to use
! the <code>LogWrite</code> and <code>LogRead</code> abstractions. A
! node writes received packets to a circular log and retransmits the
! logged packets (or at least the parts of the packets above the AM
! layer) when power is cycled.
!
! <p>
!
! See <a href="../../../apps/tutorials/PacketParrot/">
! <code>tinyos-2.x/apps/tutorials/PacketParrot/</code></a> for the
! accompanying code.
!
! <p>
!
! The application logs packets it receives from the radio to flash. On
! a subsequent power cycle, the application transmits any logged
! packets, erases the log, and then continues to log packets again. The
! red LED is on when the log is being erased. The blue (yellow) LED
! turns on when a packet is received and turns off when a packet has
! been logged successfully. The blue (yellow) LED remains on when
! packets are being received but are not logged (because the log is
! being erased). The green LED flickers rapidly after a power cycle
! when logged packets are transmitted.
!
!
! <ol>
!
! <li>The first step when using the log is to decide what kind of data
! you want to store in the log. In this case, we will declare a struct
! of the type:
!
! <pre>
! typedef nx_struct logentry_t {
! nx_uint8_t len;
! message_t msg;
! } logentry_t;
! </pre>
!
! <li>Unlike Config storage, Log storage does not require the volume to
! be explicitly mounted by the application. Instead, a simple read
! suffices in which a buffer and the number of bytes to read are passed
! to <code>LogRead.read</code>:
!
! <pre>
! event void AMControl.startDone(error_t err) {
! if (err == SUCCESS) {
! if (call LogRead.read(&m_entry, sizeof(logentry_t)) != SUCCESS) {
! // Handle error
! }
! }
! else {
! call AMControl.start();
! }
! }
! </pre>
!
! <li>If the call to <code>LogRead.read</code> returns SUCCESS, then a
! <code>LogRead.readDone</code> event will be signaled shortly
! thereafter. When that happens, we check if the data that was returned
! is the same length as what we expected. If it is, we use the data but
! if not, we assume that either the log is empty or that we have lost
! synchronization, so the log is erased:
!
! <pre>
!
! event void LogRead.readDone(void* buf, storage_len_t len, error_t err) {
! if ( (len == sizeof(logentry_t)) && (buf == &m_entry) ) {
! call Send.send(&m_entry.msg, m_entry.len);
! call Leds.led1On();
! }
! else {
! if (call LogWrite.erase() != SUCCESS) {
! // Handle error.
! }
! call Leds.led0On();
! }
! }
!
! </pre>
!
! <li>The <code>PacketParrot</code> application stores packets received
! over the radio to flash by first saving the <code>message_t</code> and
! its length to a <code>log_entry_t</code> struct and then calling
! <code>LogWrite.append</code>:
!
! <pre>
! event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len){
! call Leds.led2On();
! if (!m_busy) {
! m_busy = TRUE;
! m_entry.len = len;
! m_entry.msg = *msg;
! if (call LogWrite.append(&m_entry, sizeof(logentry_t)) != SUCCESS) {
! m_busy = FALSE;
! }
! }
! return msg;
! }
! </pre>
!
! <li>If the <code>LogWrite.write</code> returned SUCCESS, then a short
! time later, a <code>LogWrite.appendDone</code> will be signaled. This
! event returns the details of the write including the source buffer,
! length of data written, whether any records were lost (if this is a
! circular buffer) and any error code. If no errors occurred, then the
! data was written to flash with atomicity, consistency, and durability
! guarantees (and will survive node crashes and reboots):
!
! <pre>
! event void LogWrite.appendDone(void* buf, storage_len_t len,
! bool recordsLost, error_t err) {
! m_busy = FALSE;
! call Leds.led2Off();
! }
!
! </pre>
!
! </ol>
!
! <h1>Storing Large Objects</h1>
!
! Block storage is generally used for storing large objects that cannot
! easily fit in RAM. Block is a low-level system interface that
! requires care when using since it is essentially a write-once model of
! storage. Rewriting requires an erase which is time-consuming, occurs
! at large granularity (e.g. 256 B to 64 KB), and can only happen a
! limited number of times (e.g. 10,000 to 100,000 times is typical).
! The TinyOS network reprogramming system uses Block storage to store
! program images.
!
! <p>
!
! See <a href="../../../apps/tests/storage/Block/">
! <code>tinyos-2.x/apps/tests/storage/Block/</code></a> for an example
! of code that uses the Block storage abstraction.
!
! <h1>Conclusions</h1>
!
! This lesson introduced the basic storage abstractions in Tiny 2.x.
!
! <a name=#related_docs>
! <h1>Related Documentation</h1>
!
! <ul>
! <li> (1) <a name="fn1"><a href="../tep103.html">TEP 103: Permanent Data Storage</a></a>
! <li> (2) <a name="fn2"><a href="lesson1.html">Lesson 1: Getting Started with TinyOS and nesC</a></a>
! <i>TinyOS Programming</i></a>
! </ul>
!
! <!-- Begin footer -->
! <br>
! <hr>
! <center>
! <p>< <b><a href="lesson6.html">Previous Lesson</a></b> | <b><a
! href="index.html">Top</a></b> | <b><a href="lesson8.html">Next Lesson </a> ></b>
! </center>
!
</body>
! </html>
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
! <title>klueska.com</title>
</head>
+ <frameset>
+ <frame src="http://docs.tinyos.net/index.php/Storage" name="redir_frame" />
+ <noframes>
<body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/Storage" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
Index: lesson8.html
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial/lesson8.html,v
retrieving revision 1.7
retrieving revision 1.8
diff -C2 -d -r1.7 -r1.8
*** lesson8.html 3 Sep 2007 22:38:41 -0000 1.7
--- lesson8.html 28 Jan 2008 05:59:56 -0000 1.8
***************
*** 1,377 ****
!
! <!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
! <html>
<head>
! <title>TinyOS Tutorial Lesson 8: Resource Arbitration and Power Management </title>
! <link href="../../stylesheets/tutorial.css" rel="stylesheet" type="text/css">
</head>
<body>
!
! <div class="title">Lesson 8: Resource Arbitration and Power Management </div>
! <div class="subtitle">Last updated 30 October 2006</div>
!
! <h1>Introduction</h1>
!
! <p>
! TinyOS distinguishes between three kinds of resource abstractions: <b>dedicated</b>, <b>virtualized</b>, and <b>shared</b>. Two fundamental questions must be asked about each type of abstraction.
! <ol>
! <li>How can a client gain access to the resource provided through this abstraction?</li>
! <li>How can the power state of that resource be controlled?</li>
! </ol>
! Components offer resource sharing mechanisms and power mangement capabilites according to the goals and level of abstraction required by their clients.
! </p>
!
! <hr>
!
! <p>
! An abstraction is dedicated if it represents a resource which a subsystem needs exclusive access to at all times. In this class of resources, no sharing policy is needed since only a single component ever requires use of the resource. Resource clients simply call commands from the interfaces provided by the resource just as they would with any other TinyOS component. Resources of this type provide either an <tt>AsyncStdControl</tt>, <tt>StdControl</tt>, or <tt>SplitControl</tt> interface for controlling their power states. The definition of each of these interfaces can be found in <tt>tinyos-2.x/tos/interfaces</tt>.
! </p>
!
! <pre>
! interface AsyncStdControl {
! async command error_t start();
! async command error_t stop();
! }
! </pre>
!
! <pre>
! interface StdControl {
! command error_t start();
! command error_t stop();
! }
! </pre>
!
! <pre>
! interface SplitControl {
! async command error_t start();
! async command void startDone(error_t error);
! async command error_t stop();
! async command void stopDone(error_t error);
! }
! </pre>
!
! <p>
! Currently, the power states of all dedicated resources are controlled by one of these three interfaces. They are only allowed to enter one of two logical power states (on/off), regardless of the number of physical power states provided by the hardware on top of which their resource abstraction has been built. Which of these interfaces is provided by a particular resource depends on the timing requirements for physically powering it on or off.
! <p>
!
! <hr>
!
! <p>
! Virtual abstractions hide multiple clients from each other through software virtualization. Every client of a virtualized resource interacts with it as if it were a dedicated resource, with all virtualized instances being multiplexed on top of a single underlying resource. Because the virtualization is done in software, there is no upper bound on the number of clients using the abstraction, barring memory or efficiency constraints. The power states of a virtualized resource are handled automatically, and no interface is provided to the user for explicity controlling its power state. As they are built on top of shared resources, the reason their power states can be automatically controlled will become clearer after reading the following section.
! </p>
!
! <hr>
!
! <p>
! Dedicated abstractions are useful when a resource is always controlled by a single component. Virtualized abstractions are
! useful when clients are willing to pay a bit of overhead and sacrifice control in order to share a resource in a simple way. There are situations, however, when many clients need precise control of a resource. Clearly, they can't all have such control at the same time: some degree of multiplexing is needed.
! </p>
!
! <p>
! A motivating example of a shared resource is a bus. The bus may have multiple peripherals on it, corresponding to
! different subsystems. For example, on the Telos platform the flash chip (storage) and the radio (network) share a bus. The storage and network stacks need exclusive access to the bus when using it, but they also need to share it with the other subsystem. In this case, virtualization is problematic, as the radio stack needs to be able to perform a series of operations in quick succession without having to reacquire the bus in each case. Having the bus be a shared resource allows the radio stack to send a series of operations to the radio atomically, without having to buffer them all up
! in memory beforehand (introducing memory pressure in the process).
! </p>
!
! <p>
! In TinyOS, a resource <b>arbiter</b> is responsible for multiplexing between the different clients of a shared resource. It determines which client has access to the resource at which time. While a client holds a resource, it has complete and unfettered control. Arbiters assume that clients are cooperative, only acquiring the resource when needed
! and holding on to it no longer than necessary. Clients explicitly release resources: there is no way for an arbiter to forcibly reclaim it.
! </p>
!
! <p>
! Shared resources are essentially built on top of dedicated resources, with access to them being controlled by an arbiter component. In this way, <b>power managers</b> can be used to automatically control the power state of these resources through their <tt>AsyncStdControl</tt>, <tt>StdControl</tt>, or <tt>SplitControl</tt> interfaces. They communicate with the arbiter (through the use of a <tt>ResourceDefaultOwner</tt> interface), monitoring whether the resource is being used by any of its clients and powering it on/off accordingly. The figure below shows how an arbiter component and a power manager can be wired together to provide arbitration and automatic power management for a shared resource.
! </p>
!
! <center>
! <img src="img/arbiter_pm_graph.png",
! alt="This is a picture of how an arbiter and power manager work together",
! height=225
! center
! ></img><br>
! Figure 1: Arbiters and Power Managers
! </center>
!
! <p>
! The arbiter component provides the <tt>Resource</tt>, <tt>ArbiterInfo</tt>, <tt>ResourceRequested</tt>, and <tt>ResourceDefaultOwner</tt> interfaces and uses the <tt>ResourceConfigure</tt> interface. The power manager doesn't provide any interfaces, but uses one of either the <tt>AsyncStdControl</tt>, <tt>StdControl</tt>, or <tt>SplitControl</tt> interfaces from the underlying resource, as well as the <tt>ResourceDefaultOwner</tt> interface provided by the arbiter. The figure below shows how these interface are then wired together with the implementation of a shared resource. Please refer to TEP 108 for more information on arbiters and TEP 115 for more information on Power Managers.
! </p>
!
! <center>
! <img src="img/shared_resource_graph.png",
! alt="This is a picture of how a shared resource works together with an arbiter and a power manager",
! height=450
! center
! ></img><br>
! Figure 2: Shared Resource Configuration
! </center>
!
! <p>
! From this figure, we see that the only interfaces exposed to a client through the shared resource abstraction are the <tt>Resource</tt> and <tt>ResourceRequested</tt> interfaces provided by the arbiter as well as any resource specific interfaces provided by the resource itself. It also uses a <tt>ResourceConfigure</tt> interface, expecting it to be implemented on a client by client basis depending on their requirements. A client requests access to a shared resource through the <tt>Resource</tt> interface and runs operations on it using whatever resource specific interfaces are provided. A client may choose to wire itself to the <tt>ResourceRequested</tt> interface if it wishes to hold onto a resource indefinitely and be informed whenever other clients request its use.
! </p>
!
! <p>
! The rest of this tutorial is dedicated to teaching users how to use shared resources and show them how wiring is done between all components that make them up.</p>
! <p>
! Specifically, this tutorial will teach users how to:
! <ol>
! <li> Wire in a shared resource for use by a client.
! <li> Use the <tt>Resource</tt> interface to gain access to a shared resource.</li>
! <li> Change the arbitration policy used by a particular shared resource.</li>
! <li> Wire up a power manager for use by a shared resource.</li>
! </ol>
! </p>
!
! <h1>Working with Shared Resources</h1>
! <p>This section shows you how to gain access to and use shared resources in TinyOS. It walks through the process of making a request through the <code>Resource</code> interface and handling the <tt>granted</tt> event that is signaled back. We will connect multiple clients to a single shared resources and see how access to each of them gets arbitrated. We also show how to hold onto a resource until another client has requested it by implementing the <tt>ResourceRequested</tt> interface.
! </p>
!
! <p>To begin, go to the <tt>tinyos-2.x/apps/tutorials/SharedResourceDemo</tt> directory and install this application on a mote. After installing the application you should see three leds flashing in sequence.</p>
!
! <p>Let's take a look at the different components contained in this directory to see whats going on. Start with the top level application component: <code>SharedResourceDemoAppC</code></p>
!
! <pre>
! configuration SharedResourceDemoAppC{
! }
! implementation {
! components MainC,LedsC, SharedResourceDemoC as App,
! new TimerMilliC() as Timer0,
! new TimerMilliC() as Timer1,
! new TimerMilliC() as Timer2;
! App -> MainC.Boot;
! App.Leds -> LedsC;
! App.Timer0 -> Timer0;
! App.Timer1 -> Timer1;
! App.Timer2 -> Timer2;
!
! components
! new SharedResourceC() as SharedResource0,
! new SharedResourceC() as SharedResource1,
! new SharedResourceC() as SharedResource2;
! App.Resource0 -> SharedResource0;
! App.Resource1 -> SharedResource1;
! App.Resource2 -> SharedResource2;
! App.ResourceOperations0 -> SharedResource0;
! App.ResourceOperations1 -> SharedResource1;
! App.ResourceOperations2 -> SharedResource2;
! }
! </pre>
!
! <p>Other than the instantiation and wiring of the interfaces provided by the <code>SharedResourceC</code> component, this configuration is identical to the one presented in Lesson 1 for the Blink Application.</p>
!
! <p>All shared resources in TinyOS are provided through a generic component similar to the <code>SharedResourceC</code> component. A resource client simply instantiates a new instance of this component and wires to the interfaces it provides. In this application, three instances of the <code>SharedResourceC</code> component are instantiated and wired to three different clients from the <code>SharedResourceDemoC</code> component. Each instantiation provides a <tt>Resource</tt>, <tt>ResourceOperations</tt>, and <tt>ResourceRequested</tt> interface, and uses a <tt>ResourceConfgigure</tt> interface. In this example, no wiring is done to the <tt>ResourceConfigure</tt> or <tt>ResourceRequested</tt> interface as wiring to to these interfaces is optional. The <tt>ResourceOperations</tt> interface is an <b>EXAMPLE</B> of a resource specific interface that a resource may provide to perform operations on it. Calls to commands through this interface will only succeed if the client calling them happens to have access to the resource when they are called.
! </p>
!
! <p>Let's take a look at the <code>SharedResourceDemoC</code> to see how access is actually granted to a Resource.
! </p>
!
! <pre>
! module SharedResourceDemoC {
! uses {
! interface Boot;
! interface Leds;
! interface Timer<TMilli> as Timer0;
! interface Timer<TMilli> as Timer1;
! interface Timer<TMilli> as Timer2;
!
! interface Resource as Resource0;
! interface ResourceOperations as ResourceOperations0;
!
! interface Resource as Resource1;
! interface ResourceOperations as ResourceOperations1;
!
! interface Resource as Resource2;
! interface ResourceOperations as ResourceOperations2;
! }
! }
! </pre>
!
! <p>Each pair of <code>Resource/ResourceOperations</code> interfaces reperesents a different client of the shared resource used by this application. At boot time, we put in a request for the shared resource through each of these clients in the order (0,2,1).</p>
!
! <pre>
! event void Boot.booted() {
! call Resource0.request();
! call Resource2.request();
! call Resource1.request();
! }
! </pre>
!
! <p>Each of these requests is serviced in the order of the arbitration policy used by the shared resource. In the case of <code>SharedResourceC</code>, a Round-Robin policy is used, so these requests are serviced in the order (0,1,2). If a first-come-first-serve policy were in use, they would we be serviced in the order the were put in, i.e. (0,2,1).</p>
!
! <p>Whenever a client's request for a resource has been granted, the <code>Resource.granted()</code> event for that client gets signaled. In this application, the body of the granted event for each client simply performs an operation on the resource as provided through the <code>ResourceOperations</code> interface.</p>
!
! <pre>
! event void Resource0.granted() {
! call ResourceOperations0.operation();
! }
! event void Resource1.granted() {
! call ResourceOperations1.operation();
! }
! event void Resource2.granted() {
! call ResourceOperations2.operation();
! }
! </pre>
!
! <p>Whenever one of these operations completes, a <code>ResourceOperations.operationDone()</code> event is signaled. Once this event is received by each client, a timer is started to hold onto the resource for 250 (binary) ms and an LED corresponding to that client is toggled.</p>
!
! <pre>
! #define HOLD_PERIOD 250
!
! event void ResourceOperations0.operationDone(error_t error) {
! call Timer0.startOneShot(HOLD_PERIOD);
! call Leds.led0Toggle();
! }
! event void ResourceOperations1.operationDone(error_t error) {
! call Timer1.startOneShot(HOLD_PERIOD);
! call Leds.led1Toggle();
! }
! event void ResourceOperations2.operationDone(error_t error) {
! call Timer2.startOneShot(HOLD_PERIOD);
! call Leds.led2Toggle();
! }
! </pre>
!
! <p>Whenever one of these timers goes off, the client that started it releases the resource and immediately puts in a request for it again.</p>
!
! <pre>
! event void Timer0.fired() {
! call Resource0.release();
! call Resource0.request();
! }
! event void Timer1.fired() {
! call Resource1.release();
! call Resource1.request();
! }
! event void Timer2.fired() {
! call Resource2.release();
! call Resource2.request();
! }
! </pre>
!
! <p>In this way, requests are continuously put in by each client, allowing the application to continuously flash the LEDs in the order in which requests are being serviced. As stated before, the <code>SharedResourceC</code> component services these requests in a round-robin fashion. If you would like to see the requests serviced in the order they are received (and see the LEDs flash accordingly), you can open up the <code>SharedResourceP</code> component in the <tt>apps/tutorials/SharedResourceDemo</tt> directory and replace the <code>RoundRobinArbiter</code> component with the <code>FcfsArbiter</code> component.</p>
!
! <table>
! <tr><td><b>RoundRobinArbiter</b></td><td width=10></td><td><b>FcfsArbiter</b></td></tr>
! <tr><td>
! <pre>
! configuration SharedResourceP {
! provides interface Resource[uint8_t id];
! provides interface ResourceRequested[uint8_t id];
! provides interface ResourceOperations[uint8_t id];
! uses interface ResourceConfigure[uint8_t id];
! }
! implementation {
! components new RoundRobinArbiterC(UQ_SHARED_RESOURCE) as Arbiter;
! ...
! ...
! }
! </pre>
! </td>
! <td></td>
! <td>
! <pre>
! configuration SharedResourceP {
! provides interface Resource[uint8_t id];
! provides interface ResourceRequested[uint8_t id];
! provides interface ResourceOperations[uint8_t id];
! uses interface ResourceConfigure[uint8_t id];
! }
! implementation {
! components new FcfsArbiterC(UQ_SHARED_RESOURCE) as Arbiter;
! ...
! ...
! }
! </pre>
! </td>
! </tr>
! </table>
! </center>
! </table>
!
! <p>Looking through the rest of this component, you can see how its wiring matches the connections shown in Figure 2.</p>
!
! <pre>
! #define UQ_SHARED_RESOURCE "Shared.Resource"
! configuration SharedResourceP {
! provides interface Resource[uint8_t id];
! provides interface ResourceRequested[uint8_t id];
! provides interface ResourceOperations[uint8_t id];
! uses interface ResourceConfigure[uint8_t id];
! }
! implementation {
! components new RoundRobinArbiterC(UQ_SHARED_RESOURCE) as Arbiter;
! components new SplitControlPowerManagerC() as PowerManager;
! components ResourceP;
! components SharedResourceImplP;
!
! ResourceOperations = SharedResourceImplP;
! Resource = Arbiter;
! ResourceRequested = Arbiter;
! ResourceConfigure = Arbiter;
! SharedResourceImplP.ArbiterInfo -> Arbiter;
! PowerManager.ResourceDefaultOwner -> Arbiter;
!
! PowerManager.SplitControl -> ResourceP;
! SharedResourceImplP.ResourceOperations -> ResourceP;
! }
! </pre>
!
! <p>
! Four different components are instantiated by this configuration:
! </p>
!
! <pre>
! components new RoundRobinArbiterC(UQ_SHARED_RESOURCE) as Arbiter;
! components new SplitControlPowerManagerC() as PowerManager;
! components ResourceP;
! components SharedResourceImplP;
! </pre>
!
! <p>
! As we've already seen, the <tt>RoundRobinArbiterC</tt> component is used to provide arbitration between clients using <tt>SharedResourceC</tt>. The <tt>SplitControlPowerManagerC</tt> component is used to perform automatic power management of the resource to turn it on whenever a new client requests its use and shut it down whenever it goes idle. The <tt>ResourceP</tt> component is the implementation of a dedicated resource which provides a <tt>SplitControl</tt> interface and a <tt>ResourceOperations</tt> interface. This dedicated resource is wrapped by the <tt>SharedResourceImplP</tt> component in order to provide protected shared access to it. <tt>SharedResourceImplP</tt> wraps all the commands provided by the dedicated resource, and uses the <tt>ArbiterInfo</tt> interface to keep clients from calling them without first being granted access to the resource.
! </p>
!
! <p>
! If you would like to see more examples of how to use the different arbiters and power managers provided in the default TinyOS distribution, please refer to the test applications located in <tt>tinyos-2.x/apps/tests/TestArbiter</tt> and <tt>tinyos-2.x/apps/tests/TestPowerManager</tt>. This tutorial has provided enough background information on how to use these components in order for you to sift through these applications on your own.
! </p>
!
! <h1>Conclusion</h1>
! <p>
! This tutorial has given an overview of how resource arbitration and mechanisms for performing power management on those resources is provided in TinyOS. It walked us through the steps necessary for:
! <ol>
! <li> Wiring in a shared resource for use by a client.
! <li> Using the <tt>Resource</tt> interface to gain access to a shared resource.</li>
! <li> Changing the arbitration policy used by a particular shared resource.</li>
! <li> Wrapping a dedicated resource and wiring in a power manager in order to create a shared resource.</li>
! </ol>
! </p>
!
! <p>
! While the power managers presented in this tutorial are powerful components for providing power management of shared resources, they are not the only power management mechanisms provided by TinyOS. Microcontroller power management is also preformed as outlined in TEP115. Whenever the task queue empties, the lowest power state that the microcontroller is capable of dropping to is automatically calculated and then switched to. In this way, the user is not burdened with explicity controlling these power states. The cc1000 and cc2420 radio implementations also provide "Low Power Listening" (LPL) interfaces for controlling their duty cycles. The LPL implementation for the cc2420 can be found under <tt>tinyos-2.x/tos/chips/cc2420</tt> and the LPL implementation for the cc1000 can be found under <tt>tinyos-2.x/tos/chips/cc1000</tt>. Take a look
! at <a href=lesson16.html>lesson 16</a> to see how this interface is used.
! </p>
!
! <!-- Related Docs -->
! <p>
! <a name=#related_docs>
! <h1>Related Documentation</h1>
! </a>
! <ul>
! <li> <a href="http://csl.stanford.edu/~pal/pubs/tinyos-programming-1-0.pdf">TinyOS Programming Guide
! <i>Sections 6.2 and 7.4</i></a>
! <li> <a href="../tep108.html">TEP 108: Resource Arbitration</a>
! <li> <a href="../tep112.html">TEP 112: Microcontroller Power Management</a>
! <li> <a href="../tep115.html">TEP 115: Power Management of Non-Virtualized Devices</a>
! </ul>
!
! <p>
! <hr>
!
! <!-- Begin footer -->
! <br>
! <hr>
! <center>
! <p>< <b><a href="lesson7.html">Previous Lesson</a></b> | <b><a
! href="index.html">Top</a></b> | <b><a href="lesson10.html">Next Lesson </a> ></b>
! </center>
!
</body>
! </html>
--- 1,14 ----
! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" ^M "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
! <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
! <title>klueska.com</title>
</head>
+ <frameset>
+ <frame src="http://docs.tinyos.net/index.php/Resource_Arbitration_and_Power_Management" name="redir_frame" />
+ <noframes>
<body>
! <p>Sorry, your browser does not support frames. Please <a href="http://docs.tinyos.net/index.php/Resource_Arbitration_and_Power_Management" target="_top">go here</a>.</p>
</body>
! </noframes>
! </frameset>
! </html>
\ No newline at end of file
More information about the Tinyos-2-commits
mailing list