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;
+ }
+
+
}
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);
}
+ }
}