:TEP: 116
:Group: Core Working Group
:Type: Documentary
-:Status: Draft
-:TinyOS-Version: 2.x
+:Status: Final
+:TinyOS-Version: > 2.1
:Author: Philip Levis
-:Draft-Created: 10-Dec-2004
-:Draft-Version: $Revision$
-:Draft-Modified: $Date$
-:Draft-Discuss: TinyOS Developer List <tinyos-devel at mail.millennium.berkeley.edu>
-
.. Note::
This memo documents a part of TinyOS for the TinyOS Community, and
*Packet* interfaces are for accessing message fields and payloads.
*Send* interfaces are for transmitting packets, and are
distinguished by their addressing scheme.
-Finally, the *Receive* interface is for handling packet reception events.
+The *Receive* 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.
2.1 Packet interfaces
--------------------------------------------------------------------
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);
}
A component can obtain a pointer to its data region within a packet by
-calling ``getPayload()`` the optional ``len`` argument is for also
-obtaining the size of the data region. A provider of a Packet
-interface MUST check if ``len`` is NULL and ignore it if it is. A
-component can also obtain the size of the data region with a call to
-``payloadLength``.
-
-A component can set the payload length with
-``setPayLoadLength.`` 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.
+calling ``getPayload()``. A call to this command includes the length
+the caller requires. The command ``maxPayloadLength`` returns the
+maximum length the payload can be: if the ``len`` parameter to
+``getPayload`` is greater than the value ``maxPayloadLength`` would
+return, ``getPayload`` MUST return NULL.
+
+
+A component can set the payload length with ``setPayLoadLength.`` A
+component can obtain the size of the data region of packet in use with
+a call to ``payloadLength``. As Send interfaces always include a
+length parameter in their send call, ``setPayLoadLength`` 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.
The distinction between ``payloadLength`` and ``maxPayloadLength``
-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.
-
-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.
-
-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::
+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
+``payloadLength`` must be less than or equal to the return value of
+``maxPayloadLength``.
+
+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.
+
+The ``clear`` command clears out all headers, footers, and metadata
+for lower layers. For example, calling ``clear`` on a routing
+component, such as CollectionSenderC[4]_, will clear out the
+collection headers and footers. Furthermore, CollectionSenderC will
+recursively call ``clear`` on the layer below it, clearing out the
+link layer headers and footers. Calling ``clear`` 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 ``clear`` 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.
+
+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::
generic module SequenceNumber {
provides interface Packet;
};
command void Packet.clear(message_t* msg) {
- uint8_t len;
- void* payload = call SubPacket.getPayload(msg, &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) {
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;
}
}
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();
}
The command address() returns the local AM address of the
-node. AMPacket provides accessors for its two fields, destination and
-type. It also provides commands to set these fields, for the same
-reason that Packet allows a caller to set the payload length.
+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.
+
+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 ``localGroup`` returns.
2.2 Sending interfaces
--------------------------------------------------------------------
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);
}
while this is the AMSend interface::
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);
}
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: ``maxPayloadLength`` and ``getPayload`` MUST behave
-identically as ``Packet.maxPayloadLength`` and ``Packet.getPayload``,
-with the exception that the latter has no length parameter (it should
-behave as if the length parameter of the ``Packet`` call were
-NULL). Their inclusion is so that components do not have to wire to
+identically as ``Packet.maxPayloadLength`` and ``Packet.getPayload.``
+Their inclusion is so that components do not have to wire to
both Packet and the sending interface for basic use cases.
+When called with a length that is too long for the underlying
+maximum transfer unit (MTU), the send command MUST return ESIZE.
+
+The ``Send`` and ``AMSend`` interfaces have an explicit queue of
+depth one. A call to ``send`` on either of these interfaces MUST
+return EBUSY if a prior call to ``send`` returned SUCCESS but no
+``sendDone`` event has been signaled yet. More explicitly::
+
+ if (call Send.send(...) == SUCCESS &&
+ call Send.send(...) == SUCCESS) {
+ // This block is unreachable.
+ }
+
+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.
+
+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.
+
2.3 Receive interface
--------------------------------------------------------------------
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);
}
-A call to ``Receive.getPayload()`` MUST behave identically to a call
-to ``Packet.getPayload()``. The ``receive()`` event's ``payload``
-parameter MUST be identical to what a call to ``getPayload()`` would
-return, and the ``len`` parameter MUST be identical to the length that
-a call to ``getPayload`` would return. These parameters are for
+The ``receive()`` event's ``payload`` parameter MUST be identical to
+what a call to the corresponding ``Packet.getPayload()`` would return,
+and the ``len`` parameter MUST be identical to the length that a call
+to ``Packet.getPayload`` 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 ``getPayload()``, while
-``getPayload()`` is a convenience so a component does not have to wire
-to ``Packet.`` The command ``payloadLength`` has a similar motivation
-and the same semantics as its twin in ``Packet``.
-
-Receive has a *buffer-swap* 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 ``getPayload()``. Unlike Send,
+Receive does not have a convenience ``getPayload`` call, because doing
+so prevents fan-in. As Receive has only a single event, users of
+Receive can be wired multiple times.
+
+Receive has a *buffer-swap* 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 ``msg`` 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.
A *user* of the Receive interface has three basic options when it
handles a receive event:
-1) Return ``msg`` without touching it.
-2) Copy some data out of ``payload`` and return ``msg``.
-3) Store ``msg`` in its local frame and return a different ``message_t*`` for the lower layer to use.
+ 1) Return ``msg`` without touching it.
+ 2) Copy some data out of ``payload`` and return ``msg``.
+ 3) Store ``msg`` in its local frame and return a different ``message_t*`` for the lower layer to use.
These are simple code examples of the three cases::
--------------------------------------------------------------------
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
a certain am_id_t MUST NOT instantiate another AMSnoopingReceiverC,
AMSnooperC, or AMReceiverC with the same am_id_t.
-4.5 AMSender
+4.5 AMSenderC
--------------------------------------------------------------------
AMSenderC has the following signature::
packets receives a reasonable approximation of an equal share of the
available transmission bandwidth.
-4.6 Power Management
+5. Power Management and Local Address
+============================================================================
+
+In addition to standard datapath interfaces for sending and
+receiving packets, an active message layer also has control interfaces.
+
+
+5.1 Power Management
--------------------------------------------------------------------
The communication virtualizations do not support power management.
techniques, such as TDMA scheduling or low power listening, when
"on."
+5.2 Local Active Message Address
+--------------------------------------------------------------------
+
+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
+``ActiveMessageAddressC``. 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.
+
5. HAL Requirements
============================================================================
.. [4] TEP 113: Serial Communication.
-
-
-