From: razvanm Date: Mon, 19 May 2008 21:25:08 +0000 (+0000) Subject: Merge of the latest Deluge T2. X-Git-Tag: release_tinyos_2_1_0_0~395 X-Git-Url: https://oss.titaniummirror.com/gitweb/?p=tinyos-2.x.git;a=commitdiff_plain;h=62b84950912c1c033c401fb0b2a1efaceec78280 Merge of the latest Deluge T2. --- diff --git a/apps/tests/deluge/Blink/Makefile b/apps/tests/deluge/Blink/Makefile index 5a995f0b..6f7acb39 100644 --- a/apps/tests/deluge/Blink/Makefile +++ b/apps/tests/deluge/Blink/Makefile @@ -1,6 +1,7 @@ COMPONENT=BlinkAppC TINYOS_NP=BNP -CFLAGS += -DDELUGE_BASESTATION +#CFLAGS += -DDELUGE_BASESTATION +#CFLAGS += -DDELUGE_LIGHT_BASESTATION include $(MAKERULES) diff --git a/apps/tests/deluge/Blink/burn b/apps/tests/deluge/Blink/burn index f0aaddce..1e82f5d3 100755 --- a/apps/tests/deluge/Blink/burn +++ b/apps/tests/deluge/Blink/burn @@ -18,17 +18,24 @@ if [[ ! -x ${TOS_DELUGE} ]] ; then TOS_DELUGE=../../../../tools/tinyos/misc/tos-deluge fi -if [ $# -ne 2 ]; then - echo "Usage: $0 " +if [[ $# -ne 2 && $# -ne 3 ]]; then + echo "Usage: $0 [] " echo " /dev/ttyUSB0" - echo " micaz or telosb" + echo " /dev/ttyUSB1" + echo " micaz, telosb or iris" exit 2 fi -PORT=$1 +PPORT=$1 +CPORT=$1 PLATFORM=$2 -if [ ${PLATFORM} != 'micaz' -a ${PLATFORM} != 'telosb' ]; then +if [ $# -eq 3 ]; then + CPORT=$2 + PLATFORM=$3 +fi + +if [ ${PLATFORM} != 'micaz' -a ${PLATFORM} != 'telosb' -a ${PLATFORM} != 'iris' ]; then echo "\"${PLATFORM}\" is not a supported platform" exit 2 fi @@ -44,12 +51,16 @@ make clean echo ============================ Compile and load Blink ============================ if [ $PLATFORM == 'micaz' ] then - CFLAGS=-DDELUGE_BASESTATION make ${PLATFORM} install mib510,${PORT} + CFLAGS=-DDELUGE_BASESTATION make ${PLATFORM} install mib510,${PPORT} elif [ $PLATFORM == 'telosb' ] then - CFLAGS=-DDELUGE_BASESTATION make ${PLATFORM} install bsl,${PORT} + CFLAGS=-DDELUGE_BASESTATION make ${PLATFORM} install bsl,${PPORT} +elif [ $PLATFORM == 'iris' ] +then + CFLAGS=-DDELUGE_BASESTATION make ${PLATFORM} install mib510,${PPORT} fi + echo ' +-------------------------------------------------------+' echo ' | |' echo ' | At this point the first led (red) should be blinking. |' @@ -63,7 +74,7 @@ echo ============================= Compile a new Blink ======================== CFLAGS=-DBLINK_REVERSE\ -DDELUGE_BASESTATION make ${PLATFORM} echo =============================== Upload the image =============================== -${TOS_DELUGE} ${PORT} ${PLATFORM} -i 1 build/${PLATFORM}/tos_image.xml +${TOS_DELUGE} ${CPORT} ${PLATFORM} -i 1 build/${PLATFORM}/tos_image.xml echo ' +----------------------------------------------------------------+' echo ' | |' @@ -80,4 +91,4 @@ echo ' +----------------------------------------------------------------+' read echo =========================== Reboot the base station ============================ -${TOS_DELUGE} ${PORT} ${PLATFORM} -r 1 +${TOS_DELUGE} ${CPORT} ${PLATFORM} -r 1 diff --git a/apps/tests/deluge/Blink/burn-net b/apps/tests/deluge/Blink/burn-net index 0d94b40c..cc146661 100755 --- a/apps/tests/deluge/Blink/burn-net +++ b/apps/tests/deluge/Blink/burn-net @@ -7,7 +7,7 @@ fi if [ $# -ne 2 ]; then echo "Usage: $0 " - echo " micaz or telosb" + echo " micaz, telosb or iris" echo " how many motes will be used in the test" exit 2 fi @@ -15,7 +15,7 @@ fi PLATFORM=$1 NO_MOTES=$2 -if [ ${PLATFORM} != 'micaz' -a ${PLATFORM} != 'telosb' ]; then +if [ ${PLATFORM} != 'micaz' -a ${PLATFORM} != 'telosb' -a ${PLATFORM} != 'iris' ]; then echo "\"${PLAFTORM}\" is not a supported platform" exit 2 fi @@ -28,29 +28,35 @@ fi echo ================================ Compile Blink ================================= make clean -CFLAGS=-DDELUGE_BASESTATION make ${PLATFORM} ID=0 function burn_one() { ID=`expr $ID + 1` - echo -n ">>> Please plug mote $ID and type the port to continue: " + echo -n ">>> Please plug mote $ID and type the programming port to continue: " read PORT if [ ${PLATFORM} == 'micaz' ] then - CFLAGS=-DDELUGE_BASESTATION make ${PLATFORM} reinstall,$ID mib510,${PORT} + CFLAGS=$1 make ${PLATFORM} install,$ID mib510,${PORT} elif [ ${PLATFORM} == 'telosb' ] then - CFLAGS=-DDELUGE_BASESTATION make ${PLATFORM} reinstall,$ID bsl,${PORT} + CFLAGS=$1 make ${PLATFORM} install,$ID bsl,${PORT} + elif [ ${PLATFORM} == 'iris' ] + then + CFLAGS=$1 make ${PLATFORM} install,$ID mib510,${PORT} fi - } -while [[ ${NO_MOTES} > 0 ]] +while [[ ${NO_MOTES} > 1 ]] do - burn_one + burn_one -DDELUGE_LIGHT_BASESTATION NO_MOTES=`expr ${NO_MOTES} - 1` done +echo ">>> Note: this last mote will be the basestation! <<<" +burn_one -DDELUGE_BASESTATION +echo -n ">>> Please plug mote $ID and type the communication port to continue: " +read PORT +BASESTATION_PORT=$PORT echo ' +------------------------------------------------------------------------+' echo ' | |' @@ -62,10 +68,10 @@ echo ' +---------------------------------------------------------------------- read echo ============================= Compile a new Blink ============================== -CFLAGS=-DBLINK_REVERSE\ -DDELUGE_BASESTATION make ${PLATFORM} +CFLAGS=-DBLINK_REVERSE\ -DDELUGE_LIGHT_BASESTATION make ${PLATFORM} echo ========= Upload the new image to the external flash of the last mote ========== -${TOS_DELUGE} ${PORT} ${PLATFORM} -i 1 build/${PLATFORM}/tos_image.xml +${TOS_DELUGE} ${BASESTATION_PORT} ${PLATFORM} -i 1 build/${PLATFORM}/tos_image.xml echo ' +-----------------------------------------------------+' echo ' | |' @@ -76,11 +82,10 @@ echo ' | |' echo ' | Press ENTER to continue... |' echo ' | |' echo ' +-----------------------------------------------------+' - read echo ============================= Start dissemination ============================== -${TOS_DELUGE} ${PORT} ${PLATFORM} -dr 1 +${TOS_DELUGE} ${BASESTATION_PORT} ${PLATFORM} -dr 1 echo ' +------------------------------------------------------------+' echo ' | |' diff --git a/tools/tinyos/misc/Makefile.am b/tools/tinyos/misc/Makefile.am index 276314be..8dfc65b5 100644 --- a/tools/tinyos/misc/Makefile.am +++ b/tools/tinyos/misc/Makefile.am @@ -34,4 +34,4 @@ bin_SCRIPTS = tos-ident-flags \ bin_PROGRAMS = tos-serial-debug pythondir = $(bindir) -python_DATA = tinyos.py +python_DATA = tos.py diff --git a/tools/tinyos/misc/tinyos.py b/tools/tinyos/misc/tinyos.py deleted file mode 100644 index c33a8dbe..00000000 --- a/tools/tinyos/misc/tinyos.py +++ /dev/null @@ -1,459 +0,0 @@ -"""A library that implements the T2 serial communication. - -This library has two parts: one that deals with sending and receiving -packets using the serial format from T2 (TEP113) and a second one that -tries to simplifies the work with arbitrary packets. - -""" - -import sys, struct, time, serial, socket, operator -from Queue import Queue - -__version__ = "$Id$" - -__all__ = ['Serial', 'GenericPacket', 'RawPacket', - 'AckFrame', 'DataFrame', 'NoAckDataFrame', - 'ActiveMessage'] - -_seqno = 1 - -def list2hex(v): - return " ".join(["%02x" % p for p in v]) - -class Serial: - """ - A Serial object offers a way to send and data using a HDLC-like - formating. - """ - - HDLC_FLAG_BYTE = 0x7e - HDLC_CTLESC_BYTE = 0x7d - - TOS_SERIAL_ACTIVE_MESSAGE_ID = 0 - TOS_SERIAL_CC1000_ID = 1 - TOS_SERIAL_802_15_4_ID = 2 - TOS_SERIAL_UNKNOWN_ID = 255 - - SERIAL_PROTO_ACK = 67 - SERIAL_PROTO_PACKET_ACK = 68 - SERIAL_PROTO_PACKET_NOACK = 69 - SERIAL_PROTO_PACKET_UNKNOWN = 255 - - _debug = False # Debug mode - - def __init__(self, port, baudrate, flush=True): - self._s = serial.Serial(port, baudrate, rtscts=0, timeout=0.5) - self._queue = Queue() - self._ts = None - self._seqno = 0 - - self._s.flushInput() - start = time.time(); - if flush: - print "Flushing the serial port", - while time.time() - start < 1: - p = self.sniff() - sys.stdout.write(".") - if not self._debug: - sys.stdout.write("\n") - - def _format_packet(self, payload): - f = NoAckDataFrame(payload) - if f.protocol == self.SERIAL_PROTO_ACK: - rpacket = AckFrame(payload) - return "Ack seqno: %d" % (rpacket.seqno) - else: - rpacket = ActiveMessage(f.data) - return "D: %04x S: %04x L: %02x G: %02x T: %02x | %s" % \ - (rpacket.destination, rpacket.source, - rpacket.length, rpacket.group, rpacket.type, - list2hex(rpacket.data)) - - def crc16(self, base_crc, frame_data): - crc = base_crc - for b in frame_data: - crc = crc ^ (b << 8) - for i in range(0, 8): - if crc & 0x8000 == 0x8000: - crc = (crc << 1) ^ 0x1021 - else: - crc = crc << 1 - crc = crc & 0xffff - return crc - - def _encode(self, val, dim): - output = [] - for i in range(dim): - output.append(val & 0xFF) - val = val >> 8 - return output - - def _decode(self, v): - r = long(0) - for i in v[::-1]: - r = (r << 8) + i - return r - - def _get_byte(self): - try: - r = struct.unpack("B", self._s.read())[0] - return r - except struct.error: - # Serial port read timeout - raise socket.timeout - - def _put_bytes(self, data): - #print "DEBUG: _put_bytes:", data - for b in data: - self._s.write(struct.pack('B', b)) - - def _unescape(self, packet): - r = [] - esc = False - for b in packet: - if esc: - r.append(b ^ 0x20) - esc = False - elif b == self.HDLC_CTLESC_BYTE: - esc = True - else: - r.append(b) - return r - - def _escape(self, packet): - r = [] - for b in packet: - if b == self.HDLC_FLAG_BYTE or b == self.HDLC_CTLESC_BYTE: - r.append(self.HDLC_CTLESC_BYTE) - r.append(b ^ 0x20) - else: - r.append(b) - return r - - # Returns the next incoming serial packet - def sniff(self, skip_queue = False): - """Wait for a packet and return it as a RawPacket.""" - - if (not skip_queue and not self._queue.empty()): - print "DEBUG: sniff_packet: return a packet from the queue(%d)." % self._queue.qsize() - return self._queue.get() - try: - d = self._get_byte() - ts = time.time() - while d != self.HDLC_FLAG_BYTE: - d = self._get_byte() - ts = time.time() - packet = [d] - d = self._get_byte() - if d == self.HDLC_FLAG_BYTE: - d = self._get_byte() - ts = time.time() - else: - packet.append(d) - while d != self.HDLC_FLAG_BYTE: - d = self._get_byte() - packet.append(d) - if self._debug == True: - print "sniff: unescaped", packet - packet = self._unescape(packet) - - crc = self.crc16(0, packet[1:-3]) - packet_crc = self._decode(packet[-3:-1]) - - if self._debug: - if crc != packet_crc: - print "Warning: wrong CRC! %s" % packet - if self._ts == None: - self._ts = ts - else: - print "%.4f (%.4f) Recv:" % (ts, ts - self._ts), self._format_packet(packet[1:-3]) - self._ts = ts - return RawPacket(ts, packet[1:-3], crc == packet_crc) - except socket.timeout: - return None - - def sniff_am(self, skip_queue = False, timeout=0): - """Wait for a packet and return it as a ActiveMessage.""" - - start = time.time(); - p = None - done = False - while not done: - while p == None: - if timeout == 0 or time.time() - start < timeout: - p = self.sniff(skip_queue) - else: - return None - if p.crc: - done = True - return ActiveMessage(NoAckDataFrame(p.data).data) - - - # Sends data with the specified AM group ID and AM ID. To have a "reliable" - # transfer, num_tries defines how many times to retry before giving up - def write(self, payload, num_tries=3): - """ - Write a packet. If the payload argument is a list, it is - assumed to be exactly the payload. Otherwise the payload is - assume to be a GenericPacket and the real payload is obtain - by calling the .payload(). - """ - - global _seqno - if type(payload) != type([]): - # Assume this will be derived from GenericPacket - payload = payload.payload() - _seqno = (_seqno + 1) % 100 - packet = DataFrame(); - packet.protocol = self.SERIAL_PROTO_PACKET_ACK - packet.seqno = _seqno - packet.dispatch = 0 - packet.data = payload - packet = packet.payload() - crc = self.crc16(0, packet) - packet.append(crc & 0xff) - packet.append((crc >> 8) & 0xff) - packet = [self.HDLC_FLAG_BYTE] + self._escape(packet) + [self.HDLC_FLAG_BYTE] - - for i in range(num_tries): - self._put_bytes(packet) - if self._debug == True: - print "Send:", packet - - # Waits for ACK - for j in range(3): - p = self.sniff(skip_queue = True) - if p != None: - ack = AckFrame(p.data) - if ack.protocol == self.SERIAL_PROTO_ACK: - if ack.seqno != _seqno: - print ">" * 40, "Wrong ACK!", ack.seqno, _seqno, "<" * 40 - return True - else: - if self._debug == True: - print "write_packet: put a packet in the queue(%d)." % (self._queue.qsize()) - self._queue.put(p) - - return False - - def debug(self, debug): - self._debug = debug - - - -class GenericPacket: - """ GenericPacket """ - - def _decode(self, v): - r = long(0) - for i in v: - r = (r << 8) + i - return r - - def _encode(self, val, dim): - output = [] - for i in range(dim): - output.append(int(val & 0xFF)) - val = val >> 8 - output.reverse() - return output - - def __init__(self, desc, packet = None): - offset = 0 - boffset = 0 - sum = 0 - for i in range(len(desc)-1, -1, -1): - (n, t, s) = desc[i] - if s == None: - if sum > 0: - desc[i] = (n, t, -sum) - break - sum += s - self.__dict__['_schema'] = [(t, s) for (n, t, s) in desc] - self.__dict__['_names'] = [n for (n, t, s) in desc] - self.__dict__['_values'] = [] - if type(packet) == type([]): - for (t, s) in self._schema: - if t == 'int': - self._values.append(self._decode(packet[offset:offset + s])) - offset += s - elif t == 'bint': - doffset = 8 - (boffset + s) - self._values.append((packet[offset] >> doffset) & ((1< 0: - self._values.append(packet[offset:offset + s]) - offset += s - else: - self._values.append(packet[offset:s]) - offset = len(packet) + s - else: - self._values.append(packet[offset:]) - elif type(packet) == type(()): - for i in packet: - self._values.append(i) - else: - for v in self._schema: - self._values.append(None) - - def __repr__(self): - return self._values.__repr__() - - def __str__(self): - r = "" - for i in range(len(self._names)): - r += "%s: %s " % (self._names[i], self._values[i]) - for i in range(len(self._names), len(self._values)): - r += "%s" % self._values[i] - return r -# return self._values.__str__() - - # Implement the map behavior - def __getitem__(self, key): - return self.__getattr__(key) - - def __setitem__(self, key, value): - self.__setattr__(key, value) - - def __len__(self): - return len(self._values) - - def keys(self): - return self._names - - def values(self): - return self._names - - # Implement the struct behavior - def __getattr__(self, name): - #print "DEBUG: __getattr__", name - if type(name) == type(0): - return self._names[name] - else: - return self._values[self._names.index(name)] - - def __setattr__(self, name, value): - if type(name) == type(0): - self._values[name] = value - else: - self._values[self._names.index(name)] = value - - def __ne__(self, other): - if other.__class__ == self.__class__: - return self._values != other._values - else: - return True - - def __eq__(self, other): - if other.__class__ == self.__class__: - return self._values == other._values - else: - return False - - def __nonzero__(self): - return True; - - # Custom - def names(self): - return self._names - - def sizes(self): - return self._schema - - def payload(self): - r = [] - boffset = 0 - for i in range(len(self._schema)): - (t, s) = self._schema[i] - if t == 'int': - r += self._encode(self._values[i], s) - boffset = 0 - elif t == 'bint': - doffset = 8 - (boffset + s) - if boffset == 0: - r += [self._values[i] << doffset] - else: - r[-1] |= self._values[i] << doffset - boffset += s - if boffset == 8: - boffset = 0 - elif self._values[i] != []: - r += self._values[i] - for i in self._values[len(self._schema):]: - r += i - return r - - -class RawPacket(GenericPacket): - def __init__(self, ts = None, data = None, crc = None): - GenericPacket.__init__(self, - [('ts' , 'int', 4), - ('crc', 'int', 1), - ('data', 'blob', None)], - None) - self.ts = ts; - self.data = data - self.crc = crc - - -class AckFrame(GenericPacket): - def __init__(self, payload = None): - GenericPacket.__init__(self, - [('protocol', 'int', 1), - ('seqno', 'int', 1)], - payload) - -class DataFrame(GenericPacket): - def __init__(self, payload = None): - if payload != None and type(payload) != type([]): - # Assume is a GenericPacket - payload = payload.payload() - GenericPacket.__init__(self, - [('protocol', 'int', 1), - ('seqno', 'int', 1), - ('dispatch', 'int', 1), - ('data', 'blob', None)], - payload) - -class NoAckDataFrame(GenericPacket): - def __init__(self, payload = None): - if payload != None and type(payload) != type([]): - # Assume is a GenericPacket - payload = payload.payload() - GenericPacket.__init__(self, - [('protocol', 'int', 1), - ('dispatch', 'int', 1), - ('data', 'blob', None)], - payload) - -class ActiveMessage(GenericPacket): - def __init__(self, gpacket = None, am_id = 0x00, dest = 0xFFFF): - if type(gpacket) == type([]): - payload = gpacket - else: - # Assume this will be derived from GenericPacket - payload = None - GenericPacket.__init__(self, - [('destination', 'int', 2), - ('source', 'int', 2), - ('length', 'int', 1), - ('group', 'int', 1), - ('type', 'int', 1), - ('data', 'blob', None)], - payload) - if payload == None: - self.destination = dest - self.source = 0x0000 - self.group = 0x00 - self.type = am_id - self.data = gpacket.payload() - self.length = len(self.data) - diff --git a/tools/tinyos/misc/tos-build-deluge-image b/tools/tinyos/misc/tos-build-deluge-image index 08542401..3095167a 100755 --- a/tools/tinyos/misc/tos-build-deluge-image +++ b/tools/tinyos/misc/tos-build-deluge-image @@ -20,8 +20,8 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. -# @author Chieh-Jan Mike Liang # @author Razvan Musaloiu-E. +# @author Chieh-Jan Mike Liang import sys, struct, operator from xml.dom.minidom import parse @@ -147,8 +147,8 @@ for line in image.split(): all.append((start_addr, section)) if rectype == 0x03: # This last record updates the first 4 bytes which - # holds some some low level configuration. They are - # the same all the time so I guess that's why they are + # holds some low level configuration. They are the + # same all the time so I guess that's why they are # skipped. break section = [] @@ -173,6 +173,7 @@ for (addr, data) in all: all_data += encode(addr, 4) + \ encode(len(data), 4) + \ data +all_data += encode(0, 4) + encode(0, 4) # Add the marker for the end of an image padding = [0] * (DELUGE_BYTES_PER_PAGE - len(all_data) % DELUGE_BYTES_PER_PAGE) if len(padding) < DELUGE_BYTES_PER_PAGE: all_data += padding diff --git a/tools/tinyos/misc/tos-deluge b/tools/tinyos/misc/tos-deluge index 4e71e0c5..a6c99785 100755 --- a/tools/tinyos/misc/tos-deluge +++ b/tools/tinyos/misc/tos-deluge @@ -24,7 +24,7 @@ # @author Chieh-Jan Mike Liang import sys, stat, struct, subprocess, time -import tinyos +import tos from datetime import datetime import os.path @@ -36,7 +36,8 @@ FM_AMID = 0xAB DM_AMID = 0xAC SERIAL_DATA_LENGTH = 28 - 1 - 1 - 2 - 2 BAUDRATES = {'micaz': 57600, - 'telosb': 115200} + 'telosb': 115200, + 'iris': 57600} # Commands for FlashManager FM_CMD_ERASE = 0 @@ -63,54 +64,54 @@ DELUGE_MAX_PAGES = 128 DELUGE_IDENT_OFFSET = 0 DELUGE_IDENT_SIZE = 128 -class FMReqPacket(tinyos.GenericPacket): +class FMReqPacket(tos.Packet): def __init__(self, packet = None): - tinyos.GenericPacket.__init__(self, - [('cmd', 'int', 1), - ('imgNum', 'int', 1), - ('offset', 'int', 2), - ('length', 'int', 2), - ('data', 'blob', None)], - packet) - -class DMReqPacket(tinyos.GenericPacket): + tos.Packet.__init__(self, + [('cmd', 'int', 1), + ('imgNum', 'int', 1), + ('offset', 'int', 2), + ('length', 'int', 2), + ('data', 'blob', None)], + packet) + +class DMReqPacket(tos.Packet): def __init__(self, packet = None): - tinyos.GenericPacket.__init__(self, - [('cmd', 'int', 1), - ('imgNum', 'int', 1)], - packet) + tos.Packet.__init__(self, + [('cmd', 'int', 1), + ('imgNum', 'int', 1)], + packet) -class SerialReplyPacket(tinyos.GenericPacket): +class SerialReplyPacket(tos.Packet): def __init__(self, packet = None): - tinyos.GenericPacket.__init__(self, - [('error', 'int', 1), - ('data', 'blob', None)], - packet) + tos.Packet.__init__(self, + [('error', 'int', 1), + ('data', 'blob', None)], + packet) -class Ident(tinyos.GenericPacket): +class Ident(tos.Packet): def __init__(self, packet = None): - tinyos.GenericPacket.__init__(self, - [('uidhash', 'int', 4), - ('size', 'int', 4), - ('pages', 'int', 1), - ('reserved', 'int', 1), - ('crc', 'int', 2), - ('appname', 'string', 16), - ('username', 'string', 16), - ('hostname', 'string', 16), - ('platform', 'string', 16), - ('timestamp','int', 4), - ('userhash', 'int', 4)], - packet) - -class ShortIdent(tinyos.GenericPacket): + tos.Packet.__init__(self, + [('uidhash', 'int', 4), + ('size', 'int', 4), + ('pages', 'int', 1), + ('reserved', 'int', 1), + ('crc', 'int', 2), + ('appname', 'string', 16), + ('username', 'string', 16), + ('hostname', 'string', 16), + ('platform', 'string', 16), + ('timestamp','int', 4), + ('userhash', 'int', 4)], + packet) + +class ShortIdent(tos.Packet): def __init__(self, packet = None): - tinyos.GenericPacket.__init__(self, - [('appname', 'string', 16), - ('timestamp','int', 4), - ('uidhash', 'int', 4), - ('nodeid', 'int', 2)], - packet) + tos.Packet.__init__(self, + [('appname', 'string', 16), + ('timestamp','int', 4), + ('uidhash', 'int', 4), + ('nodeid', 'int', 2)], + packet) # Computes 16-bit CRC @@ -129,13 +130,15 @@ def crc16(data): def handleResponse(success, msg): if success == True: - packet = s.sniff_am() + packet = am.read(timeout=1) while packet and packet.type == 100: print "".join([chr(i) for i in packet.data]) - packet = s.sniff_am() + packet = am.read() + if not packet: + print "No response" + return False reply = SerialReplyPacket(packet.data) if reply.error == ERROR_SUCCESS: - print reply return True else: print msg, reply @@ -146,8 +149,8 @@ def handleResponse(success, msg): def ident(): sreqpkt = FMReqPacket((FM_CMD_IDENT, 0, 0, 0, [])) - if s.write(tinyos.ActiveMessage(sreqpkt, am_id=FM_AMID)): - packet = s.sniff_am() + if am.write(sreqpkt, FM_AMID): + packet = am.read() reply = SerialReplyPacket(packet.data) if reply.error == ERROR_SUCCESS: return ShortIdent(reply.data) @@ -161,8 +164,8 @@ def read(imgNum, offset, length): if sreqpkt.length > SERIAL_DATA_LENGTH: sreqpkt.length = SERIAL_DATA_LENGTH - if s.write(tinyos.ActiveMessage(sreqpkt, am_id=FM_AMID)): - packet = s.sniff_am() + if am.write(sreqpkt, FM_AMID): + packet = am.read() reply = SerialReplyPacket(packet.data) if reply.error == ERROR_SUCCESS: r.extend(reply.data) @@ -182,12 +185,12 @@ def read(imgNum, offset, length): def erase(imgNum): sreqpkt = FMReqPacket((FM_CMD_ERASE, imgNum, 0, 0, [])) - success = s.write(tinyos.ActiveMessage(sreqpkt, am_id=FM_AMID)) + success = am.write(sreqpkt, FM_AMID) return handleResponse(success, "ERROR: Unable to erase the flash volume") def sync(imgNum): sreqpkt = FMReqPacket((FM_CMD_SYNC, imgNum, 0, 0, [])) - success = s.write(tinyos.ActiveMessage(sreqpkt, am_id=FM_AMID)) + success = am.write(sreqpkt, FM_AMID) return handleResponse(success, "ERROR: Unable to sync the flash volume") def write(imgNum, data): @@ -214,13 +217,13 @@ def write(imgNum, data): sreqpkt.data = data[sreqpkt.offset:sreqpkt.offset+sreqpkt.length] # Sends over serial to the mote - if not s.write(tinyos.ActiveMessage(sreqpkt, am_id=FM_AMID)): + if not am.write(sreqpkt, FM_AMID): print print "ERROR: Unable to send the last serial packet (file offset: %d)" % sreqpkt.offset return False # Waiting for confirmation - packet = s.sniff_am() + packet = am.read() reply = SerialReplyPacket(packet.data) if reply.error != ERROR_SUCCESS: print @@ -300,11 +303,12 @@ def inject(imgNum, tos_image_xml): cmd = [PATH_PY_BUILD_IMAGE, "-i", str(imgNum), tos_image_xml] print "Create image:", ' '.join(cmd) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - print p.stderr.read(), + (out, err) = p.communicate(None) + print err, print "--------------------------------------------------" # Writes the new binary image - image = [struct.unpack("B", c)[0] for c in p.stdout.read()] + image = [struct.unpack("B", c)[0] for c in out] if len(image) > 0 and erase(imgNum): if write(imgNum, image): if sync(imgNum): @@ -333,32 +337,32 @@ def ping(imgNum): def boot(): sreqpkt = DMReqPacket((DM_CMD_BOOT, 0)) - success = s.write(tinyos.ActiveMessage(sreqpkt, am_id=DM_AMID)) + success = am.write(sreqpkt, DM_AMID) return handleResponse(success, "ERROR: Unable to boot the mote") def reprogram(imgNum): sreqpkt = DMReqPacket((DM_CMD_REPROGRAM, imgNum)) - success = s.write(tinyos.ActiveMessage(sreqpkt, am_id=DM_AMID)) + success = am.write(sreqpkt, DM_AMID) return handleResponse(success, "ERROR: Unable to reprogram the mote") def disseminate(imgNum): sreqpkt = DMReqPacket((DM_CMD_ONLY_DISSEMINATE, imgNum)) - success = s.write(tinyos.ActiveMessage(sreqpkt, am_id=DM_AMID)) + success = am.write(sreqpkt, DM_AMID) return handleResponse(success, "ERROR: Unable to disseminate") def disseminateAndReboot(imgNum): sreqpkt = DMReqPacket((DM_CMD_DISSEMINATE_AND_REPROGRAM, imgNum)) - success = s.write(tinyos.ActiveMessage(sreqpkt, am_id=DM_AMID)) + success = am.write(sreqpkt, DM_AMID) return handleResponse(success, "ERROR: Unable to disseminate-and-reboot") def stop(): sreqpkt = DMReqPacket((DM_CMD_STOP, 0)) - success = s.write(tinyos.ActiveMessage(sreqpkt, am_id=DM_AMID)) + success = am.write(sreqpkt, DM_AMID) return handleResponse(success, "ERROR: Unable to initiate the stop") def localstop(): sreqpkt = DMReqPacket((DM_CMD_LOCAL_STOP, 0)) - success = s.write(tinyos.ActiveMessage(sreqpkt, am_id=DM_AMID)) + success = am.write(sreqpkt, DM_AMID) return handleResponse(success, "ERROR: Unable to initiate the local stop") def print_usage(): @@ -402,7 +406,8 @@ if len(sys.argv) >= 4: # Initializes serial port communication try: - s = tinyos.Serial(sys.argv[1], baudrate, flush=False) + s = tos.Serial(sys.argv[1], baudrate, flush=True, debug=False) + am = tos.AM(s) except: print "ERROR: Unable to initialize serial port connection to", sys.argv[1] sys.exit(-1) diff --git a/tools/tinyos/misc/tos.py b/tools/tinyos/misc/tos.py new file mode 100644 index 00000000..e01e7ecd --- /dev/null +++ b/tools/tinyos/misc/tos.py @@ -0,0 +1,575 @@ +# Copyright (c) 2008 Johns Hopkins University. +# All rights reserved. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose, without fee, and without written +# agreement is hereby granted, provided that the above copyright +# notice, the (updated) modification history and the author appear in +# all copies of this source code. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, +# OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + +# @author Razvan Musaloiu-E. + +"""A library that implements the T2 serial communication. + +This library has two parts: one that deals with sending and receiving +packets using the serial format from T2 (TEP113) and a second one that +tries to simplifies the work with arbitrary packets. + +""" + +import sys, struct, time, serial, socket, operator, thread +from Queue import Queue +from threading import Lock, Condition + +__version__ = "$Id$" + +__all__ = ['Serial', 'AM', + 'Packet', 'RawPacket', + 'AckFrame', 'DataFrame', 'NoAckDataFrame', + 'ActiveMessage'] + +def list2hex(v): + return " ".join(["%02x" % p for p in v]) + +class Serial: + """ + A Serial object offers a way to send and data using a HDLC-like + formating. + """ + + HDLC_FLAG_BYTE = 0x7e + HDLC_CTLESC_BYTE = 0x7d + + TOS_SERIAL_ACTIVE_MESSAGE_ID = 0 + TOS_SERIAL_CC1000_ID = 1 + TOS_SERIAL_802_15_4_ID = 2 + TOS_SERIAL_UNKNOWN_ID = 255 + + SERIAL_PROTO_ACK = 67 + SERIAL_PROTO_PACKET_ACK = 68 + SERIAL_PROTO_PACKET_NOACK = 69 + SERIAL_PROTO_PACKET_UNKNOWN = 255 + + def __init__(self, port, baudrate, flush=False, debug=False, qsize=10): + self._debug = debug + self._in_queue = Queue(qsize) + self._out_lock = Lock() + self._out_ack = Condition() + self._seqno = 0 + self._ack = None + self._write_counter = 0 + self._write_counter_failures = 0 + self._read_counter = 0 + self._ts = None + + self._s = serial.Serial(port, baudrate, rtscts=0, timeout=0.5) + self._s.flushInput() + start = time.time(); + if flush: + print >>sys.stdout, "Flushing the serial port", + while time.time() - start < 1: + p = self._read() + sys.stdout.write(".") + if not self._debug: + sys.stdout.write("\n") + self._s.close() + self._s = serial.Serial(port, baudrate, rtscts=0, timeout=None) + + thread.start_new_thread(self.run, ()) + + def run(self): + + while True: + p = self._read() + self._read_counter += 1 + if self._debug: + print "Serial:run: got a packet(%d): %s" % (self._read_counter, p) + ack = AckFrame(p.data) + if ack.protocol == self.SERIAL_PROTO_ACK: + if not self._ack: + self._ack = ack + if self._debug: + print "Serial:run: got an ack:", ack + self._ack = ack + # Wake up the writer + self._out_ack.acquire() + self._out_ack.notify() + self._out_ack.release() + else: + ampkt = ActiveMessage(NoAckDataFrame(p.data).data) + if ampkt.type == 100: + for t in "".join([chr(i) for i in ampkt.data]).strip('\n\0').split('\n'): + print "PRINTF:", t.strip('\n') + else: + if self._in_queue.full(): + print "Warning: Buffer overflow" + self._in_queue.get() + self._in_queue.put(p, block=False) + + + # Returns the next incoming serial packet + def _read(self): + """Wait for a packet and return it as a RawPacket.""" + + try: + d = self._get_byte() + ts = time.time() + while d != self.HDLC_FLAG_BYTE: + d = self._get_byte() + ts = time.time() + packet = [d] + d = self._get_byte() + if d == self.HDLC_FLAG_BYTE: + d = self._get_byte() + ts = time.time() + else: + packet.append(d) + while d != self.HDLC_FLAG_BYTE: + d = self._get_byte() + packet.append(d) + if self._debug == True: + print "Serial:_read: unescaped", packet + packet = self._unescape(packet) + + crc = self._crc16(0, packet[1:-3]) + packet_crc = self._decode(packet[-3:-1]) + + if crc != packet_crc: + print "Warning: wrong CRC! %x != %x %s" % (crc, packet_crc, ["%2x" % i for i in packet]) + if self._debug: + if self._ts == None: + self._ts = ts + else: + print "Serial:_read: %.4f (%.4f) Recv:" % (ts, ts - self._ts), self._format_packet(packet[1:-3]) + self._ts = ts + return RawPacket(ts, packet[1:-3], crc == packet_crc) + except socket.timeout: + return None + + + def read(self, timeout=0): + start = time.time(); + done = False + while not done: + p = None + while p == None: + if timeout == 0 or time.time() - start < timeout: + p = self._in_queue.get() + else: + return None + if p.crc: + done = True + else: + p = None + # In the current TinyOS the packets from the mote are always NoAckDataFrame + return NoAckDataFrame(p.data) + + def write(self, payload): + """ + Write a packet. If the payload argument is a list, it is + assumed to be exactly the payload. Otherwise the payload is + assume to be a Packet and the real payload is obtain by + calling the .payload(). + """ + + if type(payload) != type([]): + # Assume this will be derived from Packet + payload = payload.payload() + self._out_lock.acquire() + self._seqno = (self._seqno + 1) % 100 + packet = DataFrame(); + packet.protocol = self.SERIAL_PROTO_PACKET_ACK + packet.seqno = self._seqno + packet.dispatch = 0 + packet.data = payload + packet = packet.payload() + crc = self._crc16(0, packet) + packet.append(crc & 0xff) + packet.append((crc >> 8) & 0xff) + packet = [self.HDLC_FLAG_BYTE] + self._escape(packet) + [self.HDLC_FLAG_BYTE] + + while True: + self._put_bytes(packet) + self._write_counter += 1 + if self._debug == True: + print "Send(%d/%d): %s" % (self._write_counter, self._write_counter_failures, packet) + print "Wait for ack %d ..." % (self._seqno) + self._out_ack.acquire() + self._out_ack.wait(0.2) + if self._debug: + print "Wait for ack %d done. Latest ack:" % (self._seqno), self._ack + self._out_ack.release() + if self._ack and self._ack.seqno == self._seqno: + if self._debug: + print "The packet was acked." + self._out_lock.release() + if self._debug: + print "Returning from Serial.write..." + return True + else: + self._write_counter_failures += 1 + if self._debug: + print "The packet was not acked. Try again." + # break # make only one sending attempt + self._out_lock.release() + return False + + + def _format_packet(self, payload): + f = NoAckDataFrame(payload) + if f.protocol == self.SERIAL_PROTO_ACK: + rpacket = AckFrame(payload) + return "Ack seqno: %d" % (rpacket.seqno) + else: + rpacket = ActiveMessage(f.data) + return "D: %04x S: %04x L: %02x G: %02x T: %02x | %s" % \ + (rpacket.destination, rpacket.source, + rpacket.length, rpacket.group, rpacket.type, + list2hex(rpacket.data)) + + def _crc16(self, base_crc, frame_data): + crc = base_crc + for b in frame_data: + crc = crc ^ (b << 8) + for i in range(0, 8): + if crc & 0x8000 == 0x8000: + crc = (crc << 1) ^ 0x1021 + else: + crc = crc << 1 + crc = crc & 0xffff + return crc + + def _encode(self, val, dim): + output = [] + for i in range(dim): + output.append(val & 0xFF) + val = val >> 8 + return output + + def _decode(self, v): + r = long(0) + for i in v[::-1]: + r = (r << 8) + i + return r + + def _get_byte(self): + try: + r = struct.unpack("B", self._s.read())[0] + return r + except struct.error: + # Serial port read timeout + raise socket.timeout + + def _put_bytes(self, data): + #print "DEBUG: _put_bytes:", data + for b in data: + self._s.write(struct.pack('B', b)) + + def _unescape(self, packet): + r = [] + esc = False + for b in packet: + if esc: + r.append(b ^ 0x20) + esc = False + elif b == self.HDLC_CTLESC_BYTE: + esc = True + else: + r.append(b) + return r + + def _escape(self, packet): + r = [] + for b in packet: + if b == self.HDLC_FLAG_BYTE or b == self.HDLC_CTLESC_BYTE: + r.append(self.HDLC_CTLESC_BYTE) + r.append(b ^ 0x20) + else: + r.append(b) + return r + + def debug(self, debug): + self._debug = debug + + +class SFClient: + def __init__(self, host, port, qsize=10): + self._in_queue = Queue(qsize) + self._s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._s.connect((host, port)) + data = self._s.recv(2) + if data != 'U ': + print "Wrong handshake" + self._s.send("U ") + print "Connected" + thread.start_new_thread(self.run, ()) + + def run(self): + while True: + length = ord(self._s.recv(1)) + data = self._s.recv(length) + data = [ord(c) for c in data][1:] + #print "Recv %d bytes" % (length), ActiveMessage(data) + if self._in_queue.full(): + print "Warning: Buffer overflow" + self._in_queue.get() + p = RawPacket() + p.crc = 1 + p.data = data + self._in_queue.put(p, block=False) + + def read(self, timeout=0): + return self._in_queue.get() + + def write(self, payload): + print "SFClient: write:", payload + if type(payload) != type([]): + # Assume this will be derived from Packet + payload = payload.payload() + payload = [0] + payload + self._s.send(chr(len(payload))) + self._s.send(''.join([chr(c) for c in payload])) + return True + +class AM: + def __init__(self, s): + self._s = s + + def read(self, timeout=0): + return ActiveMessage(self._s.read().data) + + def write(self, packet, amid): + return self._s.write(ActiveMessage(packet, amid=amid)) + + +class Packet: + """ + The Packet class offers a handy way to build pack and unpack + binary data based on a given pattern. + """ + + def _decode(self, v): + r = long(0) + for i in v: + r = (r << 8) + i + return r + + def _encode(self, val, dim): + output = [] + for i in range(dim): + output.append(int(val & 0xFF)) + val = val >> 8 + output.reverse() + return output + + def __init__(self, desc, packet = None): + offset = 0 + boffset = 0 + sum = 0 + for i in range(len(desc)-1, -1, -1): + (n, t, s) = desc[i] + if s == None: + if sum > 0: + desc[i] = (n, t, -sum) + break + sum += s + self.__dict__['_schema'] = [(t, s) for (n, t, s) in desc] + self.__dict__['_names'] = [n for (n, t, s) in desc] + self.__dict__['_values'] = [] + if type(packet) == type([]): + for (t, s) in self._schema: + if t == 'int': + self._values.append(self._decode(packet[offset:offset + s])) + offset += s + elif t == 'bint': + doffset = 8 - (boffset + s) + self._values.append((packet[offset] >> doffset) & ((1< 0: + self._values.append(packet[offset:offset + s]) + offset += s + else: + self._values.append(packet[offset:s]) + offset = len(packet) + s + else: + self._values.append(packet[offset:]) + elif type(packet) == type(()): + for i in packet: + self._values.append(i) + else: + for v in self._schema: + self._values.append(None) + + def __repr__(self): + return self._values.__repr__() + + def __str__(self): + r = "" + for i in range(len(self._names)): + r += "%s: %s " % (self._names[i], self._values[i]) + for i in range(len(self._names), len(self._values)): + r += "%s" % self._values[i] + return r +# return self._values.__str__() + + # Implement the map behavior + def __getitem__(self, key): + return self.__getattr__(key) + + def __setitem__(self, key, value): + self.__setattr__(key, value) + + def __len__(self): + return len(self._values) + + def keys(self): + return self._names + + def values(self): + return self._names + + # Implement the struct behavior + def __getattr__(self, name): + #print "DEBUG: __getattr__", name + if type(name) == type(0): + return self._names[name] + else: + return self._values[self._names.index(name)] + + def __setattr__(self, name, value): + if type(name) == type(0): + self._values[name] = value + else: + self._values[self._names.index(name)] = value + + def __ne__(self, other): + if other.__class__ == self.__class__: + return self._values != other._values + else: + return True + + def __eq__(self, other): + if other.__class__ == self.__class__: + return self._values == other._values + else: + return False + + def __nonzero__(self): + return True; + + # Custom + def names(self): + return self._names + + def sizes(self): + return self._schema + + def payload(self): + r = [] + boffset = 0 + for i in range(len(self._schema)): + (t, s) = self._schema[i] + if t == 'int': + r += self._encode(self._values[i], s) + boffset = 0 + elif t == 'bint': + doffset = 8 - (boffset + s) + if boffset == 0: + r += [self._values[i] << doffset] + else: + r[-1] |= self._values[i] << doffset + boffset += s + if boffset == 8: + boffset = 0 + elif self._values[i] != []: + r += self._values[i] + for i in self._values[len(self._schema):]: + r += i + return r + + +class RawPacket(Packet): + def __init__(self, ts = None, data = None, crc = None): + Packet.__init__(self, + [('ts' , 'int', 4), + ('crc', 'int', 1), + ('data', 'blob', None)], + None) + self.ts = ts; + self.data = data + self.crc = crc + +class AckFrame(Packet): + def __init__(self, payload = None): + Packet.__init__(self, + [('protocol', 'int', 1), + ('seqno', 'int', 1)], + payload) + +class DataFrame(Packet): + def __init__(self, payload = None): + if payload != None and type(payload) != type([]): + # Assume is a Packet + payload = payload.payload() + Packet.__init__(self, + [('protocol', 'int', 1), + ('seqno', 'int', 1), + ('dispatch', 'int', 1), + ('data', 'blob', None)], + payload) + +class NoAckDataFrame(Packet): + def __init__(self, payload = None): + if payload != None and type(payload) != type([]): + # Assume is a Packet + payload = payload.payload() + Packet.__init__(self, + [('protocol', 'int', 1), + ('dispatch', 'int', 1), + ('data', 'blob', None)], + payload) + +class ActiveMessage(Packet): + def __init__(self, gpacket = None, amid = 0x00, dest = 0xFFFF): + if type(gpacket) == type([]): + payload = gpacket + else: + # Assume this will be derived from Packet + payload = None + Packet.__init__(self, + [('destination', 'int', 2), + ('source', 'int', 2), + ('length', 'int', 1), + ('group', 'int', 1), + ('type', 'int', 1), + ('data', 'blob', None)], + payload) + if payload == None: + self.destination = dest + self.source = 0x0000 + self.group = 0x00 + self.type = amid + self.data = [] + if gpacket: + self.data = gpacket.payload() + self.length = len(self.data) + diff --git a/tos/lib/net/Deluge/Deluge.h b/tos/lib/net/Deluge/Deluge.h index 6ef74f58..fc2cfc50 100644 --- a/tos/lib/net/Deluge/Deluge.h +++ b/tos/lib/net/Deluge/Deluge.h @@ -44,6 +44,9 @@ typedef nx_struct DelugeIdent { enum { DELUGE_INVALID_UID = 0xffffffff, DELUGE_NUM_VOLUMES = 4, + DELUGE_KEY = 0xDE00, + DELUGE_AM_FLASH_VOL_MANAGER = 0xAB, + DELUGE_AM_DELUGE_MANAGER = 0xAC, }; enum { diff --git a/tos/lib/net/Deluge/DelugeC.nc b/tos/lib/net/Deluge/DelugeC.nc index 20532b56..78d550fc 100644 --- a/tos/lib/net/Deluge/DelugeC.nc +++ b/tos/lib/net/Deluge/DelugeC.nc @@ -53,7 +53,7 @@ implementation ObjectTransferC.Leds = Leds; - components new DisseminatorC(DelugeCmd, 0xDE00); + components new DisseminatorC(DelugeCmd, DELUGE_KEY); components DisseminationC; components ActiveMessageC; components NetProgC, DelugeP; @@ -67,7 +67,9 @@ implementation DelugeP.Boot -> MainC; DelugeP.Leds = Leds; +#ifndef DELUGE_BASESTATION DelugeP.DisseminationValue -> DisseminatorC; +#endif DelugeP.DisseminationStdControl -> DisseminationC; DelugeP.ObjectTransfer -> ObjectTransferC; DelugeP.NetProg -> NetProgC; @@ -78,10 +80,13 @@ implementation DelugeP.DelugeVolumeManager -> DelugeVolumeManagerClientC; DelugeP.Resource -> BlockStorageLockClientC; -#ifdef DELUGE_BASESTATION +#if defined(DELUGE_BASESTATION) || defined(DELUGE_LIGHT_BASESTATION) components SerialStarterC; - components new FlashVolumeManagerC(0xAB); - components new DelugeManagerC(0xAC); + components new FlashVolumeManagerC(DELUGE_AM_FLASH_VOL_MANAGER); +#endif + +#ifdef DELUGE_BASESTATION + components new DelugeManagerC(DELUGE_AM_DELUGE_MANAGER); DelugeManagerC.DisseminationUpdate -> DisseminatorC; #endif diff --git a/tos/lib/net/Deluge/DelugeManagerP.nc b/tos/lib/net/Deluge/DelugeManagerP.nc index 342d8ca2..4a25388f 100644 --- a/tos/lib/net/Deluge/DelugeManagerP.nc +++ b/tos/lib/net/Deluge/DelugeManagerP.nc @@ -24,6 +24,8 @@ * @author Chieh-Jan Mike Liang */ +#include "imgNum2volumeId.h" + generic module DelugeManagerP() { uses { @@ -55,12 +57,6 @@ implementation message_t serialMsg; DelugeCmd delugeCmd; - uint8_t imgNum2volumeId[] = { - VOLUME_GOLDENIMAGE, - VOLUME_DELUGE1, - VOLUME_DELUGE2, - VOLUME_DELUGE3 - }; void sendReply(error_t error) { @@ -77,9 +73,10 @@ implementation { SerialReqPacket *request = (SerialReqPacket *)payload; memset(&delugeCmd, 0, sizeof(DelugeCmd)); - call stop(); delugeCmd.type = request->cmd; + // Converts the image number that the user wants to the real image number + request->imgNum = imgNum2volumeId(request->imgNum); switch (request->cmd) { case DELUGE_CMD_STOP: @@ -90,21 +87,21 @@ implementation break; case DELUGE_CMD_ONLY_DISSEMINATE: case DELUGE_CMD_DISSEMINATE_AND_REPROGRAM: - if (request->imgNum < DELUGE_NUM_VOLUMES && + if (request->imgNum != NON_DELUGE_VOLUME && (call Resource.isOwner() || call Resource.immediateRequest() == SUCCESS)) { - call DelugeMetadata.read(imgNum2volumeId[request->imgNum]); + call DelugeMetadata.read(request->imgNum); } else { sendReply(FAIL); } break; case DELUGE_CMD_REPROGRAM: - if (!(request->imgNum < DELUGE_NUM_VOLUMES)) { + case DELUGE_CMD_REBOOT: + if (request->imgNum == NON_DELUGE_VOLUME) { sendReply(FAIL); break; } - case DELUGE_CMD_REBOOT: - delugeCmd.imgNum = imgNum2volumeId[request->imgNum]; + delugeCmd.imgNum = request->imgNum; call DelayTimer.startOneShot(1024); sendReply(SUCCESS); break; diff --git a/tos/lib/net/Deluge/DelugeMetadataP.nc b/tos/lib/net/Deluge/DelugeMetadataP.nc index 6c2fa375..f10b3144 100644 --- a/tos/lib/net/Deluge/DelugeMetadataP.nc +++ b/tos/lib/net/Deluge/DelugeMetadataP.nc @@ -24,6 +24,8 @@ * @author Chieh-Jan Mike Liang */ +#include "imgNum2volumeId.h" + module DelugeMetadataP { provides interface DelugeMetadata[uint8_t client]; @@ -48,16 +50,17 @@ implementation DelugeIdent ident; uint8_t state; - uint8_t currentImage; + uint8_t currentVolume; + uint8_t currentImageIdx; uint8_t currentPage; nx_uint16_t currentCrc; uint8_t currentClient; void nextImage() { - if (currentImage < DELUGE_NUM_VOLUMES) { + if (currentImageIdx < DELUGE_NUM_VOLUMES) { state = S_READ_IDENT; - call BlockRead.read[currentImage](0, &ident, sizeof(ident)); + call BlockRead.read[currentVolume](0, &ident, sizeof(ident)); } else { signal storageReady(); state = S_READY; @@ -82,7 +85,8 @@ implementation // CRC and check it against the corresponding value from the CRCs // block. state = S_READ_IDENT; - currentImage = 0; + currentImageIdx = 0; + currentVolume = _imgNum2volumeId[currentImageIdx]; nextImage(); } @@ -110,16 +114,16 @@ implementation if (ident.uidhash != DELUGE_INVALID_UID) { currentPage = 0; state = S_READ_CRC; - call BlockRead.read[currentImage](calcCrcAddr(), ¤tCrc, sizeof(currentCrc)); + call BlockRead.read[currentVolume](calcCrcAddr(), ¤tCrc, sizeof(currentCrc)); } else { - currentImage++; + currentImageIdx++; nextImage(); } } break; case S_READ_CRC: state = S_CRC; - call BlockRead.computeCrc[currentImage](calcPageAddr(), DELUGE_BYTES_PER_PAGE, 0); + call BlockRead.computeCrc[currentVolume](calcPageAddr(), DELUGE_BYTES_PER_PAGE, 0); break; } } @@ -131,14 +135,15 @@ implementation if (crc != currentCrc) { // printf("%04x %04x\n", crc, currentCrc); // invalidate the image by erasing it - call BlockWrite.erase[currentImage](); + call BlockWrite.erase[currentVolume](); } else { currentPage++; if (currentPage < ident.numPgs) { state = S_READ_CRC; - call BlockRead.read[currentImage](calcCrcAddr(), ¤tCrc, sizeof(currentCrc)); + call BlockRead.read[currentVolume](calcCrcAddr(), ¤tCrc, sizeof(currentCrc)); } else { - currentImage++; + currentImageIdx++; + currentVolume = _imgNum2volumeId[currentImageIdx]; nextImage(); } } @@ -157,7 +162,8 @@ implementation signal BlockWrite.eraseDone[imgNum](error); break; case S_CRC: - currentImage++; + currentImageIdx++; + currentVolume = _imgNum2volumeId[currentImageIdx]; nextImage(); break; } diff --git a/tos/lib/net/Deluge/FlashVolumeManager/FlashVolumeManagerP.nc b/tos/lib/net/Deluge/FlashVolumeManager/FlashVolumeManagerP.nc index 56558c42..06420ce4 100644 --- a/tos/lib/net/Deluge/FlashVolumeManager/FlashVolumeManagerP.nc +++ b/tos/lib/net/Deluge/FlashVolumeManager/FlashVolumeManagerP.nc @@ -24,6 +24,8 @@ * @author Razvan Musaloiu-E. */ +#include "imgNum2volumeId.h" + generic module FlashVolumeManagerP() { uses { @@ -88,13 +90,6 @@ implementation nx_uint16_t nodeid; }; - uint8_t imgNum2volumeId[] = { - VOLUME_GOLDENIMAGE, - VOLUME_DELUGE1, - VOLUME_DELUGE2, - VOLUME_DELUGE3 - }; - void sendReply(error_t error, storage_len_t len) { SerialReplyPacket *reply = (SerialReplyPacket *)call SerialAMSender.getPayload(&serialMsg, sizeof(SerialReplyPacket)); @@ -186,9 +181,9 @@ implementation } // Converts the image number that the user wants to the real image number - imgNum = request->imgNum < DELUGE_NUM_VOLUMES ? imgNum2volumeId[request->imgNum] : 0xFF; + imgNum = imgNum2volumeId(request->imgNum); - if (imgNum != 0xFF) { + if (imgNum != NON_DELUGE_VOLUME) { error = SUCCESS; // We ask for a reservation only for erase and write. switch (request->cmd) { @@ -259,10 +254,9 @@ implementation { // Release the resource. if (state == S_IDLE && call Resource.isOwner()) { - call Leds.led1Off(); call Resource.release(); } - if (state == S_IDLE && !call ArbiterInfo.inUse()) { + if (state == S_IDLE) { call Leds.led1Off(); } } diff --git a/tos/lib/net/Deluge/ReprogramGuard.nc b/tos/lib/net/Deluge/ReprogramGuard.nc new file mode 100644 index 00000000..df3ca418 --- /dev/null +++ b/tos/lib/net/Deluge/ReprogramGuard.nc @@ -0,0 +1,5 @@ +interface ReprogramGuard +{ + command error_t okToProgram(); + event void okToProgramDone(bool ok); +} diff --git a/tos/lib/net/Deluge/extra/NetProgC.nc b/tos/lib/net/Deluge/extra/NetProgC.nc index 8a4c6c12..462ff7da 100644 --- a/tos/lib/net/Deluge/extra/NetProgC.nc +++ b/tos/lib/net/Deluge/extra/NetProgC.nc @@ -40,14 +40,16 @@ configuration NetProgC { implementation { - components MainC, InternalFlashC as IFlash, CrcP, NetProgM; + components MainC, InternalFlashC as IFlash, CrcP; + components NetProgM, ReprogramGuardC; NetProg = NetProgM; MainC.SoftwareInit -> NetProgM.Init; NetProgM.IFlash -> IFlash; NetProgM.Crc -> CrcP; - + NetProgM.ReprogramGuard -> ReprogramGuardC; + components LedsC; NetProgM.Leds -> LedsC; diff --git a/tos/lib/net/Deluge/extra/NetProgM.nc b/tos/lib/net/Deluge/extra/NetProgM.nc index 478bad26..7567ad1a 100644 --- a/tos/lib/net/Deluge/extra/NetProgM.nc +++ b/tos/lib/net/Deluge/extra/NetProgM.nc @@ -42,11 +42,14 @@ module NetProgM { interface Leds; interface CC2420Config; async command void setAmAddress(am_addr_t a); + interface ReprogramGuard; } } implementation { + uint32_t reprogramImgAddr; + command error_t Init.init() { BootArgs bootArgs; @@ -81,13 +84,24 @@ implementation { } command error_t NetProg.programImageAndReboot(uint32_t imgAddr) + { + reprogramImgAddr = imgAddr; + return call ReprogramGuard.okToProgram(); + } + + event void ReprogramGuard.okToProgramDone(bool ok) { BootArgs bootArgs; + if (!ok) { + // The voltage is too low. Nothing to do. + return; + } + atomic { call IFlash.read((uint8_t*)TOSBOOT_ARGS_ADDR, &bootArgs, sizeof(bootArgs)); - bootArgs.imageAddr = imgAddr; + bootArgs.imageAddr = reprogramImgAddr; bootArgs.gestureCount = 0xff; bootArgs.noReprogram = FALSE; bootArgs.address = TOS_NODE_ID; @@ -97,11 +111,7 @@ implementation { // reboot netprog_reboot(); } - - // couldn't reboot - return FAIL; } event void CC2420Config.syncDone(error_t error) {} - } diff --git a/tos/lib/net/Deluge/extra/micaz/ReprogramGuardC.nc b/tos/lib/net/Deluge/extra/micaz/ReprogramGuardC.nc new file mode 100644 index 00000000..9f25e503 --- /dev/null +++ b/tos/lib/net/Deluge/extra/micaz/ReprogramGuardC.nc @@ -0,0 +1,13 @@ +configuration ReprogramGuardC +{ + provides interface ReprogramGuard; +} + +implementation +{ + components ReprogramGuardP; + components new VoltageC(); + + ReprogramGuard = ReprogramGuardP; + ReprogramGuardP.Voltage -> VoltageC; +} diff --git a/tos/lib/net/Deluge/extra/micaz/ReprogramGuardP.nc b/tos/lib/net/Deluge/extra/micaz/ReprogramGuardP.nc new file mode 100644 index 00000000..c5dc0c89 --- /dev/null +++ b/tos/lib/net/Deluge/extra/micaz/ReprogramGuardP.nc @@ -0,0 +1,23 @@ +module ReprogramGuardP +{ + provides interface ReprogramGuard; + uses interface Read as Voltage; +} + +implementation +{ + enum { + VTHRESH = 0x1CF, // 2.7V + }; + + command error_t ReprogramGuard.okToProgram() + { + return call Voltage.read(); + } + + event void Voltage.readDone(error_t result, uint16_t val) + { + signal ReprogramGuard.okToProgramDone(result == SUCCESS && val < VTHRESH); + } + +} diff --git a/tos/lib/net/Deluge/extra/telosb/ReprogramGuardC.nc b/tos/lib/net/Deluge/extra/telosb/ReprogramGuardC.nc new file mode 100644 index 00000000..9f25e503 --- /dev/null +++ b/tos/lib/net/Deluge/extra/telosb/ReprogramGuardC.nc @@ -0,0 +1,13 @@ +configuration ReprogramGuardC +{ + provides interface ReprogramGuard; +} + +implementation +{ + components ReprogramGuardP; + components new VoltageC(); + + ReprogramGuard = ReprogramGuardP; + ReprogramGuardP.Voltage -> VoltageC; +} diff --git a/tos/lib/net/Deluge/extra/telosb/ReprogramGuardP.nc b/tos/lib/net/Deluge/extra/telosb/ReprogramGuardP.nc new file mode 100644 index 00000000..1ffb1e9a --- /dev/null +++ b/tos/lib/net/Deluge/extra/telosb/ReprogramGuardP.nc @@ -0,0 +1,23 @@ +module ReprogramGuardP +{ + provides interface ReprogramGuard; + uses interface Read as Voltage; +} + +implementation +{ + enum { + VTHRESH = 0xE66, // 2.7V + }; + + command error_t ReprogramGuard.okToProgram() + { + return call Voltage.read(); + } + + event void Voltage.readDone(error_t result, uint16_t val) + { + signal ReprogramGuard.okToProgramDone(result == SUCCESS && val > VTHRESH); + } + +} diff --git a/tos/lib/net/Deluge/imgNum2volumeId.h b/tos/lib/net/Deluge/imgNum2volumeId.h new file mode 100644 index 00000000..0c3170ba --- /dev/null +++ b/tos/lib/net/Deluge/imgNum2volumeId.h @@ -0,0 +1,20 @@ +#ifndef __IMGNUM2VOLUMEID_H__ +#define __IMGNUM2VOLUMEID_H__ + +uint8_t _imgNum2volumeId[] = { + VOLUME_GOLDENIMAGE, + VOLUME_DELUGE1, + VOLUME_DELUGE2, + VOLUME_DELUGE3 +}; + +enum { + NON_DELUGE_VOLUME = 0xFF +}; + +uint8_t imgNum2volumeId(uint8_t imgNum) +{ + return imgNum < DELUGE_NUM_VOLUMES ? _imgNum2volumeId[imgNum] : NON_DELUGE_VOLUME; +} + +#endif diff --git a/tos/lib/tosboot/micaz/hardware.h b/tos/lib/tosboot/micaz/hardware.h index 8f7a1c7f..01fc2d1d 100644 --- a/tos/lib/tosboot/micaz/hardware.h +++ b/tos/lib/tosboot/micaz/hardware.h @@ -80,8 +80,16 @@ typedef uint32_t in_flash_addr_t; typedef uint32_t ex_flash_addr_t; -void wait( uint16_t t ) { - for ( ; t; t-- ); +static inline void wait( uint16_t dt ) { + /* In most cases (constant arg), the test is elided at compile-time */ + if (dt) + /* loop takes 8 cycles. this is 1uS if running on an internal 8MHz + clock, and 1.09uS if running on the external crystal. */ + asm volatile ( + "1: sbiw %0,1\n" + " adiw %0,1\n" + " sbiw %0,1\n" + " brne 1b" : "+w" (dt)); } // LED assignments