[Tinyos-commits] CVS: tinyos-1.x/tools/java/net/tinyos/deluge DelugeCrc.java, NONE, 1.1 DelugeImage.java, NONE, 1.1 Downloader.java, NONE, 1.1 Eraser.java, NONE, 1.1 IhexReader.java, NONE, 1.1 ImageInjector.java, NONE, 1.1 Makefile, NONE, 1.1 Pinger.java, NONE, 1.1 Rebooter.java, NONE, 1.1 TOSBootImage.java, NONE, 1.1

Jonathan Hui jwhui at users.sourceforge.net
Fri Jul 22 10:52:40 PDT 2005


Update of /cvsroot/tinyos/tinyos-1.x/tools/java/net/tinyos/deluge
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26322/deluge

Added Files:
	DelugeCrc.java DelugeImage.java Downloader.java Eraser.java 
	IhexReader.java ImageInjector.java Makefile Pinger.java 
	Rebooter.java TOSBootImage.java 
Log Message:
- Initial import of Deluge 2.0 tools.



--- NEW FILE: DelugeCrc.java ---
// $Id: DelugeCrc.java,v 1.1 2005/07/22 17:52:37 jwhui Exp $

/*									tab:2
 *
 *
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 */

/**
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

package net.tinyos.deluge;

public class DelugeCrc {

  public static short crcByte(short crc, byte b) {
    int i;
    
    crc = (short)(crc ^ b << 8);
    i = 8;
    do {
      if ((crc & 0x8000) != 0)
	crc = (short)(crc << 1 ^ 0x1021);
      else
	crc = (short)(crc << 1);
    } while (--i > 0);
    
    return crc;
  }

  public static DelugeAdvMsg computeAdvCrc(DelugeAdvMsg advMsg) {

    // calc crc of adv message
    byte[] tmpBytes = advMsg.dataGet();
    short  crc;

    int start = DelugeAdvMsg.offset_nodeDesc_vNum();
    int stop = DelugeAdvMsg.offset_nodeDesc_crc();

    crc = 0;
    for ( int i = start; i < stop; i++ )
      crc = DelugeCrc.crcByte(crc, tmpBytes[i]);
    advMsg.set_nodeDesc_crc(crc);

    start = DelugeAdvMsg.offset_imgDesc_uid();
    stop = DelugeAdvMsg.offset_imgDesc_crc();

    crc = 0;
    for ( int i = start; i < stop; i++ )
      crc = DelugeCrc.crcByte(crc, tmpBytes[i]);
    advMsg.set_imgDesc_crc(crc);

    return advMsg;

  }

}
--- NEW FILE: DelugeImage.java ---
// $Id: DelugeImage.java,v 1.1 2005/07/22 17:52:37 jwhui Exp $

/*									tab:2
 *
 *
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 */

/**
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

package net.tinyos.deluge;

public class DelugeImage {

  private static final int MAX_SIZE = 1024*512;
  
  private short image[] = new short[MAX_SIZE];
  private short numPages;
  private int byteCount;
  private int size;
  
  private short crcByte(short crc, byte b) {
    int i;
    
    crc = (short)(crc ^ b << 8);
    i = 8;
    do {
      if ((crc & 0x8000) != 0)
	crc = (short)(crc << 1 ^ 0x1021);
      else
	crc = (short)(crc << 1);
    } while (--i > 0);
    
    return crc;
  }

  public DelugeImage(byte[] tmpBytes, int length) {

    short bytes[] = new short[length];

    size = 2*DelugeConsts.DELUGE_MAX_PAGES;

    for ( int i = 0; i < length; i++ ) 
      bytes[i] = (short)(tmpBytes[i] & 0xff);

    short crc = 0;
    for ( int i = 0; i < length; i++ ) {
      if ((size % DelugeConsts.DELUGE_BYTES_PER_PAGE) == 0) {
	int offset = 2*((size-1)/DelugeConsts.DELUGE_BYTES_PER_PAGE);
	image[offset+0] = (short)((crc >> 0x0) & 0xff);
	image[offset+1] = (short)((crc >> 0x8) & 0xff);
	crc = 0;
      }
      crc = crcByte(crc, (byte)bytes[i]);
      image[size++] = bytes[i];
    }

    // finish out rest of page and calculate CRC
    while((size % DelugeConsts.DELUGE_BYTES_PER_PAGE) != 0) {
      crc = crcByte(crc, (byte)0x0);
      image[size++] = 0;
    }

    int offset = 2*((size-1)/DelugeConsts.DELUGE_BYTES_PER_PAGE);
    image[offset+0] = (short)((crc >> 0x0) & 0xff);
    image[offset+1] = (short)((crc >> 0x8) & 0xff);

    numPages = (short)(((size-1)/(DelugeConsts.DELUGE_PKTS_PER_PAGE*DelugeConsts.DELUGE_PKT_PAYLOAD_SIZE))+1);

  }

  private void printByte(int byteVal) {
    if (byteVal >= 0 && byteVal < 16)
      System.out.print("0");
    System.out.print(Integer.toHexString(byteVal).toUpperCase() + " " );
    byteCount++;
    if (byteCount >= 16) {
      System.out.println();
      byteCount = 0;
    }
  }

  public void dump() {
    byteCount = 0;
    for (int i = 0; i < size; i++ )
      printByte(image[i]);
    System.out.println();
  }

  public short[] getBytes() { return image; }

  public short getNumPages() { return numPages; }

}
--- NEW FILE: Downloader.java ---
// $Id: Downloader.java,v 1.1 2005/07/22 17:52:37 jwhui Exp $

/*									tab:2
 *
 *
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 */

