From 995837044ca8b4f298f49e7d69f3b1108247060c Mon Sep 17 00:00:00 2001 From: rincon Date: Tue, 29 May 2007 16:44:50 +0000 Subject: [PATCH] Added getSerialPacket() and setSerialPacket() methods to the Message class so we can access packet header information from the Message itself. --- .../sdk/java/net/tinyos/message/Message.java | 1173 +++++++++-------- .../sdk/java/net/tinyos/message/Receiver.java | 284 ++-- 2 files changed, 791 insertions(+), 666 deletions(-) diff --git a/support/sdk/java/net/tinyos/message/Message.java b/support/sdk/java/net/tinyos/message/Message.java index 0ebb5080..a5fdd449 100644 --- a/support/sdk/java/net/tinyos/message/Message.java +++ b/support/sdk/java/net/tinyos/message/Message.java @@ -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; + } + + } diff --git a/support/sdk/java/net/tinyos/message/Receiver.java b/support/sdk/java/net/tinyos/message/Receiver.java index 32dba5b9..6676fc5a 100644 --- a/support/sdk/java/net/tinyos/message/Receiver.java +++ b/support/sdk/java/net/tinyos/message/Receiver.java @@ -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); } + } } -- 2.39.2