]> oss.titaniummirror.com Git - tinyos-2.x.git/commitdiff
Initial commit of Harvards Python SDK. Tested to work with current release including...
authorhiro <hiro>
Fri, 14 Sep 2007 18:11:45 +0000 (18:11 +0000)
committerhiro <hiro>
Fri, 14 Sep 2007 18:11:45 +0000 (18:11 +0000)
20 files changed:
support/sdk/python/tinyos/__init__.py
support/sdk/python/tinyos/message/Makefile [new file with mode: 0644]
support/sdk/python/tinyos/message/Message.py
support/sdk/python/tinyos/message/MoteIF.py [new file with mode: 0644]
support/sdk/python/tinyos/message/SerialPacket.py [new file with mode: 0644]
support/sdk/python/tinyos/message/__init__.py
support/sdk/python/tinyos/packet/IO.py [new file with mode: 0644]
support/sdk/python/tinyos/packet/Makefile [new file with mode: 0644]
support/sdk/python/tinyos/packet/PacketDispatcher.py [new file with mode: 0644]
support/sdk/python/tinyos/packet/PacketSource.py [new file with mode: 0644]
support/sdk/python/tinyos/packet/Platform.py [new file with mode: 0644]
support/sdk/python/tinyos/packet/SFProtocol.py [new file with mode: 0644]
support/sdk/python/tinyos/packet/SFSource.py [new file with mode: 0644]
support/sdk/python/tinyos/packet/Serial.py [new file with mode: 0644]
support/sdk/python/tinyos/packet/SocketIO.py [new file with mode: 0644]
support/sdk/python/tinyos/packet/ThreadTask.py [new file with mode: 0644]
support/sdk/python/tinyos/packet/__init__.py [new file with mode: 0644]
support/sdk/python/tinyos/utils/Singleton.py [new file with mode: 0644]
support/sdk/python/tinyos/utils/Watcher.py [new file with mode: 0644]
support/sdk/python/tinyos/utils/__init__.py [new file with mode: 0644]

index f64fb74ae833e44aec05df5813532bdb7ccfe500..7b99566787be011b20dbca33268e49a3011ca84e 100644 (file)
@@ -28,4 +28,5 @@
 #
 # Author: Geoffrey Mainland <mainland@eecs.harvard.edu>
 #
-__all__ = ["message", "tossim"]
+
+__all__ = ["message", "packet", "utils", "tossim"]
diff --git a/support/sdk/python/tinyos/message/Makefile b/support/sdk/python/tinyos/message/Makefile
new file mode 100644 (file)
index 0000000..533ce2c
--- /dev/null
@@ -0,0 +1,5 @@
+SERIAL_H = $(TOSDIR)/lib/serial/Serial.h
+
+
+SerialPacket.py: 
+       mig -o $@ -python-classname=SerialPacket python $(SERIAL_H) serial_packet -I$(TOSDIR)/types
index 1d592fd22f4e1a87171713fee7808d44805fa5d9..d3befe036b7cf31f2625657c11ad642d86f6acf0 100644 (file)
@@ -46,11 +46,12 @@ class Message:
 
             if data == None or len(data) != data_length:
                 self.data = chr(0) * data_length
+
         else:
             self.data_length = len(data)
 
             self.am_type = 0
-
+            
     def dataGet(self):
         return self.data
 