/**
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

package net.tinyos.deluge;

import net.tinyos.message.*;
import java.io.*;

public class Downloader implements MessageListener {

  private static final int PAGE_SIZE = DelugeConsts.DELUGE_PKTS_PER_PAGE*DelugeConsts.DELUGE_PKT_PAYLOAD_SIZE;
  private static final int MAX_REQ_ATTEMPTS = 4;

  private Pinger pinger;
  private DelugeAdvMsg pingReply;
  private MoteIF moteif;
  private TOSBootImage tosBootImage;
  private boolean verbose;
  private short pktsToReceive[] = new short[DelugeReqMsg.totalSize_requestedPkts()];
  private int pktsReceived;
  private short imageData[] = new short[60*PAGE_SIZE];
  private short curPage;
  private String outfile;

  private int reqAttempts;
  private int reqDest;

  public Downloader(Pinger pinger, int imageNum,
		    MoteIF moteif, boolean verbose,
		    String outfile) {

    if (imageNum < 0 || imageNum >= pinger.getNumImages()) {
      throw new IllegalArgumentException( "invalid image number" );
    }
      
    if (outfile == "") {
      throw new IllegalArgumentException(
	"No outfile specified.");
    }
    
    this.pinger = pinger;
    this.pingReply = pinger.getPingReply(imageNum);
    this.moteif = moteif;
    this.tosBootImage = pinger.getImage(imageNum);
    this.verbose = verbose;
    this.outfile = outfile;

  }

  public void extract() {

    if (pingReply.get_imgDesc_numPgsComplete() == 0) {
      throw new IllegalArgumentException(
	"Image " + pingReply.get_imgDesc_imgNum() + " is empty.");
    }

    System.out.println("Download image:");
    System.out.println("  Image: " + pingReply.get_imgDesc_imgNum());
    System.out.println(tosBootImage);
    
    setupNextPage();
    reqDest = pingReply.get_sourceAddr();
    reqAttempts = MAX_REQ_ATTEMPTS;
    curPage = 0;

    moteif.registerListener(new DelugeAdvMsg(), this);
    moteif.registerListener(new DelugeDataMsg(), this);

    for (;;) {
      try {
	Thread.currentThread().sleep(600);

	if ( curPage >= pingReply.get_imgDesc_numPgs() )
	  break;

	System.out.print("\rDownloading page [" + (curPage+1) + "] of [" + pingReply.get_imgDesc_numPgs() + "] ...");

	if ( reqAttempts == 0 ) {
	  DelugeAdvMsg advMsg = (DelugeAdvMsg)pingReply.clone();
	  advMsg.set_sourceAddr(pinger.getPCAddr());
	  advMsg.set_version(DelugeConsts.DELUGE_VERSION);
	  advMsg.set_type(DelugeConsts.DELUGE_ADV_PING);
	  advMsg = DelugeCrc.computeAdvCrc(advMsg);
	  if (verbose) System.out.print(advMsg);
	  send(advMsg);
	  reqDest = MoteIF.TOS_BCAST_ADDR;
	}
	else {
	  DelugeReqMsg reqMsg = new DelugeReqMsg();
	  reqMsg.set_sourceAddr(pinger.getPCAddr());
	  reqMsg.set_dest(reqDest);
	  reqMsg.set_vNum(pingReply.get_imgDesc_vNum());
	  reqMsg.set_imgNum(pingReply.get_imgDesc_imgNum());
	  reqMsg.set_pgNum(curPage);
	  reqMsg.set_requestedPkts(pktsToReceive);
	  if (verbose) System.out.print(reqMsg);
	  send(reqMsg);
	  reqAttempts--;
	}
      } catch (Exception e) {
	e.printStackTrace();
      }
    }

    System.out.println();
    
    byte[] bytes = new byte[TOSBootImage.METADATA_SIZE];
    for ( int i = 0; i < bytes.length; i++ )
      bytes[i] = (byte)(imageData[i+256] & 0xff);
    TOSBootImage receivedImage = new TOSBootImage(bytes);
    
    try {
      BufferedWriter out = new BufferedWriter(new FileWriter(outfile));
      out.write("<tos_image>\n");
      out.write("  <ident>\n");
      out.write("    <program_name>" + receivedImage.getName() + "</program_name>\n");
      out.write("    <unix_time>" + Long.toHexString(receivedImage.getUnixTime()).toUpperCase() + "L</unix_time>\n");
      out.write("    <platform>" + receivedImage.getPlatform() + "</platform>\n");
      out.write("    <deluge_support>" + (receivedImage.getDelugeSupport() ? "yes" : "no") + "</deluge_support>\n");
      out.write("    <user_id>" + receivedImage.getUserID() + "</user_id>\n");
      out.write("    <hostname>" + receivedImage.getHostname() + "</hostname>\n");
      out.write("    <user_hash>" + Long.toHexString(receivedImage.getUserHash()).toUpperCase() + "L</user_hash>\n");
      out.write("    <uid_hash>" + Long.toHexString(receivedImage.getUIDHash()).toUpperCase() + "L</uid_hash>\n");
      out.write("  </ident>\n");
      out.write("  <image format=\"ihex\">\n");
      
      int curOffset = 256 + TOSBootImage.METADATA_SIZE;
      int addr = 0;
      int length = 0;
      
      for ( int i = 0; i < 4; i++ )
	addr |= (imageData[curOffset++] & 0xff) << i*8;
      for ( int i = 0; i < 4; i++ )
	length |= (imageData[curOffset++] & 0xff) << i*8;
      
      byte record[] = new byte[21];
      
      while ( length > 0 ) {
	if (length >= 16)
	  record[0] = 16;
	else
	  record[0] = (byte)length;
	
	record[1] = (byte)((addr >> 8) & 0xff);
	record[2] = (byte)(addr & 0xff);
	record[3] = 0;
	for ( int i = 0; i < record[0]; i++, curOffset++ )
	  record[4+i] = (byte)imageData[curOffset];
	int checkSum = 0;
	for ( int i = 0; i < 4 + record[0]; i++ )
	  checkSum += record[i];
	record[4+record[0]] = (byte)((~(checkSum & 0xff) + 1) & 0xff);
	
	out.write(":");
	for ( int i = 0; i < 5 + record[0]; i++ )
	  printByte(out, record[i], true);
	out.write("\n");
	
	addr += record[0];
	length -= record[0];
	
	if (length == 0) {
	  addr = length = 0;
	  for ( int i = 0; i < 4; i++ )
	    addr |= (imageData[curOffset++] & 0xff) << i*8;
	  for ( int i = 0; i < 4; i++ )
	    length |= (imageData[curOffset++] & 0xff) << i*8;
	}
      }
      
      out.write(":0400000300005000A9\n");
      out.write(":00000001FF\n");

      out.write("  </image>\n");
      
      addr = length = 0;
      for ( int i = 0; i < 4; i++ )
	addr |= (imageData[curOffset++] & 0xff) << i*8;
      for ( int i = 0; i < 4; i++ )
	length |= (imageData[curOffset++] & 0xff) << i*8;

      if ( length > 0 ) {
	out.write("  <supplement format=\"hex\">\n");
	int hexOffset = 0;
	for ( int i = 0; i < length; i++ ) {
	  printByte(out, (byte)imageData[curOffset++], false);
	  if ((++hexOffset % 32) == 0)
	    out.write("\n");
	}
	if ((++hexOffset % 32) != 0)
	  out.write("\n");
	out.write("  </supplement>\n");
      }

      out.write("</tos_image>\n");
      out.close();
    } catch ( IOException e ) {
      e.printStackTrace();
    }
    
  }

  private void printByte(BufferedWriter out, byte byteVal, boolean uppercase) {
    try {
      if (byteVal >= 0 && byteVal < 16)
	out.write("0");
      String tmpStr = Integer.toHexString(byteVal & 0xff);
      if (uppercase)
	tmpStr = tmpStr.toUpperCase();
      out.write( tmpStr );
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  private void setupNextPage() {

    for ( int i = 0; i < pktsToReceive.length; i++ )
      pktsToReceive[i] = 0xff;
    pktsReceived = 0;

  }

  private void send(Message m) {
    try {
      moteif.send(MoteIF.TOS_BCAST_ADDR, m);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void messageReceived(int to, Message m) {

    switch(m.amType()) {

    case DelugeAdvMsg.AM_TYPE:

      DelugeAdvMsg adv = (DelugeAdvMsg)m;

      if ( verbose ) System.out.print(adv);

      if ( adv.get_type() != DelugeConsts.DELUGE_ADV_NORMAL )
	return;

      if ( reqDest == MoteIF.TOS_BCAST_ADDR
	   && adv.get_imgDesc_vNum() == pingReply.get_imgDesc_vNum()
	   && adv.get_imgDesc_numPgsComplete() > curPage ) {
	reqDest = adv.get_sourceAddr();
	reqAttempts = MAX_REQ_ATTEMPTS;
      }
      
      break;

    case DelugeDataMsg.AM_TYPE:

      DelugeDataMsg data = (DelugeDataMsg)m;
      short pgNum = data.get_pgNum();
      short pktNum = data.get_pktNum();

      if ( data.get_imgNum() == pingReply.get_imgDesc_imgNum()
	   && data.get_vNum() == pingReply.get_imgDesc_vNum()
	   && data.get_pgNum() == curPage ) {

	reqAttempts = MAX_REQ_ATTEMPTS;

	if (verbose) System.out.print(data);
	
	if ((pktsToReceive[pktNum/8] & (0x1 << (pktNum%8))) != 0) {
	  
	  pktsToReceive[pktNum/8] &= ~(0x1 << (pktNum%8));
	  pktsReceived++;
	  
	  System.arraycopy(data.get_data(), 0, imageData,
			   pgNum*PAGE_SIZE + pktNum*DelugeConsts.DELUGE_PKT_PAYLOAD_SIZE,
			   DelugeConsts.DELUGE_PKT_PAYLOAD_SIZE);
	  
	  if (pktsReceived >= DelugeConsts.DELUGE_PKTS_PER_PAGE) {
	    setupNextPage();
	    curPage++;
	  }
	}

      }

      break;

    }

  }

}
--- NEW FILE: Eraser.java ---
// $Id: Eraser.java,v 1.1 2005/07/22 17:52:37 jwhui Exp $

/*									tab:2
 *
 *
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 */

