]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - doc/html/tutorial/lesson6.html
Merge over into the trunk.
[tinyos-2.x.git] / doc / html / tutorial / lesson6.html
index 41deb458fa24b9621b7736307393167ed82f0cc2..7d838a78f43140cea2f373fad7e23b7cdbc1d71e 100644 (file)
@@ -7,37 +7,99 @@
 <body>
 
 <div class="title">Lesson 6: TinyOS Boot and System Initialization</div>
-<div class="subtitle">Last updated 18 May 2006</div>
-
-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 in favor of grasping the general idea. We will
-now revisit the boot sequence indetail. Understanding how TinyOS
-initializes will help solidify understanding of the execution model
-and answer the question "Where is <code>main()</code>?".
+<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>
  
-The TinyOS boot sequence is comprised of three steps:
-<ul> 
-<li> Scheduler initialization
-<li> Component initialization
-<li> Signal that the boot process has completed 
-</ul>
+<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>
 
-<p><b>Scheduler initialization.</b> The scheduler is initialized
-before any components are initialized. If the scheduler were not
+      
+      <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 compoenents that do. 
+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>
 
-<p>The <code>Scheduler</code> interface defines a scheduling
-component's signature in
-<code>tos/interfaces/Scheduler.nc</code>.  TinyOS developers can
-define their own scheduler to meet their application's needs.</p> An
-implementation of the <code>Scheduler</code> interface is provided in
-<code>tos/system/TinySchedulerC.nc</code>.</p>
 
-<p><b>Component initialization.</b> After the scheduler is initialized, 
-components are initialized. The <code>Init</code> interface implements only
+<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>
@@ -49,27 +111,6 @@ interface Init {
 }
 </pre>
 
-<p>To provide the initialization flexibility required by sensor
-network components, the TinyOS's boot sequence breaks down the component
-initialization into a <i>platform initialization phase</i> (run first) and a <i>software 
-initialization phase</i>. This is accomplished by making the TinyOS component that
-executes the boot sequence use two <code>Init</code> interfaces:
-one called <code>PlatformInit</code> and one called <code>SoftwareInit</code>:
-
-<pre></pre>
-<prehead>tos/system/RealMainP.nc:</prehead>
-<pre>
-module RealMainP {
-  provides interface Boot;
-  uses interface Scheduler;
-  uses interface Init as PlatformInit;
-  uses interface Init as SoftwareInit;
-}
-implementation {
-  // implementation covered below
-}
-</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
@@ -104,7 +145,7 @@ parts of the system. These are handled in three ways in TinyOS:
 each platform's <code>PlatformC</code> component.
 
 <li> System services (e.g., the timer, the radio) are typically written to
-be independently initialisable. For instance, a radio that uses a timer
+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
@@ -112,52 +153,86 @@ 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.
+(and other) interfaces of the other components forming the service,
+                 if a specific order is needed.
 </ul>
 
-<p><b>Signal that the boot process has completed.</b> Once all
+<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.
+event is TinyOS's analogue of <code>main</code> in a Unix application.</p>
 
-<p>But if you're curious, <code>main</code> is actually found inside
-<code>RealMainP</code>. It executes the steps outlined above, i.e.,
-initialises the scheduler, calls the initialization interfaces, signals the
-<code>booted</code> event and then starts the main TinyOS scheduling loop:
+<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>
 
-<pre></pre>
-<prehead>tos/system/RealMainP.nc:</prehead>
-<pre>
-module RealMainP {
-  // signature
-}
-implementation {
-  int main() __attribute__ ((C, spontaneous)) {
-    atomic 
-      {    
-       call Scheduler.init(); 
-    
-       call PlatformInit.init();    
-       while (call Scheduler.runNextTask());
-
-       call SoftwareInit.init(); 
-       while (call Scheduler.runNextTask());
-      }
+           <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>
 
-    /* Enable interrupts now that system is ready. */
-    __nesc_enable_interrupt();
 
-    signal Boot.booted();
+           <h1>Boot and SoftwareInit</h1>
 
-    /* Spin in the Scheduler */       
-    call Scheduler.taskLoop();
-  }
+           <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>
@@ -171,7 +246,7 @@ implementation {
 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 Phil Levis' <a href="http://csl.stanford.edu/~pal/pubs/tinyos-programming-1-0.pdf">
+From <a href="../../pdf/tinyos-programming.pdf">
 <i>TinyOS Programming</i></a>
 
 <!-- Begin footer -->