From: razvanm Date: Wed, 18 Jun 2008 20:22:51 +0000 (+0000) Subject: Performance enhancements to tos.py, rename of TINYOS_NP=BNP to BOOTLOADER=tosboot... X-Git-Tag: release_tinyos_2_1_0_0~235 X-Git-Url: https://oss.titaniummirror.com/gitweb/?p=tinyos-2.x.git;a=commitdiff_plain;h=f4263e3d036f79a8127d49ced6ec40be6e81d1e2 Performance enhancements to tos.py, rename of TINYOS_NP=BNP to BOOTLOADER=tosboot, move tos.py in support. --- diff --git a/apps/tests/deluge/Blink/Makefile b/apps/tests/deluge/Blink/Makefile index 6f7acb39..5aad1f19 100644 --- a/apps/tests/deluge/Blink/Makefile +++ b/apps/tests/deluge/Blink/Makefile @@ -1,5 +1,5 @@ COMPONENT=BlinkAppC -TINYOS_NP=BNP +BOOTLOADER=tosboot #CFLAGS += -DDELUGE_BASESTATION #CFLAGS += -DDELUGE_LIGHT_BASESTATION diff --git a/apps/tests/deluge/GoldenImage/Makefile b/apps/tests/deluge/GoldenImage/Makefile index 31873768..cbdea503 100644 --- a/apps/tests/deluge/GoldenImage/Makefile +++ b/apps/tests/deluge/GoldenImage/Makefile @@ -1,5 +1,5 @@ COMPONENT=GoldenImageC -TINYOS_NP=BNP +BOOTLOADER=tosboot CFLAGS += -DDELUGE_BASESTATION diff --git a/apps/tests/deluge/SerialBlink/Makefile b/apps/tests/deluge/SerialBlink/Makefile index c77ce966..319a5d83 100644 --- a/apps/tests/deluge/SerialBlink/Makefile +++ b/apps/tests/deluge/SerialBlink/Makefile @@ -1,4 +1,4 @@ COMPONENT=BlinkAppC -TINYOS_NP=BNP +BOOTLOADER=tosboot include $(MAKERULES) diff --git a/support/make/Makedefaults b/support/make/Makedefaults index 334d1542..70773c17 100644 --- a/support/make/Makedefaults +++ b/support/make/Makedefaults @@ -4,7 +4,7 @@ DEFAULT_LOCAL_GROUP ?= 0x22 OPTFLAGS ?= -Os NESC_FLAGS ?= -Wnesc-all -GOALS += ident_flags tos_image bnp +GOALS += ident_flags tos_image tosboot define DEFAULT_HELP diff --git a/support/make/avr/avrisp.extra b/support/make/avr/avrisp.extra index 0394adc4..875cb329 100644 --- a/support/make/avr/avrisp.extra +++ b/support/make/avr/avrisp.extra @@ -8,20 +8,20 @@ endif PROGRAM = avrisp ifeq ($(PROGRAMMER),avrdude) - ifdef BOOTLOADER + ifdef BOOTLOADER_IMG ifeq ($(shell [ -f /bin/cygwin1.dll ] && echo cygwin),cygwin) - BOOTLOADER := $(shell cygpath -m $(BOOTLOADER)) + BOOTLOADER_IMG := $(shell cygpath -m $(BOOTLOADER_IMG)) endif endif PROGRAMMER_FLAGS = -cstk500 -P$(MIB510) -U hfuse:w:$(AVR_FUSE_H):m $(PROGRAMMER_PART) $(PROGRAMMER_EXTRA_FLAGS) $(PROGRAMMER_EXTRA_FLAGS_AVRISP) PROGRAMMER_INSTALL_SREC_FLAGS = -U flash:w:$(INSTALL_SREC):a - PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = -V -D -U flash:w:$(BOOTLOADER):a + PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = -V -D -U flash:w:$(BOOTLOADER_IMG):a endif ifeq ($(PROGRAMMER),uisp) PROGRAMMER_FLAGS = -dprog=stk500 -dserial=$(AVRISP) --wr_fuse_h=$(AVR_FUSE_H) $(PROGRAMMER_PART) $(PROGRAMMER_EXTRA_FLAGS) $(PROGRAMMER_EXTRA_FLAGS_AVRISP) PROGRAMMER_INSTALL_SREC_FLAGS = --erase --upload if=$(INSTALL_SREC) --verify - PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = --upload if=$(BOOTLOADER) --verify + PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = --upload if=$(BOOTLOADER_IMG) --verify endif program: FORCE diff --git a/support/make/avr/dapa.extra b/support/make/avr/dapa.extra index 20a6cb15..7bae57d6 100644 --- a/support/make/avr/dapa.extra +++ b/support/make/avr/dapa.extra @@ -8,20 +8,20 @@ PROGRAM = dapa ifeq ($(PROGRAMMER),avrdude) - ifdef BOOTLOADER + ifdef BOOTLOADER_IMG ifeq ($(shell [ -f /bin/cygwin1.dll ] && echo cygwin),cygwin) - BOOTLOADER := $(shell cygpath -m $(BOOTLOADER)) + BOOTLOADER_IMG := $(shell cygpath -m $(BOOTLOADER_IMG)) endif endif PROGRAMMER_FLAGS = -cdapa -U hfuse:w:$(AVR_FUSE_H):m $(PROGRAMMER_PART) $(PROGRAMMER_EXTRA_FLAGS) $(PROGRAMMER_EXTRA_FLAGS_MIB) PROGRAMMER_INSTALL_SREC_FLAGS = -U flash:w:$(INSTALL_SREC):a - PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = -V -D -U flash:w:$(BOOTLOADER):a + PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = -V -D -U flash:w:$(BOOTLOADER_IMG):a endif ifeq ($(PROGRAMMER),uisp) PROGRAMMER_FLAGS = -dprog=dapa --wr_fuse_h=$(AVR_FUSE_H) $(PROGRAMMER_PART) $(PROGRAMMER_EXTRA_FLAGS) $(PROGRAMMER_EXTRA_FLAGS_MIB) PROGRAMMER_INSTALL_SREC_FLAGS = --erase --upload if=$(INSTALL_SREC) --verify - PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = --upload if=$(BOOTLOADER) --verify + PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = --upload if=$(BOOTLOADER_IMG) --verify endif program: FORCE diff --git a/support/make/avr/eprb.extra b/support/make/avr/eprb.extra index e53bfc60..92d8982d 100644 --- a/support/make/avr/eprb.extra +++ b/support/make/avr/eprb.extra @@ -8,20 +8,20 @@ endif PROGRAM = eprb ifeq ($(PROGRAMMER),avrdude) - ifdef BOOTLOADER + ifdef BOOTLOADER_IMG ifeq ($(shell [ -f /bin/cygwin1.dll ] && echo cygwin),cygwin) - BOOTLOADER := $(shell cygpath -m $(BOOTLOADER)) + BOOTLOADER_IMG := $(shell cygpath -m $(BOOTLOADER_IMG)) endif endif PROGRAMMER_FLAGS = -cstk500 -P$(EPRB) -U hfuse:w:$(AVR_FUSE_H):m $(PROGRAMMER_PART) $(PROGRAMMER_EXTRA_FLAGS) $(PROGRAMMER_EXTRA_FLAGS_STK) PROGRAMMER_INSTALL_SREC_FLAGS = -U flash:w:$(INSTALL_SREC):a - PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = -V -D -U flash:w:$(BOOTLOADER):a + PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = -V -D -U flash:w:$(BOOTLOADER_IMG):a endif ifeq ($(PROGRAMMER),uisp) PROGRAMMER_FLAGS = -dprog=stk500 -dhost=$(EPRB) --wr_fuse_h=$(AVR_FUSE_H) $(PROGRAMMER_PART) $(PROGRAMMER_EXTRA_FLAGS) $(PROGRAMMER_EXTRA_FLAGS_STK) PROGRAMMER_INSTALL_SREC_FLAGS = --erase --upload if=$(INSTALL_SREC) --verify - PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = --upload if=$(BOOTLOADER) --verify + PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = --upload if=$(BOOTLOADER_IMG) --verify endif program: FORCE diff --git a/support/make/avr/install.extra b/support/make/avr/install.extra index c212cbea..672ee9de 100644 --- a/support/make/avr/install.extra +++ b/support/make/avr/install.extra @@ -4,8 +4,8 @@ NODEID = $(INSTALL) BUILD_DEPS = srec tosimage bytes $(POST_BUILD_EXTRA_DEPS) setid program delsetid -ifdef TINYOS_NP - ifeq ($(TINYOS_NP),BNP) +ifdef BOOTLOADER + ifeq ($(BOOTLOADER),tosboot) BUILD_DEPS += program_bl endif endif diff --git a/support/make/avr/mib510.extra b/support/make/avr/mib510.extra index 02af509b..974b0e26 100644 --- a/support/make/avr/mib510.extra +++ b/support/make/avr/mib510.extra @@ -8,20 +8,20 @@ endif PROGRAM = mib510 ifeq ($(PROGRAMMER),avrdude) - ifdef BOOTLOADER + ifdef BOOTLOADER_IMG ifeq ($(shell [ -f /bin/cygwin1.dll ] && echo cygwin),cygwin) - BOOTLOADER := $(shell cygpath -m $(BOOTLOADER)) + BOOTLOADER_IMG := $(shell cygpath -m $(BOOTLOADER_IMG)) endif endif PROGRAMMER_FLAGS = -cmib510 -P$(MIB510) -U hfuse:w:$(AVR_FUSE_H):m $(PROGRAMMER_PART) $(PROGRAMMER_EXTRA_FLAGS) $(PROGRAMMER_EXTRA_FLAGS_MIB) PROGRAMMER_INSTALL_SREC_FLAGS = -U flash:w:$(INSTALL_SREC):a - PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = -V -D -U flash:w:$(BOOTLOADER):a + PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = -V -D -U flash:w:$(BOOTLOADER_IMG):a endif ifeq ($(PROGRAMMER),uisp) PROGRAMMER_FLAGS = -dprog=mib510 -dserial=$(MIB510) --wr_fuse_h=$(AVR_FUSE_H) $(PROGRAMMER_PART) $(PROGRAMMER_EXTRA_FLAGS) $(PROGRAMMER_EXTRA_FLAGS_MIB) PROGRAMMER_INSTALL_SREC_FLAGS = --erase --upload if=$(INSTALL_SREC) --verify - PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = --upload if=$(BOOTLOADER) --verify + PROGRAMMER_INSTALL_BOOTLOADER_FLAGS = --upload if=$(BOOTLOADER_IMG) --verify endif program: FORCE diff --git a/support/make/avr/reinstall.extra b/support/make/avr/reinstall.extra index 1c8748f1..cabb81cc 100644 --- a/support/make/avr/reinstall.extra +++ b/support/make/avr/reinstall.extra @@ -4,8 +4,8 @@ NODEID = $(REINSTALL) BUILD_DEPS = setid program delsetid -ifdef TINYOS_NP - ifeq ($(TINYOS_NP),BNP) +ifdef BOOTLOADER + ifeq ($(BOOTLOADER),tosboot) BUILD_DEPS += program_bl endif endif diff --git a/support/make/bnp.extra b/support/make/bnp.extra deleted file mode 100644 index 7368c195..00000000 --- a/support/make/bnp.extra +++ /dev/null @@ -1,37 +0,0 @@ -#-*-Makefile-*- vim:syntax=make -#$Id$ - -DELUGE_DIR ?= $(TOSDIR)/lib/net/Deluge -DELUGE_EXTRA ?= $(DELUGE_DIR)/extra -TOSBOOT_DIR ?= $(TOSDIR)/lib/tosboot/build - -ifeq ($(TINYOS_NP),BNP) - - CFLAGS += -DDELUGE - CFLAGS += -I$(TOSDIR)/lib/net -I$(TOSDIR)/lib/net/drip -I$(DELUGE_DIR) -I$(DELUGE_DIR)/FlashVolumeManager -I$(DELUGE_DIR)/BlockStorageManager - - ifneq ($(filter telosb tmote,$(TARGETS)),) - CFLAGS += -I$(DELUGE_EXTRA) -I$(DELUGE_EXTRA)/msp430 -I$(DELUGE_EXTRA)/telos -I$(DELUGE_EXTRA)/telosb - ifeq ($(filter docs,$(GOALS)),) - CFLAGS += -Wl,--section-start=.text=0x4a00,--defsym=_reset_vector__=0x4000 - endif - BOOTLOADER ?= $(TOSBOOT_DIR)/telosb/main.ihex - ifeq ($(shell [ -f /bin/cygwin1.dll ] && echo cygwin),cygwin) - BOOTLOADER := $(shell cygpath -m $(BOOTLOADER)) - endif - endif - - ifeq ($(TARGETS),micaz) - CFLAGS += -I$(DELUGE_EXTRA) -I$(DELUGE_EXTRA)/avr -I$(DELUGE_EXTRA)/micaz -I$(DELUGE_EXTRA)/mica2 - BOOTLOADER ?= $(TOSBOOT_DIR)/micaz/main.ihex - AVR_FUSE_H ?= 0xda - endif - - ifeq ($(TARGETS),iris) - CFLAGS += -I$(DELUGE_EXTRA)/iris -I$(DELUGE_EXTRA)/micaz -I$(DELUGE_EXTRA)/mica2 -I$(DELUGE_EXTRA)/avr -I$(DELUGE_EXTRA) - BOOTLOADER ?= $(TOSBOOT_DIR)/iris/main.ihex - AVR_FUSE_H ?= 0xda - endif - - -endif diff --git a/support/make/msp/bsl.extra b/support/make/msp/bsl.extra index d5c0f54e..4be2e8a2 100644 --- a/support/make/msp/bsl.extra +++ b/support/make/msp/bsl.extra @@ -52,7 +52,7 @@ program_no_e: $(BSL_TARGETS) $(TELOS_PROGRAM_DEPS) FORCE program_bl: $(BSL_TARGETS) $(TELOS_PROGRAM_DEPS) FORCE @echo " installing $(PLATFORM) bootloader using bsl" - $(MSP_BSL) $(MSP_BSL_FLAGS) -c $(BSL) -r -e -I -p $(BOOTLOADER) + $(MSP_BSL) $(MSP_BSL_FLAGS) -c $(BSL) -r -e -I -p $(BOOTLOADER_IMG) program_input: ihex @: diff --git a/support/make/msp/install.extra b/support/make/msp/install.extra index 91ef45fc..9627a1c9 100644 --- a/support/make/msp/install.extra +++ b/support/make/msp/install.extra @@ -4,8 +4,8 @@ NODEID = $(INSTALL) BUILD_DEPS = tosimage $(POST_BUILD_EXTRA_DEPS) bytes setid program -ifdef TINYOS_NP - ifeq ($(TINYOS_NP),BNP) +ifdef BOOTLOADER + ifeq ($(BOOTLOADER),tosboot) BUILD_DEPS = tosimage $(POST_BUILD_EXTRA_DEPS) setid program_bl program_no_e endif endif diff --git a/support/make/msp/jtag.extra b/support/make/msp/jtag.extra index 35355ccd..3a048ed0 100644 --- a/support/make/msp/jtag.extra +++ b/support/make/msp/jtag.extra @@ -17,7 +17,7 @@ program_no_e: FORCE program_bl: FORCE @echo " installing $(PLATFORM) bootloader using jtag" - $(MSP_JTAG) $(MSP_JTAG_FLAGS) -r -e -I -p $(BOOTLOADER) + $(MSP_JTAG) $(MSP_JTAG_FLAGS) -r -e -I -p $(BOOTLOADER_IMG) program_input: ihex @: diff --git a/support/make/msp/reinstall.extra b/support/make/msp/reinstall.extra index cf0d9d87..360eb5de 100644 --- a/support/make/msp/reinstall.extra +++ b/support/make/msp/reinstall.extra @@ -4,11 +4,11 @@ NODEID = $(REINSTALL) BUILD_DEPS = setid program -ifdef TINYOS_NP - ifeq ($(TINYOS_NP),BNP) +ifdef BOOTLOADER + ifeq ($(BOOTLOADER),tosboot) BUILD_DEPS = setid program_bl program_no_e endif endif -check_bnp: FORCE - @perl -e 'exit 0 if (<> =~ /^\:103000/); print "\nERROR: Trying to install with BNP support.\n main.ihex was not built properly, please recompile.\n\n"; exit 1;' $(INSTALL_IHEX) +check_tosboot: FORCE + @perl -e 'exit 0 if (<> =~ /^\:103000/); print "\nERROR: Trying to install with tosboot support.\n main.ihex was not built properly, please recompile.\n\n"; exit 1;' $(INSTALL_IHEX) diff --git a/support/make/tinynode/gdb.extra b/support/make/tinynode/gdb.extra index 2f27b9c9..76e3a3a0 100644 --- a/support/make/tinynode/gdb.extra +++ b/support/make/tinynode/gdb.extra @@ -22,5 +22,5 @@ program_no_e: FORCE program_bl: FORCE @echo " installing $(PLATFORM) bootloader using gdb" @echo " installing $(PLATFORM) binary using gdb (without mass erase)" - cat $(INIT_GDB) $(FLASH_GDB) $(FLASH_GDB_NO_E) $(GDB_SCRIPT) | sed -e "s/@HOST@/$(PROXY_HOST)/g" -e "s#@EXE@#$(BOOTLOADER)#g" -e "s#@MAIN@#$(MAIN_EXE)#g" -e "s#@PROMPT@#msp-gdb $(COMPONENT)#g"> build/init.gdb; \ + cat $(INIT_GDB) $(FLASH_GDB) $(FLASH_GDB_NO_E) $(GDB_SCRIPT) | sed -e "s/@HOST@/$(PROXY_HOST)/g" -e "s#@EXE@#$(BOOTLOADER_IMG)#g" -e "s#@MAIN@#$(MAIN_EXE)#g" -e "s#@PROMPT@#msp-gdb $(COMPONENT)#g"> build/init.gdb; \ msp430-gdb $(GDB_ARGS) -silent -x build/init.gdb -se $(MAIN_EXE); \ No newline at end of file diff --git a/support/sdk/python/tos.py b/support/sdk/python/tos.py new file mode 100644 index 00000000..19fd2d36 --- /dev/null +++ b/support/sdk/python/tos.py @@ -0,0 +1,985 @@ +# 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'] + +ACK_WAIT = 0.2 # Maximum amount of time to wait for an ack +ACK_WARN = 0.2 # Warn if acks take longer than this to arrive + +def list2hex(v): + return " ".join(["%02x" % p for p in v]) + + +class Error(Exception): + """Base error class for this module""" + pass + + +class TimeoutError(Error): + """Thrown when a serial operation times out""" + pass + + +class ReadError(Error): + """Base class for read error exceptions""" + pass + + +class WriteError(Error): + """Base class for write error exceptions""" + pass + + +class ReadTimeoutError(TimeoutError, ReadError): + """Thrown when a serial read operation times out""" + pass + + +class ReadCRCError(ReadError): + """Thrown when a read packet fails a CRC check""" + pass + + +class BadAckSeqnoError(ReadError): + """Thrown if an ack packet has an unexpected sequenc number""" + pass + + +class WriteTimeoutError(TimeoutError, WriteError): + """Thrown when a serial write operation times out""" + pass + + +class SimpleSerial: + """ + A SimpleSerial object offers a way to send and data using a HDLC-like + formating. + + Use SimpleSerial objects for basic low-level serial communications. Use + Serial objects for higher level logic (retry sends, log printfs, etc). + """ + + 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, + timeout=None): + self._debug = debug + self._in_queue = [] + self._qsize = qsize + self._ack = None + self._write_counter = 0 + self._write_counter_failures = 0 + self._read_counter = 0 + self._ts = None + self.timeout = timeout # Public attribute + self._received_packet_filters = [] # filter functions for received packets + + # Remember sent (and unacknowledged) seqno numbers for 15 seconds: + self._unacked_seqnos = SeqTracker(15.0) + + self._s = serial.Serial(port, baudrate, rtscts=0, timeout=0.5) + self._s.flushInput() + if flush: + print >>sys.stdout, "Flushing the serial port", + endtime = time.time() + 1 + while time.time() < endtime: + try: + self._read() + except ReadError: + pass + sys.stdout.write(".") + if not self._debug: + sys.stdout.write("\n") + self._s.close() + self._s = serial.Serial(port, baudrate, rtscts=0, timeout=timeout) + + # Add a filter for received 'write ack' packets + self.add_received_packet_filter(self._write_ack_filter) + + # Returns the next incoming serial packet + def _read(self, timeout=None): + """Wait for a packet and return it as a RawPacket. + + Throws: + - ReadCRCError if a CRC check fails + - ReadTimeoutError if the timeout expires. + + """ + + # Developer notes: + # + # Packet data read from Serial is in this format: + # [HDLC_FLAG_BYTE][Escaped data][HDLC_FLAG_BYTE] + # + # [Escaped data] is encoded so that [HDLC_FLAG_BYTE] byte + # values cannot occur within it. When [Escaped data] has been + # unescaped, the last 2 bytes are a 16-bit CRC of the earlier + # part of the packet (excluding the initial HDLC_FLAG_BYTE + # byte) + # + # It's also possible that the serial device was half-way + # through transmitting a packet when this function was called + # (app was just started). So we also neeed to handle this case: + # + # [Incomplete escaped data][HDLC_FLAG_BYTE][HDLC_FLAG_BYTE][Escaped data][HDLC_FLAG_BYTE] + # + # In this case we skip over the first (incomplete) packet. + # + + if self._s.timeout != timeout and timeout != None: + if self._debug: + print "Set the timeout to %s, previous one was %s" % (timeout, self._s.timeout) + self._s.timeout = timeout + + try: + # Read bytes until we get to a HDLC_FLAG_BYTE value + # (either the end of a packet, or the start of a new one) + d = self._get_byte(timeout) + ts = time.time() + if self._debug and d != self.HDLC_FLAG_BYTE: + print "Skipping incomplete packet" + while d != self.HDLC_FLAG_BYTE: + d = self._get_byte(timeout) + ts = time.time() + + # Store HDLC_FLAG_BYTE at the start of the retrieved packet + # data: + packet = [d] + + # Is the next byte also HDLC_FLAG_BYTE? + d = self._get_byte(timeout) + if d == self.HDLC_FLAG_BYTE: + # Yes. This means that the previous byte was for + # the end of the previous packet, and this byte is for + # the start of the next packet. + + # Get the 2nd byte of the new packet: + d = self._get_byte(timeout) + ts = time.time() + + # We are now on the 2nd byte of the packet. Add it to + # our retrieved packet data: + packet.append(d) + + # Read bytes from serial until we read another + # HDLC_FLAG_BYTE value (end of the current packet): + while d != self.HDLC_FLAG_BYTE: + d = self._get_byte(timeout) + packet.append(d) + + # Done reading a whole packet from serial + if self._debug: + print "SimpleSerial:_read: unescaped", packet + + # Decode the packet, and check CRC: + 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]) + raise ReadCRCError + 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 + + # Packet was successfully retrieved, so return it in a + # RawPacket wrapper object (but leave out the + # HDLC_FLAG_BYTE and CRC bytes) + return RawPacket(ts, packet[1:-3]) + except socket.timeout: + raise ReadTimeoutError + + def _write_ack_filter(self, packet): + """Filter for recieved write acknowledgement packets""" + ack = AckFrame(packet.data) + if ack.protocol == self.SERIAL_PROTO_ACK: + if self._debug: + print "_filter_read: got an ack:", ack + self._ack = ack + packet = None # No further processing of received ack packet + return packet + + def _filter_read(self, timeout=None): + """Read a packet from the serial device, perform filtering, and return + the packet if it hasn't been processed yet. + + """ + p = self._read(timeout) + self._read_counter += 1 + if self._debug: + print "_filter_read: got a packet(%d): %s" % (self._read_counter, p) + + # Pass the received packet through the filter functions: + if p is not None: + for filter_func in self._received_packet_filters: + p = filter_func(p) + # Stop now if the packet doesn't need further processing: + if p is None: + break + + # Return the packet (if there was no timeout and it wasn't filtered) + return p + + def _get_ack(self, timeout, expected_seqno): + """Get the next ack packet + + Read packets from the serial device until we get the next ack (which + then gets stored in self._ack), or the timeout expires. non-ack packets + are buffered. + + Throws: + - ReadTimeoutError if the timeout expires. + - BadAckSeqnoError if an ack with a bad sequence number is received + + """ + endtime = time.time() + timeout + while time.time() < endtime: + # Read the a packet over serial + self._ack = None + remaining = endtime - time.time() + p = self._filter_read(timeout) + + # Was the packet filtered? + if p: + # Got an unfiltered packet + if len(self._in_queue) >= self._qsize: + print "Warning: Buffer overflow" + self._in_queue.pop(0) + self._in_queue.append(p) + else: + # Packet was filtered. Was it an ack? + if self._ack is not None: + # The packet was an ack, so remove it from our + # 'unacknowledged seqnos' list (or raise a BadAckSeqnoError + # error if it isn't in the list) + self._unacked_seqnos.seqno_acked(self._ack.seqno) + + # Stop reading packets if it's the ack we are waiting for: + if self._ack.seqno == expected_seqno: + return + + # Timed out + raise ReadTimeoutError + + def close(self): + """Close the serial device""" + self._s.close() + + def read(self, timeout=None): + """Read a packet, either from the input buffer or from the serial + device. + + Returns a RawPacket object, otherwise None if the packet was filtered + (by eg: Serial's printf-filtering function) + + Does not retry reads if the first one fails. Use Serial.read() for + that. + + """ + if self._in_queue: + return self._in_queue.pop(0) + else: + return self._filter_read(timeout) + + def write(self, payload, seqno, timeout=0.2): + """ + 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(). + + Only attempts to write once, and times out if an ack packet is not + received within [timeout] seconds. Use Serial.write() if you want + automatic write retries. + + seqno should be an integer between 0 and 99 which changes each time you + send a new packet. The value should remain the same when you are + retrying a packet write that just failed. + + Raises WriteTimeoutError if the write times out (ack packet doesn't + arrive within [timeout] seconds). + + """ + if type(payload) != type([]): + # Assume this will be derived from Packet + payload = payload.payload() + 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] + + # Write the packet: + self._unacked_seqnos.seqno_sent(seqno) # Keep track of sent seqno's + self._put_bytes(packet) + self._write_counter += 1 + + # Wait for an ack packet: + if self._debug: + print "Send(%d/%d): %s" % (self._write_counter, self._write_counter_failures, packet) + print "Wait for ack %d ..." % (seqno) + + try: + self._get_ack(timeout, seqno) + except ReadTimeoutError: + # Re-raise read timeouts (of ack packets) as write timeouts (of + # the write operation) + self._write_counter_failures += 1 + raise WriteTimeoutError + + # Received an ack packet, with the expected sequence number + if self._debug: + print "Wait for ack %d done. Latest ack:" % (seqno), self._ack + print "The packet was acked." + print "Returning from SimpleSerial.write..." + + def add_received_packet_filter(self, filter_func): + """Register a received packet-filtering callback function + + _filter_read() calls all of the registered filter functions for each + packet received over serial. Registered filter functions are called in + the order they were registered. + + Filter functions are called like this: filter_func(packet) + + When a filter function recognises and handles a received packet it + should return a None value to indicate that no further processing + is required for the packet. + + When a filter function skips a packet (or for some reason you want + further processing to happen on a packet you've just processed), the + function should return the packet that was passed to it as an argument. + + """ + self._received_packet_filters.append(filter_func) + + def remove_received_packet_filter(self, filter_func): + """Remove a filter function added with add_received_packet_filter()""" + self._received_packet_filters.remove(filter_func) + + 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, timeout=None): +# old_timeout = self._s.timeout +# if timeout is not None: +# self._s.timeout = timeout + try: + r = struct.unpack("B", self._s.read())[0] + return r + except struct.error: + # Serial port read timeout + raise socket.timeout +# finally: +# self._s.timeout = old_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 SeqTracker: + """Class for keeping track of unacknowledged packet sequence numbers. + + SeqTracker is used by SimpleSerial to keep track of sequence numbers which + have been sent with write packets, but not yet acknowledged by received + write ack packets. + + """ + def __init__(self, keep_for): + """Initialise a SeqTracker object. + + args: + + - keep_for is the length of time for which unacknowledged sequence + numbers should be remembered. After this period has elapsed, the + sequence numbers should be forgotten. If the sequence number is + acknowledged later, it will be treated as unkown + + """ + self._keep_for = keep_for + self._queue = [] + + def seqno_sent(self, seqno): + """Register that a packet with the specified sequence number was just + sent.""" + self._gc() + self._queue.append((seqno, time.time())) + + def seqno_acked(self, seqno): + """Register that a sequence number was just acknowledged. + + Find the oldest-known occurance of seqno in the queue and remove it. If + not found then raise a BadAckSeqnoError to inform applications that + the sequence number is not known. + + """ + self._gc() + for item in self._queue: + if item[0] == seqno: + # Found seqno + self._queue.remove(item) + return + # seqno not found! + raise BadAckSeqnoError + + def get_seqno_sent_times(self, seqno): + """Return the times when packets with the given sequence number were + sent.""" + self._gc() + return [item[1] for item in self._queue if item[0] == seqno] + + def __contains__(self, seqno): + """Return True if the seqno was sent recently (and not acknowledged + yet)""" + self._gc() + for item in self._queue: + if item[0] == seqno: + return True + return False + + def _gc(self): + """Remove old items from the queue""" + remove_before = time.time() - self._keep_for + for item in self._queue: + # Time for the sequence to be removed? + if item[1] < remove_before: + # Sequence data is old, so remove it + self._queue.remove(item) + else: + # Sequence number was added recently, so don't remove it. Also + # stop processing the queue because all later items will be + # newer + break + + +class Serial: + """ + Wraps a SimpleSerial object, and provides some higher-level functionality + like retrying writes and logging printf packets. + """ + def __init__(self, port, baudrate, flush=False, debug=False, qsize=10, + timeout=None): + """Initialise a Serial object""" + self._debug = debug + self.timeout = timeout # Public attribute + self._seqno = 0 + self._simple_serial = SimpleSerial(port, baudrate, flush, debug, qsize, + timeout) + + # Setup automatic logging of received printf packets: + self._printf_msg = "" + self._simple_serial.add_received_packet_filter(self._printf_filter) + + def close(self): + """Close the serial device""" + self._simple_serial.close() + + def read(self, timeout=None): + """Read a packet from the serial port. + + Retries packet reads until the timeout expires. + + Throws ReadTimeoutError if a a packet can't be read within the timeout. + + """ + if timeout is None: + timeout = self.timeout + endtime = None + + if timeout is not None: + endtime = time.time() + timeout + + while endtime is None or time.time() < endtime: + remaining = None + if endtime is not None: + remaining = endtime - time.time() + try: + p = self._simple_serial.read(remaining) + except ReadError: + if self._debug: + print "Packet read failed. Try again." + else: + # Was the packet filtered? + if p is not None: + # Not filtered, so return it. + # In the current TinyOS the packets from the mote are + # always NoAckDataFrame + return NoAckDataFrame(p.data) + + # Read timeout expired + raise ReadTimeoutError + + def write(self, payload, timeout=None): + """Write a packet to the serial port + + Keeps retrying endlessly, unless a timeout is set. If the timeout + expires then WriteTimeoutError is thrown. + + """ + if timeout is None: + timeout = self.timeout + + endtime = None + if timeout is not None: + endtime = time.time() + timeout + + # Generate the next sequence number: + self._seqno = (self._seqno + 1) % 100 + + while endtime is None or time.time() < endtime: + try: + ackwait = ACK_WAIT + if endtime is not None: + remaining = endtime - time.time() + ackwait = min(ACK_WAIT, remaining) + + before = time.time() + self._simple_serial.write(payload, self._seqno, ackwait) + length = time.time() - before + + if length >= ACK_WARN: + print "Warning: Packet write took %.3fs!" % (length) + return True + except Error: + if self._debug: + print "The packet was not acked. Try again." + + # Write operation timed out + raise WriteTimeoutError + + def _printf_filter(self, packet): + """Filter for recieved printf packets""" + ampkt = ActiveMessage(NoAckDataFrame(packet.data).data) + if ampkt.type == 100: + self._printf_msg += "".join([chr(i) for i in ampkt.data]).strip('\0') + # Split printf data on newline character: + # (last string in the split list doesn't have a newline after + # it, so we keep it until next time) + lines = self._printf_msg.split('\n') + for line in lines[:-1]: + print "PRINTF:", line + self._printf_msg = lines[-1] + packet = None # No further processing for the printf packet + return packet + +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.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=None): + return ActiveMessage(self._s.read(timeout).data) + + def write(self, packet, amid, timeout=None): + return self._s.write(ActiveMessage(packet, amid=amid), timeout=timeout) + + +class SimpleSerialAM(SimpleSerial): + """A derived class of SimpleSerial so that apps can read and write using + higher-level packet structures. + + Serves a simalar purpose to the AM class, but for SimpleSerial objects + instead instead of Serial. + + """ + + def read_am(self, timeout=None): + """Read a RawPacket object (or None), convert it to ActiveMessage + (or None), and return to the caller""" + + # Get a tos.Rawpacket (or None, if filtered) object + p = self.read(timeout) + if p is not None: + assert isinstance(p, RawPacket) + # Convert tos.RawPacket object into an ActiveMessage: + p = NoAckDataFrame(p.data) + p = ActiveMessage(p.data) + + # Return the ActiveMessage (or None) packet: + return p + + def write_am(self, packet, amid, seqno, timeout=2.0): + """Convert app packet format to ActiveMessage, and write the + ActiveMessage packet to serial""" + + # Convert from app-specific packet to ActiveMessage: + p = ActiveMessage(packet, amid=amid) + + # Write to the serial device + self.write(p, seqno, timeout) + + +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): + Packet.__init__(self, + [('ts' , 'int', 4), + ('data', 'blob', None)], + None) + self.ts = ts; + self.data = data + +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/tools/tinyos/misc/Makefile.am b/tools/tinyos/misc/Makefile.am index 295fad4f..76498bb1 100644 --- a/tools/tinyos/misc/Makefile.am +++ b/tools/tinyos/misc/Makefile.am @@ -34,6 +34,3 @@ bin_SCRIPTS = tos-ident-flags \ tos-deluge bin_PROGRAMS = tos-serial-debug - -pythondir = $(bindir) -python_DATA = tos.py diff --git a/tools/tinyos/misc/tos-deluge b/tools/tinyos/misc/tos-deluge index a6c99785..b8e79ce4 100755 --- a/tools/tinyos/misc/tos-deluge +++ b/tools/tinyos/misc/tos-deluge @@ -23,10 +23,14 @@ # @author Razvan Musaloiu-E. # @author Chieh-Jan Mike Liang -import sys, stat, struct, subprocess, time -import tos +import sys, stat, struct, subprocess, time, os.path +try: + import tos +except ImportError: + import posix + sys.path = [os.path.join(posix.environ['TOSROOT'], 'support', 'sdk', 'python')] + sys.path + import tos from datetime import datetime -import os.path # Path to the python script that builds Deluge image from XML PATH_PY_BUILD_IMAGE = os.path.join(os.path.dirname(sys.argv[0]), 'tos-build-deluge-image') @@ -125,12 +129,12 @@ def crc16(data): else: crc = crc << 1 crc = crc & 0xffff - + return crc def handleResponse(success, msg): if success == True: - packet = am.read(timeout=1) + packet = am.read(timeout=2) while packet and packet.type == 100: print "".join([chr(i) for i in packet.data]) packet = am.read() @@ -143,14 +147,14 @@ def handleResponse(success, msg): else: print msg, reply return False - + print "ERROR: Unable to send the command" return False -def ident(): +def ident(timeout=None): sreqpkt = FMReqPacket((FM_CMD_IDENT, 0, 0, 0, [])) - if am.write(sreqpkt, FM_AMID): - packet = am.read() + if am.write(sreqpkt, FM_AMID, timeout=timeout): + packet = am.read(timeout=timeout) reply = SerialReplyPacket(packet.data) if reply.error == ERROR_SUCCESS: return ShortIdent(reply.data) @@ -158,12 +162,12 @@ def ident(): def read(imgNum, offset, length): r = [] - + sreqpkt = FMReqPacket((FM_CMD_READ, imgNum, offset, length, [])) while True: if sreqpkt.length > SERIAL_DATA_LENGTH: sreqpkt.length = SERIAL_DATA_LENGTH - + if am.write(sreqpkt, FM_AMID): packet = am.read() reply = SerialReplyPacket(packet.data) @@ -175,7 +179,7 @@ def read(imgNum, offset, length): else: r = None break - + sreqpkt.offset += sreqpkt.length if sreqpkt.offset >= (offset + length): break @@ -199,29 +203,29 @@ def write(imgNum, data): total_length = length # For progress bar next_tick = 100 # For progress bar start_time = time.time() - + print "[0% 25% 50% 75% 100%]\r[", - + sreqpkt.offset = 0 while length > 0: if ((length * 100) / total_length) < next_tick: next_tick = next_tick - 2 sys.stdout.write('-') sys.stdout.flush() - + # Calculates the payload size for the current packet if length >= SERIAL_DATA_LENGTH: sreqpkt.length = SERIAL_DATA_LENGTH else: sreqpkt.length = length sreqpkt.data = data[sreqpkt.offset:sreqpkt.offset+sreqpkt.length] - + # Sends over serial to the mote 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 = am.read() reply = SerialReplyPacket(packet.data) @@ -229,7 +233,7 @@ def write(imgNum, data): print print "ERROR: Unable to write to the flash volume (file offset: %d)" % sreqpkt.offset return False - + length -= sreqpkt.length sreqpkt.offset += sreqpkt.length @@ -237,7 +241,7 @@ def write(imgNum, data): elasped_time = time.time() - start_time print "\r%s bytes in %.2f seconds (%.4f bytes/s)" % (total_length, elasped_time, int(total_length) / (elasped_time)) return True - + # Checks for valid CRC and timestamp def verifyIdent(i): if i != None: @@ -286,7 +290,7 @@ def inject(imgNum, tos_image_xml): except: print "ERROR: Unable to find the image building utility, \"%s\"" % PATH_PY_BUILD_IMAGE return False - + # Gets status information of stored image i = getIdent(imgNum) if ident: @@ -306,7 +310,7 @@ def inject(imgNum, tos_image_xml): (out, err) = p.communicate(None) print err, print "--------------------------------------------------" - + # Writes the new binary image image = [struct.unpack("B", c)[0] for c in out] if len(image) > 0 and erase(imgNum): @@ -316,7 +320,7 @@ def inject(imgNum, tos_image_xml): print "Replace image with:" print formatIdent(getIdent(imgNum)) print "--------------------------------------------------" - + return False def ping(imgNum): @@ -331,7 +335,7 @@ def ping(imgNum): print formatIdent(i) print "--------------------------------------------------" return True - + print "--------------------------------------------------" return False @@ -403,7 +407,7 @@ if len(sys.argv) >= 4: except: print "ERROR: Wrong baudrate" sys.exit(-1) - + # Initializes serial port communication try: s = tos.Serial(sys.argv[1], baudrate, flush=True, debug=False) @@ -412,10 +416,18 @@ if len(sys.argv) >= 4: print "ERROR: Unable to initialize serial port connection to", sys.argv[1] sys.exit(-1) + # Check if the mote has the Deluge T2 basestation component: + try: + print "Checking if node is a Deluge T2 base station ..." + ident(timeout=5) + except tos.TimeoutError: + print "ERROR: Timeout. Is the node a Deluge T2 base station?" + sys.exit(-1) + if sys.argv[3] in ["-p", "--ping"]: checkImgNum() print "Pinging node ..." - ping(imgNum) + ping(imgNum) elif sys.argv[3] in ["-i", "--inject"] and len(sys.argv) == 6: checkImgNum() print "Pinging node ..." diff --git a/tools/tinyos/misc/tos-deluge.1 b/tools/tinyos/misc/tos-deluge.1 index 33813baa..b8037cf4 100644 --- a/tools/tinyos/misc/tos-deluge.1 +++ b/tools/tinyos/misc/tos-deluge.1 @@ -26,7 +26,7 @@ COM10 .TP .I baudrate -Two shortcuts are available: \fBmicaz\fR for 57600 and \fBtelosb\fR for 115200. +Three shortcuts are available: \fBmicaz\fR and \fBiris\fR for 57600 and \fBtelosb\fR for 115200. .TP .I image_number A integer number. 0 is the first image. @@ -34,22 +34,25 @@ A integer number. 0 is the first image. .SH OPTIONS .TP .B -p, --ping -Provide status of the image in the external flash +This command is useful for checking the status of program images on a mote. It provides information such as program name, compile time, size of the image, and so on. .TP .B -i, --inject -Inject a compiled TinyOS application. The tos_image.xml file path +This command creates a program image from the supplied tos_image.xml file, and it injects the image into specified volume on the mote. .TP .B -r, --reprogram -Reprogram the network +This command sets up the directly-connected mote to reprogram itself after reboot, and then it reboots the mote. .TP -.B -b, --reprogram_bs -Reprogram only the directly-connected mote +.B -d, --disseminate +This command instructs the base station mote to disseminate an image to the network. This image is specified by the volume ID. .TP -.B -d, --dissemination -Disseminate the image in the external flash to the network +.B -dr, --disseminate-and-reprogram +This command asks the motes in the network not only to disseminate an image but also to start running it. This is accomplish using a reboot. .TP .B -e, --erase -Erase an image in the external flash +This command erases a flash volume on the base station mote. .TP -.B -s, --reset -Reset the versioning information for a given image +.B -s, --stop +The effect of -d and -dr is continuous which means a new mote will become infected if he is nearby. This command stops the infection. +.TP +.B -ls, --local-stop +When -d or -dr are in effect, the volume used by them is locked. This command can be used to unlock the volume in order to erase or inject a new image. diff --git a/tools/tinyos/misc/tos.py b/tools/tinyos/misc/tos.py deleted file mode 100644 index e01e7ecd..00000000 --- a/tools/tinyos/misc/tos.py +++ /dev/null @@ -1,575 +0,0 @@ -# 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) -