public class Drip implements MessageListener { public static int SEND_COUNT = 12; public static int SEND_RATE = DripConsts.DRIP_TIMER_PERIOD; public static int WAKEUP_SEND_COUNT = 25; public static int WAKEUP_SEND_RATE = 40; private Logger log = Logger.getLogger(Drip.class.getName()); private static final int IDLE = 0; private static final int PROBING = 1; private static final int SENDING_SEQNO = 2; private static final int SENT_SEQNO = 3; private static final int SENDING_NEW = 4; private int state = IDLE; int id; int seqno; int sendCount = 0; int maxSendCount; Timer trickle; TimerTask trickleTask; MoteIF moteIF; DripMsg dripMsg; boolean hasMessage = false; boolean sentOK = true; boolean wakeupMsg = false; public Drip(int id) { log.info("Started id=" + id); try { moteIF = new MoteIF(); moteIF.registerListener(new DripMsg(), this); } catch (Exception e) { System.out.println("ERROR: Couldn't contact serial forwarder."); System.exit(1); } this.id = id; } public Drip(int id, MoteIF p_moteIF) { log.info("Started with own moteIF id=" + id); try { moteIF = p_moteIF; moteIF.registerListener(new DripMsg(), this); } catch (Exception e) { System.out.println("ERROR: Couldn't contact serial forwarder."); System.exit(1); } this.id = id; } void setupDrip(Message msg, int msgSize) { trickle = new Timer(); trickleTask = new DripSender(); dripMsg = new DripMsg(DripMsg.DEFAULT_MESSAGE_SIZE + msgSize); dripMsg.dataSet(msg.dataGet(), 0, dripMsg.offset_data(0), msgSize); sendCount = 0; } Message buildAddrMsg(int dest, Message msg, int msgSize) { AddressMsg addrMsg = new AddressMsg(AddressMsg.DEFAULT_MESSAGE_SIZE + msgSize); String moteid = Env.getenv("MOTEID"); int source = 0xFFFF; if (moteid != null) { source = Integer.parseInt(moteid); } addrMsg.dataSet(msg.dataGet(), 0, addrMsg.offset_data(0), msgSize); addrMsg.set_dest(dest); addrMsg.set_source(source); return addrMsg; } public synchronized void send(Message msg, int msgSize) { setupDrip(msg, msgSize); state = PROBING; wakeupMsg = false; sendCount = 0; maxSendCount = SEND_COUNT; trickle.schedule(trickleTask, 0, 500); try { wait(); } catch (InterruptedException e) { // return } } public synchronized void sendAddressed(int dest, Message msg, int msgSize) { AddressMsg addrMsg = (AddressMsg) buildAddrMsg(dest, msg, msgSize); send(addrMsg, msgSize + AddressMsg.DEFAULT_MESSAGE_SIZE); } public synchronized void sendUnreliable(Message msg, int msgSize) { setupDrip(msg, msgSize); state = SENDING_NEW; wakeupMsg = false; sendCount = 0; maxSendCount = 1; trickle.schedule(trickleTask, 0, SEND_RATE); try { wait(); } catch (InterruptedException e) { // return } } public synchronized void sendAddressedUnreliable(int dest, Message msg, int msgSize) { AddressMsg addrMsg = (AddressMsg) buildAddrMsg(dest, msg, msgSize); sendUnreliable(addrMsg, msgSize + AddressMsg.DEFAULT_MESSAGE_SIZE); } public synchronized void sendWakeup(Message msg, int msgSize) { setupDrip(msg, msgSize); state = SENDING_NEW; wakeupMsg = true; sendCount = 0; maxSendCount = WAKEUP_SEND_COUNT; trickle.schedule(trickleTask, 0, WAKEUP_SEND_RATE); try { wait(); } catch (InterruptedException e) { // return } } private synchronized void sendDone() { notifyAll(); state = IDLE; } class DripSender extends TimerTask { public void run() { boolean stopSending = false; log.debug("DripSender.run(state=" + state + " sendCount= " + sendCount + ")"); dripMsg.set_metadata_id((short) id); switch (state) { case PROBING: if (sendCount < maxSendCount) { log.debug("probing"); dripMsg.set_metadata_seqno((byte) DripConsts.DRIP_SEQNO_OLDEST); } else { log.debug("probing finished"); stopSending = true; } break; case SENDING_SEQNO: if (sendCount < maxSendCount) { log.debug("sending new seqno " + seqno); dripMsg.set_metadata_seqno((byte) seqno); } else { log.debug("sending finished"); stopSending = true; } break; case SENDING_NEW: if (sendCount < maxSendCount) { log.debug("sending unreliably"); dripMsg.set_metadata_seqno((byte) DripConsts.DRIP_SEQNO_NEWEST); } else { log.debug("sending unreliably finished"); stopSending = true; } break; case SENT_SEQNO: log.debug("done sending"); stopSending = true; return; default: } if (wakeupMsg == true) { dripMsg.set_metadata_seqno((short) ((dripMsg.get_metadata_seqno() + 1) % 256)); } if (stopSending) { trickle.cancel(); trickleTask.cancel(); sendDone(); } else { log.info( "Sending Msg " + sendCount + ": id=" + id + ",seqno=" + dripMsg.get_metadata_seqno()); send(dripMsg); sendCount++; } } } private void send(Message m) { try { moteIF.send(MoteIF.TOS_BCAST_ADDR, m); } catch (IOException e) { e.printStackTrace(); System.out.println("ERROR: Can't send message"); System.exit(1); } catch (Exception e) { e.printStackTrace(); } } public void messageReceived(int to, Message m) { DripMsg msg = (DripMsg) m; int newId = msg.get_metadata_id(); int newSeqno = msg.get_metadata_seqno(); log.debug("Received Msg: id=" + newId + ",seqno=" + newSeqno); if (newId != id) { log.debug("dropped, not ID " + id); return; } if ((newSeqno & ~DripConsts.DRIP_WAKEUP_BIT) == DripConsts.DRIP_SEQNO_NEWEST) { log.debug("dropped, a special seqno " + newSeqno); return; } switch (state) { case PROBING: seqno = newSeqno; log.info( "Receive: id=" + id + ",seqno=" + dripMsg.get_metadata_seqno() + " Heard Old Seqno"); incrementSeqno(); state = SENDING_SEQNO; case SENDING_SEQNO: if (seqno == newSeqno) { log.info( "Receive: id=" + id + ",seqno=" + dripMsg.get_metadata_seqno() + " Heard New Seqno"); trickle.cancel(); trickleTask.cancel(); sendDone(); } default: } } private void incrementSeqno() { if (wakeupMsg && ((seqno & DripConsts.DRIP_WAKEUP_BIT) == 0)) { seqno = (seqno + 1) % 256; } if (!wakeupMsg && ((seqno & DripConsts.DRIP_WAKEUP_BIT) == 1)) { seqno = (seqno + 1) % 256; } seqno = (seqno + 1) % 256; seqno = (seqno + 1) % 256; while ((seqno & ~DripConsts.DRIP_WAKEUP_BIT) == DripConsts.DRIP_SEQNO_OLDEST || (seqno & ~DripConsts.DRIP_WAKEUP_BIT) == DripConsts.DRIP_SEQNO_NEWEST || (seqno & ~DripConsts.DRIP_WAKEUP_BIT) == DripConsts.DRIP_SEQNO_UNKNOWN) { seqno = (seqno + 1) % 256; seqno = (seqno + 1) % 256; } } private static int data = 1000; private static int channel = 254; private static boolean wakeup = false; public static void main(String[] args) { parseArgs(args); Drip drip = new Drip(channel); TestDripMsg msg = new TestDripMsg(); msg.set_data((short) data); if (wakeup) { drip.sendWakeup(msg, TestDripMsg.DEFAULT_MESSAGE_SIZE); } else { drip.send(msg, TestDripMsg.DEFAULT_MESSAGE_SIZE); } System.exit(0); } private static void parseArgs(String args[]) { ArrayList cleanedArgs = new ArrayList(); for (int i = 0; i < args.length; i++) { if (args[i].startsWith("--")) { // Parse Long Options String longopt = args[i].substring(2); if (longopt.equals("help")) { usage(); } } else if (args[i].startsWith("-")) { // Parse Short Options String opt = args[i].substring(1); if (opt.equals("d")) { data = Integer.parseInt(args[++i]); } else if (opt.equals("w")) { wakeup = true; } else if (opt.equals("c")) { channel = Integer.parseInt(args[++i]); } else if (opt.equals("h")) { usage(); } } else { // Place into args string cleanedArgs.add(args[i]); } } } private static void usage() { System.err.println("usage: java net.tinyos.drain.Drip <opts>"); System.err.println(" -d <data value>"); System.err.println(" -c <channel id>"); System.err.println(" -w : send message with wakeup bit set"); System.err.println(" -h, --help : this information"); System.exit(1); } }
public class DrainConnector implements MessageListener { public static int TOS_UART_ADDR = 0x7e; public static int DEFAULT_MOTE_ID = 0xfffe; public static int BCAST_ID = 0xff; private MoteIF moteIF; private Logger log = Logger.getLogger(DrainConnector.class.getName()); private int spAddr; private Hashtable seqNos = new Hashtable(); private HashMap idTable = new HashMap(); public DrainConnector() { this(DrainLib.setSPAddr(), DrainLib.startMoteIF()); } public DrainConnector(int p_spAddr, MoteIF p_moteIF) { spAddr = p_spAddr; moteIF = p_moteIF; moteIF.registerListener(new DrainMsg(), this); log.info("Started myAddr = " + spAddr + ", listening for DrainMsg"); } public void registerListener(int id, MessageListener m) { HashSet listenerSet = (HashSet) idTable.get(new Integer(id)); if (listenerSet == null) { listenerSet = new HashSet(); idTable.put(new Integer(id), listenerSet); } listenerSet.add(m); log.info("New Listener for id=" + id); } public void deregisterListener(int id, MessageListener m) { HashSet listenerSet = (HashSet) idTable.get(new Integer(id)); if (listenerSet == null) { throw new IllegalArgumentException("No listeners registered for message type " + id); } listenerSet.remove(m); } public synchronized void messageReceived(int to, Message m) { DrainMsg mhMsg = (DrainMsg) m; log.debug( "incoming: localDest: " + to + " type:" + mhMsg.get_type() + " hops:" + (16 - mhMsg.get_ttl()) + " seqNo:" + mhMsg.get_seqNo() + " source:" + mhMsg.get_source() + " finalDest:" + mhMsg.get_dest()); // lets assume that the network cannot buffer more than 25 drain msgs from a single source at a // time (should be more than reasonable) if (seqNos.containsKey(new Integer(mhMsg.get_source()))) { int oldSeqNo = ((Integer) seqNos.get(new Integer(mhMsg.get_source()))).intValue(); int upperBound = mhMsg.get_seqNo() + 25; int wrappedUpperBound = 25 - (255 - mhMsg.get_seqNo()); if ((oldSeqNo >= mhMsg.get_seqNo() && oldSeqNo < upperBound) || (oldSeqNo >= 0 && oldSeqNo < wrappedUpperBound)) { log.debug( "Dropping message from " + mhMsg.get_source() + " with duplicate seqNo: " + mhMsg.get_seqNo()); return; } } seqNos.put(new Integer(mhMsg.get_source()), new Integer(mhMsg.get_seqNo())); if (to != spAddr && to != MoteIF.TOS_BCAST_ADDR && to != TOS_UART_ADDR) { log.debug("Dropping message not for me."); return; } HashSet promiscuousSet = (HashSet) idTable.get(new Integer(BCAST_ID)); HashSet listenerSet = (HashSet) idTable.get(new Integer(mhMsg.get_type())); if (listenerSet != null && promiscuousSet != null) { listenerSet.addAll(promiscuousSet); } else if (listenerSet == null && promiscuousSet != null) { listenerSet = promiscuousSet; } if (listenerSet == null) { log.debug("No Listener for type: " + mhMsg.get_type()); return; } for (Iterator it = listenerSet.iterator(); it.hasNext(); ) { MessageListener ml = (MessageListener) it.next(); ml.messageReceived(to, mhMsg); } } public static void main(String args[]) { DrainConnector dc = new DrainConnector(); } }