[Tinyos-2-commits] CVS: tinyos-2.x/tools/tinyos/misc tinyos.py, NONE, 1.1 tos-build-deluge-image, NONE, 1.1 tos-deluge, NONE, 1.1

Razvan Musaloiu-E. razvanm at users.sourceforge.net
Tue May 22 13:34:22 PDT 2007


Update of /cvsroot/tinyos/tinyos-2.x/tools/tinyos/misc
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv24715/tools/tinyos/misc

Added Files:
	tinyos.py tos-build-deluge-image tos-deluge 
Log Message:
Initial commit of the Deluge T2. Some notes:
- TOSBoot includes some code to allow the MicaZ version to compile but it's not support for it it's not done yet.
- tools/tinyos/misc/Makefile.am is not updated yet so the new tools will not be installed by default.


--- NEW FILE: tinyos.py ---
import struct, time, serial, socket

# 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 <cliang4 at cs.jhu.edu>
# @author Razvan Musaloiu-E. <razvanm at cs.jhu.edu>

class Serial:
    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
  
    __s = None       # An instance of serial.Serial object
    __debug = False   # Debug mode
    
    def __init__(self, port, baudrate):
       self.__s = serial.Serial(port, baudrate, rtscts=0, timeout=0.5)
    
    def __format_packet(self, packet):
        return " ".join(["%02x" % p for p in packet]) + " | " + \
               " ".join(["%d" % p for p in packet])
    
    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):
        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_packet(self):
        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)
            un_packet = self.__unescape(packet)
            
            crc = self.crc16(0, un_packet[1:-3])
            packet_crc = self.__decode(un_packet[-3:-1])
            
            if self.__debug == True:
                if crc != packet_crc:
                    print "Warning: wrong CRC!"
                print "Recv:", self.__format_packet(un_packet)
            return (ts, un_packet)
        except socket.timeout:
            return None
    
    # Filters and returns the next incoming serial packet with 
    # specified AM group ID and AM ID
    def read_packet(self, am_group, am_id):
        packet = None
        
        while True:
            packet = self.sniff_packet()
            if not packet == None and len(packet[1]) >= 10:
                if (packet[1])[8] == am_group and (packet[1])[9] == am_id:
                    break
            
        return packet
    
    # 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_packet(self, am_group, am_id, data, num_tries=10):
        for i in range(num_tries):
            # The first byte after SERIAL_PROTO_PACKET_ACK is a sequence
            # number that will be send back by the mote to ack the receive of
            # the data.
            packet = [self.SERIAL_PROTO_PACKET_ACK, 0, self.TOS_SERIAL_ACTIVE_MESSAGE_ID,
                      0xff, 0xff,
                      0, 0,
                      len(data), am_group, am_id] + data
            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]
            
            self.__put_bytes(packet)
            if self.__debug == True:
                print "Send:", self.__format_packet(packet)
            
            # Waits for ACK
            for j in range(3):
                while True:
                    packet = self.sniff_packet()
                    if packet == None:
                        break
                    elif (packet[1])[1] == self.SERIAL_PROTO_ACK:
                        return True
                        
            # Debug messages
            if self.__debug == True:
                if i == (num_tries - 1):
                    print "Failed to send the packet!" 
                else:
                    print "Timeout waiting for ACK... Retry"
                        
        return False
    
    def set_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):
        self.__dict__['_schema'] = [(t, s) for (n, t, s) in desc]
        self.__dict__['_names'] = [n for (n, t, s) in desc]
        self.__dict__['_values'] = []
        offset = 10
        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 == 'blob':
                    if s:
                        self._values.append(packet[offset:offset + s])
                        offset += s
                    else:
                        self._values.append(packet[offset:-3])
        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):
        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):
        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

    # Custom
    def names(self):
        return self._names

    def sizes(self):
        return self._schema

    def payload(self):
        r = []
        for i in range(len(self._schema)):
            (t, s) = self._schema[i]
            if t == 'int':
                r += self.__encode(self._values[i], s)
            else:
                r += self._values[i]
        return r

--- NEW FILE: tos-build-deluge-image ---
#!/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 <cliang4 at cs.jhu.edu>
# @author Razvan Musaloiu-E. <razvanm at cs.jhu.edu>

import sys, struct, operator
from xml.dom.minidom import parse

DELUGE_PKTS_PER_PAGE = 48
DELUGE_PKT_PAYLOAD_SIZE = 23
DELUGE_BYTES_PER_PAGE = DELUGE_PKTS_PER_PAGE * DELUGE_PKT_PAYLOAD_SIZE
DELUGE_MAX_PAGES = 128

DELUGE_METADATA_SIZE = 16
DELUGE_IDENT_SIZE = 128

def sencode(s, dim):
  s = [ord(c) for c in s]
  if len(s) > dim:
    return s[:dim]
  return s + [0] * (dim - len(s))

