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.
+active message interfaces AMSenderC and AMReceiverC.
1. Introduction
============================================================================
*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
--------------------------------------------------------------------
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.
+memory allocation.
The distinction between ``payloadLength`` and ``maxPayloadLength``
comes from whether the packet is being received or sent. In the receive
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);
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 ``setDestination``
-and ``setType`` commands fulfill a similar purpose to
-``Packet.setLength``.
+type. 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.
2.2 Sending interfaces
--------------------------------------------------------------------
NULL). 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 SHOULD occur as if the cancel
+was not called.
+
2.3 Receive interface
--------------------------------------------------------------------
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::
}
//Case 3
- message_t* ptr;
+ message_t buf;
+ message_t* ptr = &buf;
message_t* Receive.receive(message_t* msg, void* payload, uint8_t len) {
message_t* tmp = ptr;
ptr = msg;
--------------------------------------------------------------------
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
============================================================================
can be passed to another data link layer (e.g., the UART) without
shifting the data payload. This means that the ``message_header_t`` 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::
+in addition to those of the data link. For example, this is an example
+structure for a CC2420 (802.15.4) header::
typedef nx_struct cc2420_header_t {
nx_uint8_t length;