diff --git a/support/sdk/python/tinyos/message/MoteIF.py b/support/sdk/python/tinyos/message/MoteIF.py
new file mode 100644 (file)
index 0000000..984b779
--- /dev/null
@@ -0,0 +1,151 @@
+#
+# Copyright (c) 2005-2006
+#      The President and Fellows of Harvard College.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY 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 UNIVERSITY OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# 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: Geoffrey Mainland <mainland@eecs.harvard.edu>
+# Tinyos-2: Stephen Dawson-Haggerty
+
+import os
+import re
+import struct
+import sys
+import traceback
+from tinyos.utils.Watcher import Watcher
+
+from tinyos.packet.Serial import Serial
+from tinyos.message.SerialPacket import SerialPacket
+import tinyos.packet.PacketDispatcher
+import tinyos.packet.PacketSource
+import tinyos.packet.SFSource
+try:
+    import tinyos.packet.SerialSource
+except:
+    tinyos.packet.SerialSource = None
+
+DEBUG = False
+
+class MoteIFException(Exception):
+    def __init__(self, *args):
+        self.args = args
+
+class MoteIF:
+    def __init__(self):
+        self.listeners = {}
+        self.watcher = Watcher.getInstance()
+
+    def addListener(self, listener, msgClass):
+        if listener not in self.listeners:
+            self.listeners[listener] = {}
+
+        amTypes = self.listeners[listener]
+        amTypes[msgClass.get_amType()] = msgClass
+
+    def removeListener(self, listener):
+        del self.listeners[listener]
+
+    def dispatchPacket(self, source, packet):
+        #try:
+            #print "Packet length: ", len(packet)
+            #            print "Dispatching from MoteIF"
+            #             for i in packet:
+            #                 print ord(i)," ",
+            #             print
+        try:
+            # Message.py ignores base_offset, so we'll just chop off
+            # the first byte (the SERIAL_AMTYPE) here.
+            serial_pkt = SerialPacket(packet[1:],
+                                      data_length=len(packet)-1)
+        except:
+            traceback.print_exc()
+
+
+        try:
+            data_start = serial_pkt.offset_data(0) + 1
+            data_end = data_start + serial_pkt.get_header_length()
+            data = packet[data_start:data_end]
+            amType = serial_pkt.get_header_type()
+
+        except Exception, x:
+            print >>sys.stderr, x
+            print >>sys.stderr, traceback.print_tb(sys.exc_info()[2])
+
+        for l in self.listeners:
+            amTypes = self.listeners[l]
+            if amType in amTypes:
+                try:
+                    msgClass = amTypes[amType]
+                    msg = msgClass(data=data,
+                                   data_length = len(data),
+                                   addr=serial_pkt.get_header_src(),
+                                   gid=serial_pkt.get_header_group())
+                    l.receive(source, msg)
+                except Exception, x:
+                    print >>sys.stderr, x
+                    print >>sys.stderr, traceback.print_tb(sys.exc_info()[2])
+
+    def sendMsg(self, dest, addr, amType, group, msg):
+        try:
+            payload = msg.dataGet()
+            msg = SerialPacket(None)
+            msg.set_header_dest(int(addr))
+            msg.set_header_group(int(group))
+            msg.set_header_type(int(amType))
+            msg.set_header_length(len(payload))
+
+            # from tinyos.packet.Serial
+            data = chr(Serial.TOS_SERIAL_ACTIVE_MESSAGE_ID)
+            data += msg.dataGet()[0:msg.offset_data(0)]
+            data += payload
+
+            dest.writePacket(data)
+        except Exception, x:
+            print >>sys.stderr, x
+            print >>sys.stderr, traceback.print_tb(sys.exc_info()[2])
+
+    def addSource(self, name=None):
+        if name == None:
+            name = os.environ.get("MOTECOM", "sf@localhost:9002")
+
+        m = re.match(r'([^@]*)@(.*)', name)
+        if m == None:
+            raise MoteIFException("base source '%s'" % (name))
+
+        (sourceType, args) = m.groups()
+
+        if sourceType == "sf":
+            source = tinyos.packet.SFSource.SFSource(self, args)
+        elif sourceType == "serial" and tinyos.packet.SerialSource != None:
+            source = tinyos.packet.SerialSource.SerialSource(self, args)
+        else:
+            raise MoteIFException("bad source")
+        
+        source.start()
+
+        return source
+
+    def finishAll(self):
+        tinyos.packet.PacketSource.finishAll()
diff --git a/support/sdk/python/tinyos/message/SerialPacket.py b/support/sdk/python/tinyos/message/SerialPacket.py
new file mode 100644 (file)
index 0000000..8029a70
--- /dev/null
@@ -0,0 +1,449 @@
+#
+# This class is automatically generated by mig. DO NOT EDIT THIS FILE.
+# This class implements a Python interface to the 'SerialPacket'
+# message type.
+#
+
+import tinyos.message.Message
+
+# The default size of this message type in bytes.
+DEFAULT_MESSAGE_SIZE = 7
+
+# The Active Message type associated with this message.
+AM_TYPE = -1
+
+class SerialPacket(tinyos.message.Message.Message):
+    # Create a new SerialPacket of size 7.
+    def __init__(self, data="", addr=None, gid=None, base_offset=0, data_length=7):
+        tinyos.message.Message.Message.__init__(self, data, addr, gid, base_offset, data_length)
+        self.amTypeSet(AM_TYPE)
+    
+    # Get AM_TYPE
+    def get_amType(cls):
+        return AM_TYPE
+    
+    get_amType = classmethod(get_amType)
+    
+    #
+    # Return a String representation of this message. Includes the
+    # message type name and the non-indexed field values.
+    #
+    def __str__(self):
+        s = "Message <SerialPacket> \n"
+        try:
+            s += "  [header.dest=0x%x]\n" % (self.get_header_dest())
+        except:
+            pass
+        try:
+            s += "  [header.src=0x%x]\n" % (self.get_header_src())
+        except:
+            pass
+        try:
+            s += "  [header.length=0x%x]\n" % (self.get_header_length())
+        except:
+            pass
+        try:
+            s += "  [header.group=0x%x]\n" % (self.get_header_group())
+        except:
+            pass
+        try:
+            s += "  [header.type=0x%x]\n" % (self.get_header_type())
+        except:
+            pass
+        try:
+            pass
+        except:
+            pass
+        return s
+
+    # Message-type-specific access methods appear below.
+
+    #
+    # Accessor methods for field: header.dest
+    #   Field type: int
+    #   Offset (bits): 0
+    #   Size (bits): 16
+    #
+
+    #
+    # Return whether the field 'header.dest' is signed (False).
+    #
+    def isSigned_header_dest(self):
+        return False
+    
+    #
+    # Return whether the field 'header.dest' is an array (False).
+    #
+    def isArray_header_dest(self):
+        return False
+    
+    #
+    # Return the offset (in bytes) of the field 'header.dest'
+    #
+    def offset_header_dest(self):
+        return (0 / 8)
+    
+    #
+    # Return the offset (in bits) of the field 'header.dest'
+    #
+    def offsetBits_header_dest(self):
+        return 0
+    
+    #
+    # Return the value (as a int) of the field 'header.dest'
+    #
+    def get_header_dest(self):
+        return self.getUIntElement(self.offsetBits_header_dest(), 16, 1)
+    
+    #
+    # Set the value of the field 'header.dest'
+    #
+    def set_header_dest(self, value):
+        self.setUIntElement(self.offsetBits_header_dest(), 16, value, 1)
+    
+    #
+    # Return the size, in bytes, of the field 'header.dest'
+    #
+    def size_header_dest(self):
+        return (16 / 8)
+    
+    #
+    # Return the size, in bits, of the field 'header.dest'
+    #
+    def sizeBits_header_dest(self):
+        return 16
+    
+    #
+    # Accessor methods for field: header.src
+    #   Field type: int
+    #   Offset (bits): 16
+    #   Size (bits): 16
+    #
+
+    #
+    # Return whether the field 'header.src' is signed (False).
+    #
+    def isSigned_header_src(self):
+        return False
+    
+    #
+    # Return whether the field 'header.src' is an array (False).
+    #
+    def isArray_header_src(self):
+        return False
+    
+    #
+    # Return the offset (in bytes) of the field 'header.src'
+    #
+    def offset_header_src(self):
+        return (16 / 8)
+    
+    #
+    # Return the offset (in bits) of the field 'header.src'
+    #
+    def offsetBits_header_src(self):
+        return 16
+    
+    #
+    # Return the value (as a int) of the field 'header.src'
+    #
+    def get_header_src(self):
+        return self.getUIntElement(self.offsetBits_header_src(), 16, 1)
+    
+    #
+    # Set the value of the field 'header.src'
+    #
+    def set_header_src(self, value):
+        self.setUIntElement(self.offsetBits_header_src(), 16, value, 1)
+    
+    #
+    # Return the size, in bytes, of the field 'header.src'
+    #
+    def size_header_src(self):
+        return (16 / 8)
+    
+    #
+    # Return the size, in bits, of the field 'header.src'
+    #
+    def sizeBits_header_src(self):
+        return 16
+    
+    #
+    # Accessor methods for field: header.length
+    #   Field type: short
+    #   Offset (bits): 32
+    #   Size (bits): 8
+    #
+
+    #
+    # Return whether the field 'header.length' is signed (False).
+    #
+    def isSigned_header_length(self):
+        return False
+    
+    #
+    # Return whether the field 'header.length' is an array (False).
+    #
+    def isArray_header_length(self):
+        return False
+    
+    #
+    # Return the offset (in bytes) of the field 'header.length'
+    #
+    def offset_header_length(self):
+        return (32 / 8)
+    
+    #
+    # Return the offset (in bits) of the field 'header.length'
+    #
+    def offsetBits_header_length(self):
+        return 32
+    
+    #
+    # Return the value (as a short) of the field 'header.length'
+    #
+    def get_header_length(self):
+        return self.getUIntElement(self.offsetBits_header_length(), 8, 1)
+    
+    #
+    # Set the value of the field 'header.length'
+    #
+    def set_header_length(self, value):
+        self.setUIntElement(self.offsetBits_header_length(), 8, value, 1)
+    
+    #
+    # Return the size, in bytes, of the field 'header.length'
+    #
+    def size_header_length(self):
+        return (8 / 8)
+    
+    #
+    # Return the size, in bits, of the field 'header.length'
+    #
+    def sizeBits_header_length(self):
+        return 8
+    
+    #
+    # Accessor methods for field: header.group
+    #   Field type: short
+    #   Offset (bits): 40
+    #   Size (bits): 8
+    #
+
+    #
+    # Return whether the field 'header.group' is signed (False).
+    #
+    def isSigned_header_group(self):
+        return False
+    
+    #
+    # Return whether the field 'header.group' is an array (False).
+    #
+    def isArray_header_group(self):
+        return False
+    
+    #
+    # Return the offset (in bytes) of the field 'header.group'
+    #
+    def offset_header_group(self):
+        return (40 / 8)
+    
+    #
+    # Return the offset (in bits) of the field 'header.group'
+    #
+    def offsetBits_header_group(self):
+        return 40
+    
+    #
+    # Return the value (as a short) of the field 'header.group'
+    #
+    def get_header_group(self):
+        return self.getUIntElement(self.offsetBits_header_group(), 8, 1)
+    
+    #
+    # Set the value of the field 'header.group'
+    #
+    def set_header_group(self, value):
+        self.setUIntElement(self.offsetBits_header_group(), 8, value, 1)
+    
+    #
+    # Return the size, in bytes, of the field 'header.group'
+    #
+    def size_header_group(self):
+        return (8 / 8)
+    
+    #
+    # Return the size, in bits, of the field 'header.group'
+    #
+    def sizeBits_header_group(self):
+        return 8
+    
+    #
+    # Accessor methods for field: header.type
+    #   Field type: short
+    #   Offset (bits): 48
+    #   Size (bits): 8
+    #
+
+    #
+    # Return whether the field 'header.type' is signed (False).
+    #
+    def isSigned_header_type(self):
+        return False
+    
+    #
+    # Return whether the field 'header.type' is an array (False).
+    #
+    def isArray_header_type(self):
+        return False
+    
+    #
+    # Return the offset (in bytes) of the field 'header.type'
+    #
+    def offset_header_type(self):
+        return (48 / 8)
+    
+    #
+    # Return the offset (in bits) of the field 'header.type'
+    #
+    def offsetBits_header_type(self):
+        return 48
+    
+    #
+    # Return the value (as a short) of the field 'header.type'
+    #
+    def get_header_type(self):
+        return self.getUIntElement(self.offsetBits_header_type(), 8, 1)
+    
+    #
+    # Set the value of the field 'header.type'
+    #
+    def set_header_type(self, value):
+        self.setUIntElement(self.offsetBits_header_type(), 8, value, 1)
+    
+    #
+    # Return the size, in bytes, of the field 'header.type'
+    #
+    def size_header_type(self):
+        return (8 / 8)
+    
+    #
+    # Return the size, in bits, of the field 'header.type'
+    #
+    def sizeBits_header_type(self):
+        return 8
+    
+    #
+    # Accessor methods for field: data
+    #   Field type: short[]
+    #   Offset (bits): 56
+    #   Size of each element (bits): 8
+    #
+
+    #
+    # Return whether the field 'data' is signed (False).
+    #
+    def isSigned_data(self):
+        return False
+    
+    #
+    # Return whether the field 'data' is an array (True).
+    #
+    def isArray_data(self):
+        return True
+    
+    #
+    # Return the offset (in bytes) of the field 'data'
+    #
+    def offset_data(self, index1):
+        offset = 56
+        if index1 < 0:
+            raise IndexError
+        offset += 0 + index1 * 8
+        return (offset / 8)
+    
+    #
+    # Return the offset (in bits) of the field 'data'
+    #
+    def offsetBits_data(self, index1):
+        offset = 56
+        if index1 < 0:
+            raise IndexError
+        offset += 0 + index1 * 8
+        return offset
+    
+    #
+    # Return the entire array 'data' as a short[]
+    #
+    def get_data(self):
+        raise IndexError
+    
+    #
+    # Set the contents of the array 'data' from the given short[]
+    #
+    def set_data(self, value):
+        for index0 in range(0, len(value)):
+            self.setElement_data(index0, value[index0])
+
+    #
+    # Return an element (as a short) of the array 'data'
+    #
+    def getElement_data(self, index1):
+        return self.getUIntElement(self.offsetBits_data(index1), 8, 1)
+    
+    #
+    # Set an element of the array 'data'
+    #
+    def setElement_data(self, index1, value):
+        self.setUIntElement(self.offsetBits_data(index1), 8, value, 1)
+    
+    #
+    # Return the size, in bytes, of each element of the array 'data'
+    #
+    def elementSize_data(self):
+        return (8 / 8)
+    
+    #
+    # Return the size, in bits, of each element of the array 'data'
+    #
+    def elementSizeBits_data(self):
+        return 8
+    
+    #
+    # Return the number of dimensions in the array 'data'
+    #
+    def numDimensions_data(self):
+        return 1
+    
+    #
+    # Return the number of elements in the array 'data'
+    # for the given dimension.
+    #
+    def numElements_data(self, dimension):
+        array_dims = [ 0,  ]
+        if dimension < 0 or dimension >= 1:
+            raise IndexException
+        if array_dims[dimension] == 0:
+            raise IndexError
+        return array_dims[dimension]
+    
+    #
+    # Fill in the array 'data' with a String
+    #
+    def setString_data(self, s):
+         l = len(s)
+         for i in range(0, l):
+             self.setElement_data(i, ord(s[i]));
+         self.setElement_data(l, 0) #null terminate
+    
+    #
+    # Read the array 'data' as a String
+    #
+    def getString_data(self):
+        carr = "";
+        for i in range(0, 4000):
+            if self.getElement_data(i) == chr(0):
+                break
+            carr += self.getElement_data(i)
+        return carr
+    
index a2d8cf6df43b9e09f30a747d5757e674262feb21..75859605d62af0765edb648b432cb05dc7416ec5 100644 (file)
@@ -28,4 +28,4 @@
 #
 # Author: Geoffrey Mainland <mainland@eecs.harvard.edu>
 #
