• No results found

Reliable Transmission in Java

7.5 Example: Simple Reliable Transmission

7.5.2 Reliable Transmission in Java

The ReliableMoteIF class contains the Java implementation of the simple reliable message transmission protocol. It uses mig to generate AckMsg and ReliableMsg so that it can build and decode ack msg t and reliable msg t packets respectively. ReliableMoteIF uses ncg to access the retransmission timeout (ACK MSG TIMEOUT) specified in the nesC implementation (the ReliableSerialC component).

This class is implementing a generic reusable layer, so should be capable of transmitting and receiving an arbitrary message whose layout is specified by a mig-generated class. As a result, the interface is so similar to that of of MoteIF that ReliableMoteIF we simply make it a subclass of MoteIF. We first show the transmission side:

import net.tinyos.packet.*;

import net.tinyos.message.*;

import java.io.*;

class ReliableMoteIF extends MoteIF {

/* Build an object for performing reliable transmission via ’base’ */

public ReliableMoteIF(PhoenixSource base) {

super(base);

/* Register handler (’ackMsgReceived’ method below) for receiving acks */

super.registerListener

(new AckMsg(), new MessageListener() {

public void messageReceived(int to, Message m) {

ackMsgReceived((AckMsg)m); } }); } /* Send side */ /* --- */

private Object ackLock = new Object(); /* For synchronization with ack handler */

private short sendCookie = 1; /* Next cookie to use in transmission */

private boolean acked; /* Set by ack handler when ack received */

7.5. Example: Simple Reliable Transmission 108

/* Send message ’m’ reliably with destination ’to’ */

public void send(int to, Message m) throws IOException {

synchronized (ackLock) {

/* Build a reliable_msg_t packet with the current cookie and the payload in m, * total packet size is ’m.dataLength() + offsetUserData’ */

ReliableMsg rmsg = new ReliableMsg(m.dataLength() + offsetUserData); rmsg.set_cookie(sendCookie);

System.arraycopy(m.dataGet(), m.baseOffset(), rmsg.dataGet(), offsetUserData, m.dataLength());

/* Repeatedly transmit ’rmsg’ until the ack handler tells us an ack is received. */ acked = false; for (;;) { super.send(to, rmsg); try { ackLock.wait(RelConstants.ACK_TIMEOUT); } catch (InterruptedException e) { } if (acked) break; System.err.printf("retry\n"); }

/* Pick a new cookie for the next transmission */ sendCookie = (short)((sendCookie * 3) & 0xff); }

}

/* Handler for ack messages. If we see an ack for the current transmission, * notify the ’send’ method. */

void ackMsgReceived(AckMsg m) { synchronized (ackLock) { if (m.get_cookie() == sendCookie) { acked = true; ackLock.notify(); } } } ... receive side ... }

Listing 7.10: Reliable Transmission Protocol in Java –Transmission

The send method is synchronized to enforce the rule that a message must be acknowledged before the next message is sent.

This code relies on the fact that the ackMsgReceived handler executes in a different thread than send. After sending a message, the send thread goes to sleep for ACK MSG TIMEOUT ms. When an acknowledgment is received, ackMsgReceived checks the cookie against that of the message being transmitted. If it is equal, acked is set to true and the send thread is woken up. If no acknowledgement is received within ACK MSG TIMEOUT ms, send will resend the message and wait again. Note that acknowledgments received when send is not waiting are effectively ignored, as they should be.

After transmission is successful, send picks a new cookie — we multiply the old value by three just to make it clear that these cookies are not sequence numbers. . .

109 7.5. Example: Simple Reliable Transmission

to copying data between the backing arrays of the user’s and reliable msg t’s mig-generated classes. Note also how the mig-generated offset data method is used to find the payload offset in reliable msg t (see the offsetUserData constant). This code is very similar to MoteIF’s embedding of user messages in serial packets.

Reliable reception is implemented by overriding MoteIF.registerListener. Note however that our reliable transmission protocol only knows about one message type (it has no equivalent to AM’s type field), so you can only actually register a listener for one message type:

class ReliableMoteIF extends MoteIF {

...

/* Receive side */ /* --- */

private Message template;

private MessageListener listener;

/* Build a reliable receive handler for ’template’ messages */

public void registerListener(Message m, MessageListener l) {

template = m; listener = l;

/* Register handler (reliableMsgReceived method below) for receiving * reliable_msg_t messages */

super.registerListener

(new ReliableMsg(),

new MessageListener() {

public void messageReceived(int to, Message m) {

reliableMsgReceived(to, (ReliableMsg)m); }

}); }

private short recvCookie; /* Cookie of last received message */

void reliableMsgReceived(int to, ReliableMsg rmsg) { /* Acknowledge all received messages */

AckMsg ack = new AckMsg();

ack.set_cookie(rmsg.get_cookie());

try {

super.send(MoteIF.TOS_BCAST_ADDR, ack);

}

catch (IOException e) {

/* The sender will retry and we’ll re-ack if the send failed */ }

/* Don’t notify user of duplicate messages */

if (rmsg.get_cookie() != recvCookie) { recvCookie = rmsg.get_cookie();

/* Extract payload from ’rmsg’ and copy it into a copy of ’template’. * The payload is all the data in ’rmsg’ from ’offsetUserData’ on */ Message userMsg = template.clone(rmsg.dataLength() - offsetUserData); System.arraycopy(rmsg.dataGet(), rmsg.baseOffset() + offsetUserData,

userMsg.dataGet(), 0,

rmsg.dataLength() - offsetUserData); listener.messageReceived(to, userMsg);

7.6. Exercises 110

} }

Listing 7.11: Reliable Transmission Protocol in Java –Reception

The protocol implementation part of reliableMsgReceived is straightforward: it simply acknowledges all received messages, and ignores consecutive messages with the same cookie. Its main complexity is in extracting the payload from received reliable msg t packets and building a message that follows the users template object. This task is accomplished by using theclone(n) method of Message, which makes a copy of a message with a new backing array. The data from the payload portion of the backing array of the received reliable msg t packet is then simply copied over to this new backing array. Again, this code is very similar to that found in MoteIF to extract the payload from a received serial packet.