/**
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

package net.tinyos.deluge;

import net.tinyos.message.*;

import java.io.*;

public class Eraser implements MessageListener {

  private Pinger pinger;
  private DelugeAdvMsg advMsg;
  private DelugeAdvMsg pingReply;
  private MoteIF  moteif;
  private TOSBootImage oldTOSBootImage;
  private boolean verbose;
  private boolean force = false;
  private boolean injectAcked = false;

  public Eraser(Pinger pinger, int imageNum, 
		MoteIF moteif, boolean verbose, boolean force) {

    if (imageNum < 0 || imageNum >= pinger.getNumImages()) {
      throw new IllegalArgumentException( "invalid image number" );
    }

    if (imageNum == DelugeConsts.DELUGE_GOLDEN_IMAGE_NUM
	&& pinger.getPCAddr() != Pinger.TOS_UART_ADDR) {
      throw new IllegalArgumentException( "must have direct connection to erase Golden Image" );
    }

    this.pinger = pinger;
    this.pingReply = pinger.getPingReply(imageNum);
    this.oldTOSBootImage = pinger.getImage(imageNum);
    this.moteif = moteif;
    this.verbose = verbose;
    this.force = force;

    advMsg = (DelugeAdvMsg)pingReply.clone();
    advMsg.set_sourceAddr(pinger.getPCAddr());
    advMsg.set_type(DelugeConsts.DELUGE_ADV_PC);
    advMsg.set_imgDesc_vNum(DelugeConsts.DELUGE_INVALID_VNUM);
    advMsg.set_imgDesc_numPgs((short)0);
    advMsg.set_imgDesc_numPgsComplete((short)0);

  }

  public void reset() {

    if ( advMsg.get_sourceAddr() == MoteIF.TOS_BCAST_ADDR ) {
      throw new IllegalArgumentException(
	"This operation requires a direct connection to the node." );
    }

    System.out.println("Reset image:");
    System.out.println("  Image: " + pingReply.get_imgDesc_imgNum());
    if (oldTOSBootImage != null) {
      System.out.println(oldTOSBootImage);
    }
    else {
      System.out.println("    No metadata associated with this image.");
    }

    if( !force )
    {
      System.out.println();
      System.out.println("--------------------------------------------------");
      System.out.println("| WARNING: This operation resets the versioning  |");
      System.out.println("|          info for this image. This operation   |");
      System.out.println("|          is not epidemic and only affects the  |");
      System.out.println("|          currently connected node.             |");
      System.out.println("--------------------------------------------------");
      System.out.println();

      System.out.print("Continue operation? (y/[n]) " );
      BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
      try {
	for (;;) {
	  String ans = in.readLine();
	  ans = ans.toLowerCase();
	  if (ans.equals("") || ans.equals("n") || ans.equals("no")) {
	    throw new IllegalArgumentException("operation cancelled");
	  }
	  if (ans.equals("y") || ans.equals("yes"))
	    break;
	  System.out.print("Please enter yes or no: ");
	}
      } catch (IOException e) {
	e.printStackTrace();
      }
    }

    advMsg.set_type(DelugeConsts.DELUGE_ADV_RESET);
    advMsg.set_imgDesc_vNum(DelugeConsts.DELUGE_INVALID_VNUM);

    moteif.registerListener(new DelugeAdvMsg(), this);

    while(!injectAcked) {
      try {
	advMsg = DelugeCrc.computeAdvCrc(advMsg);
	send(advMsg);
	if (verbose) System.out.print(advMsg);
	Thread.currentThread().sleep(1000);
      } catch (Exception e) {
	e.printStackTrace();
      }
    }    
  }

  public void erase() {

    short newVersion;

    for ( int i = 0; i < pinger.getNumImages() && i < pingReply.get_imgDesc_imgNum(); i++ ) {
      DelugeAdvMsg tmpAdvMsg = pinger.getPingReply(i);
      if (tmpAdvMsg.get_imgDesc_numPgs() != tmpAdvMsg.get_imgDesc_numPgsComplete()) {
	throw new IllegalArgumentException(
          "Image " + i + " is incomplete.\nPlease complete or erase image " + i
	  + " before modifying image " + pingReply.get_imgDesc_imgNum() );
      }
    }

    if (pingReply.get_imgDesc_numPgs() == 0) {
      System.out.println("ERROR: Image already erased.");
      return;
    }
    else {
      System.out.println("Erase image:");
      System.out.println("  Image: " + pingReply.get_imgDesc_imgNum());
      if (oldTOSBootImage != null) {
	System.out.println(oldTOSBootImage);
      }
      else {
	System.out.println("    No metadata associated with this image.");
      }
      newVersion = (short)((short)pingReply.get_imgDesc_vNum() + (short)1);
      if (newVersion == DelugeConsts.DELUGE_INVALID_VNUM)
	newVersion = 0;

      if (pingReply.get_imgDesc_imgNum() == DelugeConsts.DELUGE_GOLDEN_IMAGE_NUM
	  && !force ) {
	System.out.println();
	System.out.println("--------------------------------------------------");
	System.out.println("| WARNING: Erasing Golden Image. This operation  |");
	System.out.println("|          is not epidemic and only affects the  |");
	System.out.println("|          directly connected node.              |");
	System.out.println("--------------------------------------------------");
	System.out.println();
      }

    }

    if( !force )
    {
      System.out.print("Continue operation? (y/[n]) " );
      BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
      try {
	for (;;) {
	  String ans = in.readLine();
	  ans = ans.toLowerCase();
	  if (ans.equals("") || ans.equals("n") || ans.equals("no")) {
	    throw new IllegalArgumentException("operation cancelled");
	  }
	  if (ans.equals("y") || ans.equals("yes"))
	    break;
	  System.out.print("Please enter yes or no: ");
	}
      } catch (IOException e) {
	e.printStackTrace();
      }
    }

    advMsg.set_imgDesc_vNum(newVersion);

    moteif.registerListener(new DelugeAdvMsg(), this);

    while(!injectAcked) {
      try {
	advMsg = DelugeCrc.computeAdvCrc(advMsg);
	send(advMsg);
	if (verbose) System.out.print(advMsg);
	Thread.currentThread().sleep(1000);
      } catch (Exception e) {
	e.printStackTrace();
      }
    }

  }

  private void send(Message m) {
    try {
      moteif.send(MoteIF.TOS_BCAST_ADDR, m);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void messageReceived(int to, Message m) {

    switch(m.amType()) {

    case DelugeAdvMsg.AM_TYPE:

      DelugeAdvMsg rxAdvMsg = (DelugeAdvMsg)m;

      if (verbose) System.out.print(rxAdvMsg);

      if ( rxAdvMsg.get_type() != DelugeConsts.DELUGE_ADV_NORMAL )
	return;

      if (advMsg.get_imgDesc_vNum() == rxAdvMsg.get_imgDesc_vNum()
	  && advMsg.get_imgDesc_numPgs() == rxAdvMsg.get_imgDesc_numPgsComplete()) {
	// ALL DONE, QUIT!
	injectAcked = true;
      }

      break;
      
    }

  }

}

--- NEW FILE: IhexReader.java ---
// $Id: IhexReader.java,v 1.1 2005/07/22 17:52:37 jwhui Exp $

/*									tab:2
 *
 *
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 */