-__all__ = ["Message"]
+__all__ = ["Message", "MoteIF", "SerialPacket"]
diff --git a/support/sdk/python/tinyos/packet/IO.py b/support/sdk/python/tinyos/packet/IO.py
new file mode 100644 (file)
index 0000000..b9053e8
--- /dev/null
@@ -0,0 +1,57 @@
+#
+# Copyright (c) 2005
+#      The President and Fellows of Harvard College.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY 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 UNIVERSITY OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# 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: Geoffrey Mainland <mainland@eecs.harvard.edu>
+#
+class IODone(Exception):
+    pass
+
+class IO:
+    def __init__(self):
+        self.done = False
+
+    def isDone(self):
+        return self.done
+
+    def cancel(self):
+        self.done = True
+
+    def open(self):
+        pass
+
+    def close(self):
+        pass
+
+    def read(self, count):
+        pass
+
+    def write(self, data):
+        pass
+
+    def flush(self):
+        pass
diff --git a/support/sdk/python/tinyos/packet/Makefile b/support/sdk/python/tinyos/packet/Makefile
new file mode 100644 (file)
index 0000000..7759567
--- /dev/null
@@ -0,0 +1,6 @@
+# Makefile for tools/java/net/tinyos/packet
+
+SERIAL_H = $(TOSDIR)/lib/serial/Serial.h
+
+Serial.py:  
+       ncg -o $@ -python-classname=Serial python $(SERIAL_H) Serial.h
diff --git a/support/sdk/python/tinyos/packet/PacketDispatcher.py b/support/sdk/python/tinyos/packet/PacketDispatcher.py
new file mode 100644 (file)
index 0000000..287f90c
--- /dev/null
@@ -0,0 +1,59 @@
+#
+# Copyright (c) 2005
+#      The President and Fellows of Harvard College.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY 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 UNIVERSITY OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# 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: Geoffrey Mainland <mainland@eecs.harvard.edu>
+#
+import struct
+
+class PacketDispatcher:
+    def __init__(self):
+        self.listeners = {}
+
+    def addListener(self, listener, msgClass):
+        if listener not in self.listeners:
+            self.listeners[listener] = {}
+
+        amTypes = self.listeners[listener]
+        amTypes[msgClass.get_amType()] = msgClass
+
+    def removeListener(self, listener):
+        del self.listeners[listener]
+
+    def dispatchPacket(self, source, packet):
+        (addr, amType, group, length) = struct.unpack("<HBBB", packet[0:5])
+        msgData = packet[5:]
+
+        #print (addr, amType, group, length)
+
+        for l in self.listeners:
+            amTypes = self.listeners[l]
+            if amType in amTypes:
+                msgClass = amTypes[amType]
+                msg = msgClass(msgData)
+
+                l.receive(source, msg)
diff --git a/support/sdk/python/tinyos/packet/PacketSource.py b/support/sdk/python/tinyos/packet/PacketSource.py
new file mode 100644 (file)
index 0000000..4b785e4
--- /dev/null
@@ -0,0 +1,132 @@
+#
+# Copyright (c) 2005-2006
+#      The President and Fellows of Harvard College.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY 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 UNIVERSITY OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# 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: Geoffrey Mainland <mainland@eecs.harvard.edu>
+#
+import signal
+import sys
+import traceback
+
+from IO import *
+from ThreadTask import *
+
+DEBUG = False
+
+runner = ThreadTaskRunner()
+
+def finishAll():
+    global runner
+
+    runner.cancelAll()
+    runner.finish()
+
+class PacketSourceException(Exception):
+    def __init__(self, *args):
+        self.args = args
+
+class PacketSource(ThreadTask):
+    def __init__(self, dispatcher):
+        global runner
+        ThreadTask.__init__(self, runner)
+        self.dispatcher = dispatcher
+
+    def __call__(self):
+        try:
+            self.open()
+        except Exception, x:
+            if DEBUG:
+                print "Exception while opening packet source:"
+                print x
+                print traceback.print_tb(sys.exc_info()[2])
+            self.done = True
+        except:
+            if DEBUG:
+                print "Unknown exception while opening packet source"
+            self.done = True
+
+        while not self.isDone():
+            try:
+                packet = self.readPacket()
+            except IODone:
+                if DEBUG:
+                    print "IO finished"
+                break
+            except Exception, x:
+                if DEBUG:
+                    print "IO exception:"
+                    print x
+                    print traceback.print_tb(sys.exc_info()[2])
+                break
+            except:
+                if DEBUG:
+                    print "Unknown IO exception"
+                break
+
+            if packet:
+                try:
+#                     print "About to run packet dispatcher!"
+#                     for i in packet:
+#                         print ord(i)," ",
+#                     print
+
+                    self.dispatcher.dispatchPacket(self, packet)
+                except Exception, x:
+                    if DEBUG:
+                        print "Exception when dispatching packet:"
+                        print x
+                        print traceback.print_tb(sys.exc_info()[2])
+#                    break
+                except:
+                    if DEBUG:
+                        print "Unknown exception when dispatching packet"
+#                    break
+
+        try:
+            self.close()
+        except:
+            pass
+
+        self.finish()
+
+    def start(self):
+        global runner
+
+        runner.start(self)
+
+    def open(self):
+        pass
+
+    def close(self):
+        pass
+
+    def readPacket(self):
+        return None
+
+    def writePacket(self, packet):
+        pass
+
diff --git a/support/sdk/python/tinyos/packet/Platform.py b/support/sdk/python/tinyos/packet/Platform.py
new file mode 100644 (file)
index 0000000..66df0cc
--- /dev/null
@@ -0,0 +1,89 @@
+#
+# Copyright (c) 2006
+#      The President and Fellows of Harvard College.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY 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 UNIVERSITY OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# 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: Geoffrey Mainland <mainland@eecs.harvard.edu>
+#
+import re
+import socket
+import sys
+import traceback
+
+DEBUG = False
+
+PLATFORMS = {"mica": ("avrmote", 1, 19200),
+             "mica2dot": ("avrmote", 1, 19200),
+             "mica2": ("avrmote", 1, 57600),
+             "telos": ("telos", 2, 57600),
+             "tmote": ("telos", 2, 57600),
+             "micaz": ("avrmote", 3, 57600),
+             "eyes": ("eyes", 4, 19200)}
+
+ID_AVRMOTE = 1
+ID_TELOS = 2
+ID_MICAZ = 3
+ID_EYES = 4
+
+DEFAULT_BAUD = 19200
+
+class UnknownPlatform(Exception):
+    pass
+
+def baud_from_name(name):
+    try:
+        return PLATFORMS[name][2]
+    except:
+        raise UnknownPlatform()
+
+def default_factory():
+    return factory_from_platform("avrmote")
+
+def factory_from_name(name):
+    try:
+        return factory_from_platform(PLATFORMS[name][0])
+    except:
+        raise UnknownPlatform()
+
+def factory_from_id(i):
+    if i == ID_AVRMOTE:
+        return factory_from_platform("avrmote")
+    elif i == ID_TELOS:
+        return factory_from_platform("telos")
+    elif i == ID_MICAZ:
+        return factory_from_platform("avrmote")
+    else:
+        raise UnknownPlatform()
+
+def factory_from_platform(platform):
+    try:
+        mod = __import__("tinyos.packet.%s" % platform)
+        return mod.packet.__dict__[platform].TOS_Msg
+    except Exception, x:
+        if DEBUG:
+            print >>sys.stderr, x
+            print >>sys.stderr, traceback.print_tb(sys.exc_info()[2])
+        raise UnknownPlatform()
diff --git a/support/sdk/python/tinyos/packet/SFProtocol.py b/support/sdk/python/tinyos/packet/SFProtocol.py
new file mode 100644 (file)
index 0000000..831cea4
--- /dev/null
@@ -0,0 +1,77 @@
+#
+# Copyright (c) 2005-2006
+#      The President and Fellows of Harvard College.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY 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 UNIVERSITY OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# 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: Geoffrey Mainland <mainland@eecs.harvard.edu>
+#
+VERSION = "U"
+SUBVERSION = " "
+
+PLATFORM_UNKNOWN = 0
+
+class SFProtocolException(Exception):
+    def __init__(self, *args):
+        self.args = args
+
+class SFProtocol:
+    def __init__(self, ins, outs):
+        self.ins = ins
+        self.outs = outs
+        self.platform = None
+
+    def open(self):
+        self.outs.write(VERSION + SUBVERSION)
+        partner = self.ins.read(2)
+        if partner[0] != VERSION:
+            print "SFProtocol : version error"
+            raise SFProtocolException("protocol version error")
+
+       # Actual version is min received vs our version
+        # ourversion = partner[1] & 0xff
+        
+        if self.platform == None:
+            self.platform = PLATFORM_UNKNOWN
+
+        # In tinyox-1.x, we then exchanged platform information
+
+        # the tinyos-2.x serial forwarder doesn't do that, so the
+        # connection is all set up at this point.
+
+
+    def readPacket(self):
+        size = self.ins.read(1)
+        packet = self.ins.read(ord(size))
+        return packet
+
+    def writePacket(self, packet):
+        if len(packet) > 255:
+            raise SFProtocolException("packet too long")
+
+        self.outs.write(chr(len(packet)))
+        self.outs.write(packet)
+        self.outs.flush()
+        
diff --git a/support/sdk/python/tinyos/packet/SFSource.py b/support/sdk/python/tinyos/packet/SFSource.py
new file mode 100644 (file)
index 0000000..9015401
--- /dev/null
@@ -0,0 +1,69 @@
+#
+# Copyright (c) 2005-2006
+#      The President and Fellows of Harvard College.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY 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 UNIVERSITY OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# 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: Geoffrey Mainland <mainland@eecs.harvard.edu>
+#
+import re
+import socket
+
+from PacketSource import *
+from Platform import *
+from SFProtocol import *
+from SocketIO import *
+
+class SFSource(PacketSource):
+    def __init__(self, dispatcher, args):
+        PacketSource.__init__(self, dispatcher)
+
+        m = re.match(r'(.*):(.*)', args)
+        if m == None:
+            raise PacketSourceException("bad arguments")
+
+        (host, port) = m.groups()
+        port = int(port)
+
+        self.io = SocketIO(host, port)
+        self.prot = SFProtocol(self.io, self.io)
+
+    def cancel(self):
+        self.done = True
+        self.io.cancel()
+
+    def open(self):
+        self.io.open()
+        self.prot.open()
+        PacketSource.open(self)
+
+    def close(self):
+        self.io.close()
+
+    def readPacket(self):
+        return self.prot.readPacket()
+
+    def writePacket(self, packet):
+        self.prot.writePacket(packet)
diff --git a/support/sdk/python/tinyos/packet/Serial.py b/support/sdk/python/tinyos/packet/Serial.py
new file mode 100644 (file)
index 0000000..27ae1f1
--- /dev/null
@@ -0,0 +1,18 @@
+ #
+ # This class is automatically generated by ncg. DO NOT EDIT THIS FILE.
+ # This class includes values of some nesC constants from
+ # /opt/tinyos-2.x/tos/lib/serial/Serial.h.
+ #/
+
+class Serial:
+    HDLC_CTLESC_BYTE = 125
+    SERIAL_PROTO_ACK = 67
+    TOS_SERIAL_802_15_4_ID = 2
+    SERIAL_PROTO_PACKET_UNKNOWN = 255
+    SERIAL_PROTO_PACKET_NOACK = 69
+    TOS_SERIAL_CC1000_ID = 1
+    HDLC_FLAG_BYTE = 126
+    TOS_SERIAL_ACTIVE_MESSAGE_ID = 0
+    SERIAL_PROTO_PACKET_ACK = 68
+    TOS_SERIAL_UNKNOWN_ID = 255
+
diff --git a/support/sdk/python/tinyos/packet/SocketIO.py b/support/sdk/python/tinyos/packet/SocketIO.py
new file mode 100644 (file)
index 0000000..f928021
--- /dev/null
@@ -0,0 +1,80 @@
+#
+# Copyright (c) 2005
+#      The President and Fellows of Harvard College.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY 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 UNIVERSITY OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# 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: Geoffrey Mainland <mainland@eecs.harvard.edu>
+#
+import socket
+
+from IO import *
+
+class SocketIO(IO):
+    def __init__(self, host, port):
+        IO.__init__(self)
+
+        self.done = False
+
+        self.host = host
+        self.port = port
+
+        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.socket.setsockopt(socket.IPPROTO_TCP,
+                               socket.TCP_NODELAY,
+                               1)
+        self.socket.settimeout(1)
+        self.socket.bind(("", 0))
+
+    def cancel(self):
+        self.done = True
+
+    def open(self):
+        print "SocketIO: Connecting socket to "+str(self.host)+":"+str(self.port)
+        self.socket.connect((self.host, self.port))
+        self.socket.settimeout(1)
+
+    def close(self):
+        self.socket.close()
+        self.socket = None
+
+    def read(self, count):
+        data = ""
+        while count - len(data) > 0:
+            if self.isDone():
+                raise IODone()
+
+            try:
+                data += self.socket.recv(count - len(data))
+            except:
+                pass
+
+        return data
+
+    def write(self, data):
+        return self.socket.send(data)
+
+    def flush(self):
+        pass
diff --git a/support/sdk/python/tinyos/packet/ThreadTask.py b/support/sdk/python/tinyos/packet/ThreadTask.py
new file mode 100644 (file)
index 0000000..5f1360f
--- /dev/null
@@ -0,0 +1,91 @@
+#
+# Copyright (c) 2005
+#      The President and Fellows of Harvard College.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY 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 UNIVERSITY OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# 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: Geoffrey Mainland <mainland@eecs.harvard.edu>
+#
+import threading
+import time
+
+class ThreadTask:
+    def __init__(self, runner):
+        self.done = False
+        self.runner = runner
+
+        runner.add(self)
+
+    def isDone(self):
+        return self.done
+
+    def cancel(self):
+        self.done = True
+
+    def finish(self):
+        self.runner.remove(self)
+
+class ThreadTaskRunner:
+    def __init__(self):
+        self.taskList = []
+        self.taskListLock = threading.Lock()
+
+    def add(self, task):
+        self.taskListLock.acquire()
+        self.taskList = [task] + self.taskList
+        self.taskListLock.release()
+
+    def remove(self, task):
+        self.taskListLock.acquire()
+        self.taskList.remove(task)
+        self.taskListLock.release()
+
+    def start(self, task):
+        thread = threading.Thread(None, task)
+        thread.start()
+
+    def cancelAll(self):
+        self.taskListLock.acquire()
+
+        for t in self.taskList:
+            try:
+                t.cancel()
+            except:
+                pass
+
+        self.taskListLock.release()
+
+    def finish(self):
+        try:
+            self.taskListLock.acquire()
+
+            while len(self.taskList) != 0:
+                self.taskListLock.release()
+                time.sleep(0.2)
+                self.taskListLock.acquire()
+
+            self.taskListLock.release()
+        except:
+            pass
diff --git a/support/sdk/python/tinyos/packet/__init__.py b/support/sdk/python/tinyos/packet/__init__.py
new file mode 100644 (file)
index 0000000..9b5c173
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2005
+#      The President and Fellows of Harvard College.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY 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 UNIVERSITY OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# 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: Geoffrey Mainland <mainland@eecs.harvard.edu>
+#
+__all__ = ["PacketDispatcher", "PacketSource", "Packetizer",
+           "SFProtocol", "SFSource", "ThreadTask",
+           "avrmote", "micaz", "telos"]
diff --git a/support/sdk/python/tinyos/utils/Singleton.py b/support/sdk/python/tinyos/utils/Singleton.py
new file mode 100644 (file)
index 0000000..09d5924
--- /dev/null
@@ -0,0 +1,249 @@
+# Copyright (c) 2006-2007 Chad Metcalf <chad@5secondfuse.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a 
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# Author: Chad Metcalf <chad@5secondfuse.com>
+#
+
+"""
+A Python Singleton mixin class that makes use of some of the ideas
+found at http://c2.com/cgi/wiki?PythonSingleton. Just inherit
+from it and you have a singleton. No code is required in
+subclasses to create singleton behavior -- inheritance from 
+Singleton is all that is needed.
+
+Assume S is a class that inherits from Singleton. Useful behaviors
+are:
+
+1) Getting the singleton:
+
+    S.getInstance() 
+    
+returns the instance of S. If none exists, it is created. 
+
+2) The usual idiom to construct an instance by calling the class, i.e.
+
+    S()
+    
+is disabled for the sake of clarity. If it were allowed, a programmer
+who didn't happen  notice the inheritance from Singleton might think he
+was creating a new instance. So it is felt that it is better to
+make that clearer by requiring the call of a class method that is defined in
+Singleton. An attempt to instantiate via S() will restult in an SingletonException
+being raised.
+
+3) If S.__init__(.) requires parameters, include them in the
+first call to S.getInstance(.). If subsequent calls have parameters,
+a SingletonException is raised.
+
+4) As an implementation detail, classes that inherit 
+from Singleton may not have their own __new__
+methods. To make sure this requirement is followed, 
+an exception is raised if a Singleton subclass includ
+es __new__. This happens at subclass instantiation
+time (by means of the MetaSingleton metaclass.
+
+By Gary Robinson, grobinson@transpose.com. No rights reserved -- 
+placed in the public domain -- which is only reasonable considering
+how much it owes to other people's version which are in the
+public domain. The idea of using a metaclass came from 
+a  comment on Gary's blog (see 
+http://www.garyrobinson.net/2004/03/python_singleto.html#comments). 
+Other improvements came from comments and email from other
+people who saw it online. (See the blog post and comments
+for further credits.)
+
+Not guaranteed to be fit for any particular purpose. Use at your
+own risk. 
+"""
+
+class SingletonException(Exception):
+    def __init__(self, *args):
+        Exception.__init__(self)
+        self.args = args
+
+class MetaSingleton(type):
+    def __new__(metaclass, strName, tupBases, dict):
+        if dict.has_key('__new__'):
+            raise SingletonException, 'Can not override __new__ in a Singleton'
+        return super(MetaSingleton,metaclass).__new__(metaclass, strName, tupBases, dict)
+        
+    def __call__(cls, *lstArgs, **dictArgs):
+        raise SingletonException, 'Singletons may only be instantiated through getInstance()'
+        
+class Singleton(object):
+    __metaclass__ = MetaSingleton
+    
+    def getInstance(cls, *lstArgs):
+        """
+        Call this to instantiate an instance or retrieve the existing instance.
+        If the singleton requires args to be instantiated, include them the first
+        time you call getInstance.        
+        """
+        if cls._isInstantiated():
+            if len(lstArgs) != 0:
+                raise SingletonException, 'If no supplied args, singleton must already be instantiated, or __init__ must require no args'
+        else:
+            if cls._getConstructionArgCountNotCountingSelf() > 0 and len(lstArgs) <= 0:
+                raise SingletonException, 'If the singleton requires __init__ args, supply them on first instantiation'
+            instance = cls.__new__(cls)
+            instance.__init__(*lstArgs)
+            cls.cInstance = instance
+        return cls.cInstance
+    getInstance = classmethod(getInstance)
+    
+    def _isInstantiated(cls):
+        return hasattr(cls, 'cInstance')
+    _isInstantiated = classmethod(_isInstantiated)  
+
+    def _getConstructionArgCountNotCountingSelf(cls):
+        return cls.__init__.im_func.func_code.co_argcount - 1
+    _getConstructionArgCountNotCountingSelf = classmethod(_getConstructionArgCountNotCountingSelf)
+
+    def _forgetClassInstanceReferenceForTesting(cls):
+        """
+        This is designed for convenience in testing -- sometimes you 
+        want to get rid of a singleton during test code to see what
+        happens when you call getInstance() under a new situation.
+        
+        To really delete the object, all external references to it
+        also need to be deleted.
+        """
+        try:
+            delattr(cls,'cInstance')
+        except AttributeError:
+            # run up the chain of base classes until we find the one that has the instance
+            # and then delete it there
+            for baseClass in cls.__bases__: 
+                if issubclass(baseClass, Singleton):
+                    baseClass._forgetClassInstanceReferenceForTesting()
+    _forgetClassInstanceReferenceForTesting = classmethod(_forgetClassInstanceReferenceForTesting)
+    
+
+
+if __name__ == '__main__':
+    import unittest
+    
+    class PublicInterfaceTest(unittest.TestCase):
+        def testReturnsSameObject(self):
+            """
+            Demonstrates normal use -- just call getInstance and it returns a singleton instance
+            """
+        
+            class A(Singleton): 
+                def __init__(self):
+                    super(A, self).__init__()
+                    
+            a1 = A.getInstance()
+            a2 = A.getInstance()
+            self.assertEquals(id(a1), id(a2))
+            
+        def testInstantiateWithMultiArgConstructor(self):
+            """
+            If the singleton needs args to construct, include them in the first
+            call to get instances.
+            """
+                    
+            class B(Singleton): 
+                    
+                def __init__(self, arg1, arg2):
+                    super(B, self).__init__()
+                    self.arg1 = arg1
+                    self.arg2 = arg2
+
+            b1 = B.getInstance('arg1 value', 'arg2 value')
+            b2 = B.getInstance()
+            self.assertEquals(b1.arg1, 'arg1 value')
+            self.assertEquals(b1.arg2, 'arg2 value')
+            self.assertEquals(id(b1), id(b2))
+            
+            
+        def testTryToInstantiateWithoutNeededArgs(self):
+            
+            class B(Singleton): 
+                    
+                def __init__(self, arg1, arg2):
+                    super(B, self).__init__()
+                    self.arg1 = arg1
+                    self.arg2 = arg2
+
+            self.assertRaises(SingletonException, B.getInstance)
+            
+        def testTryToInstantiateWithoutGetInstance(self):
+            """
+            Demonstrates that singletons can ONLY be instantiated through
+            getInstance, as long as they call Singleton.__init__ during construction.
+            
+            If this check is not required, you don't need to call Singleton.__init__().
+            """
+
+            class A(Singleton): 
+                def __init__(self):
+                    super(A, self).__init__()
+                    
+            self.assertRaises(SingletonException, A)
+            
+        def testDontAllowNew(self):
+        
+            def instantiatedAnIllegalClass():
+                class A(Singleton): 
+                    def __init__(self):
+                        super(A, self).__init__()
+                        
+                    def __new__(metaclass, strName, tupBases, dict):
+                        return super(MetaSingleton,metaclass).__new__(metaclass, strName, tupBases, dict)
+                                        
+            self.assertRaises(SingletonException, instantiatedAnIllegalClass)
+        
+        
+        def testDontAllowArgsAfterConstruction(self):
+            class B(Singleton): 
+                    
+                def __init__(self, arg1, arg2):
+                    super(B, self).__init__()
+                    self.arg1 = arg1
+                    self.arg2 = arg2
+
+            b1 = B.getInstance('arg1 value', 'arg2 value')
+            self.assertRaises(SingletonException, B, 'arg1 value', 'arg2 value')
+            
+        def test_forgetClassInstanceReferenceForTesting(self):
+            class A(Singleton): 
+                def __init__(self):
+                    super(A, self).__init__()
+            class B(A): 
+                def __init__(self):
+                    super(B, self).__init__()
+                    
+            # check that changing the class after forgetting the instance produces
+            # an instance of the new class
+            a = A.getInstance()
+            assert a.__class__.__name__ == 'A'
+            A._forgetClassInstanceReferenceForTesting()
+            b = B.getInstance()
+            assert b.__class__.__name__ == 'B'
+            
+            # check that invoking the 'forget' on a subclass still deletes the instance
+            B._forgetClassInstanceReferenceForTesting()
+            a = A.getInstance()
+            B._forgetClassInstanceReferenceForTesting()
+            b = B.getInstance()
+            assert b.__class__.__name__ == 'B'
+
+    unittest.main()
diff --git a/support/sdk/python/tinyos/utils/Watcher.py b/support/sdk/python/tinyos/utils/Watcher.py
new file mode 100644 (file)
index 0000000..e96f466
--- /dev/null
@@ -0,0 +1,72 @@
+# Copyright (c) 2006-2007 Chad Metcalf <chad@5secondfuse.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a 
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# Author: Chad Metcalf <chad@5secondfuse.com>
+#
+
+import os
+import sys
+import signal
+
+from tinyos.utils.Singleton import Singleton
+
+class Watcher(Singleton):
+    """ As seen in:
+    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496735
+    
+    This class solves two problems with multithreaded
+    programs in Python, (1) a signal might be delivered
+    to any thread (which is just a malfeature) and (2) if
+    the thread that gets the signal is waiting, the signal
+    is ignored (which is a bug).
+
+    The watcher is a concurrent process (not thread) that
+    waits for a signal and the process that contains the
+    threads.  See Appendix A of The Little Book of Semaphores.
+    http://greenteapress.com/semaphores/
+    """
+    
+    def __init__(self):
+        """ Creates a child thread, which returns.  The parent
+            thread waits for a KeyboardInterrupt and then kills
+            the child thread.
+        """  
+        Singleton.__init__(self)
+        
+        self.child = os.fork()
+        if self.child != 0:
+            self.watch()
+
+    def watch(self):
+        try:
+            os.wait()
+        except KeyboardInterrupt:
+            # I put the capital B in KeyBoardInterrupt so I can
+            # tell when the Watcher gets the SIGINT
+            print 'KeyBoardInterrupt'
+            self.kill()
+        sys.exit()
+
+    def kill(self):
+        try:
+            os.kill(self.child, signal.SIGKILL)
+        except OSError, x: 
+            print "os.kill failed"
+            print x
\ No newline at end of file
diff --git a/support/sdk/python/tinyos/utils/__init__.py b/support/sdk/python/tinyos/utils/__init__.py
new file mode 100644 (file)
index 0000000..e1ac828
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright (c) 2006-2007 Chad Metcalf <chad@5secondfuse.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a 
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# Author: Chad Metcalf <chad@5secondfuse.com>
+#
+
+__all__ = ["Singleton", "Watcher"]