def encode(val, dim):
  output = []
  for i in range(dim):
      output.append(val & 0xFF)
      val = val >> 8
  return output

def decode(v):
  r = long(0)
  for i in v[::-1]:
      r = (r << 8) + i
  return r

def int2byte(v):
    return "".join([struct.pack("B", i) for i in v])

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

def pages(data):
    return (len(data) / DELUGE_BYTES_PER_PAGE) + \
               (len(data) % DELUGE_BYTES_PER_PAGE != 0)

def align(data):
  mod = len(data) % DELUGE_BYTES_PER_PAGE
  if mod == 0:
    return data
  return data + [0] * (DELUGE_BYTES_PER_PAGE - mod)

def deluge_metadata(data, img_num):
  uid = ident['uid_hash']
  num_pages = pages(data)
  image_number = img_num
  crc = crc16([image_number] + [num_pages])
  completed_pages = num_pages
  return encode(uid, 4) + \
         encode(version, 2) + \
         [image_number] + \
         [num_pages] + \
         encode(crc, 2) + \
         [completed_pages] + \
         [0] + \
         encode(len(data) + 16, 2) + \
         ([0] * 2)

def deluge_ident():
  tmp = sencode(ident['program_name'], 16) + \
        sencode(ident['user_id'], 16) + \
        sencode(ident['hostname'], 16) + \
        sencode(ident['platform'], 16) + \
        encode(ident['size'], 4) + \
        encode(ident['unix_time'], 4) + \
        encode(ident['user_hash'], 4) + \
        encode(ident['uid_hash'], 4)
  return tmp + [0] * (DELUGE_IDENT_SIZE - len(tmp))

def deluge_crc(data):
  crc = [0] * DELUGE_MAX_PAGES
  crc[0] = crc16(data[2*DELUGE_MAX_PAGES:DELUGE_BYTES_PER_PAGE])
  #sys.stderr.write("crc[0] = 0x%x\n" % (crc[0]))
  j = 1
  for i in range(DELUGE_BYTES_PER_PAGE, len(data)-1, DELUGE_BYTES_PER_PAGE):
    crc[j] = crc16(data[i:i+DELUGE_BYTES_PER_PAGE])
    #sys.stderr.write("crc[%d] = 0x%x\n" % (j, crc[j]))
    j += 1
  return reduce(operator.add, [encode(i, 2) for i in crc]) + data[2*DELUGE_MAX_PAGES:]

version = 0

for i in range(len(sys.argv)):
  if sys.argv[i] == '-v':
    version = int(sys.argv[i+1])
  elif sys.argv[i] == '-i':
    img_num = int(sys.argv[i+1])
    
dom = parse(sys.argv[-1])
ident = {}
ident_list = [(n.localName, n.firstChild.nodeValue)
              for n in dom.getElementsByTagName('ident')[0].childNodes if n.localName != None]
for (k, v) in ident_list:
  ident[k] = v
for p in ['unix_time', 'user_hash', 'uid_hash']:
  ident[p] = int(ident[p][:-1], 16)
image = dom.getElementsByTagName('image')[0].firstChild.nodeValue

all = []
section = []
end_addr = None
for line in image.split():
    #print "DEBUG:", line
    length = int(line[1:3], 16)
    addr = int(line[3:7], 16)
    rectype = int(line[7:9], 16)
    data = []
    if len(line) > 11:
        data = [int(line[i:i+2], 16) for i in range(9, len(line)-2, 2)]
    crc = int(line[-2:], 16)
    if rectype in [0x00, 0x03]:
        if not end_addr:
            end_addr = addr
            start_addr = addr
        if end_addr != addr:
            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
                # skipped.
                break
            section = []
            start_addr = addr
        section += data
        end_addr = addr + length
    elif rectype == 0x01:
        all.append((start_addr, section))
        section = []
        start_addr = addr

sys.stderr.write('Ihex read complete:\n')
sys.stderr.write('  Total bytes = %d\n' % reduce(operator.add, [len(l) for (_, l) in all]))
sys.stderr.write('  Sections = %d\n' % len(all))

# Usually, there are two sections: one for the code and one for the
# interrupt vector.

all_data = []
for (addr, data) in all:
  all_data += encode(addr, 4) + \
              encode(len(data), 4) + \
              data
ident['size'] = len(all_data)
all_data = deluge_ident() + all_data
all_data = align([0] * 2 * DELUGE_MAX_PAGES + all_data)
all_data = deluge_crc(all_data)
sys.stdout.write(int2byte(deluge_metadata(all_data, img_num)) + \
      int2byte(all_data))


--- NEW FILE: tos-deluge ---
#!/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 <cliang4 at cs.jhu.edu>
# @author Razvan Musaloiu-E. <razvanm at cs.jhu.edu>

###############################################################################
# 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 <device> <-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]: <tos_image.xml file path>"
    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()



More information about the Tinyos-2-commits mailing list