]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - doc/html/tep116.html
Merge TinyOS 2.1.1 into master.
[tinyos-2.x.git] / doc / html / tep116.html
index 50b9aa6383ea42c7bacbeb292cc32270cbf69605..07c122e9f2b53220256e54a18656cff5839643ca 100644 (file)
@@ -41,11 +41,6 @@ blockquote.epigraph {
 dd {
   margin-bottom: 0.5em }
 
-/* Uncomment (& remove this text!) to get bold-faced definition list terms
-dt {
-  font-weight: bold }
-*/
-
 div.abstract {
   margin: 2em 5em }
 
@@ -296,19 +291,11 @@ ul.auto-toc {
 <tr class="field"><th class="docinfo-name">Type:</th><td class="field-body">Documentary</td>
 </tr>
 <tr><th class="docinfo-name">Status:</th>
-<td>Draft</td></tr>
-<tr class="field"><th class="docinfo-name">TinyOS-Version:</th><td class="field-body">2.x</td>
+<td>Final</td></tr>
+<tr class="field"><th class="docinfo-name">TinyOS-Version:</th><td class="field-body">&gt; 2.1</td>
 </tr>
 <tr><th class="docinfo-name">Author:</th>
 <td>Philip Levis</td></tr>
-<tr class="field"><th class="docinfo-name">Draft-Created:</th><td class="field-body">10-Dec-2004</td>
-</tr>
-<tr class="field"><th class="docinfo-name">Draft-Version:</th><td class="field-body">1.2</td>
-</tr>
-<tr class="field"><th class="docinfo-name">Draft-Modified:</th><td class="field-body">2006-07-12</td>
-</tr>
-<tr class="field"><th class="docinfo-name">Draft-Discuss:</th><td class="field-body">TinyOS Developer List &lt;tinyos-devel at mail.millennium.berkeley.edu&gt;</td>
-</tr>
 </tbody>
 </table>
 <div class="note">
@@ -323,7 +310,7 @@ TEP 1.</p>
 <p>The memo documents the interfaces used by packet protocol components in
 TinyOS 2.x as well as the structure and implementation of ActiveMessageC,
 the basic data-link HIL component. It also documents the virtualized
-active message interfaces AMSender and AMReceiver.</p>
+active message interfaces AMSenderC and AMReceiverC.</p>
 </div>
 <div class="section">
 <h1><a id="introduction" name="introduction">1. Introduction</a></h1>
@@ -384,7 +371,10 @@ HIL.</p>
 <em>Packet</em> interfaces are for accessing message fields and payloads.
 <em>Send</em> interfaces are for transmitting packets, and are
 distinguished by their addressing scheme.
-Finally, the <em>Receive</em> interface is for handling packet reception events.</p>
+The <em>Receive</em> interface is for handling packet reception events.
+Finally, depending on whether the protocol has a dispatch identifier
+field, the Receive and Send interfaces may be parameterized in order
+to support multiple higher-level clients.</p>
 <div class="section">
 <h2><a id="packet-interfaces" name="packet-interfaces">2.1 Packet interfaces</a></h2>
 <p>The basic TinyOS 2.x message buffer type is message_t, which is
@@ -406,35 +396,50 @@ interface Packet {
   command uint8_t payloadLength(message_t* msg);
   command void setPayLoadLength(message_t* msg, uint8_t len);
   command uint8_t maxPayloadLength();
-  command void* getPayload(message_t* msg, uint8_t* len);
+  command void* getPayload(message_t* msg, uint8_t len);
 }
 </pre>
 <p>A component can obtain a pointer to its data region within a packet by
-calling <tt class="docutils literal"><span class="pre">getPayload()</span></tt> the optional <tt class="docutils literal"><span class="pre">len</span></tt> argument is for also
-obtaining the size of the data region. A provider of a Packet
-interface MUST check if <tt class="docutils literal"><span class="pre">len</span></tt> is NULL and ignore it if it is. A
-component can also obtain the size of the data region with a call to
-<tt class="docutils literal"><span class="pre">payloadLength</span></tt>.</p>
-<p>A component can set the payload length with
-<tt class="docutils literal"><span class="pre">setPayLoadLength.</span></tt> As Send interfaces always include a length
-parameter in their send call, this command is not required for
-sending, and so is never called in common use cases. Instead,
-it is a way for queues and other packet buffering components
-to store the full state of a packet without requiring additional
-memory allocation.</p>
+calling <tt class="docutils literal"><span class="pre">getPayload()</span></tt>. A call to this command includes the length
+the caller requires. The command <tt class="docutils literal"><span class="pre">maxPayloadLength</span></tt> returns the
+maximum length the payload can be: if the <tt class="docutils literal"><span class="pre">len</span></tt> parameter to
+<tt class="docutils literal"><span class="pre">getPayload</span></tt> is greater than the value <tt class="docutils literal"><span class="pre">maxPayloadLength</span></tt> would
+return, <tt class="docutils literal"><span class="pre">getPayload</span></tt> MUST return NULL.</p>
+<p>A component can set the payload length with <tt class="docutils literal"><span class="pre">setPayLoadLength.</span></tt> A
+component can obtain the size of the data region of packet in use with
+a call to <tt class="docutils literal"><span class="pre">payloadLength</span></tt>. As Send interfaces always include a
+length parameter in their send call, <tt class="docutils literal"><span class="pre">setPayLoadLength</span></tt> is not
+required for sending, and so is never called in common use
+cases. Instead, it is a way for queues and other packet buffering
+components to store the full state of a packet without requiring
+additional memory allocation.</p>
 <p>The distinction between <tt class="docutils literal"><span class="pre">payloadLength</span></tt> and <tt class="docutils literal"><span class="pre">maxPayloadLength</span></tt>
-comes from whether the packet is being received or sent. In the receive
-case, determining the size of the existing data payload is needed;
-in the send case, a component needs to know how much data it can put
-in the packet.</p>
-<p>The Packet interface assumes that headers have a fixed size.
-It is difficult to return a pointer into the data region when its
-position will only be known once the header values are bound.</p>
-<p>Generally, an incoming call to the Packet interface of a protocol
-has an accompanying outgoing call to the Packet interface of the
-component below it. The one exception to this is the data link
-layer. For example, if there is a network that introduces
-16-bit sequence numbers to packets, it might look like this:</p>
+comes from whether the packet is being received or sent. In the
+receive case, determining the size of the existing data payload is
+needed; in the send case, a component needs to know how much data it
+can put in the packet. By definition, the return value of
+<tt class="docutils literal"><span class="pre">payloadLength</span></tt> must be less than or equal to the return value of
+<tt class="docutils literal"><span class="pre">maxPayloadLength</span></tt>.</p>
+<p>The Packet interface assumes that headers have a fixed size. It is
+difficult to return a pointer into the data region when its position
+will only be known once the header values are bound.</p>
+<p>The <tt class="docutils literal"><span class="pre">clear</span></tt> command clears out all headers, footers, and metadata
+for lower layers. For example, calling <tt class="docutils literal"><span class="pre">clear</span></tt> on a routing
+component, such as CollectionSenderC[4]_, will clear out the
+collection headers and footers. Furthermore, CollectionSenderC will
+recursively call <tt class="docutils literal"><span class="pre">clear</span></tt> on the layer below it, clearing out the
+link layer headers and footers. Calling <tt class="docutils literal"><span class="pre">clear</span></tt> is typically
+necessary when moving a packet across two link layers. Otherwise, the
+destination link layer may incorrectly interpret metadata from the
+source link layer, and, for example, transmit the packet on the wrong
+RF channel. Because <tt class="docutils literal"><span class="pre">clear</span></tt> prepares a packet for a particular link
+layer, in this example correct code would call the command on the
+destination link layer, not the source link layer.</p>
+<p>Typically, an incoming call to the Packet interface of a protocol has
+an accompanying outgoing call to the Packet interface of the component
+below it. The one exception to this is the data link layer. For
+example, if there is a network that introduces 16-bit sequence numbers
+to packets, it might look like this:</p>
 <pre class="literal-block">
 generic module SequenceNumber {
   provides interface Packet;
@@ -450,9 +455,11 @@ implementation {
   };
 
   command void Packet.clear(message_t* msg) {
-    uint8_t len;
-    void* payload = call SubPacket.getPayload(msg, &amp;len);
-    memset(payload, len, 0);
+    void* payload = call SubPacket.getPayload(msg, call SubPacket.maxPayloadLength());
+    call SubPacket.clear();
+    if (payload != NULL) {
+      memset(payload, sizeof(seq_header_t), 0);
+    }
   }
 
   command uint8_t Packet.payloadLength(message_t* msg) {
@@ -467,12 +474,12 @@ implementation {
     return SubPacket.maxPayloadLength(msg) - SEQNO_OFFSET;
   }
 
-  command void* Packet.getPayload(message_t* msg, uint8_t* len) {
-    uint8_t* payload = call SubPacket.getPayload(msg, len);
-    if (len != NULL) {
-      *len -= SEQNO_OFFSET;
+  command void* Packet.getPayload(message_t* msg, uint8_t len) {
+    uint8_t* payload = call SubPacket.getPayload(msg, len + SEQNO_OFFSET);
+    if (payload != NULL) {
+      payload += SEQNO_OFFSET;
     }
-    return payload + SEQNO_OFFSET;
+    return payload;
   }
 }
 </pre>
@@ -498,18 +505,30 @@ has this signature:</p>
 interface AMPacket {
   command am_addr_t address();
   command am_addr_t destination(message_t* amsg);
+  command am_addr_t source(message_t* amsg);
   command void setDestination(message_t* amsg, am_addr_t addr);
+  command void setSource(message_t* amsg, am_addr_t addr);
   command bool isForMe(message_t* amsg);
   command am_id_t type(message_t* amsg);
   command void setType(message_t* amsg, am_id_t t);
+  command am_group_t group(message_t* amsg);
+  command void setGroup(message_t* amsg, am_group_t grp);
+  command am_group_t localGroup();
 }
 </pre>
 <p>The command address() returns the local AM address of the
-node. AMPacket provides accessors for its two fields, destination and
-type. It does not provide commands to set these fields, as they are
-set in the sending call path (see Section 2.3). The <tt class="docutils literal"><span class="pre">setDestination</span></tt>
-and <tt class="docutils literal"><span class="pre">setType</span></tt> commands fulfill a similar purpose to
-<tt class="docutils literal"><span class="pre">Packet.setLength</span></tt>.</p>
+node. AMPacket provides accessors for its four fields, destination,
+source, type and group. It also provides commands to set these
+fields, for the same
+reason that Packet allows a caller to set the payload length.  Packet
+interfaces SHOULD provide accessors and mutators for all of their
+fields to enable queues and other buffering to store values in a
+packet buffer. Typically, a component stores these values in the
+packet buffer itself (where the field is), but when necessary it may
+use the metadata region of message_t or other locations.</p>
+<p>The group field refers to the AM group, a logical network identifier.
+Link layers will typically only signal reception for packets whose AM
+group matches the node's, which <tt class="docutils literal"><span class="pre">localGroup</span></tt> returns.</p>
 </div>
 <div class="section">
 <h2><a id="sending-interfaces" name="sending-interfaces">2.2 Sending interfaces</a></h2>
@@ -526,7 +545,7 @@ interface Send {
   event void sendDone(message_t* msg, error_t error);
 
   command uint8_t maxPayloadLength();
-  command void* getPayload(message_t* msg);
+  command void* getPayload(message_t* msg, uint8_t len);
 }
 </pre>
 <p>while this is the AMSend interface:</p>
@@ -537,17 +556,38 @@ interface AMSend {
   event void sendDone(message_t* msg, error_t error);
 
   command uint8_t maxPayloadLength();
-  command void* getPayload(message_t* msg);
+  command void* getPayload(message_t* msg, uint8_t len);
 }
 </pre>
 <p>Sending interfaces MUST include these four commands and one event.
 The duplication of some of the commands in Packet is solely for ease
 of use: <tt class="docutils literal"><span class="pre">maxPayloadLength</span></tt> and <tt class="docutils literal"><span class="pre">getPayload</span></tt> MUST behave
-identically as <tt class="docutils literal"><span class="pre">Packet.maxPayloadLength</span></tt> and <tt class="docutils literal"><span class="pre">Packet.getPayload</span></tt>,
-with the exception that the latter has no length parameter (it should
-behave as if the length parameter of the <tt class="docutils literal"><span class="pre">Packet</span></tt> call were
-NULL). Their inclusion is so that components do not have to wire to
+identically as <tt class="docutils literal"><span class="pre">Packet.maxPayloadLength</span></tt> and <tt class="docutils literal"><span class="pre">Packet.getPayload.</span></tt>
+Their inclusion is so that components do not have to wire to
 both Packet and the sending interface for basic use cases.</p>
+<p>When called with a length that is too long for the underlying
+maximum transfer unit (MTU), the send command MUST return ESIZE.</p>
+<p>The <tt class="docutils literal"><span class="pre">Send</span></tt> and <tt class="docutils literal"><span class="pre">AMSend</span></tt> interfaces have an explicit queue of
+depth one. A call to <tt class="docutils literal"><span class="pre">send</span></tt> on either of these interfaces MUST
+return EBUSY if a prior call to <tt class="docutils literal"><span class="pre">send</span></tt> returned SUCCESS but no
+<tt class="docutils literal"><span class="pre">sendDone</span></tt> event has been signaled yet. More explicitly:</p>
+<pre class="literal-block">
+if (call Send.send(...) == SUCCESS &amp;&amp;
+    call Send.send(...) == SUCCESS) {
+   // This block is unreachable.
+}
+</pre>
+<p>Systems that need send queues have two options. They can
+use a QueueC (found in tos/system) to store pending packet pointers
+and serialize them onto sending interface, or they can introduce
+a new sending interface that supports multiple pending transmissions.</p>
+<p>The cancel command allows a sender to cancel the current transmission.
+A call to cancel when there is no pending sendDone event MUST return
+FAIL.  If there is a pending sendDone event and the cancel returns
+SUCCESS, then the packet layer MUST NOT transmit the packet and MUST
+signal sendDone with ECANCEL as its error code. If there is a pending
+sendDone event and cancel returns FAIL, then sendDone MUST occur as if
+the cancel was not called.</p>
 </div>
 <div class="section">
 <h2><a id="receive-interface" name="receive-interface">2.3 Receive interface</a></h2>
@@ -555,41 +595,40 @@ both Packet and the sending interface for basic use cases.</p>
 <pre class="literal-block">
 interface Receive {
   event message_t* receive(message_t* msg, void* payload, uint8_t len);
-  command void* getPayload(message_t* msg, uint8_t* len);
-  command uint8_t payloadLength(message_t* msg);
 }
 </pre>
-<p>A call to <tt class="docutils literal"><span class="pre">Receive.getPayload()</span></tt> MUST behave identically to a call
-to <tt class="docutils literal"><span class="pre">Packet.getPayload()</span></tt>. The <tt class="docutils literal"><span class="pre">receive()</span></tt> event's <tt class="docutils literal"><span class="pre">payload</span></tt>
-parameter MUST be identical to what a call to <tt class="docutils literal"><span class="pre">getPayload()</span></tt> would
-return, and the <tt class="docutils literal"><span class="pre">len</span></tt> parameter MUST be identical to the length that
-a call to <tt class="docutils literal"><span class="pre">getPayload</span></tt> would return. These parameters are for
+<p>The <tt class="docutils literal"><span class="pre">receive()</span></tt> event's <tt class="docutils literal"><span class="pre">payload</span></tt> parameter MUST be identical to
+what a call to the corresponding <tt class="docutils literal"><span class="pre">Packet.getPayload()</span></tt> would return,
+and the <tt class="docutils literal"><span class="pre">len</span></tt> parameter MUST be identical to the length that a call
+to <tt class="docutils literal"><span class="pre">Packet.getPayload</span></tt> would return. These parameters are for
 convenience, as they are commonly used by receive handlers, and their
-presence removes the need for a call to <tt class="docutils literal"><span class="pre">getPayload()</span></tt>, while
-<tt class="docutils literal"><span class="pre">getPayload()</span></tt> is a convenience so a component does not have to wire
-to <tt class="docutils literal"><span class="pre">Packet.</span></tt> The command <tt class="docutils literal"><span class="pre">payloadLength</span></tt> has a similar motivation
-and the same semantics as its twin in <tt class="docutils literal"><span class="pre">Packet</span></tt>.</p>
-<p>Receive has a <em>buffer-swap</em> policy. The handler of the event MUST return
-a pointer to a valid message buffer for the signaler to use. This
-approach enforces an equilibrium between upper and lower packet
-layers. If an upper layer cannot handle packets as quickly as they
-are arriving, it still has to return a valid buffer to the lower
+presence removes the need for a call to <tt class="docutils literal"><span class="pre">getPayload()</span></tt>. Unlike Send,
+Receive does not have a convenience <tt class="docutils literal"><span class="pre">getPayload</span></tt> call, because doing
+so prevents fan-in. As Receive has only a single event, users of
+Receive can be wired multiple times.</p>
+<p>Receive has a <em>buffer-swap</em> policy. The handler of the event MUST
+return a pointer to a valid message buffer for the signaler to
+use. This approach enforces an equilibrium between upper and lower
+packet layers. If an upper layer cannot handle packets as quickly as
+they are arriving, it still has to return a valid buffer to the lower
 layer. This buffer could be the <tt class="docutils literal"><span class="pre">msg</span></tt> parameter passed to it: it
 just returns the buffer it was given without looking at it. Following
-this policy means that a data-rate mismatch in an upper-level component
-will be isolated to that component. It will drop packets, but it will
-not prevent other components from receiving packets. If an upper
-layer did not have to return a buffer immediately, then when an
+this policy means that a data-rate mismatch in an upper-level
+component will be isolated to that component. It will drop packets,
+but it will not prevent other components from receiving packets. If an
+upper layer did not have to return a buffer immediately, then when an
 upper layer cannot handle packets quickly enough it will end up
 holding all of them, starving lower layers and possibly preventing
 packet reception.</p>
 <p>A <em>user</em> of the Receive interface has three basic options when it
 handles a receive event:</p>
+<blockquote>
 <ol class="arabic simple">
 <li>Return <tt class="docutils literal"><span class="pre">msg</span></tt> without touching it.</li>
 <li>Copy some data out of <tt class="docutils literal"><span class="pre">payload</span></tt> and return <tt class="docutils literal"><span class="pre">msg</span></tt>.</li>
 <li>Store <tt class="docutils literal"><span class="pre">msg</span></tt> in its local frame and return a different <tt class="docutils literal"><span class="pre">message_t*</span></tt> for the lower layer to use.</li>
 </ol>
+</blockquote>
 <p>These are simple code examples of the three cases:</p>
 <pre class="literal-block">
 // Case 1
@@ -608,7 +647,8 @@ message_t* Receive.receive(message_t* msg, void* payload, uint8_t len) {
 }
 
 //Case 3
-message_t* ptr;
+message_t buf;
+message_t* ptr = &amp;buf;
 message_t* Receive.receive(message_t* msg, void* payload, uint8_t len) {
   message_t* tmp = ptr;
   ptr = msg;
@@ -624,8 +664,8 @@ the signaling of <tt class="docutils literal"><span class="pre">receive.</span><
 <div class="section">
 <h2><a id="dispatch" name="dispatch">2.4 Dispatch</a></h2>
 <p>A packet protocol MAY have a dispatch identifier. This generally manifests
-as the protocol component provided parameterized interfaces (rather than
-a single interface instances). A dispatch identifier allows multiple
+as the protocol component providing parameterized interfaces (rather than
+a single interface instance). A dispatch identifier allows multiple
 services to use a protocol independently. If a protocol provides a
 dispatch mechanism, then each dispatch identifier SHOULD correspond to
 a single packet format: if an identifier corresponds to multiple packet
@@ -754,7 +794,7 @@ a certain am_id_t MUST NOT instantiate another AMSnoopingReceiverC,
 AMSnooperC, or AMReceiverC with the same am_id_t.</p>
 </div>
 <div class="section">
-<h2><a id="amsender" name="amsender">4.5 AMSender</a></h2>
+<h2><a id="amsenderc" name="amsenderc">4.5 AMSenderC</a></h2>
 <p>AMSenderC has the following signature:</p>
 <pre class="literal-block">
 generic configuration AMSenderC(am_id_t AMId) {
@@ -774,8 +814,13 @@ but it MUST be fair, where fair means that each client with outstanding
 packets receives a reasonable approximation of an equal share of the
 available transmission bandwidth.</p>
 </div>
+</div>
+<div class="section">
+<h1><a id="power-management-and-local-address" name="power-management-and-local-address">5. Power Management and Local Address</a></h1>
+<p>In addition to standard datapath interfaces for sending and
+receiving packets, an active message layer also has control interfaces.</p>
 <div class="section">
-<h2><a id="power-management" name="power-management">4.6 Power Management</a></h2>
+<h2><a id="power-management" name="power-management">5.1 Power Management</a></h2>
 <p>The communication virtualizations do not support power management.
 ActiveMessageC provides SplitControl for explicit power control.
 For packet communication to operate properly, a component in an
@@ -784,6 +829,17 @@ The HAL underneath ActiveMessageC  MAY employ power management
 techniques, such as TDMA scheduling or low power listening, when
 &quot;on.&quot;</p>
 </div>
+<div class="section">
+<h2><a id="local-active-message-address" name="local-active-message-address">5.2 Local Active Message Address</a></h2>
+<p>An application can change ActiveMessageC's local AM address
+at runtime. This will change which packets a node receives and
+the source address it embeds in packets. To change the local AM
+address at runtime, a component can wire to the component
+<tt class="docutils literal"><span class="pre">ActiveMessageAddressC</span></tt>. This component only changes the
+AM address of the default radio stack (AMSenderC, etc.); if
+a radio has multiple stacks those may have other components
+for changing their addresses in a stack-specific fashion.</p>
+</div>
 </div>
 <div class="section">
 <h1><a id="hal-requirements" name="hal-requirements">5. HAL Requirements</a></h1>
@@ -812,8 +868,8 @@ that an active message received from one data link layer (e.g., the radio)
 can be passed to another data link layer (e.g., the UART) without
 shifting the data payload. This means that the <tt class="docutils literal"><span class="pre">message_header_t</span></tt> must
 include all data needed for AM fields, which might introduce headers
-in addition to those of the data link. For example, this is the
-structure of the CC2420 header:</p>
+in addition to those of the data link. For example, this is an example
+structure for a CC2420 (802.15.4) header:</p>
 <pre class="literal-block">
 typedef nx_struct cc2420_header_t {
   nx_uint8_t length;