X-Git-Url: https://oss.titaniummirror.com/gitweb/?a=blobdiff_plain;f=tools%2Ftinyos%2Fmisc%2Ftos-deluge;fp=tools%2Ftinyos%2Fmisc%2Ftos-deluge;h=ec12aad2fcb7dc78b93bf2b3be6f25549d80d048;hb=e7b03f1e5e4f410541744b9ebc686f1be1a8054b;hp=0000000000000000000000000000000000000000;hpb=0bb2071fbbfcd2a942455db9bd825cce7de88244;p=tinyos-2.x.git diff --git a/tools/tinyos/misc/tos-deluge b/tools/tinyos/misc/tos-deluge new file mode 100755 index 00000000..ec12aad2 --- /dev/null +++ b/tools/tinyos/misc/tos-deluge @@ -0,0 +1,399 @@ +#!/usr/bin/env python + +# Copyright (c) 2007 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 Chieh-Jan Mike Liang +# @author Razvan Musaloiu-E. + +############################################################################### +# Deluge Python Toolchain +# +# A command line utility to interact with nodes via a direct serial connection. +# For the usage menu, please run this tool without any arguments. For example, +# "./tos-deluge.py" +############################################################################### + +import sys, os, stat, struct, subprocess +import tinyos +from datetime import datetime +import os.path + +# Script-specific parameters +HEX_OUTPUT_LINE_SIZE = 16 +# Path to the python script that builds Deluge image from XML +PY_PATH_BUILD_IMAGE = os.path.join(os.path.dirname(sys.argv[0]), 'tos-build-deluge-image') + +# TinyOS serial communication parameters +SERIAL_AMGROUP = 0 +SERIAL_AMID = 0xAB +SERIAL_DATA_PAYLOAD_SIZE = 80 + +# Serial message types +MSG_ERASE = 0 +MSG_WRITE = 1 +MSG_READ = 2 +MSG_REPROG = 5 +MSG_DISS = 6 + +ERROR_SUCCESS = 0 +ERROR_FAIL = 1 + +# Deluge-specific parameters +DELUGE_PKTS_PER_PAGE = 48 +DELUGE_PKT_PAYLOAD_SIZE = 23 +DELUGE_MAX_PAGES = 128 +DELUGE_METADATA_SIZE = 16 + 16 + 16 + 16 + 4 + 4 + 4 + 4 # Metadata size in binary + # image + +class SerialReqPacket(tinyos.GenericPacket): + def __init__(self, packet = None): + tinyos.GenericPacket.__init__(self, + [('msg_type', 'int', 1), + ('img_num', 'int', 1), + ('offset', 'int', 2), + ('len', 'int', 2), + ('data', 'blob', None)], + packet) + +class SerialReplyPacket(tinyos.GenericPacket): + def __init__(self, packet = None): + tinyos.GenericPacket.__init__(self, + [('error', 'int', 1), + ('data', 'blob', None)], + packet) + +# Displays an integer representation of byte stream to hex representation +def print_hex(start_addr, byte_stream): + num_iterations = int( (len(byte_stream) - 1) / HEX_OUTPUT_LINE_SIZE ) + 1 + + for i in range(num_iterations): + line = "%07x" % start_addr + " " # Prints memory address + for j in range(HEX_OUTPUT_LINE_SIZE): + if (i * HEX_OUTPUT_LINE_SIZE + j) < len(byte_stream): + line += "%02x" % byte_stream[i * HEX_OUTPUT_LINE_SIZE + j] + " " + print line + + start_addr += HEX_OUTPUT_LINE_SIZE + +# Computes 16-bit CRC +def crc16(data): + crc = 0 + for b in 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 + +# Converts a byte-stream array to int representation +def toInt(byte_stream): + r = long(0) + for i in byte_stream[::-1]: + r = (r << 8) + i + + return r + +# Converts a byte-stream array to string representation +def toString(byte_stream): + r = "" + for i in range(len(byte_stream)): + if byte_stream[i] == 0: + r += " " + else: + r += struct.pack("B", byte_stream[i]) + + return r + +# Converts a byte-stream array to image status string representation +def toStatusStr(num_space, binary_stream): + r = "%sProg Name: %s\n" % (" " * num_space, + toString(binary_stream[16:32])) + r += "%sCompiled On: %s\n" % (" " * num_space, + datetime.fromtimestamp(toInt(binary_stream[84:88])).strftime('%a %h %d %T %Y')) + r += "%sPlatform: %s\n" % (" " * num_space, + toString(binary_stream[64:80])) + r += "%sUser ID: %s\n" % (" " * num_space, + toString(binary_stream[32:48])) + r += "%sHost Name: %s\n" % (" " * num_space, + toString(binary_stream[48:64])) + r += "%sUser Hash: %s\n" % (" " * num_space, + hex(toInt(binary_stream[88:92]))) + r += "%sNum Pages: %d/%d" % (" " * num_space, + toInt(binary_stream[7:8]), + toInt(binary_stream[10:11])) + + r += "\n\n" + r += "%sSize: %d\n" % (" " * num_space, + toInt(binary_stream[12:14])) + r += "%sUID: %d\n" % (" " * num_space, + toInt(binary_stream[0:4])) + r += "%sVersion: %d" % (" " * num_space, + toInt(binary_stream[4:6])) + + return r + +# Returns the metadata (first 16 bytes of the image) plus the "ident" +# (DELUGE_METADATA_SIZE bytes after CRC) +def getMetaData(s, img_num): + r = [] + # Gets the metadata (first 16 bytes of the image) + sreqpkt = SerialReqPacket((MSG_READ, img_num, 0, 16, [])) + + if s.write_packet(SERIAL_AMGROUP, SERIAL_AMID, sreqpkt.payload()): + packet = s.read_packet(SERIAL_AMGROUP, SERIAL_AMID) + sreplypkt = SerialReplyPacket(packet[1]) + if sreplypkt.error == ERROR_SUCCESS: + r.extend(sreplypkt.data) + + # Gets the "ident" portion of the image + sreqpkt["offset"] = 16 + (2 * DELUGE_MAX_PAGES) + sreqpkt["len"] = DELUGE_METADATA_SIZE + if s.write_packet(SERIAL_AMGROUP, SERIAL_AMID, sreqpkt.payload()): + packet = s.read_packet(SERIAL_AMGROUP, SERIAL_AMID) + sreplypkt = SerialReplyPacket(packet[1]) + if sreplypkt.error == ERROR_SUCCESS: + r.extend(sreplypkt.data) + + # Checks for valid CRC and timestamp + if crc16(r[6:8]) == toInt(r[8:10]) and r[84:88] != [0xFF, 0xFF, 0xFF, 0xFF]: + return r + else: + print "ERROR: Unable to retrieve image information" + else: + print "ERROR: Unable to retrieve image information" + + return None + +# Prints status of the image in the external flash +def op_ping(s, img_num): + metadata = getMetaData(s, img_num) + if not metadata == None: + print "Connected to Deluge node." + # Prints out image status + print "--------------------------------------------------" + print "Stored image %d" % img_num + print toStatusStr(2, metadata) + print "--------------------------------------------------" + return True + + print "No proper Deluge image found!" + return False + +# Erases an image volume +def op_erase(s, img_num): + sreqpkt = SerialReqPacket((MSG_ERASE, img_num, 0, 0, [])) + success = s.write_packet(SERIAL_AMGROUP, SERIAL_AMID, sreqpkt.payload()) + if success == True: + packet = s.read_packet(SERIAL_AMGROUP, SERIAL_AMID) + sreplypkt = SerialReplyPacket(packet[1]) + if sreplypkt.error == ERROR_SUCCESS: + return True + else: + print "ERROR: Unable to erase the flash volume" + return False + + print "ERROR: Unable to send the command" + return False + +# Writes to an image volume +def op_write(s, img_num, binary_stream): + sreqpkt = SerialReqPacket((MSG_WRITE, img_num, 0, 0, [])) + local_crc = 0 # Running CRC + length = len(binary_stream) + + sreqpkt.offset = 0 + while length > 0: + # Calculates the payload size for the current packet + if length >= SERIAL_DATA_PAYLOAD_SIZE: + sreqpkt.len = SERIAL_DATA_PAYLOAD_SIZE + else: + sreqpkt.len = length + sreqpkt.data = [] + + # Reads in the file we want to transmit + for i in range(sreqpkt.len): + sreqpkt.data.append(struct.unpack("B", binary_stream[sreqpkt.offset + i])[0]) + + # Sends over serial to the mote + if s.write_packet(SERIAL_AMGROUP, SERIAL_AMID, sreqpkt.payload()) == False: + print "ERROR: Unable to send the last serial packet (file offset: %d)" % sreqpkt.offset + return False + + # Waiting for confirmation + packet = s.read_packet(SERIAL_AMGROUP, SERIAL_AMID) + sreplypkt = SerialReplyPacket(packet[1]) + if sreplypkt.error != ERROR_SUCCESS: + print "ERROR: Unable to write to the flash volume (file offset: %d)" % sreqpkt.offset + return False + + local_crc = s.crc16(local_crc, sreqpkt.data) # Computes running CRC + length -= sreqpkt.len + sreqpkt.offset += sreqpkt.len + + return True + +# Injects an image (specified by tos_image_xml) to an image volume +def op_inject(s, img_num, tos_image_xml): + # Gets status information of stored image + metadata = getMetaData(s, img_num) + print "Connected to Deluge nodes." + print "--------------------------------------------------" + print "Stored image %d" % img_num + version = 0 + if not metadata == None: + version = toInt(metadata[4:6]) + 1 # Increments the version + print toStatusStr(2, metadata) + else: + print " No proper Deluge image found!" + print "--------------------------------------------------" + + # Creates binary image from the TOS image XML + try: + os.stat(tos_image_xml) # Checks whether tos_image_xml is a valid file + os.stat(PY_PATH_BUILD_IMAGE) # Checks whether PY_PATH_BUILD_IMAGE is a valid file + except: + print "ERROR: Unable to create a binary image from the TOS image XML, \"%s\"" % tos_image_xml + return False + p = subprocess.Popen([PY_PATH_BUILD_IMAGE, "-v", str(version), "-i", str(img_num), tos_image_xml], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + print p.stderr.read(), + print "--------------------------------------------------" + + # Writes the new binary image + if op_erase(s, img_num): + if op_write(s, img_num, p.stdout.read()): + metadata = getMetaData(s, img_num) + if not metadata == None: + print "Replace image with:" + print toStatusStr(2, metadata) + print "--------------------------------------------------" + + return True + + return False + +# Requests the mote to reboot and reprogram itself +def op_reprog(s, img_num): + if getMetaData(s, img_num) == None: + print "ERROR: No proper Deluge image found!" + else: + sreqpkt = SerialReqPacket((MSG_REPROG, img_num, 0, 0, [])) + success = s.write_packet(SERIAL_AMGROUP, SERIAL_AMID, sreqpkt.payload()) + if success == True: + packet = s.read_packet(SERIAL_AMGROUP, SERIAL_AMID) + sreplypkt = SerialReplyPacket(packet[1]) + if sreplypkt.error == ERROR_SUCCESS: + return True + else: + print "ERROR: Unable to reboot the mote" + return False + + print "ERROR: Unable to send the command" + return False + +# Requests the mote to disseminate an image +def op_diss(s, img_num): + if getMetaData(s, img_num) == None: + print "ERROR: No proper Deluge image found!" + else: + sreqpkt = SerialReqPacket((MSG_DISS, img_num, 0, 0, [])) + success = s.write_packet(SERIAL_AMGROUP, SERIAL_AMID, sreqpkt.payload()) + if success == True: + packet = s.read_packet(SERIAL_AMGROUP, SERIAL_AMID) + sreplypkt = SerialReplyPacket(packet[1]) + if sreplypkt.error == ERROR_SUCCESS: + return True + else: + print "ERROR: Unable to start the command dissemination" + return False + + print "ERROR: Unable to send the command" + return False + +# Resets image versioning information +def op_reset(s, img_num): + sreqpkt = SerialReqPacket((MSG_WRITE, img_num, 4, 2, [0, 0])) + if s.write_packet(SERIAL_AMGROUP, SERIAL_AMID, sreqpkt.payload()) == False: + print "ERROR: Unable to send the last serial packet (file offset: %d)" % sreqpkt.offset + return False + + # Waiting for confirmation + packet = s.read_packet(SERIAL_AMGROUP, SERIAL_AMID) + sreplypkt = SerialReplyPacket(packet[1]) + if sreplypkt.error != ERROR_SUCCESS: + print "ERROR: Unable to write new versioning information" + return False + + return True + +def print_usage(): + print "Usage: %s <-p|-i|-r|-d|-e|-s> image_number [options]" % sys.argv[0] + print " -p --ping\n Provide status of the image in the external flash" + print " -i --inject\n Inject a compiled TinyOS application" + print " [options]: " + print " -r --reboot\n Reboot and reprogram the directly-connected mote" + print " -d --dissemination\n Disseminate the image in the external flash to the network" + print " -e --erase\n Erase an image in the external flash" + print " -s --reset\n Reset the versioning information for a given image" + +# ======== MAIN ======== # +num_req_arg = 4 # Minimum number of required arguments for this script +if len(sys.argv) >= num_req_arg: + try: + sys.argv[3] = int(sys.argv[3]) + except: + print "ERROR: Volume ID is not valid" + os._exit(-1) + + # Initializes serial port communication + try: + s = tinyos.Serial(sys.argv[1], 115200) + s.set_debug(False) # Disables debug msg + except: + print "ERROR: Unable to initialize serial port connection" + os._exit(-1) + + if sys.argv[2] in ["-p", "--ping"]: + print "Pinging node ..." + op_ping(s, sys.argv[3]) + elif sys.argv[2] in ["-i", "--inject"] and len(sys.argv) == (num_req_arg + 1): + print "Pinging node ..." + op_inject(s, sys.argv[3], sys.argv[4]) + elif sys.argv[2] in ["-r", "--reboot"]: + if op_reprog(s, sys.argv[3]): + print "Command sent" + elif sys.argv[2] in ["-d", "--dissemination"]: + if op_diss(s, sys.argv[3]): + print "Command sent" + elif sys.argv[2] in ["-e", "--erase"]: + if op_erase(s, sys.argv[3]): + print "Image number %d erased" % sys.argv[3] + elif sys.argv[2] in ["-s", "--reset"]: + if op_reset(s, sys.argv[3]): + print "Successfully reset image versioning information" + else: + print_usage() + +else: + print_usage()