📄 tep111.txt
字号:
This ensures that enough space is allocated for all underlying link layers.
3. The message_t fields
====================================================================
TinyOS 2.x components treat packets as abstract data types (ADTs),
rather than C structures, obtaining all of the traditional benefits
of this approach. First and foremost, clients of a packet layer
do not depend on particular field names or locations, allowing the
implementations to choose packet formats and make a variety of
optimizations.
Components above the basic data-link layer MUST always access
packet fields through interfaces. A component that introduces
new packet fields SHOULD provide an interface to those that
are of interest to other components. These interfaces SHOULD take
the form of get/set operations that take and return values, rather
than offsts into the structure.
For example, active messages have an interface named ``AMPacket``
which provides access commands to AM fields. In TinyOS 1.x, a
component would directly access ``TOS_Msg.addr``; in TinyOS 2.x,
a component calls ``AMPacket.getAddress(msg)``.
The most basic of these interfaces is Packet, which provides
access to a packet payload. TEP 116 describes common TinyOS
packet ADT interfaces [3]_.
Link layer components MAY access packet fields differently than other
components, as they are aware of the actual packet format. They can
therefore implement the interfaces that provide access to the fields
for other components.
3.1 Headers
----------------------------------------------------------------
The message_t header field is an array of bytes whose size is
the size of a platform's union of data-link headers.
Because radio stacks often prefer packets to be stored contiguously,
the layout of a packet in memory does not necessarily reflect the
layout of its nesC structure.
A packet header MAY start somewhere besides the beginning of
the message_t. For example, consider the Telos platform::
typedef union message_header {
cc2420_header_t cc2420;
serial_header_t serial;
} message_header_t;
The CC2420 header is 11 bytes long, while the serial header is
5 bytes long. The serial header ends at the beginning of the
data payload, and so six padding bytes precede it. This figure
shows the layout of message_t, a 12-byte CC2420 packet, and
a 12-byte serial packet on the Telos platform::
11 bytes TOSH_DATA_LENGTH 7 bytes
+-----------+-----------------------------+-------+
message_t | header | data | meta |
+-----------+-----------------------------+-------+
+-----------+------------+ +-------+
CC2420 | header | data | | meta |
+-----------+------------+ +-------+
+-----+------------+
Serial | hdr | data |
+-----+------------+
Neither the CC2420 nor the serial stack has packet footers, and
the serial stack does not have any metadata.
The packet for a link layer does not necessarily start at the beginning
of the message_t. Instead, it starts at a negative offset from the
data field. When a link layer component needs to read or write protocol
header fields, it MUST compute the location of the header as a negative
offset from the data field. For example, the serial stack header has
active message fields, such as the AM type. The command that returns
the AM type, ``AMPacket.type()``, looks like this::
serial_header_t* getHeader(message_t* msg) {
return (serial_header_t*)(msg->data - sizeof(serial_header_t));
}
command am_id_t AMPacket.type(message_t* msg) {
serial_header_t* hdr = getheader(msg);
return hdr->type;
}
Because calculating the negative offset is a little bit unwieldy, the
serial stack uses the internal helper function getHeader(). Many
single-hop stacks follow this approach, as it is very likely
that nesC will inline the function, eliminating the possible overhead.
In most cases, the C compiler also compiles the call into a simple
memory offset load.
The following code is incorrect, as it directly casts the header field.
It is an example of what components MUST NOT do::
serial_header_t* getHeader(message_t* msg) {
return (serial_header_t*)(msg->header);
}
In the case of Telos, for example, this would result in a packet
layout that looks like this::
11 bytes TOSH_DATA_LENGTH 7 bytes
+-----------+-----------------------------+-------+
message_t | header | data | meta |
+-----------+-----------------------------+-------+
+-----+ +------------+
Serial | hdr | | data |
+-----+ +------------+
3.2 Data
----------------------------------------------------------------
The data field of message_t stores the single-hop packet payload.
It is TOSH_DATA_LENGTH bytes long. The default size is 28 bytes.
A TinyOS application can redefine TOSH_DATA_LENGTH at compile time
with a command-line option to ncc: ``-DTOSH_DATA_LENGTH=x``.
Because this value can be reconfigured, it is possible that two
different versions of an application can have different MTU sizes.
If a packet layer receives a packet whose payload size is
longer than TOSH_DATA_LENGTH, it MUST discard the packet. As
headers are right justified to the beginning of the data payload,
the data payloads of all link layers on a platform start
at the same fixed offset from the beginning of the message buffer.
3.3 Footer
----------------------------------------------------------------
The message_footer_t field ensures that message_t has enough space to
store the footers for all underlying link layers when there are
MTU-sized packets. Like headers, footers are not necessarily stored
where the C structs indicate they are: instead, their placement is
implementation dependent. A single-hop layer MAY store the footer
contiguously with the data region. For short packets, this can mean
that the footer will actually be stored in the data field.
3.4 Metadata
----------------------------------------------------------------
The metadata field of message_t stores data that
a single-hop stack uses or collects does not transmit.
This mechanism allows packet layers to store per-packet
information such as RSSI or timestamps. For example, this is
the CC2420 metadata structure::
typedef nx_struct cc2420_metadata_t {
nx_uint8_t tx_power;
nx_uint8_t rssi;
nx_uint8_t lqi;
nx_bool crc;
nx_bool ack;
nx_uint16_t time;
} cc2420_metadata_t;
3.5 Variable Sized Structures
----------------------------------------------------------------
The message_t structure is optimized for packets with fixed-size
headers and footers. Variable-sized footers are generally easy
to implement. Variable-sized headers are a bit more difficult.
There are three general approaches that can be used.
If the underlying link hardware is byte-based, the header can
just be stored at the beginning of the message_t, giving it
a known offset. There may be padding between the header and
the data region, but assuming a byte-based send path this merely
requires adjusting the index.
If the underlying link hardware is packet-based, then the
protocol stack can either include metadata (e.g., in the
metadata structure) stating where the header begins or it
can place the header at a fixed position and use ``memmove(3)``
on reception and transmit. In this latter case, on
reception the packet is continguously read into the message_t
beginning at the offset of the header structure. Once the
packet is completely received, the header can be decoded,
its length calculated, and the data region of the packet
can be moved to the ``data`` field. On transmission,
the opposite occurs: the data region (and footer if need
be) are moved to be contiguous with the header. Note that
on completion of transmission, they need to be moved back.
Alternatively, the radio stack can institute a single
copy at the botttom layer.
4. Implementation
====================================================================
The definition of message_t can be found in
``tinyos-2.x/tos/types/message.h``.
The definition of the CC2420
message format can be found in ``tinyos-2.x/tos/chips/cc2420/CC2420.h``.
The defintion of the CC1000 message format can be found in
``tinyos-2.x/tos/chips/cc1000/CC1000Msg.h``.
The definition
of the standard serial stack packet format can be found in
``tinyos-2.x/tos/lib/serial/Serial.h``
The definition of
the telos family packet format can be found in
``tinyos-2.x/tos/platform/telosa/platform_message.h`` and the micaz format can be found in
``tinyos-2.x/tos/platforms/micaz/platform_message.h``.
5. Author's Address
====================================================================
| Philip Levis
| 358 Gates Hall
| Computer Science Laboratory
| Stanford University
| Stanford, CA 94305
|
| phone - +1 650 725 9046
| email - pal@cs.stanford.edu
6. Citations
====================================================================
.. [1] `nesC: A Programming Language for Deeply Embedded Networks. <http://nescc.sourceforge.net>`_
.. [2] TEP 113: Serial Communication.
.. [3] TEP 116: Packet Protocols.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -