]> oss.titaniummirror.com Git - tinyos-2.x.git/commitdiff
Added getSerialPacket() and setSerialPacket() methods to the Message class so we...
authorrincon <rincon>
Tue, 29 May 2007 16:44:50 +0000 (16:44 +0000)
committerrincon <rincon>
Tue, 29 May 2007 16:44:50 +0000 (16:44 +0000)
support/sdk/java/net/tinyos/message/Message.java
support/sdk/java/net/tinyos/message/Receiver.java

index 0ebb5080f9c712a2526166cfdb16f5490b81747d..a5fdd4495a6d801fe4ae531b9e4d69ca6b154004 100644 (file)
@@ -49,540 +49,641 @@ package net.tinyos.message;
 
 public class Message implements Cloneable {
 
-    /**
-     * The maximum number of characters read from an 8-bit array field
-     * being converted into a Java String.
-     */
-    public static final int MAX_CONVERTED_STRING_LENGTH = 512;
-
-    /** 
-     * The underlying byte array storing the data for this message. 
-     * This is private to enforce access to the data through the accessor
-     * methods in this class, which do bounds checking and manage the
-     * base_offset for embedded messages.
-     */
-    private byte[] data;
-
-    /** 
-     * The base offset into the data. This allows the message data to
-     * exist at some non-zero offset into the actual data.
-     */
-    protected int base_offset;
-
-    /**
-     * The actual length of the message data. Must be less than or
-     * equal to (data.length - base_offset).
-     */
-    protected int data_length;
-
-    /**
-     * The AM type corresponding to this object. Set to -1 if no AM type
-     * is known.
-     */
-    protected int am_type;
-
-    /** Limit no-arg instantiation. */
-    protected Message() {
-    }
-
-    /**
-     * Construct a new message of the given size.
-     * @param data_length The size of the message to create.
-     */
-    public Message(int data_length) {
-       init(data_length);
-    }
-    public void init(int data_length) {
-       init(new byte[data_length]);
-    }
-
-    /**
-     * Construct a new message of the given size and base offset.
-     * Allocates a new byte array of size data_length+base_offset.
-     * @param data_length The size of the message to create.
-     * @param base_offset The base offset into the newly created message.
-     */
-    public Message(int data_length, int base_offset) {
-      init(data_length, base_offset);
-    }
-    protected void init(int data_length, int base_offset) {
-      init(new byte[data_length+base_offset], base_offset);
-    }
-
-    /**
-     * Construct a message using data as the storage.
-     * The length of data determines the length of this message.
-     * @param data the storage for this message
-     */
-    public Message(byte[] data) {
-       init(data);
-    }
-    protected void init(byte[] data) {
-       init(data, 0);
-    }
-
-    /**
-     * Construct a message using data as the storage.
-     * Use the given base_offset as the base offset into the 
-     * data array. The data length will be (data.length - base_offset).
-     * @param data the storage for this message
-     * @param base_offset the base offset into the data array
-     */
-    public Message(byte[] data, int base_offset) {
-       init(data, base_offset);
-    }
-    protected void init(byte[] data, int base_offset) {
-       init(data, base_offset, data.length - base_offset);
-    }
-
-    /**
-     * Construct a message using data as the storage.
-     * Use the given base_offset as the base offset into the 
-     * data array, and the specified data length.
-     * @param data the storage for this message
-     * @param base_offset the base offset into the data array
-     * @param data_length the length of the message data
-     */
-    public Message(byte[] data, int base_offset, int data_length) {
-       init(data, base_offset, data_length);
-    }
-    protected void init(byte[] data, int base_offset, int data_length) {
-       this.data = data;
-       this.base_offset = base_offset;
-       this.data_length = data_length;
-       if (base_offset + data_length > data.length) throw new ArrayIndexOutOfBoundsException("Cannot create Message with base_offset "+base_offset+", data_length "+data_length+" and data array size "+data.length);
-    }
-
-    /**
-     * Construct an embedded message within the given 'msg'.
-     * Use the given base_offset as the base offset into the 
-     * data array, and the specified data length.
-     * @param msg the message to embed this message into
-     * @param base_offset the base offset into the data array
-     * @param data_length the length of the message data
-     */
-    public Message(Message msg, int base_offset, int data_length) {
-       init(msg, base_offset, data_length);
-    }
-    protected void init(Message msg, int base_offset, int data_length) {
-       init(msg.dataGet(), msg.base_offset+base_offset, data_length);
-    }
-
-    private Message cloneself() {
-       Message copy;
-
-       try {
-           copy = (Message)super.clone();
-       }
-       catch (CloneNotSupportedException e) {
-           System.err.println("Message: WARNING: CloneNotSupportedException in cloneself(): "+e);
-           System.err.println("Message: This is a bug - please contact dgay@intel-research.net");
-           copy = null;
-           System.exit(2);
-       }
-       return copy;
-    }
-
-    /**
-     * Clone this Message, including making a copy of its data
-     */
-    public Object clone() {
-       Message copy = cloneself();
-       copy.init((byte[])data.clone(), base_offset, data_length);
-       copy.am_type = this.am_type;
-       return copy;
-    }
-
-    /**
-     * Clone this Message, but give it a new unitialised data array of size
-     * size
-     * @param size size of the new data array
-     */
-    public Message clone(int size) {
-       Message copy = cloneself();
-       copy.init(new byte[size], 0, size);
-       copy.am_type = this.am_type;
-       return copy;
-    }
-
-    /**
-     * Copy new data for this message from 'data'. 
-     * Copies min(data.length, this.data_length) bytes.
-     * @param data the array containing the data to be copied
-     * @exception ArrayIndexOutOfBoundsException if any of
-     * data[0..getData().length - 1] are invalid
-     */
-    public void dataSet(byte[] data) {
-       dataSet(data, 0, this.base_offset, Math.min(this.data_length, data.length));
-    }
-
-    /**
-     * Copy new data for this message from offsetFrom in data to
-     * offsetTo in this message. Copies a total of length bytes
-     * @param data the array containing the data to be copied
-     * @param offsetFrom the offset in data to start copying from
-     * @param offsetTo the offset at which to start copying data into
-     * this message.
-     * @param length bytes are copied.
-     * @exception ArrayIndexOutOfBoundsException if any of
-     * the source or target indices are invalid
-     */
-    public void dataSet(byte[] data, int offsetFrom, int offsetTo, int length) {
-      System.arraycopy(data, offsetFrom, this.data, offsetTo+base_offset, length);
-    }
-
-    /**
-     * Copy new data for this message from the raw data in msg to
-     * offsetTo in this message. Copies a total of msg.dataLength() bytes
-     * @param msg the message containing the data to be copied
-     * @param offsetTo the offset at which to start copying data into
-     * this message.
-     * @exception ArrayIndexOutOfBoundsException if any of
-     * the target indices are invalid
-     */
-    public void dataSet(Message msg, int offsetTo) {
-      System.arraycopy(msg.dataGet(), msg.baseOffset(),
-                      this.data, offsetTo+base_offset,
-                      msg.dataLength());
-    }
-
-    /**
-     * Return the raw byte array representing the data of this message.
-     * Note that only indices in the range
-     * (this.baseOffset(), this.baseOffset()+this.dataLength()) are
-     * valid. 
-     */
-    public byte[] dataGet() {
-       return data;
-    }
-
-    /**
-     * Return the base offset into the data array for this message.
-     */
-    public int baseOffset() {
-        return base_offset;
-    }
-
-    /**
-     * Return the length of the data (in bytes) contained in this message.
-     */
-    public int dataLength() {
-        return data_length;
-    }
-
-    /**
-     * Return the active message type of this message (-1 if unknown)
-     */
-    public int amType() {
-       return am_type;
-    }
-
-    /**
-     * Set the active message type of this message
-     */
-    public void amTypeSet(int type) {
-      this.am_type = type;
-    }
-
-    // Check that length bits from offset are in bounds
-    private void checkBounds(int offset, int length) {
-       if (offset < 0 || length <= 0 || offset + length > (data_length * 8))
-         throw new ArrayIndexOutOfBoundsException("Message.checkBounds: bad offset ("+offset+") or length ("+length+"), for data_length "+data_length+ " in class " + this.getClass());
-    }
-
-    // Check that value is valid for a bitfield of length length
-    private void checkValue(int length, long value) {
-       if (length != 64 && (value < 0 || value >= 1L << length))
-           throw new IllegalArgumentException("Message.checkValue: bad length ("+length+" or value ("+value+")");
-    }
-
-    // Unsigned byte read
-    private int ubyte(int offset) {
-       int val = data[base_offset+offset];
-
-       if (val < 0) return val + 256;
-       else return val;
-    }
-
-    // ASSUMES: little endian bits & bytes for the methods without BE, and
-    //   big endian bits & bytes for the methods with BE
-
-    /**
-     * Read the length bit unsigned little-endian int at offset
-     * @param offset bit offset where the unsigned int starts
-     * @param length bit length of the unsigned int
-     * @exception ArrayIndexOutOfBoundsException for invalid offset, length
-     */
-    protected long getUIntElement(int offset, int length) {
-       checkBounds(offset, length);
-
-       int byteOffset = offset >> 3;
-       int bitOffset = offset & 7;
-       int shift = 0;
-       long val = 0;
-
-       // all in one byte case
-       if (length + bitOffset <= 8)
-           return (ubyte(byteOffset) >> bitOffset) & ((1 << length) - 1);
-
-       // get some high order bits
-       if (bitOffset > 0) {
-           val = ubyte(byteOffset) >> bitOffset;
-           byteOffset++;
-           shift += 8 - bitOffset;
-           length -= 8 - bitOffset;
-       }
-
-       while (length >= 8) {
-           val |= (long)ubyte(byteOffset++) << shift;
-           shift += 8;
-           length -= 8;
-       }
-
-       // data from last byte
-       if (length > 0)
-           val |= (long)(ubyte(byteOffset) & ((1 << length) - 1)) << shift;
-
-       return val;
-    }
-
-    /**
-     * Set the length bit unsigned little-endian int at offset to val
-     * @param offset bit offset where the unsigned int starts
-     * @param length bit length of the unsigned int
-     * @param val value to set the bit field to
-     * @exception ArrayIndexOutOfBoundsException for invalid offset, length
-     * @exception IllegalArgumentException if val is an out-of-range value
-     * for this bitfield
-     */
-    protected void setUIntElement(int offset, int length, long val) {
-       checkBounds(offset, length);
-       //checkValue(length, val);
-
-       int byteOffset = offset >> 3;
-       int bitOffset = offset & 7;
-       int shift = 0;
-
-       // all in one byte case
-       if (length + bitOffset <= 8) {
-           data[base_offset+byteOffset] = (byte)
-               ((ubyte(byteOffset) & ~(((1 << length) - 1) << bitOffset))
-                | val << bitOffset);
-           return;
-       }
-
-       // set some high order bits
-       if (bitOffset > 0) {
-           data[base_offset+byteOffset] = (byte)
-               ((ubyte(byteOffset) & ((1 << bitOffset) - 1)) | val << bitOffset);
-           byteOffset++;
-           shift += 8 - bitOffset;
-           length -= 8 - bitOffset;
-       }
-
-       while (length >= 8) {
-           data[base_offset+(byteOffset++)] = (byte)(val >> shift);
-           shift += 8;
-           length -= 8;
-       }
-
-       // data for last byte
-       if (length > 0)
-           data[base_offset+byteOffset] = (byte)
-               ((ubyte(byteOffset) & ~((1 << length) - 1)) | val >> shift);
-    }
-
-    /**
-     * Read the length bit signed little-endian int at offset
-     * @param offset bit offset where the signed int starts
-     * @param length bit length of the signed int
-     * @exception ArrayIndexOutOfBoundsException for invalid offset, length
-     */
-    protected long getSIntElement(int offset, int length)
-       throws ArrayIndexOutOfBoundsException {
-       long val = getUIntElement(offset, length);
-
-       if (length == 64)
-           return val;
-
-       if ((val & 1L << (length - 1)) != 0)
-           return val - (1L << length);
-
-       return val;
-    }
-
-    /**
-     * Set the length bit signed little-endian int at offset to val
-     * @param offset bit offset where the signed int starts
-     * @param length bit length of the signed int
-     * @param value value to set the bit field to
-     * @exception ArrayIndexOutOfBoundsException for invalid offset, length
-     * @exception IllegalArgumentException if val is an out-of-range value
-     * for this bitfield
-     */ 
-   protected void setSIntElement(int offset, int length, long value)
-       throws ArrayIndexOutOfBoundsException {
-       if (length != 64 && value >= 1L << (length - 1))
-           throw new IllegalArgumentException();
-
-       if (length != 64 && value < 0)
-           value += 1L << length;
-
-       setUIntElement(offset, length, value);
-    }
-
-    /**
-     * Read the length bit unsigned big-endian int at offset
-     * @param offset bit offset where the unsigned int starts. Note that
-     *   these are big-endian bit offsets: bit 0 is the MSB, bit 7 the LSB.
-     * @param length bit length of the unsigned int
-     * @exception ArrayIndexOutOfBoundsException for invalid offset, length
-     */
-    protected long getUIntBEElement(int offset, int length) {
-       checkBounds(offset, length);
-
-       int byteOffset = offset >> 3;
-       int bitOffset = offset & 7;
-       long val = 0;
-
-       // All in one byte case
-       if (length + bitOffset <= 8)
-           return (ubyte(byteOffset) >> (8 - bitOffset - length)) &
-               ((1 << length) - 1);
-
-       // get some high order bits
-       if (bitOffset > 0) {
-           length -= 8 - bitOffset;
-           val = (long)(ubyte(byteOffset) & ((1 << (8 - bitOffset)) - 1)) << length;
-           byteOffset++;
-       }
-
-       while (length >= 8) {
-           length -= 8;
-           val |= (long)ubyte(byteOffset++) << length;
-       }
-
-       // data from last byte
-       if (length > 0)
-           val |= ubyte(byteOffset) >> (8 - length);
-
-       return val;
-    }
-
-    /**
-     * Set the length bit unsigned big-endian int at offset to val
-     * @param offset bit offset where the unsigned int starts. Note that
-     *   these are big-endian bit offsets: bit 0 is the MSB, bit 7 the LSB.
-     * @param length bit length of the unsigned int
-     * @param val value to set the bit field to
-     * @exception ArrayIndexOutOfBoundsException for invalid offset, length
-     * @exception IllegalArgumentException if val is an out-of-range value
-     * for this bitfield
-     */
-    protected void setUIntBEElement(int offset, int length, long val) {
-       checkBounds(offset, length);
-       //checkValue(length, val);
-
-       int byteOffset = offset >> 3;
-       int bitOffset = offset & 7;
-       int shift = 0;
-
-       // all in one byte case
-       if (length + bitOffset <= 8) {
-           int mask = ((1 << length) - 1) << (8 - bitOffset - length);
-
-           data[base_offset+byteOffset] = (byte)
-               ((ubyte(byteOffset) & ~mask)
-                | val << (8 - bitOffset - length));
-           return;
-       }
-
-       // set some high order bits
-       if (bitOffset > 0) {
-           int mask = (1 << (8 - bitOffset)) - 1;
-
-           length -= 8 - bitOffset;
-           data[base_offset+byteOffset] = (byte)
-               (ubyte(byteOffset) & ~mask | val >> length);
-           byteOffset++;
-       }
-
-       while (length >= 8) {
-           length -= 8;
-           data[base_offset+(byteOffset++)] = (byte)(val >> length);
-       }
-
-       // data for last byte
-       if (length > 0) {
-           int mask = (1 << (8 - length)) - 1;
-
-           data[base_offset+byteOffset] = (byte)
-               ((ubyte(byteOffset) & mask) | val << (8 - length));
-       }
-    }
-
-    /**
-     * Read the length bit signed big-endian int at offset
-     * @param offset bit offset where the signed int starts
-     * @param length bit length of the signed int
-     * @exception ArrayIndexOutOfBoundsException for invalid offset, length
-     */
-    protected long getSIntBEElement(int offset, int length)
-       throws ArrayIndexOutOfBoundsException {
-       long val = getUIntBEElement(offset, length);
-
-       if (length == 64)
-           return val;
-
-       if ((val & 1L << (length - 1)) != 0)
-           return val - (1L << length);
-
-       return val;
-    }
-
-    /**
-     * Set the length bit signed big-endian int at offset to val
-     * @param offset bit offset where the signed int starts
-     * @param length bit length of the signed int
-     * @param value value to set the bit field to
-     * @exception ArrayIndexOutOfBoundsException for invalid offset, length
-     * @exception IllegalArgumentException if val is an out-of-range value
-     * for this bitfield
-     */ 
-   protected void setSIntBEElement(int offset, int length, long value)
-       throws ArrayIndexOutOfBoundsException {
-       if (length != 64 && value >= 1L << (length - 1))
-           throw new IllegalArgumentException();
-
-       if (length != 64 && value < 0)
-           value += 1L << length;
-
-       setUIntBEElement(offset, length, value);
-    }
-
-    /**
-     * Read the 32 bit IEEE float at offset
-     * @param offset bit offset where the float starts
-     * @param length is ignored
-     * @exception ArrayIndexOutOfBoundsException for invalid offset
-     */
-    protected float getFloatElement(int offset, int length)
-       throws ArrayIndexOutOfBoundsException {
-
-       return Float.intBitsToFloat((int)getUIntElement(offset, 32));
-    }
-
-    /**
-     * Set the 32 bit IEEE float at offset to value
-     * @param offset bit offset where the float starts
-     * @param length is ignored
-     * @param value value to store in bitfield
-     * @exception ArrayIndexOutOfBoundsException for invalid offset
-     */
-    protected void setFloatElement(int offset, int length, float value)
-       throws ArrayIndexOutOfBoundsException {
-
-       // using SInt because floatToRawIntBits might return a negative value
-       setSIntElement(offset, 32, Float.floatToRawIntBits(value));
-    }
+  /**
+   * The maximum number of characters read from an 8-bit array field being
+   * converted into a Java String.
+   */
+  public static final int MAX_CONVERTED_STRING_LENGTH = 512;
+
+  /**
+   * The underlying byte array storing the data for this message. This is
+   * private to enforce access to the data through the accessor methods in this
+   * class, which do bounds checking and manage the base_offset for embedded
+   * messages.
+   */
+  private byte[] data;
+
+  /**
+   * The base offset into the data. This allows the message data to exist at
+   * some non-zero offset into the actual data.
+   */
+  protected int base_offset;
+
+  /**
+   * The actual length of the message data. Must be less than or equal to
+   * (data.length - base_offset).
+   */
+  protected int data_length;
+
+  /**
+   * The AM type corresponding to this object. Set to -1 if no AM type is known.
+   */
+  protected int am_type;
+
+  /** The serial packet this message originated from */
+  private SerialPacket serialPacket;
+  
+  /** Limit no-arg instantiation. */
+  protected Message() {
+  }
+
+  /**
+   * Construct a new message of the given size.
+   * 
+   * @param data_length
+   *          The size of the message to create.
+   */
+  public Message(int data_length) {
+    init(data_length);
+  }
+
+  public void init(int data_length) {
+    init(new byte[data_length]);
+  }
+
+  /**
+   * Construct a new message of the given size and base offset. Allocates a new
+   * byte array of size data_length+base_offset.
+   * 
+   * @param data_length
+   *          The size of the message to create.
+   * @param base_offset
+   *          The base offset into the newly created message.
+   */
+  public Message(int data_length, int base_offset) {
+    init(data_length, base_offset);
+  }
+
+  protected void init(int data_length, int base_offset) {
+    init(new byte[data_length + base_offset], base_offset);
+  }
+
+  /**
+   * Construct a message using data as the storage. The length of data
+   * determines the length of this message.
+   * 
+   * @param data
+   *          the storage for this message
+   */
+  public Message(byte[] data) {
+    init(data);
+  }
+
+  protected void init(byte[] data) {
+    init(data, 0);
+  }
+
+  /**
+   * Construct a message using data as the storage. Use the given base_offset as
+   * the base offset into the data array. The data length will be (data.length -
+   * base_offset).
+   * 
+   * @param data
+   *          the storage for this message
+   * @param base_offset
+   *          the base offset into the data array
+   */
+  public Message(byte[] data, int base_offset) {
+    init(data, base_offset);
+  }
+
+  protected void init(byte[] data, int base_offset) {
+    init(data, base_offset, data.length - base_offset);
+  }
+
+  /**
+   * Construct a message using data as the storage. Use the given base_offset as
+   * the base offset into the data array, and the specified data length.
+   * 
+   * @param data
+   *          the storage for this message
+   * @param base_offset
+   *          the base offset into the data array
+   * @param data_length
+   *          the length of the message data
+   */
+  public Message(byte[] data, int base_offset, int data_length) {
+    init(data, base_offset, data_length);
+  }
+
+  protected void init(byte[] data, int base_offset, int data_length) {
+    this.data = data;
+    this.base_offset = base_offset;
+    this.data_length = data_length;
+    if (base_offset + data_length > data.length)
+      throw new ArrayIndexOutOfBoundsException(
+          "Cannot create Message with base_offset " + base_offset
+              + ", data_length " + data_length + " and data array size "
+              + data.length);
+  }
+
+  /**
+   * Construct an embedded message within the given 'msg'. Use the given
+   * base_offset as the base offset into the data array, and the specified data
+   * length.
+   * 
+   * @param msg
+   *          the message to embed this message into
+   * @param base_offset
+   *          the base offset into the data array
+   * @param data_length
+   *          the length of the message data
+   */
+  public Message(Message msg, int base_offset, int data_length) {
+    init(msg, base_offset, data_length);
+  }
+
+  protected void init(Message msg, int base_offset, int data_length) {
+    init(msg.dataGet(), msg.base_offset + base_offset, data_length);
+  }
+
+  private Message cloneself() {
+    Message copy;
+
+    try {
+      copy = (Message) super.clone();
+    } catch (CloneNotSupportedException e) {
+      System.err
+          .println("Message: WARNING: CloneNotSupportedException in cloneself(): "
+              + e);
+      System.err
+          .println("Message: This is a bug - please contact dgay@intel-research.net");
+      copy = null;
+      System.exit(2);
+    }
+    return copy;
+  }
+
+  /**
+   * Clone this Message, including making a copy of its data
+   */
+  public Object clone() {
+    Message copy = cloneself();
+    copy.init((byte[]) data.clone(), base_offset, data_length);
+    copy.am_type = this.am_type;
+    return copy;
+  }
+
+  /**
+   * Clone this Message, but give it a new unitialised data array of size size
+   * 
+   * @param size
+   *          size of the new data array
+   */
+  public Message clone(int size) {
+    Message copy = cloneself();
+    copy.init(new byte[size], 0, size);
+    copy.am_type = this.am_type;
+    return copy;
+  }
+
+  /**
+   * Copy new data for this message from 'data'. Copies min(data.length,
+   * this.data_length) bytes.
+   * 
+   * @param data
+   *          the array containing the data to be copied
+   * @exception ArrayIndexOutOfBoundsException
+   *              if any of data[0..getData().length - 1] are invalid
+   */
+  public void dataSet(byte[] data) {
+    dataSet(data, 0, this.base_offset, Math.min(this.data_length, data.length));
+  }
+
+  /**
+   * Copy new data for this message from offsetFrom in data to offsetTo in this
+   * message. Copies a total of length bytes
+   * 
+   * @param data
+   *          the array containing the data to be copied
+   * @param offsetFrom
+   *          the offset in data to start copying from
+   * @param offsetTo
+   *          the offset at which to start copying data into this message.
+   * @param length
+   *          bytes are copied.
+   * @exception ArrayIndexOutOfBoundsException
+   *              if any of the source or target indices are invalid
+   */
+  public void dataSet(byte[] data, int offsetFrom, int offsetTo, int length) {
+    System.arraycopy(data, offsetFrom, this.data, offsetTo + base_offset,
+        length);
+  }
+
+  /**
+   * Copy new data for this message from the raw data in msg to offsetTo in this
+   * message. Copies a total of msg.dataLength() bytes
+   * 
+   * @param msg
+   *          the message containing the data to be copied
+   * @param offsetTo
+   *          the offset at which to start copying data into this message.
+   * @exception ArrayIndexOutOfBoundsException
+   *              if any of the target indices are invalid
+   */
+  public void dataSet(Message msg, int offsetTo) {
+    System.arraycopy(msg.dataGet(), msg.baseOffset(), this.data, offsetTo
+        + base_offset, msg.dataLength());
+  }
+
+  /**
+   * Return the raw byte array representing the data of this message. Note that
+   * only indices in the range (this.baseOffset(),
+   * this.baseOffset()+this.dataLength()) are valid.
+   */
+  public byte[] dataGet() {
+    return data;
+  }
+
+  /**
+   * Return the base offset into the data array for this message.
+   */
+  public int baseOffset() {
+    return base_offset;
+  }
+
+  /**
+   * Return the length of the data (in bytes) contained in this message.
+   */
+  public int dataLength() {
+    return data_length;
+  }
+
+  /**
+   * Return the active message type of this message (-1 if unknown)
+   */
+  public int amType() {
+    return am_type;
+  }
+
+  /**
+   * Set the active message type of this message
+   */
+  public void amTypeSet(int type) {
+    this.am_type = type;
+  }
+
+  // Check that length bits from offset are in bounds
+  private void checkBounds(int offset, int length) {
+    if (offset < 0 || length <= 0 || offset + length > (data_length * 8))
+      throw new ArrayIndexOutOfBoundsException(
+          "Message.checkBounds: bad offset (" + offset + ") or length ("
+              + length + "), for data_length " + data_length + " in class "
+              + this.getClass());
+  }
+
+  // Check that value is valid for a bitfield of length length
+  private void checkValue(int length, long value) {
+    if (length != 64 && (value < 0 || value >= 1L << length))
+      throw new IllegalArgumentException("Message.checkValue: bad length ("
+          + length + " or value (" + value + ")");
+  }
+
+  // Unsigned byte read
+  private int ubyte(int offset) {
+    int val = data[base_offset + offset];
+
+    if (val < 0)
+      return val + 256;
+    else
+      return val;
+  }
+
+  // ASSUMES: little endian bits & bytes for the methods without BE, and
+  // big endian bits & bytes for the methods with BE
+
+  /**
+   * Read the length bit unsigned little-endian int at offset
+   * 
+   * @param offset
+   *          bit offset where the unsigned int starts
+   * @param length
+   *          bit length of the unsigned int
+   * @exception ArrayIndexOutOfBoundsException
+   *              for invalid offset, length
+   */
+  protected long getUIntElement(int offset, int length) {
+    checkBounds(offset, length);
+
+    int byteOffset = offset >> 3;
+    int bitOffset = offset & 7;
+    int shift = 0;
+    long val = 0;
+
+    // all in one byte case
+    if (length + bitOffset <= 8)
+      return (ubyte(byteOffset) >> bitOffset) & ((1 << length) - 1);
+
+    // get some high order bits
+    if (bitOffset > 0) {
+      val = ubyte(byteOffset) >> bitOffset;
+      byteOffset++;
+      shift += 8 - bitOffset;
+      length -= 8 - bitOffset;
+    }
+
+    while (length >= 8) {
+      val |= (long) ubyte(byteOffset++) << shift;
+      shift += 8;
+      length -= 8;
+    }
+
+    // data from last byte
+    if (length > 0)
+      val |= (long) (ubyte(byteOffset) & ((1 << length) - 1)) << shift;
+
+    return val;
+  }
+
+  /**
+   * Set the length bit unsigned little-endian int at offset to val
+   * 
+   * @param offset
+   *          bit offset where the unsigned int starts
+   * @param length
+   *          bit length of the unsigned int
+   * @param val
+   *          value to set the bit field to
+   * @exception ArrayIndexOutOfBoundsException
+   *              for invalid offset, length
+   * @exception IllegalArgumentException
+   *              if val is an out-of-range value for this bitfield
+   */
+  protected void setUIntElement(int offset, int length, long val) {
+    checkBounds(offset, length);
+    // checkValue(length, val);
+
+    int byteOffset = offset >> 3;
+    int bitOffset = offset & 7;
+    int shift = 0;
+
+    // all in one byte case
+    if (length + bitOffset <= 8) {
+      data[base_offset + byteOffset] = (byte) ((ubyte(byteOffset) & ~(((1 << length) - 1) << bitOffset)) | val << bitOffset);
+      return;
+    }
+
+    // set some high order bits
+    if (bitOffset > 0) {
+      data[base_offset + byteOffset] = (byte) ((ubyte(byteOffset) & ((1 << bitOffset) - 1)) | val << bitOffset);
+      byteOffset++;
+      shift += 8 - bitOffset;
+      length -= 8 - bitOffset;
+    }
+
+    while (length >= 8) {
+      data[base_offset + (byteOffset++)] = (byte) (val >> shift);
+      shift += 8;
+      length -= 8;
+    }
+
+    // data for last byte
+    if (length > 0)
+      data[base_offset + byteOffset] = (byte) ((ubyte(byteOffset) & ~((1 << length) - 1)) | val >> shift);
+  }
+
+  /**
+   * Read the length bit signed little-endian int at offset
+   * 
+   * @param offset
+   *          bit offset where the signed int starts
+   * @param length
+   *          bit length of the signed int
+   * @exception ArrayIndexOutOfBoundsException
+   *              for invalid offset, length
+   */
+  protected long getSIntElement(int offset, int length)
+      throws ArrayIndexOutOfBoundsException {
+    long val = getUIntElement(offset, length);
+
+    if (length == 64)
+      return val;
+
+    if ((val & 1L << (length - 1)) != 0)
+      return val - (1L << length);
+
+    return val;
+  }
+
+  /**
+   * Set the length bit signed little-endian int at offset to val
+   * 
+   * @param offset
+   *          bit offset where the signed int starts
+   * @param length
+   *          bit length of the signed int
+   * @param value
+   *          value to set the bit field to
+   * @exception ArrayIndexOutOfBoundsException
+   *              for invalid offset, length
+   * @exception IllegalArgumentException
+   *              if val is an out-of-range value for this bitfield
+   */
+  protected void setSIntElement(int offset, int length, long value)
+      throws ArrayIndexOutOfBoundsException {
+    if (length != 64 && value >= 1L << (length - 1))
+      throw new IllegalArgumentException();
+
+    if (length != 64 && value < 0)
+      value += 1L << length;
+
+    setUIntElement(offset, length, value);
+  }
+
+  /**
+   * Read the length bit unsigned big-endian int at offset
+   * 
+   * @param offset
+   *          bit offset where the unsigned int starts. Note that these are
+   *          big-endian bit offsets: bit 0 is the MSB, bit 7 the LSB.
+   * @param length
+   *          bit length of the unsigned int
+   * @exception ArrayIndexOutOfBoundsException
+   *              for invalid offset, length
+   */
+  protected long getUIntBEElement(int offset, int length) {
+    checkBounds(offset, length);
+
+    int byteOffset = offset >> 3;
+    int bitOffset = offset & 7;
+    long val = 0;
+
+    // All in one byte case
+    if (length + bitOffset <= 8)
+      return (ubyte(byteOffset) >> (8 - bitOffset - length))
+          & ((1 << length) - 1);
+
+    // get some high order bits
+    if (bitOffset > 0) {
+      length -= 8 - bitOffset;
+      val = (long) (ubyte(byteOffset) & ((1 << (8 - bitOffset)) - 1)) << length;
+      byteOffset++;
+    }
+
+    while (length >= 8) {
+      length -= 8;
+      val |= (long) ubyte(byteOffset++) << length;
+    }
+
+    // data from last byte
+    if (length > 0)
+      val |= ubyte(byteOffset) >> (8 - length);
+
+    return val;
+  }
+
+  /**
+   * Set the length bit unsigned big-endian int at offset to val
+   * 
+   * @param offset
+   *          bit offset where the unsigned int starts. Note that these are
+   *          big-endian bit offsets: bit 0 is the MSB, bit 7 the LSB.
+   * @param length
+   *          bit length of the unsigned int
+   * @param val
+   *          value to set the bit field to
+   * @exception ArrayIndexOutOfBoundsException
+   *              for invalid offset, length
+   * @exception IllegalArgumentException
+   *              if val is an out-of-range value for this bitfield
+   */
+  protected void setUIntBEElement(int offset, int length, long val) {
+    checkBounds(offset, length);
+    // checkValue(length, val);
+
+    int byteOffset = offset >> 3;
+    int bitOffset = offset & 7;
+    int shift = 0;
+
+    // all in one byte case
+    if (length + bitOffset <= 8) {
+      int mask = ((1 << length) - 1) << (8 - bitOffset - length);
+
+      data[base_offset + byteOffset] = (byte) ((ubyte(byteOffset) & ~mask) | val << (8 - bitOffset - length));
+      return;
+    }
+
+    // set some high order bits
+    if (bitOffset > 0) {
+      int mask = (1 << (8 - bitOffset)) - 1;
+
+      length -= 8 - bitOffset;
+      data[base_offset + byteOffset] = (byte) (ubyte(byteOffset) & ~mask | val >> length);
+      byteOffset++;
+    }
+
+    while (length >= 8) {
+      length -= 8;
+      data[base_offset + (byteOffset++)] = (byte) (val >> length);
+    }
+
+    // data for last byte
+    if (length > 0) {
+      int mask = (1 << (8 - length)) - 1;
+
+      data[base_offset + byteOffset] = (byte) ((ubyte(byteOffset) & mask) | val << (8 - length));
+    }
+  }
+
+  /**
+   * Read the length bit signed big-endian int at offset
+   * 
+   * @param offset
+   *          bit offset where the signed int starts
+   * @param length
+   *          bit length of the signed int
+   * @exception ArrayIndexOutOfBoundsException
+   *              for invalid offset, length
+   */
+  protected long getSIntBEElement(int offset, int length)
+      throws ArrayIndexOutOfBoundsException {
+    long val = getUIntBEElement(offset, length);
+
+    if (length == 64)
+      return val;
+
+    if ((val & 1L << (length - 1)) != 0)
+      return val - (1L << length);
+
+    return val;
+  }
+
+  /**
+   * Set the length bit signed big-endian int at offset to val
+   * 
+   * @param offset
+   *          bit offset where the signed int starts
+   * @param length
+   *          bit length of the signed int
+   * @param value
+   *          value to set the bit field to
+   * @exception ArrayIndexOutOfBoundsException
+   *              for invalid offset, length
+   * @exception IllegalArgumentException
+   *              if val is an out-of-range value for this bitfield
+   */
+  protected void setSIntBEElement(int offset, int length, long value)
+      throws ArrayIndexOutOfBoundsException {
+    if (length != 64 && value >= 1L << (length - 1))
+      throw new IllegalArgumentException();
+
+    if (length != 64 && value < 0)
+      value += 1L << length;
+
+    setUIntBEElement(offset, length, value);
+  }
+
+  /**
+   * Read the 32 bit IEEE float at offset
+   * 
+   * @param offset
+   *          bit offset where the float starts
+   * @param length
+   *          is ignored
+   * @exception ArrayIndexOutOfBoundsException
+   *              for invalid offset
+   */
+  protected float getFloatElement(int offset, int length)
+      throws ArrayIndexOutOfBoundsException {
+
+    return Float.intBitsToFloat((int) getUIntElement(offset, 32));
+  }
+
+  /**
+   * Set the 32 bit IEEE float at offset to value
+   * 
+   * @param offset
+   *          bit offset where the float starts
+   * @param length
+   *          is ignored
+   * @param value
+   *          value to store in bitfield
+   * @exception ArrayIndexOutOfBoundsException
+   *              for invalid offset
+   */
+  protected void setFloatElement(int offset, int length, float value)
+      throws ArrayIndexOutOfBoundsException {
+
+    // using SInt because floatToRawIntBits might return a negative value
+    setSIntElement(offset, 32, Float.floatToRawIntBits(value));
+  }
+
+  /**
+   * 
+   * @return the SerialPacket this message originated from, if it was set
+   *     externally
+   */
+  public SerialPacket getSerialPacket() {
+    return serialPacket;
+  }
+
+  /**
+   * 
+   * @param mySerialPacket the SerialPacket this message originated from
+   */
+  protected void setSerialPacket(SerialPacket mySerialPacket) {
+    serialPacket = mySerialPacket;
+  }
+  
+  
 }
index 32dba5b98e8609a9e0f38ee818b921db92fb71a3..6676fc5aceda1d3c550337b2980fe3611192b028 100644 (file)
@@ -43,147 +43,171 @@ package net.tinyos.message;
 import net.tinyos.util.*;
 import net.tinyos.packet.*;
 import java.util.*;
-import java.io.*;
 
 /**
  * Receiver class (receive tinyos messages).
- *
- * A receiver class provides a simple interface built on Message for
- * receiving tinyos messages from a SerialForwarder
- *
- * @version    1, 15 Jul 2002
- * @author     David Gay
+ * 
+ * A receiver class provides a simple interface built on Message for receiving
+ * tinyos messages from a SerialForwarder
+ * 
+ * @version 1, 15 Jul 2002
+ * @author David Gay
  */
 public class Receiver implements PacketListenerIF {
-    public static final boolean DEBUG = false;
-    public static final boolean DISPLAY_ERROR_MSGS = true;
-
-    Hashtable templateTbl; // Mapping from AM type to msgTemplate
-    PhoenixSource source;
-    /**
-     * Inner class representing a single MessageListener and its
-     * associated Message template.
-     */
-    class msgTemplate {
-       Message template;
-       MessageListener listener;
-       msgTemplate(Message template, MessageListener listener) {
-           this.template = template;
-           this.listener = listener;
-       }
-
-       public boolean equals(Object o) {
-           try {
-               msgTemplate mt = (msgTemplate)o;
-               if (mt.template.getClass().equals(this.template.getClass()) &&
-                   mt.listener.equals(this.listener)) {
-                   return true;
-               }
-           } catch (Exception e) {
-               return false;
-           }
-           return false;
-       }
-
-       public int hashCode() {
-           return listener.hashCode();
-       }
-    }
+  public static final boolean DEBUG = false;
 
-    /**
-     * Create a receiver messages from forwarder of any group id and
-     * of active message type m.getType()
-     * When such a message is received, a new instance of m's class is
-     * created with the received data and send to listener.messageReceived
-     * @param forwarder packet source to listen to
-     */
-    public Receiver(PhoenixSource forwarder) {
-       this.templateTbl = new Hashtable();
-       this.source = forwarder;
-       forwarder.registerPacketListener(this);
-    }
+  public static final boolean DISPLAY_ERROR_MSGS = true;
 
-    /**
-     * Register a particular listener for a particular message type.
-     * More than one listener can be registered for each message type.
-     * @param template specify message type and template we're listening for
-     * @param listener destination for received messages
-     */
-    public void registerListener(Message template, MessageListener listener) {
-       Integer amType = new Integer(template.amType());
-       Vector vec = (Vector)templateTbl.get(amType);
-       if (vec == null) {
-           vec = new Vector();
-       }
-       vec.addElement(new msgTemplate(template, listener));
-       templateTbl.put(amType, vec);
-    }
+  Hashtable templateTbl; // Mapping from AM type to msgTemplate
 
-    /**
-     * Stop listening for messages of the given type with the given listener.
-     * @param template specify message type and template we're listening for
-     * @param listener destination for received messages
-     */
-    public void deregisterListener(Message template, MessageListener listener) {
-       Integer amType = new Integer(template.amType());
-       Vector vec = (Vector)templateTbl.get(amType);
-       if (vec == null) {
-           throw new IllegalArgumentException("No listeners registered for message type "+template.getClass().getName()+" (AM type "+template.amType()+")");
-       }
-       msgTemplate mt = new msgTemplate(template, listener);
-       // Remove all occurrences
-       while (vec.removeElement(mt)) ;
-       if (vec.size() == 0) templateTbl.remove(amType);
+  PhoenixSource source;
+
+  /**
+   * Inner class representing a single MessageListener and its associated
+   * Message template.
+   */
+  class msgTemplate {
+    Message template;
+
+    MessageListener listener;
+
+    msgTemplate(Message template, MessageListener listener) {
+      this.template = template;
+      this.listener = listener;
     }
 
-    private void error(msgTemplate temp, String msg) {
-       System.err.println("receive error for " + temp.template.getClass().getName() +
-                          " (AM type " + temp.template.amType() +
-                          "): " + msg);
+    public boolean equals(Object o) {
+      try {
+        msgTemplate mt = (msgTemplate) o;
+        if (mt.template.getClass().equals(this.template.getClass())
+            && mt.listener.equals(this.listener)) {
+          return true;
+        }
+      } catch (Exception e) {
+        return false;
+      }
+      return false;
     }
 
-    public void packetReceived(byte[] packet) {
-       if (DEBUG) Dump.dump("Received message", packet);
-
-       if (packet[0] != Serial.TOS_SERIAL_ACTIVE_MESSAGE_ID)
-           return; // not for us.
-
-       SerialPacket msg = new SerialPacket(packet, 1);
-       Integer type = new Integer(msg.get_header_type());
-       Vector vec = (Vector)templateTbl.get(type);
-       if (vec == null) {
-           if (DEBUG) Dump.dump("Received packet with type " + type +
-                                ", but no listeners registered", packet);
-           return;
-       }
-       int length = msg.get_header_length();
-
-       Enumeration en = vec.elements();
-       while (en.hasMoreElements()) {
-           msgTemplate temp = (msgTemplate)en.nextElement();
-
-           Message received;
-
-           // Erk - end up cloning the message multiple times in case
-           // different templates used for different listeners
-           try {
-               received = temp.template.clone(length);
-               received.dataSet(msg.dataGet(), msg.offset_data(0) + msg.baseOffset(), 0, length);
-           } catch (ArrayIndexOutOfBoundsException e) {
-               error(temp, "invalid length message received (too long)");
-               continue;
-           } catch (Exception e) {
-               error(temp, "couldn't clone message!");
-               continue;
-           }
-
-           /* Messages that are longer than the template might have
-              a variable-sized array at their end */
-           if (temp.template.dataGet().length > length) {
-               error(temp, "invalid length message received (too short)");
-               continue;
-           }
-           temp.listener.messageReceived(msg.get_header_dest(), received);
-       }
+    public int hashCode() {
+      return listener.hashCode();
+    }
+  }
+
+  /**
+   * Create a receiver messages from forwarder of any group id and of active
+   * message type m.getType() When such a message is received, a new instance of
+   * m's class is created with the received data and send to
+   * listener.messageReceived
+   * 
+   * @param forwarder
+   *          packet source to listen to
+   */
+  public Receiver(PhoenixSource forwarder) {
+    this.templateTbl = new Hashtable();
+    this.source = forwarder;
+    forwarder.registerPacketListener(this);
+  }
+
+  /**
+   * Register a particular listener for a particular message type. More than one
+   * listener can be registered for each message type.
+   * 
+   * @param template
+   *          specify message type and template we're listening for
+   * @param listener
+   *          destination for received messages
+   */
+  public void registerListener(Message template, MessageListener listener) {
+    Integer amType = new Integer(template.amType());
+    Vector vec = (Vector) templateTbl.get(amType);
+    if (vec == null) {
+      vec = new Vector();
+    }
+    vec.addElement(new msgTemplate(template, listener));
+    templateTbl.put(amType, vec);
+  }
+
+  /**
+   * Stop listening for messages of the given type with the given listener.
+   * 
+   * @param template
+   *          specify message type and template we're listening for
+   * @param listener
+   *          destination for received messages
+   */
+  public void deregisterListener(Message template, MessageListener listener) {
+    Integer amType = new Integer(template.amType());
+    Vector vec = (Vector) templateTbl.get(amType);
+    if (vec == null) {
+      throw new IllegalArgumentException(
+          "No listeners registered for message type "
+              + template.getClass().getName() + " (AM type "
+              + template.amType() + ")");
+    }
+    msgTemplate mt = new msgTemplate(template, listener);
+    // Remove all occurrences
+    while (vec.removeElement(mt))
+      ;
+    if (vec.size() == 0)
+      templateTbl.remove(amType);
+  }
+
+  private void error(msgTemplate temp, String msg) {
+    System.err.println("receive error for "
+        + temp.template.getClass().getName() + " (AM type "
+        + temp.template.amType() + "): " + msg);
+  }
+
+  public void packetReceived(byte[] packet) {
+    if (DEBUG)
+      Dump.dump("Received message", packet);
+
+    if (packet[0] != Serial.TOS_SERIAL_ACTIVE_MESSAGE_ID)
+      return; // not for us.
+
+    SerialPacket msg = new SerialPacket(packet, 1);
+    Integer type = new Integer(msg.get_header_type());
+    Vector vec = (Vector) templateTbl.get(type);
+    if (vec == null) {
+      if (DEBUG)
+        Dump.dump("Received packet with type " + type
+            + ", but no listeners registered", packet);
+      return;
+    }
+    int length = msg.get_header_length();
+
+    Enumeration en = vec.elements();
+    while (en.hasMoreElements()) {
+      msgTemplate temp = (msgTemplate) en.nextElement();
+
+      Message received;
+
+      // Erk - end up cloning the message multiple times in case
+      // different templates used for different listeners
+      try {
+        received = temp.template.clone(length);
+        received.dataSet(msg.dataGet(), SerialPacket.offset_data(0) + msg.baseOffset(),
+            0, length);
+        received.setSerialPacket(msg); 
+        
+      } catch (ArrayIndexOutOfBoundsException e) {
+        error(temp, "invalid length message received (too long)");
+        continue;
+      } catch (Exception e) {
+        error(temp, "couldn't clone message!");
+        continue;
+      }
+
+      /*
+       * Messages that are longer than the template might have a variable-sized
+       * array at their end
+       */
+      if (temp.template.dataGet().length > length) {
+        error(temp, "invalid length message received (too short)");
+        continue;
+      }
+      temp.listener.messageReceived(msg.get_header_dest(), received);
     }
+  }
 }