/**
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

package net.tinyos.deluge;

import java.io.*; 
import java.util.*;

public class IhexReader {

  private static final int MAX_SIZE = 1024*512;

  private static final int RECTYP_DATA     = 0;
  private static final int RECTYP_EOF      = 1;
  private static final int RECTYP_EXTSEG   = 2;
  private static final int RECTYP_STARTSEG = 3;

  private byte ihexdata[] = new byte[MAX_SIZE];

  private int imageOffset = 0;

  public IhexReader(String str) throws IOException {
    int totalBytes = 0;
    int physicalAddr = 0;
    int sectionBaseAddr = 0;
    int sectionCount = 0;
    int imgStartOffset = 0;
    int upperSegBaseAddr = 0;

    try {
      StringTokenizer strtok = new StringTokenizer(str, "\n");

      String line;

      int rectyp = RECTYP_DATA;

      while(strtok.hasMoreTokens() && rectyp != RECTYP_EOF) {
	line = strtok.nextToken();
	char bline[] = line.toUpperCase().toCharArray();

	if (bline[0] != ':')
	  throw new IOException("Parse error in ihex file.");

	int reclen = Integer.parseInt(Character.toString(bline[1]) + 
				      Character.toString(bline[2]),
				      16);

	int offset = Integer.parseInt(Character.toString(bline[3]) + 
				      Character.toString(bline[4]) +
				      Character.toString(bline[5]) +
				      Character.toString(bline[6]),
				      16);

	rectyp = Integer.parseInt(Character.toString(bline[7]) +
				  Character.toString(bline[8]),
				  16);

	switch(rectyp) {
	  
	case RECTYP_DATA:
	  if ((upperSegBaseAddr+offset) != physicalAddr) {
	    int sectionLen = physicalAddr - sectionBaseAddr;
	    for ( int i = 0; i < 4; i++ )
	      ihexdata[imgStartOffset+4+i] = (byte)((sectionLen >> (i*8)) & 0xff);
	  }
	  
	  if (imageOffset == 0 || (upperSegBaseAddr+offset) != physicalAddr) {
	    sectionCount++;
	    physicalAddr = (upperSegBaseAddr+offset);
	    sectionBaseAddr = (upperSegBaseAddr+offset);
	    imgStartOffset = imageOffset;
	    ihexdata[imageOffset+0] = (byte)((physicalAddr >> 0) & 0xff);
	    ihexdata[imageOffset+1] = (byte)((physicalAddr >> 8) & 0xff);
	    imageOffset += 8;
	  }
	  
	  for ( int i = 0; i < reclen; i++ ) {
	    ihexdata[imageOffset++] = (byte)Integer.parseInt(Character.toString(bline[2*i+9]) +
								 Character.toString(bline[2*i+10]),
								 16);
	    totalBytes++;
	    physicalAddr++;
	  }
	  break;

	case RECTYP_EXTSEG:
	  upperSegBaseAddr = Integer.parseInt(Character.toString(bline[9]) +
					      Character.toString(bline[10]) +
					      Character.toString(bline[11]) +
					      Character.toString(bline[12]),
					      16);
	  upperSegBaseAddr <<= 4;
	  break;

	case RECTYP_EOF:
	  int sectionLen = physicalAddr - sectionBaseAddr;
	  for ( int i = 0; i < 4; i++ )
	    ihexdata[imgStartOffset+4+i] = (byte)((sectionLen >> (i*8)) & 0xff);
	  for ( int i = 0; i < 8; i++ )
	    ihexdata[imageOffset++] = 0x0;
	  break;

	case RECTYP_STARTSEG:
	  break;

	default:
	  System.out.println(bline);
	  throw new IOException("Parse error in ihex file (unexpected type " + rectyp + ")");
	  
	}
      }
    } catch (Exception e) {
      e.printStackTrace();
    }

    System.out.println("Ihex read complete:");
    System.out.println("  Total bytes = " + totalBytes);
    System.out.println("  Sections = " + sectionCount);

  }

  public int getSize() { return imageOffset; }

  public byte[] getBytes() { return ihexdata; }

}
--- NEW FILE: ImageInjector.java ---
// $Id: ImageInjector.java,v 1.1 2005/07/22 17:52:37 jwhui Exp $

/*									tab:2
 *
 *
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 */

