[Tinyos-devel] message_t
Miklos Maroti
mmaroti at math.u-szeged.hu
Thu Mar 12 14:03:07 PDT 2009
Guys,
Here is may alternative proposal for the new message_t. Basically, I
would require all message_t to be formated (the old Packet.clear with
some parameters), then everyone knows where the payload is and where
the other header and footer fields are, so we can flexibly set those
values (64 bit addresses, security data), finally we send the message.
You need to format a message only if you do not know (first use) or
want to change its layout (forward).
Comments are welcome.
Miklos
-------------- next part --------------
====================================================================
The KISS message_t proposal for TinyOS
====================================================================
First we need to identify the problems with message_t, then seek a
good solution. I see the following ones:
1) RAM is wasted with the current message_t. For example, if a packet
has security enabled, then the header needs some 14 extra bytes but
because of hardware limitations the payload length is reduced by these
14 bytes. Taking the maximum header, maximum payload, maximum footer
and maximum metadata sizes wastes a lot of memory.
2) The networks layers cannot be seamlessly mixed because most of the
parameters are passed with the Send.send command. For example, if we
want to add an embedded time stamp in the message, then the event time
is passed in the TimeSyncAMSend.send command along with other stuff.
However, if we want to use time synchronization with 802.15.4 packets,
then again a new interface and component need to be developed (e.g.
TimeSyncIeee154Send or something). The existing LowPowerListening,
PacketAcknowledgements, PacketLink interfaces do not have this problem
because they do change the layout of the message (and the metadata
section thus wasting RAM when not in use).
The limitations of message_t are exposed exactly because that kind of
network layers are interacting that want to change the layout of the
message. Realize, that the user payload is just another network layer,
and we so far circumvent the layout problem by aligning the payload.
But this is not a scalable solution, and I propose to use a flat
buffer for message_t:
/**
* This defines a opaque message buffer. The layout of every message
* buffer is [header] [payload] [footer] [free space] [metadata].
* The first three grow upwards, the metadata grows downwards with
* the nesting of components.
*/
typedef struct message_t
{
uint8_t buffer[MSG_MAX_LENGTH];
} message_t;
The second problem is harder to solve. The real problem is that the
headers of a layer cannot be set before the headers of lower layers
are set because we do not know where to put it into the message_t
buffer. (Jan Hauer's solution to this problem is to grow the header
and footer around the payload and allow it to wrap around the message
buffer, but that solution does not allow the mixing of network layers
either since all parameters need to be passed in the send command).
One solution would be to use a
XXXPacket.format(XXXparameters,..., payloadLength)
command to format the layout of the packet and move the layout
changing parameters of the current XXXSend.send(...) command to this
call. You could stack XXXPacket implementations on top of each other
passing down layout changing XXXparameters that are relevant in the
lower layers.
Most of the layout changing parameters can be handled by flags:
enum layout_flags_enum
{
LAYOUT_IEEE154_64BIT_ADDRS = 1 << 0,
LAYOUT_IEEE154_SECURITY = 1 << 1,
LAYOUT_6LOWPAN = 1 << 2,
LAYOUT_TIMESYNC = 1 << 3,
};
Of course this could be generated by some unique() magic, also you
might need to get more bits for the IEEE154 addressing modes. Each
user would format the message with a layout parameter, then fill in
all necessary parameters, then send it:
// create the layout of the message
call Packet.format(msg, LAYOUT_6LOWPAN | LAYOUT_TIMESYNC,
payloadLength);
// fill in payload data
void* payload = call Packet.getPayload(msg);
...
// set layer specific configuration
call Packet6LowPan.setNetwork(msg, ...);
call PacketAncknowledgements.reqAck(msg);
call PacketTimeSync.setTimeStamp(msg, stamp);
// send the message
call Send.send(msg);
So here are my proposed interfaces. These are the bare minimums, you
can add syntactic sugar, like AMSend and friends.
interface Send
{
command error_t send(message_t* msg);
command void sendDone(message_t* msg, error_t error);
command errot_t cancel(message_t* msg);
}
interface Receive
{
message_t receive(message_t* msg);
}
interface Packet
{
/**
* Returns the header length of the message as seen by the
* network layer implementing this interface. Typical
* implementation would call SubPacket.getHeaderLength(), then
* add a constant or read the message at the header section
* of this layer (at msg->data + subHeaderLength) and return
* a variable sized header
*/
uint8_t getHeaderLength(message_t* msg);
/**
* The same are true for the other functions, even for
* metadata which grows downward
*/
uint8_t getPayloadLength(message_t* msg);
uint8_t getFooterLength(message_t* msg);
uint8_t getMetadataLength(message_t* msg);
/**
* Sets only those parts of the message that completely
determine
* the layout of the message and leaves most of the fields
empty.
*/
error_t format(message_t* msg, uint8_t layoutFlags, uint8_t
payloadLength);
// convenience function, implementation is given here
void* getPayload(message_t* msg) {
return msg->data + getHeaderLength(msg);
}
}
These interfaces could be stacked very very nicely. Each network layer
would also provide a PacketXXX interface to manipulate the fields of
the message, just like PacketLink, PacketAcknowledgement,
LowPowerListening, and PacketTimeSync.
When the layout of a message is changed, then the payload data need to
be copied, but only once. This proposal contains no magic, very easy
to understand and I think has a lot of flexibility.
Miklos
More information about the Tinyos-devel
mailing list