/**
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

package net.tinyos.deluge;

import net.tinyos.message.*;
import java.io.*;

public class ImageInjector implements MessageListener {

  private Pinger pinger;
  private DelugeAdvMsg advMsg;
  private DelugeAdvMsg pingReply;
  private MoteIF  moteif;
  private TOSBootImage oldTOSBootImage, newTOSBootImage;
  private DelugeImage delugeImage;
  private short[] imageBytes;
  private Thread pageInjectorThread;
  private PageInjector pageInjector;
  private boolean verbose;
  private boolean force = false;
  private boolean injectAcked = false;

  public ImageInjector(Pinger pinger, int imageNum,
		       TOSBootImage newTOSBootImage, 
		       MoteIF moteif, boolean verbose, boolean force) {

    if (imageNum < 0 || imageNum >= pinger.getNumImages()) {
      throw new IllegalArgumentException( "invalid image number " + imageNum );
    }

    if (imageNum == DelugeConsts.DELUGE_GOLDEN_IMAGE_NUM
	&& pinger.getPCAddr() != Pinger.TOS_UART_ADDR) {
      throw new IllegalArgumentException( "must have direct connection to overwrite Golden Image" );
    }

    byte[] tbimageBytes = newTOSBootImage.getBytes();

    this.pinger = pinger;
    this.pingReply = pinger.getPingReply(imageNum);
    this.oldTOSBootImage = pinger.getImage(imageNum);
    this.newTOSBootImage = newTOSBootImage;
    this.delugeImage = new DelugeImage(tbimageBytes, tbimageBytes.length);
    this.moteif = moteif;
    this.verbose = verbose;
    this.force = force;
    
    if (delugeImage.getNumPages() > 58) {
      throw new IllegalArgumentException( "tos image is too large" );
    }

    advMsg = (DelugeAdvMsg)pingReply.clone();
    advMsg.set_sourceAddr(pinger.getPCAddr());
    advMsg.set_type(DelugeConsts.DELUGE_ADV_PC);
    advMsg.set_imgDesc_uid(newTOSBootImage.getUIDHash());
    advMsg.set_imgDesc_numPgs(delugeImage.getNumPages());
    advMsg.set_imgDesc_numPgsComplete(delugeImage.getNumPages());

    imageBytes = delugeImage.getBytes();

  }

  public void inject() {

    short newVersion;

    for ( int i = 0; i < pinger.getNumImages() && i < pingReply.get_imgDesc_imgNum(); i++ ) {
      DelugeAdvMsg tmpAdvMsg = pinger.getPingReply(i);
      if (tmpAdvMsg.get_imgDesc_numPgs() != tmpAdvMsg.get_imgDesc_numPgsComplete()) {
	throw new IllegalArgumentException(
          "Image " + i + " is incomplete.\nPlease complete or erase image " + i
	  + " before modifying image " + pingReply.get_imgDesc_imgNum() );
      }
    }

    if (pingReply.get_imgDesc_numPgs() == 0) {
      System.out.println("Replace empty image with:");
      System.out.println("  Image: " + pingReply.get_imgDesc_imgNum());
      System.out.println(newTOSBootImage);
      newVersion = (short)((short)pingReply.get_imgDesc_vNum() + (short)1);
      if (newVersion == DelugeConsts.DELUGE_INVALID_VNUM)
	newVersion = 0;
    }
    else if (pingReply.get_imgDesc_uid() == newTOSBootImage.getUIDHash()) {

      if (pingReply.get_imgDesc_numPgsComplete() == pingReply.get_imgDesc_numPgs()) {
	System.out.println("ERROR: Image already injected:");
	System.out.println("  Image: " + pingReply.get_imgDesc_imgNum());
	System.out.println(oldTOSBootImage);
	return;
      }
      else {
	System.out.println("Resume injection of image:");
	System.out.println("  Image: " + pingReply.get_imgDesc_imgNum());
	System.out.println(newTOSBootImage);
	newVersion = pingReply.get_imgDesc_vNum();
      }

    }
    else {
      System.out.println("Replace image:");
      System.out.println("  Image: " + pingReply.get_imgDesc_imgNum());
      if (oldTOSBootImage != null)
	System.out.println(oldTOSBootImage);
      else
	System.out.println("    No metadata associated with this image.");
      System.out.println("With image:");
      System.out.println("  Image: " + pingReply.get_imgDesc_imgNum());
      System.out.println(newTOSBootImage);
      newVersion = (short)((short)pingReply.get_imgDesc_vNum() + (short)1);
      if (newVersion == DelugeConsts.DELUGE_INVALID_VNUM)
	newVersion = 0;
    }

    if (!newTOSBootImage.getDelugeSupport()) {
      System.out.println();
      System.out.println("--------------------------------------------------");
      System.out.println("| WARNING: New image does not include Deluge.    |");
      System.out.println("|          Network programming will not be       |");
      System.out.println("|          possible when running this app.       |");
      System.out.println("--------------------------------------------------");
      System.out.println();
    }

    if (pingReply.get_imgDesc_imgNum() == DelugeConsts.DELUGE_GOLDEN_IMAGE_NUM
	&& !force ) {
      System.out.println();
      System.out.println("--------------------------------------------------");
      System.out.println("| WARNING: Writing to Golden Image. This         |");
      System.out.println("|          operation is not epidemic and only    |");
      System.out.println("|          affects the directly connected node.  |");
      System.out.println("--------------------------------------------------");
      System.out.println();
    }

    advMsg.set_imgDesc_vNum(newVersion);

    if( !force ) {
      System.out.print("Continue operation? (y/[n]) " );
      BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
      try {
	for (;;) {
	  String ans = in.readLine();
	  ans = ans.toLowerCase();
	  if (ans.equals("") || ans.equals("n") || ans.equals("no")) {
	    throw new IllegalArgumentException("operation cancelled");
	  }
	  if (ans.equals("y") || ans.equals("yes"))
	    break;
	  System.out.print("Please enter yes or no: ");
	}
      } catch (IOException e) {
	e.printStackTrace();
      }
    }

    moteif.registerListener(new DelugeAdvMsg(), this);
    moteif.registerListener(new DelugeReqMsg(), this);
    pageInjector = new PageInjector();
    pageInjectorThread = new Thread(pageInjector);
    pageInjectorThread.start();

    while(!injectAcked) {
      try {
	advMsg = DelugeCrc.computeAdvCrc(advMsg);
	send(advMsg);
	if (verbose) System.out.print(advMsg);
	Thread.currentThread().sleep(500);
      } catch (Exception e) {
	e.printStackTrace();
      }
    }

  }

  private void send(Message m) {
    try {
      moteif.send(MoteIF.TOS_BCAST_ADDR, m);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void messageReceived(int to, Message m) {

    switch(m.amType()) {

    case DelugeAdvMsg.AM_TYPE:

      DelugeAdvMsg rxAdvMsg = (DelugeAdvMsg)m;

      if (verbose) System.out.print(rxAdvMsg);

      if ( rxAdvMsg.get_type() != DelugeConsts.DELUGE_ADV_NORMAL )
	return;

      if (advMsg.get_imgDesc_vNum() == rxAdvMsg.get_imgDesc_vNum()
	  && advMsg.get_imgDesc_numPgs() == rxAdvMsg.get_imgDesc_numPgsComplete()) {
	// ALL DONE, QUIT!
	System.out.println();
	injectAcked = true;
      }

      break;
      
    case DelugeReqMsg.AM_TYPE:

      DelugeReqMsg req = (DelugeReqMsg)m;
      boolean  pktsToSend[] = new boolean[DelugeConsts.DELUGE_PKTS_PER_PAGE];

      if (verbose) System.out.print(req);

      if (advMsg.get_imgDesc_vNum() != req.get_vNum()
	  || advMsg.get_imgDesc_imgNum() != req.get_imgNum())
	return;
      
      for ( int i = 0; i < DelugeConsts.DELUGE_PKTS_PER_PAGE; i++ ) {
	short[] tmp = req.get_requestedPkts();
	if ((tmp[i/8]&(1 << (i%8))) != 0)
	  pktsToSend[i] = true;
      }
      
      pageInjector.transmitPage(req.get_pgNum(), pktsToSend);

      break;

    }

  }

  private class PageInjector implements Runnable {

    private boolean pktsToSend[] = new boolean[DelugeConsts.DELUGE_PKTS_PER_PAGE];
    private int     pageToSend = DelugeConsts.DELUGE_INVALID_PGNUM;
    private boolean transmittingPage = false;
    private int     curPkt = 0;

    public PageInjector() {

    }

    public boolean isTransmitting() {
      return transmittingPage;
    }

    synchronized public void transmitPage(int pgNum, boolean pktsToSend[]) {
      
      if (pgNum > pageToSend)
	return;
      
      if (pgNum < pageToSend) {
	for ( int i = 0; i < this.pktsToSend.length; i++ )
	  this.pktsToSend[i] = false;
	this.pageToSend = pgNum;
	curPkt = 0;
      }
      for ( int i = 0; i < this.pktsToSend.length; i++ )
	this.pktsToSend[i] |= pktsToSend[i];
      
      notifyAll();
      
    }

    private boolean arePacketsToSend() {
      for ( int i = 0; i < DelugeConsts.DELUGE_PKTS_PER_PAGE; i++ ) {
	if (pktsToSend[i])
	  return true;
      }
      return false;
    }
    
    synchronized private void transmitPacket() {
      
      DelugeDataMsg dataMsg = new DelugeDataMsg();
      short packet[] = new short[DelugeConsts.DELUGE_PKT_PAYLOAD_SIZE];
      
      while ( !arePacketsToSend() ) {
	pageToSend = DelugeConsts.DELUGE_INVALID_PGNUM;
	try {
	  transmittingPage = false;
	  wait();
	  transmittingPage = true;
	  System.out.print("\rInjecting page [" + (pageToSend+1) + "] of [" + delugeImage.getNumPages() + "] ...");
	} catch (Exception e) {
	  e.printStackTrace();
	}
      }
      
      dataMsg.set_vNum(advMsg.get_imgDesc_vNum());
      dataMsg.set_imgNum(advMsg.get_imgDesc_imgNum());
      dataMsg.set_pgNum((short)pageToSend);
      
      while (!pktsToSend[curPkt])
	curPkt = (curPkt+1) % DelugeConsts.DELUGE_PKTS_PER_PAGE;
      
      System.arraycopy(imageBytes, pageToSend*(DelugeConsts.DELUGE_PKTS_PER_PAGE*DelugeConsts.DELUGE_PKT_PAYLOAD_SIZE)
		       + curPkt*DelugeConsts.DELUGE_PKT_PAYLOAD_SIZE, 
		       packet, 0,
		       DelugeConsts.DELUGE_PKT_PAYLOAD_SIZE);
      
      dataMsg.set_pktNum((short)curPkt);
      dataMsg.set_data(packet);
      if (verbose) System.out.print(dataMsg);
      send(dataMsg);
      pktsToSend[curPkt] = false;
      curPkt = (curPkt + 1) % DelugeConsts.DELUGE_PKTS_PER_PAGE;
      
    }
    
    synchronized private void send(Message m) {
      try {
	moteif.send(MoteIF.TOS_BCAST_ADDR, m);
      } catch (Exception e) {
	e.printStackTrace();
      }
    }
    
    public void run() {
      for(;;) {
	try {
	  transmitPacket();
	  Thread.sleep(8);
	} catch (Exception e) {
	  e.printStackTrace();
	}
      }
    }
  }

}

--- NEW FILE: Makefile ---
# $Id: Makefile,v 1.1 2005/07/22 17:52:37 jwhui Exp $
#
# TinyOS Tools Makefile
#
# @author  TinyOS Team
#

TOS = $(shell ncc -print-tosdir)
PACKAGE = net.tinyos.deluge

MIG = mig java
NCG = ncg java

MSGS = DelugeAdvMsg.java DelugeReqMsg.java DelugeDataMsg.java DelugeDataMsg.java DelugeConsts.java NetProgMsg.java

INITIAL_TARGETS = $(MSGS)

OTHER_CLEAN = cleanmig

ROOT = $(TOS)/../tools/java
include $(ROOT)/Makefile.include

#
# Deluge
#

DELUGE_PLATFORM=telosb
DELUGE_LIB=$(TOS)/lib/Deluge
INCLUDES=-I$(DELUGE_LIB) -I$(TOS)/lib/CC2420Radio

DelugeAdvMsg.java:
	$(MIG) -java-classname=$(PACKAGE).DelugeAdvMsg -target=$(DELUGE_PLATFORM) $(INCLUDES) $(DELUGE_LIB)/DelugeMsgs.h DelugeAdvMsg -o $@

DelugeReqMsg.java:
	$(MIG) -java-classname=$(PACKAGE).DelugeReqMsg -target=$(DELUGE_PLATFORM) $(INCLUDES) $(DELUGE_LIB)/DelugeMsgs.h DelugeReqMsg -o $@

DelugeDataMsg.java:
	$(MIG) -java-classname=$(PACKAGE).DelugeDataMsg -target=$(DELUGE_PLATFORM) $(INCLUDES) $(DELUGE_LIB)/DelugeMsgs.h DelugeDataMsg -o $@

NetProgMsg.java:
	$(MIG) -java-classname=$(PACKAGE).NetProgMsg -target=$(DELUGE_PLATFORM) $(INCLUDES) $(DELUGE_LIB)/NetProgMsgs.h NetProgMsg -o $@

DelugeConsts.java:
	$(NCG) -java-classname=$(PACKAGE).DelugeConsts -target=$(DELUGE_PLATFORM) $(INCLUDES) $(DELUGE_LIB)/DelugeC.nc Deluge.h DelugePageTransfer.h DelugeMsgs.h DelugeConsts -o $@

#
# Clean
#

cleanmig:
	rm -f $(MSGS)

--- NEW FILE: Pinger.java ---
// $Id: Pinger.java,v 1.1 2005/07/22 17:52:37 jwhui Exp $

/*									tab:2
 *
 *
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 */

/**
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

package net.tinyos.deluge;

import net.tinyos.message.*;
import net.tinyos.util.*;

import java.util.*;

public class Pinger implements MessageListener {

  public  static final short TOS_UART_ADDR = 0x007e;
  private static final int STRING_SIZE = 16;
  private static final int MAX_ATTEMPTS = 3;

  private static final int START_PKT = DelugeConsts.DELUGE_CRC_BLOCK_SIZE/DelugeConsts.DELUGE_PKT_PAYLOAD_SIZE;
  // ONE PACKET WORTH OF DATA ARE RESERVED BUT UNUSED
  // IF MORE IDENT DATA IS REQUIRED, REMOVE SUBTRACTION ON END POINT
  private static final int END_PKT = DelugeConsts.DELUGE_IDENT_SIZE/DelugeConsts.DELUGE_PKT_PAYLOAD_SIZE - 1;

  private MoteIF moteif;
  private boolean verbose;
  private short curImage = -1;

  private DelugeAdvMsg advMsg = new DelugeAdvMsg();
  private NetProgMsg netProgMsg = new NetProgMsg();

  private Hashtable pingReplies = new Hashtable();
  private Hashtable images = new Hashtable();

  private short pcAddr = 0x7e;

  private short pktsToReceive[] = new short[DelugeReqMsg.totalSize_requestedPkts()];
  private short imageData[] = new short[DelugeConsts.DELUGE_PKTS_PER_PAGE*DelugeConsts.DELUGE_PKT_PAYLOAD_SIZE];
  private int pktsReceived = 0;

  private boolean resolvedNodeType = false;
  private int numImages = -1;

  private boolean pingComplete = false;
  private boolean receivedExecutingIdent = false;
  private boolean requesting = false;
  private int dest = MoteIF.TOS_BCAST_ADDR;
  private boolean skipNextAdv = false;
  private int attempts = 0;
  private String identString = "";
  private boolean error = false;

  public Pinger(MoteIF moteif, boolean verbose) {
    this.moteif = moteif;
    this.verbose = verbose;
    this.moteif.registerListener(new DelugeAdvMsg(), this);
    this.moteif.registerListener(new DelugeDataMsg(), this);
    this.moteif.registerListener(new NetProgMsg(), this);
  }

  public void ping() {

    advMsg.set_sourceAddr(pcAddr);
    advMsg.set_version(DelugeConsts.DELUGE_VERSION);
    advMsg.set_type((short)DelugeConsts.DELUGE_ADV_PING);
    advMsg.set_nodeDesc_vNum((short)DelugeConsts.DELUGE_INVALID_VNUM);
    advMsg.set_imgDesc_vNum(DelugeConsts.DELUGE_INVALID_VNUM);

    System.out.println("Pinging node ...");

    // get executing image
    for (;;) {
      try {
	if (receivedExecutingIdent)
	  break;

	netProgMsg.set_sourceAddr(pcAddr);
	send(netProgMsg);
	if (verbose) System.out.print(netProgMsg);
	
	if (!resolvedNodeType) {
	  if (pcAddr == (short)MoteIF.TOS_BCAST_ADDR)
	    pcAddr = TOS_UART_ADDR;
	  else
	    pcAddr = (short)MoteIF.TOS_BCAST_ADDR;
	}

	Thread.currentThread().sleep(500);
      } catch (Exception e) {
	e.printStackTrace();
      }
    }

    setupNewImage();

    // get deluge image info
    for (;;) {
      try {
	attempts++;
	if (attempts > MAX_ATTEMPTS)
	  dest = MoteIF.TOS_BCAST_ADDR;

	if ( ( curImage >= numImages && numImages != -1)
	    || error )
	  break;

	advMsg.set_sourceAddr(pcAddr);
	advMsg.set_imgDesc_imgNum(curImage);
	advMsg = DelugeCrc.computeAdvCrc(advMsg);
	requesting = false;
	if (!skipNextAdv) send(advMsg);

	skipNextAdv = false;

	if (verbose) System.out.print(advMsg);

	if (!resolvedNodeType) {
	  if (pcAddr == (short)MoteIF.TOS_BCAST_ADDR)
	    pcAddr = TOS_UART_ADDR;
	  else
	    pcAddr = (short)MoteIF.TOS_BCAST_ADDR;
	}

	Thread.currentThread().sleep(500);
      } catch (Exception e) {
	e.printStackTrace();
      }
    }

    moteif.deregisterListener(new DelugeAdvMsg(), this);
    moteif.deregisterListener(new DelugeDataMsg(), this);
    moteif.deregisterListener(new NetProgMsg(), this);

  }

  public boolean existsError() {
    return error;
  }

  public DelugeAdvMsg getPingReply(int imageNum) {
    return (DelugeAdvMsg)pingReplies.get(new Integer(imageNum));
  }

  public TOSBootImage getImage(int imageNum) {
    return (TOSBootImage)images.get(new Integer(imageNum));
  }

  public short getPCAddr() {
    return pcAddr;
  }

  public int getNumImages() { 
    return numImages; 
  }

  private void send(Message m) {
    try {
      moteif.send(dest, m);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  private void setupNewImage() {
    for ( int i = START_PKT; i < START_PKT+END_PKT; i++ )
      pktsToReceive[i/8] |= (0x1 << (i%8));
    pktsReceived = 0;
    curImage++;
    skipNextAdv = true;
    if ( curImage < numImages || numImages == -1 ) {
      advMsg.set_sourceAddr(pcAddr);
      advMsg.set_imgDesc_imgNum(curImage);
      advMsg = DelugeCrc.computeAdvCrc(advMsg);
      send(advMsg);
    }
    if (verbose) System.out.print(advMsg);
  }

  public String getExecutingIdent() {
    return identString;
  }

  public void messageReceived(int toAddr, Message m) {

    // figure out what type of node we're connected to
    if (!resolvedNodeType) {
      if (toAddr != TOS_UART_ADDR) {
	pcAddr = (short)MoteIF.TOS_BCAST_ADDR;
	resolvedNodeType = true;
	System.out.println("Connected to TOSBase node.");
      }
      else if (toAddr == TOS_UART_ADDR) {
	pcAddr = TOS_UART_ADDR;
	resolvedNodeType = true;
	System.out.println("Connected to Deluge node.");
      }
    }

    switch(m.amType()) {

    case NetProgMsg.AM_TYPE:

      netProgMsg = (NetProgMsg)m;

      if (verbose) System.out.print(netProgMsg);

      // extract ident information
      {
	byte tmpBytes[] = new byte[STRING_SIZE];
	for ( int i = 0; i < STRING_SIZE; i++ )
	  tmpBytes[i] = (byte)(netProgMsg.getElement_ident_program_name(i) & 0xff);

	String name = new String(tmpBytes);
	if (name.indexOf('\0') != -1)
	  name = name.substring(0, name.indexOf('\0'));

	Date date = new Date(netProgMsg.get_ident_unix_time()*1000);

	identString = "    Prog Name:   " + name + "\n" +
	  "    Compiled On: " + date + "\n" +
	  "    User Hash:   0x" + Long.toHexString(netProgMsg.get_ident_user_hash());
	receivedExecutingIdent = true;
      }

      break;

    case DelugeAdvMsg.AM_TYPE:

      DelugeAdvMsg pingReply = (DelugeAdvMsg)m;
      int imgNum = pingReply.get_imgDesc_imgNum();

      if (verbose) System.out.print(pingReply);

      if ( pingReply.get_type() == DelugeConsts.DELUGE_ADV_ERROR )
	error = true;

      if (dest == MoteIF.TOS_BCAST_ADDR)
	dest = pingReply.get_sourceAddr();

      if ( pingReply.get_type() != DelugeConsts.DELUGE_ADV_NORMAL )
	return;

      if (dest != pingReply.get_sourceAddr())
	return;

      if (numImages == -1)
	numImages = pingReply.get_numImages();

      if (pingReplies.get(new Integer(imgNum)) == null) {
	pingReplies.put(new Integer(imgNum), pingReply);
      }
      if (curImage == imgNum) {
	if (pingReply.get_imgDesc_numPgsComplete() == 0) {
	  setupNewImage();
	  return;
	}

	DelugeReqMsg reqMsg = new DelugeReqMsg();
	reqMsg.set_sourceAddr(pcAddr);
	reqMsg.set_dest(pingReply.get_sourceAddr());
	reqMsg.set_vNum(pingReply.get_imgDesc_vNum());
	reqMsg.set_imgNum(pingReply.get_imgDesc_imgNum());
	reqMsg.set_pgNum((short)0);
	reqMsg.set_requestedPkts(pktsToReceive);
	if (verbose) System.out.print(reqMsg);
	send(reqMsg);
      }

      break;

    case DelugeDataMsg.AM_TYPE:

      DelugeDataMsg dataMsg = (DelugeDataMsg)m;
      short pktNum = dataMsg.get_pktNum();

      if (verbose) System.out.print(dataMsg);

      pingReply = (DelugeAdvMsg)pingReplies.get(new Integer(curImage));

      if (pingReply == null
	  || dataMsg.get_vNum() != pingReply.get_imgDesc_vNum()
	  || dataMsg.get_imgNum() != curImage
	  || dataMsg.get_pgNum() != 0
	  || dataMsg.get_pktNum() >= DelugeConsts.DELUGE_PKTS_PER_PAGE)
	return;

      if ((pktsToReceive[pktNum/8] & (0x1 << (pktNum%8))) != 0) {

	pktsToReceive[pktNum/8] &= ~(0x1 << (pktNum%8));
	System.arraycopy(dataMsg.get_data(), 0, imageData, 
			 pktNum*DelugeConsts.DELUGE_PKT_PAYLOAD_SIZE, 
			 DelugeConsts.DELUGE_PKT_PAYLOAD_SIZE);
	pktsReceived++;

	if (pktsReceived >= END_PKT) {
	  byte[] bytes = new byte[TOSBootImage.METADATA_SIZE];
	  for ( int i = 0; i < bytes.length; i++ )
	    bytes[i] = (byte)(imageData[i+256] & 0xff);

	  images.put(new Integer(curImage), new TOSBootImage(bytes));

	  setupNewImage();
	}

      }

      break;

    }


  }

}

--- NEW FILE: Rebooter.java ---
// $Id: Rebooter.java,v 1.1 2005/07/22 17:52:37 jwhui Exp $

/*									tab:2
 *
 *
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 */

/**
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

package net.tinyos.deluge;

import net.tinyos.message.*;
import net.tinyos.util.*;

import java.io.*;
import java.util.*;

public class Rebooter implements MessageListener {

  private MoteIF moteif;
  private boolean verbose;
  private DelugeAdvMsg pingReply;
  private TOSBootImage newImage;
  private short pcAddr;
  private short newVersion;
  private boolean rebootAcked = false;
  private Pinger pinger;
  private boolean force;

  private DelugeAdvMsg advMsg = new DelugeAdvMsg();

  public Rebooter(Pinger pinger, int imageNum, MoteIF moteif, boolean verbose, boolean force) {

    if (imageNum < 0 || imageNum >= pinger.getNumImages()) {
      throw new IllegalArgumentException( "invalid image number" );
    }

    if ( pinger.existsError() && imageNum > 0 ) {
      throw new IllegalArgumentException( 
	"Deluge is not running on one or more nodes.");
    }

    this.pinger = pinger;
    this.pingReply = pinger.getPingReply(imageNum);
    this.newImage = pinger.getImage(imageNum);
    this.pcAddr = pinger.getPCAddr();
    this.moteif = moteif;
    this.verbose = verbose;
    this.force = force;
    this.moteif.registerListener(new DelugeAdvMsg(), this);
    
    newVersion = (short)((short)pingReply.get_nodeDesc_vNum() + (short)1);
    if (newVersion == DelugeConsts.DELUGE_INVALID_VNUM)
      newVersion = 0;

  }

  public void reboot() {

    if (pingReply.get_imgDesc_imgNum() != 0) {
      if (pingReply.get_imgDesc_numPgs() != pingReply.get_imgDesc_numPgsComplete()) {
	throw new IllegalArgumentException( "cannot reboot to an incomplete image" );
      }
      else if (pingReply.get_imgDesc_numPgs() == 0) {
	throw new IllegalArgumentException( "cannot reboot to an empty image" );
      }
    }

    System.out.println("  Reboot From Image:");

    System.out.println(pinger.getExecutingIdent());

    TOSBootImage image = newImage;
    System.out.println("  To Image: " + pingReply.get_imgDesc_imgNum());
    if ( !pinger.existsError() && pingReply.get_imgDesc_numPgs() != 0 ) {
      System.out.println(image);
    }
    else {
      System.out.println("    Golden Image.");
      System.out.println();
      System.out.println("--------------------------------------------------");
      System.out.println("| WARNING: No info for Golden Image is available |");
      System.out.println("|          but reboot attempts to this image are |");
      System.out.println("|          allowed. If no such image exists,     |");
      System.out.println("|          no reprogramming will occur.          |");
      System.out.println("--------------------------------------------------");
      System.out.println();
    }

    if ( pingReply.get_nodeDesc_uid() == pingReply.get_imgDesc_uid() )
      throw new IllegalArgumentException( "already executing image" );

    if( !force )
    {
      System.out.print("Continue operation? (y/[n]) " );
      BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
      try {
	for (;;) {
	  String ans = in.readLine();
	  ans = ans.toLowerCase();
	  if (ans.equals("") || ans.equals("n") || ans.equals("no")) {
	    throw new IllegalArgumentException( "operation cancelled" );
	  }
	  if (ans.equals("y") || ans.equals("yes"))
	    break;
	  System.out.print("Please enter yes or no: ");
	}
      } catch (IOException e) {
	e.printStackTrace();
      }
    }

    advMsg.set_sourceAddr(pcAddr);
    advMsg.set_version(DelugeConsts.DELUGE_VERSION);
    advMsg.set_type((short)DelugeConsts.DELUGE_ADV_PC);
    advMsg.set_nodeDesc_vNum(newVersion);
    advMsg.set_nodeDesc_uid(pingReply.get_imgDesc_uid());
    advMsg.set_nodeDesc_imgNum(pingReply.get_imgDesc_imgNum());
    advMsg.set_imgDesc_vNum(DelugeConsts.DELUGE_INVALID_VNUM);
    advMsg.set_imgDesc_imgNum(pingReply.get_imgDesc_imgNum());

    System.out.println("Sending reboot message ...");

    while(!rebootAcked) {
      try {
	advMsg = DelugeCrc.computeAdvCrc(advMsg);
	send(advMsg);
	if (verbose) System.out.print(advMsg);
	if (advMsg.get_type() == DelugeConsts.DELUGE_ADV_PC)
	  advMsg.set_type(DelugeConsts.DELUGE_ADV_PING);
	else
	  advMsg.set_type(DelugeConsts.DELUGE_ADV_PC);
	Thread.currentThread().sleep(1000);
      } catch (Exception e) {
	e.printStackTrace();
      }
    }

  }

  private void send(Message m) {
    try {
      moteif.send(MoteIF.TOS_BCAST_ADDR, m);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void messageReceived(int to, Message m) {

    switch(m.amType()) {

    case DelugeAdvMsg.AM_TYPE:
      
      DelugeAdvMsg rxAdvMsg = (DelugeAdvMsg)m;
      
      if (verbose) System.out.print(rxAdvMsg);
      
      if ( rxAdvMsg.get_type() != DelugeConsts.DELUGE_ADV_NORMAL )
	return;    
      
      if (newVersion == rxAdvMsg.get_nodeDesc_vNum()
	  && !rebootAcked) {
	System.out.println("Reboot message sent.");	  
	rebootAcked = true;
      }
      
      break;

    }
    
  }

}

--- NEW FILE: TOSBootImage.java ---
// $Id: TOSBootImage.java,v 1.1 2005/07/22 17:52:37 jwhui Exp $

/*									tab:2
 *
 *
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 */

/**
 * @author Jonathan Hui <jwhui at cs.berkeley.edu>
 */

package net.tinyos.deluge;

import java.io.*;
import java.lang.*;
import java.util.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;

public class TOSBootImage {

  public final static int METADATA_SIZE = 128;
  private final static int STRING_SIZE = 16;
  private final static int SIZE_SIZE = 4;
  private final static int UNIX_TIME_SIZE = 4;
  private final static int USER_HASH_SIZE = 4;
  private final static int UID_HASH_SIZE = 4;

  private String name;     // 16
  private String userid;   // 16
  private String hostname; // 16
  private String platform; // 16
  private int    size;     // 4
  private long   unixTime; // 4
  private long   userHash; // 4
  private long   uidHash;  // 4

  private boolean delugeSupport = false;

  private IhexReader image = null;
  private byte supplement[] = null;
  private int supplementSize;

  public TOSBootImage(String filename) {

    if (filename.equals("")) {
      throw new IllegalArgumentException( "no file specified" );
    }

    File file = new File(filename);
    if (!file.exists()) {
      throw new IllegalArgumentException( "no such file " + filename );
    }

    try {

      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder parser = factory.newDocumentBuilder();
      Document doc = parser.parse(filename);
      String tmp;

      NodeList nlist=doc.getElementsByTagName("program_name");
      name = nlist.item(0).getFirstChild().getNodeValue();

      nlist=doc.getElementsByTagName("unix_time");
      tmp = nlist.item(0).getFirstChild().getNodeValue();
      unixTime = Long.parseLong(tmp.substring(0,tmp.indexOf('L')),16);

      nlist=doc.getElementsByTagName("user_id");
      userid = nlist.item(0).getFirstChild().getNodeValue();

      nlist=doc.getElementsByTagName("hostname");
      hostname = nlist.item(0).getFirstChild().getNodeValue();

      nlist=doc.getElementsByTagName("user_hash");
      tmp = nlist.item(0).getFirstChild().getNodeValue();
      userHash = Long.parseLong(tmp.substring(0,tmp.indexOf('L')),16);

      nlist=doc.getElementsByTagName("uid_hash");
      tmp = nlist.item(0).getFirstChild().getNodeValue();
      uidHash = Long.parseLong(tmp.substring(0,tmp.indexOf('L')),16);

      nlist=doc.getElementsByTagName("platform");
      tmp = nlist.item(0).getFirstChild().getNodeValue();
      platform = nlist.item(0).getFirstChild().getNodeValue();

      nlist=doc.getElementsByTagName("image");
      String imageStr = nlist.item(0).getFirstChild().getNodeValue();
      image = new IhexReader(imageStr);

      nlist=doc.getElementsByTagName("supplement");
      if (nlist.item(0) != null) {
	String supplementStr = nlist.item(0).getFirstChild().getNodeValue().trim();
	for ( int i = 0; i < supplementStr.length(); i++ ) {
	  if (supplementStr.charAt(i) == '\n') continue;
	  supplementSize++;
	  i++;
	}
	supplement = new byte[supplementSize];
	supplementSize = 0;
	for ( int i = 0; i < supplementStr.length(); i++ ) {
	  if (supplementStr.charAt(i) == '\n') continue;
	  supplement[supplementSize++] = (byte)Integer.parseInt(supplementStr.substring(i,i+2), 16);
	  i++;
	}
	System.out.println("Supplement read complete:");
	System.out.println("  Total bytes = " + supplementSize);
      }

      nlist=doc.getElementsByTagName("deluge_support");
      tmp = nlist.item(0).getFirstChild().getNodeValue();
      delugeSupport = tmp.equals("yes");

    } catch (Exception e) {
      e.printStackTrace();
    }

  }

  TOSBootImage(byte[] bytes) {

    int curOffset = 0;

    byte tmpBytes[] = new byte[STRING_SIZE];
    for ( int i = 0; i < STRING_SIZE; i++ )
      tmpBytes[i] = (byte)(bytes[curOffset++] & 0xff);
    name = new String(tmpBytes);

    if (name.indexOf('\0') != -1)
      name = name.substring(0, name.indexOf('\0'));

    for ( int i = 0; i < STRING_SIZE; i++ )
      tmpBytes[i] = (byte)(bytes[curOffset++] & 0xff);
    userid = new String(tmpBytes);

    if (userid.indexOf('\0') != -1)
      userid = userid.substring(0, userid.indexOf('\0'));
    if (userid.length() == 0) 
      userid = "N/A";

    for ( int i = 0; i < STRING_SIZE; i++ )
      tmpBytes[i] = (byte)(bytes[curOffset++] & 0xff);
    hostname = new String(tmpBytes);

    if (hostname.indexOf('\0') != -1)
      hostname = hostname.substring(0, hostname.indexOf('\0'));
    if (hostname.length() == 0) 
      hostname = "N/A";

    for ( int i = 0; i < STRING_SIZE; i++ )
      tmpBytes[i] = (byte)(bytes[curOffset++] & 0xff);
    platform = new String(tmpBytes);

    if (platform.indexOf('\0') != -1)
      platform = platform.substring(0, platform.indexOf('\0'));
    if (platform.length() == 0) 
      platform = "N/A";

    unixTime = 0;
    for ( int i = 0; i < UNIX_TIME_SIZE; i++ )
      unixTime |= (long)(bytes[curOffset++] & 0xff) << (i*8);

    userHash = 0;
    for ( int i = 0; i < USER_HASH_SIZE; i++ )
      userHash |= (long)(bytes[curOffset++] & 0xff) << (i*8);

    uidHash = 0;
    for ( int i = 0; i < UID_HASH_SIZE; i++ )
      uidHash |= (long)(bytes[curOffset++] & 0xff) << (i*8);

    delugeSupport = ( bytes[curOffset++] != 0 ) ? true : false;

  }

  public byte[] getBytes() {

    byte bytes[];
    int curOffset = 0;

    if ( supplementSize != 0 )
      bytes = new byte[METADATA_SIZE + image.getSize() + supplementSize + 8];
    else
      bytes = new byte[METADATA_SIZE + image.getSize() + 8];

    byte tmpBytes[] = name.getBytes();
    System.arraycopy(tmpBytes, 0, bytes, curOffset, tmpBytes.length);
    curOffset += STRING_SIZE;

    tmpBytes = userid.getBytes();
    System.arraycopy(tmpBytes, 0, bytes, curOffset, tmpBytes.length);
    curOffset += STRING_SIZE;

    tmpBytes = hostname.getBytes();
    System.arraycopy(tmpBytes, 0, bytes, curOffset, tmpBytes.length);
    curOffset += STRING_SIZE;

    tmpBytes = platform.getBytes();
    System.arraycopy(tmpBytes, 0, bytes, curOffset, tmpBytes.length);
    curOffset += STRING_SIZE;

    for ( int i = 0; i < 4; i++ )
      bytes[curOffset++] = (byte)((unixTime >> (8*i)) & 0xff);

    for ( int i = 0; i < 4; i++ )
      bytes[curOffset++] = (byte)((userHash >> (8*i)) & 0xff);

    for ( int i = 0; i < 4; i++ )
      bytes[curOffset++] = (byte)((uidHash >> (8*i)) & 0xff);

    bytes[curOffset++] = (byte)((delugeSupport) ? 0x1 : 0x0);

    System.arraycopy(image.getBytes(), 0, bytes, METADATA_SIZE, image.getSize());

    if (supplementSize != 0) {
      for ( int i = 0; i < 4; i++ )
	bytes[METADATA_SIZE + image.getSize() + i] = 0;
      for ( int i = 0; i < 4; i++ )
	bytes[METADATA_SIZE + image.getSize() + 4 + i] = (byte)((supplementSize >> (8*i)) & 0xff);
      System.arraycopy(supplement, 0, bytes, 
		       METADATA_SIZE + image.getSize() + 8, supplementSize);
    }
    else {
      for ( int i = 0; i < 8; i++ ) {
	bytes[bytes.length - i - 1] = 0;
      }
    }

    return bytes;

  }

  public String toString() {
    Date date = new Date(unixTime*1000);
    return ("    Prog Name:   " + name + "\n" +
	    "    Compiled On: " + date + "\n" +
	    "    Platform:    " + platform + "\n" +
	    "    User ID:     " + userid + "\n" +
	    "    Hostname:    " + hostname + "\n" +
	    "    User Hash:   0x" + Long.toHexString(userHash));
  }

  public String getName() { return name; }
  public String getHostname() { return hostname; }
  public String getUserID() { return userid; }
  public String getPlatform() { return platform; }
  public int getSize() { return size; }
  public long getUnixTime() { return unixTime; }
  public long getUserHash() { return userHash; }
  public long getUIDHash() { return uidHash; }
  public boolean getDelugeSupport() { return delugeSupport; }

}



More information about the Tinyos-commits mailing list