[Tinyos-commits] CVS: tinyos-1.x/tools/python/pytos/util
JavaInheritor.py, NONE, 1.1 KeyPress.py, NONE, 1.1 NescApp.py,
NONE, 1.1 RoutingMessages.py, NONE, 1.1 SupplementQuery.py,
NONE, 1.1 Timer.py, NONE, 1.1 __init__.py, NONE,
1.1 nescDecls.py, NONE, 1.1
Kamin Whitehouse
kaminw at users.sourceforge.net
Fri Sep 23 03:20:36 PDT 2005
Update of /cvsroot/tinyos/tinyos-1.x/tools/python/pytos/util
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5850/pytos/util
Added Files:
JavaInheritor.py KeyPress.py NescApp.py RoutingMessages.py
SupplementQuery.py Timer.py __init__.py nescDecls.py
Log Message:
pytos is a python-based toolchain for tinyos with a dynamic typing system. it automatically imports the enums, types, message formats, modules, variables, and rpc functions from applications that are compiled with the 'rpc' and 'nescDecls' targets.
--- NEW FILE: JavaInheritor.py ---
# "Copyright (c) 2000-2003 The Regents of the University of California.
# 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 following
# two paragraphs and the author appear in all copies of this software.
#
# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY
# OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
#
# @author Kamin Whitehouse
#
import re
from jpype import jimport
class JavaInheritor ( object ) :
"""This python class should usually be inherited from. It has one
field called self.javaParents which should be a list of java
objects, and this python class \"inherits\" all fields and
functions of those java objects. If two java objects have the
same field or function, the one from the first object in the list
is used. The fields and functions, of course, can be overridden
in the derived python class.
At the end of the constructor of the derived python class, the
constructor of this class MUST be called as follows:
JavaInheritor.__init__(self, javaParents)
"""
def __init__(self, javaParents):
self._inheritedFields = {}
self._fullClassnames = []
self._inheritedFieldNames = []
self._javaParents = javaParents
classmatch = re.compile('^<jpype\\._jclass\\.(.*\\.(.+?)) ')
pythonfield = re.compile('__.+__')
allFieldNames = set(dir(self)) | \
set(dir(jimport.java.lang.Object))
for parent in self._javaParents :
fieldNames = set(dir(parent)) - allFieldNames
allFieldNames |= fieldNames
match = classmatch.match(repr(parent))
self._fullClassnames.append(match.group(1))
className = match.group(2)
for field in fieldNames :
if pythonfield.match(field) :
continue
self._inheritedFields[field] = parent
self.__dict__[field]=None
name = className + "." + field
if type(parent.__getattribute__(field)) == \
type(parent.__getattribute__("hashCode")):
name += "()"
self._inheritedFieldNames.append(name)
self.__initialized = True
def __repr__(self) :
return "%s object at %s:\n\n%s" % (self.__class__, hex(id(self)), str(self))
def __str__(self) :
"""The type of object"""
string= "Python object derived from java classes:\n"
for parent in self._fullClassnames:
string += "\t%s\n" % parent
string += "\nThe following java fields/methods are inherited:\n"
for field in self._inheritedFieldNames:
string += "\t%s\n" % field
return string
def __getattribute__(self, name) :
"""get the value of the first field with this name.
This is also used for calling parent functions. It has
the weird semantics that a field can override a function,
and vice versa"""
fields = object.__getattribute__(self,"__dict__")
if not fields.has_key("_JavaInheritor__initialized"):
return object.__getattribute__(self, name)
_inheritedFields = object.__getattribute__(self, "_inheritedFields")
if _inheritedFields.has_key(name) :
return _inheritedFields[name].__getattribute__(name)
return object.__getattribute__(self, name)
def __setattr__(self, name, value) :
"""Set the attr on this python object if it exists.
Otherwise, check if the field exists on the java object,
and set it as long as it is not a function."""
if not self.__dict__.has_key("_JavaInheritor__initialized") or \
(self.__dict__.has_key(name) and
not name in self._inheritedFields.keys() ) :
self.__dict__[name] = value
return
elif self.__dict__.has_key("_javaParents") and \
name in self._inheritedFields.keys() :
return self._inheritedFields[name].__setattr__(name, value)
raise AttributeError("Object has no attribute '%s'" % name)
--- NEW FILE: KeyPress.py ---
#!/usr/bin/env python
# $Id: KeyPress.py,v 1.1 2005/09/23 10:20:33 kaminw Exp $
# tab:2
# "Copyright (c) 2000-2003 The Regents of the University of California.
# 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 following
# two paragraphs and the author appear in all copies of this software.
#
# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
# CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
#
# Copyright (c) 2002-2003 Intel Corporation
# All rights reserved.
#
# This file is distributed under the terms in the attached INTEL-LICENSE
# file. If you do not find these files, copies can be found by writing to
# Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA,
# 94704. Attention: Intel License Inquiry.
#
#
# @author Shawn Schaffert
#
import os
if os.name == "posix" :
import sys, select, termios
class KeyPress:
def __init__(self):
self.f = sys.stdin
self.oldAttr = termios.tcgetattr( self.f )
# we need to adjust some parameters of the term
# (1) do not echo
# (2) turn off canonical mode input (ie, switch to non-canonical mode input)
# so that input is not processed in line chunks
# (3) set the VMIN (the min num of bytes needed before returning during a read) to 1
# (4) set the VTIME (the inter-byte timer) to 0, so we do not delay
newAttr = self.oldAttr[:]
newAttr[3] = newAttr[3] & ~termios.ECHO & ~termios.ICANON
newAttr[6][termios.VMIN] = 1
newAttr[6][termios.VTIME] = 0
termios.tcsetattr( self.f , termios.TCSANOW , newAttr )
def destroy(self):
termios.tcsetattr( self.f , termios.TCSANOW , self.oldAttr )
def getChar( self , blocking = False ):
if blocking :
ready = select.select( [self.f] , [] , [] )
else :
ready = select.select( [self.f] , [] , [] , 0 )
if ready[0] :
ch = self.f.read(1)
else:
ch = ""
return ch
elif os.name == "nt" :
import msvcrt
class KeyPress:
def __init__( self ):
pass
def destroy( self ):
pass
def getChar( self , blocking = False ):
if blocking :
return msvcrt.getch()
else :
if msvcrt.kbhit() :
return msvcrt.getch()
else:
return ""
else :
raise OSError
if __name__=="__main__":
import time
kp = KeyPress()
i = 0
print "press \'q\' to quit"
while kp.getChar() != "q" :
i += 1
print i
time.sleep(.25)
kp.destroy()
--- NEW FILE: NescApp.py ---
# "Copyright (c) 2000-2003 The Regents of the University of California.
# 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 following
# two paragraphs and the author appear in all copies of this software.
#
# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY
# OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
#
# @author Kamin Whitehouse
#
from nescDecls import *
import pytos.tools.Rpc as Rpc
import pytos.tools.RamSymbols as RamSymbols
import re
class NescTypes( object ) :
"""A class that holds all types defined in a specific nesc application.
usage:
myTypes = NescTypes('/path/to/nescDecls.xml')
print myTypes
var = myTypes.typeName
"""
def __init__( self, xmlFilename=None, applicationName="Unknown App" ) :
self.applicationName = applicationName
self._typeNames = []
self._types = {}
#figure out the sizes of all the basic types for this platform (by scanning the xml file)
platformTypes = {}
typeRE = re.compile('cname=\"([\w\s]+?)\" size=\"I:(\d+?)\"')
xmlFilename = findBuildFile(xmlFilename, "nescDecls.xml")
infile = open(xmlFilename, 'r')
for line in infile :
match = typeRE.search(line)
if match != None:
platformTypes[match.groups()[0]] = int(match.groups()[1])
#define all the basic types
self.addType(
nescType("uint8_t", "unsigned char", "int", "type-int", "B",1,0))
self.addType(
nescType("int8_t", "signed char", "int", "type-int", "b", 1, 0))
if (platformTypes.has_key("int") and platformTypes["int"] == 4) or \
(platformTypes.has_key("unsigned int") and platformTypes["unsigned int"] == 4) :
self.addType(
nescType("uint16_t", "unsigned short", "int", "type-int", "H", 2, 0))
self.addType(
nescType("int16_t", "short", "int", "type-int", "h", 2, 0))
self.addType(
nescType("uint32_t", "unsigned int", "int", "type-int", "L",4,0))
self.addType(
nescType("int32_t", "int", "int", "type-int", "L", 4, 0))
self.addType(
nescType("unsigned long", "unsigned long", "int", "type-int", "L",4,0))
self.addType(
nescType("long", "long", "int", "type-int", "l", 4, 0))
else : #int is 2 bytes long (the default)
self.addType(
nescType("unsigned short", "unsigned short", "int", "type-int", "H", 2, 0))
self.addType(
nescType("short", "short", "int", "type-int", "h", 2, 0))
self.addType(
nescType("uint16_t", "unsigned int", "int", "type-int", "H", 2, 0))
self.addType(
nescType("int16_t", "int", "int", "type-int", "h", 2, 0))
self.addType(
nescType("uint32_t", "unsigned long", "int", "type-int", "L",4,0))
self.addType(
nescType("int32_t", "long", "int", "type-int", "l", 4, 0))
self.addType(
nescType("int64_t", "long long", "long", "type-int", "q", 8, 0))
self.addType(
nescType("uint64_t", "unsigned long long", "long", "type-int", "Q", 8, 0))
self.addType(
nescType("float", "float", "float", "type-float", "f", 4, 0))
if platformTypes.has_key("double") and platformTypes["double"] == 8 :
self.addType(
nescType("double", "double", "float", "type-float", "d", 8, 0))
else : #double is 4 bytes (the default)
self.addType(
nescType("double", "double", "float", "type-float", "f", 4, 0))
self.addType(
nescType("char", "char", "str", "type-int", "c", 1, '\x00'))
self.addType(
nescType("void", "void", "", "type-void", "", 0, ''))
#some arrays for error reporting:
self.unknownStructs = []
self.anonymousStructs = []
self.anonymousRefStructs = []
self.undefinedTypes = []
self.createTypesFromXml(xmlFilename)
self._typeNames.sort()
#self.printSkippedTypes()
def addType(self, value) :
if not value.nescType in self._typeNames :
self._typeNames.append(value.nescType)
self._types[value.nescType] = value #XXX: why does this have to be unconditional??
if not self._types.has_key(value.cType):
self._types[value.cType] = value
self._typeNames.append(value.cType)
def __getattr__(self, name) :
if name in self._typeNames :
return deepcopy(self._types[name])
else:
raise AttributeError("No type \"%s\" defined" % name)
def __getitem__(self, key) :
if key in self._typeNames :
return deepcopy(self._types[key])
else:
raise AttributeError("No type \"%s\" defined" % key)
def __repr__(self) :
return "%s object at %s:\n\n\t%s" % (self.__class__, hex(id(self)), str(self))
def __str__(self) :
""" Print all available types."""
string = "\n"
for t in self._typeNames :
string += "\t%s\n" % t
return string
def createTypesFromXml(self, xmlFilename) :
"""Go through the struct and typedef elements in the nescDecls.xml file"""
dom = minidom.parse(xmlFilename)
typeDefs = [node for node in dom.getElementsByTagName("struct")]
for node in dom.getElementsByTagName("typedef") :
typeDefs.append(node)
numSkipped = 0
#keep going through the queue until it is empty
while len(typeDefs) > 0:
typeDef = typeDefs.pop(0)
#if this is a typedef, see if the value is there
if typeDef.tagName == "typedef" :
value = typeDef.getAttribute("value")
name = typeDef.getAttribute("name")
#if the real value exists and typedef doesn't already exist, copy and rename original
if self._types.has_key(value) :
newType = deepcopy(self._types[value])
newType.nescType = name
self.addType(newType)
numSkipped=0
else :
#try again later
typeDefs.append(typeDef)
numSkipped += 1
else :
#if all types within the struct are already defined, it can be defined
try :
self.addType(nescStruct(self, typeDef ) )
numSkipped=0
except Exception, e:
if len(e.args) > 0 and e.args[0] == "Undefined struct":
#otherwise, put it back in the queue and move on to the next one
typeDefs.append(typeDef)
numSkipped += 1
elif len(e.args) > 0 and e.args[0] == "Anonymous struct" :
self.anonymousStructs.append(typeDef)
elif len(e.args) > 0 and e.args[0] == "Anonymous struct reference" :
self.anonymousRefStructs.append( (typeDef, e.args[1]) )
elif len(e.args) > 0 and e.args[0] == "Unknown type" :
self.unknownStructs.append( (typeDef, e.args[1]) )
else :
#if it's an unknown exception, reraise it
raise
#make sure we are not cycling endlessly
if numSkipped >= len(typeDefs) > 0:
self.undefinedTypes = typeDefs
break
def printSkippedTypes(self):
err = ""
if len(self.anonymousStructs) >0 :
err += "\nWarning: %d structs were anonymous." % len(self.anonymousStructs)
# for struc in anonymousStructs :
# err += "\t%s\n" % struc.getAttribute("ref")
if len(self.anonymousRefStructs) >0 :
err += "\nWarning: The following structs referenced anonymous structs:\n"
for pair in self.anonymousRefStructs :
err += "\t%s\n" % pair[0].getAttribute("name")
if len(self.undefinedTypes) >0 :
err += "\nWarning: The following types are ill-defined or had circular dependencies:\n"
for struc in self.undefinedTypes :
err += "\t%s\n" % struc.getAttribute("name")
if len(self.unknownStructs) >0 :
err += "\nWarning: The following structs had unknown xml types:\n"
for pair in self.unknownStructs :
err += "\t%s (%s)\n" % (pair[0].getAttribute("name"),
pair[1].tagName )
if len(err) > 0 : print err
def getTypeFromXML(self, xmlDefinition) :
"""Find the type name value given an xml definition.
If it is an array or pointer, define the new type here."""
#first, see if the tag is type or if child is type
if xmlDefinition.tagName.find("type-") < 0 or \
xmlDefinition.tagName.find("type-qualified") >= 0 :
foundType = 0
childNodes = [node for node in xmlDefinition.childNodes
if node.nodeType == 1]
for tag in childNodes :
if tag.tagName.find("type-") >= 0 :
foundType += 1
typeTag = tag
if foundType < 1 :
raise Exception("No type tag found")
if foundType > 1 :
raise Exception("Too many type tags found")
else :
return self.getTypeFromXML(typeTag)
#now check all the existing types to see if it is one of them
for val in self._typeNames :
typeObj = self._types[val]
if typeObj.isType(xmlDefinition) :
return deepcopy(typeObj)
#if the type doesn't already exist, try creating a new one
try :
return nescArray(self, xmlDefinition)
except Exception, e:
if len(e.args) <= 0 or e.args[0] != "Not array definition":
raise
try :
return nescPointer(self, xmlDefinition)
except Exception, e:
if len(e.args) <= 0 or e.args[0] != "Not pointer definition":
raise
#it is not a simple type, array, or pointer,
#so it must be a yet undefined struct
child = getUniqueChild(xmlDefinition)
if ( xmlDefinition.tagName == "type-tag" and child != None and
child.tagName == "struct-ref" ):
if child.hasAttribute("name"):
raise Exception("Undefined struct")
else :
raise Exception("Anonymous struct reference", child)
else:
#otherwise, raise an exception
#(but first make sure the right kind of unknown type is displayed)
if xmlDefinition.tagName == "type-tag":
xmlDefinition = child
raise Exception("Unknown type", xmlDefinition)
class NescEnums( object ) :
"""A class that holds all enums defined in a specific nesc application.
usage:
myEnums = NescEnums('/path/to/nescDecls.xml')
print myEnums
var = myEnums.enumName
"""
def __init__( self, xmlFilename=None, applicationName="Unknown App" ) :
self.applicationName = applicationName
self._enums = []
if type(xmlFilename) == str:
xmlFilename = findBuildFile(xmlFilename, "nescDecls.xml")
xmlFilename = minidom.parse(xmlFilename)
self.createEnumsFromXml(xmlFilename)
def __getitem__(self, key) :
if key in self._enums :
return self.__dict__[key]
else:
raise AttributeError("No such enum defined")
def createEnumsFromXml(self, dom) :
#now define all the struct types
enumDefs = [node for node in dom.getElementsByTagName("enum")]
integer = re.compile('^I:(\d+)$')
hexidecimal = re.compile('^(0x[\dabcdefABCDEF]+)$')
for enumDef in enumDefs :
name = enumDef.getAttribute("name")
if name in self._enums :
continue
value = enumDef.getAttribute("value")
match = integer.match(value)
if match != None :
self.__dict__[name] = int(match.groups()[0])
else :
match = hexidecimal.match(value)
if match != None :
self.__dict__[name] = int(match.groups()[0], 16)
else :
self.__dict__[name] = value
self._enums.append(name)
namedEnums = [node for node in dom.getElementsByTagName("namedEnum")]
for namedEnum in namedEnums :
name = namedEnum.getAttribute("name")
self.__dict__[name] = NescEnums(namedEnum,name)
self._enums.append(name)
def __repr__(self) :
return "%s object at %s:\n\n\t%s" % (self.__class__, hex(id(self)), str(self))
def __str__(self) :
""" Print all available enums."""
string = "\n"
for key in self._enums :
string += "\t%s = %s\n" % (key, str(self[key]))
return string
class NescMsgs( object ) :
"""A class that holds all msgs defined in a specific nesc application.
It assumes a struct is a message if AM_STRUCTNAME is defined.
usage:
myMsgs = NescMsgs(myTypes, myEnums[, applicationName])
print myMsgs
var = myMsgs.msgName
"""
def __init__( self, types, enums, applicationName="Unknown App" ) :
self.applicationName = applicationName
msgTypes = [enum for enum in enums._enums if enum.find("AM_") ==0]
name = re.compile("^AM_(\w+)$")
self._msgNames = []
self._msgs = {}
for msgType in msgTypes :
if type(enums[msgType]) == int:
msgName = name.match(msgType)
if msgName != None :
msgName = msgName.groups()[0]
for key in types._typeNames :
if key.lower() == msgName.lower() :
msg = TosMsg(enums[msgType], types[key])
self._msgs[key] = msg
self._msgNames.append(key)
break
def __getattr__(self, name) :
if name in self._msgNames :
return deepcopy(self._msgs[name])
else:
raise AttributeError("No such message defined")
def __getitem__(self, key) :
if key in self._msgNames :
return deepcopy(self._msgs[key])
else:
raise AttributeError("No such message defined")
def __repr__(self) :
return "%s object at %s:\n\n\t%s" % (self.__class__, hex(id(self)), str(self))
def __str__(self) :
""" Print all available msgs."""
string = "\n"
for key in self._msgNames :
string += "\t%5d : %s\n" % (self._msgs[key].amType, key)
return string
class Shortcut (object) :
"""A class that provides all rpc functions and ram symbols for a module"""
def __init__(self, moduleName, rpc, ram):
self.moduleName = moduleName
self.rpc = rpc
self.ram = ram
def __getattr__(self, name) :
try :
return self.ram.__getattr__(name)
except :
try:
return self.rpc.__getattr__(name)
except :
raise Exception("Module %s does not have rpc function or ram symbol %s" % (
self.moduleName, name))
def __repr__(self):
return "%s object at %s:\n\n%s" % (self.__class__, hex(id(self)), str(self))
def __str__(self):
string = "Module %s\n\n" % self.moduleName
if self.ram:
string += "%s\n" % str(self.ram)
if self.rpc:
string += "%s\n" % str(self.rpc)
return string
class NescApp( object ) :
"""A class that holds all types and enums defined in a specific nesc application.
usage:
myApp = nescApp('/path/to/nescDecls.xml')
print myApp
var = myApp.enums.enumName
var = myApp.types.typeName
"""
def __init__( self, buildDir=None, port=None, tosbase=True, applicationName="Unknown App" ) :
#first, import all enums, types, msgs, rpc functions, and ram symbols
self.applicationName = applicationName
try:
f = findBuildFile(buildDir, "nescDecls.xml")
except Exception, e:
if len(e.args) > 0 and e.args[0].find("File ") == 0:
raise Exception("%s. Perhaps you provided the wrong build directory, or perhaps you did not compile with the \"nescDecls\" build argument. Your nesC app cannot be imported." % e.args[0])
else :
raise
self.enums = NescEnums(buildDir, applicationName)
self.types = NescTypes(buildDir, applicationName)
self.msgs = NescMsgs(self.types, self.enums, applicationName)
try:
f = findBuildFile(buildDir, "rpcSchema.xml")
except Exception, e:
if len(e.args) > 0 and e.args[0].find("File ") == 0:
print "Warning: %s. You did not compile with the \"rpc\" make argument. No rpc commands or ram symbols will be imported." % e.args[0]
return
else :
raise
self.rpc = Rpc.Rpc(self, buildDir, sendComm=port, tosbase=tosbase)
self.ramSymbols = RamSymbols.RamSymbols(self, buildDir,
sendComm=self.rpc.sendComm,
receiveComm=self.rpc.receiveComm,
tosbase=tosbase)
#now create shortcuts to all the application modules
moduleNames = {}
self._moduleNames = []
moduleName = re.compile('^(\w+).')
names = self.rpc._messages.keys()
names.extend(self.ramSymbols._messages.keys())
names.sort()
for name in names :
match = moduleName.match(name)
if match != None :
moduleNames[match.groups(0)[0]] = True
for name in moduleNames.keys() :
try :
rpc = self.rpc.__getattr__(name)
except:
rpc = None
try :
ram = self.ramSymbols.__getattr__(name)
except:
ram = None
self.__dict__[name] = Shortcut(name, rpc, ram)
self._moduleNames.append(name)
self._moduleNames.sort()
def __repr__(self) :
return "%s object at %s:\n\n%s" % (self.__class__, hex(id(self)), str(self))
def __str__(self) :
""" Print all application declarations."""
string = "%20s : %d\n" % ("Enums", len(self.enums._enums))
string += "%20s : %d\n" % ("Types", len(self.types._types))
string += "%20s : %d\n" % ("Messages", len(self.msgs._msgNames))
if self.__dict__.has_key("rpc") :
string += "%20s : %d\n" % ("Rpc functions", len(self.rpc._messages.keys()))
string += "%20s : %d\n" % ("Ram symbols", len(self.ramSymbols._messages.keys()))
string += "%20s : " % ("Modules")
for name in self._moduleNames :
string += "%s\n%23s" % (name,"")
return string
--- NEW FILE: RoutingMessages.py ---
# "Copyright (c) 2000-2003 The Regents of the University of California.
# 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 following
# two paragraphs and the author appear in all copies of this software.
#
# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY
# OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
#
# @author Kamin Whitehouse
#
"""\
RoutingMessages: This is a package of classes that have some functionality
commonly used by routing messages, eg. Rpc and RamSymbol.
This class is not intended to be used on its own.
"""
import sys, string, time, types
import pytos.util.nescDecls as nescDecls
import pytos.Comm as Comm
import pytos.tools.Drip as Drip
import pytos.tools.Drain as Drain
from copy import deepcopy
class RoutingMessage( nescDecls.TosMsg ) :
def __init__(self, parent, amType, *structArgs) :
#store the parent
self.parent = parent
#initialize the default call parameters to none (ie, use the parent's defaults)
for (callParam,default) in self.parent.defaultCallParams :
self.__dict__[callParam] = None
nescDecls.TosMsg.__init__(self, parent.app.enums.AM_RPCCOMMANDMSG, *structArgs)
def _assignParam(self, field, param, paramId) :
"""assign a call parameter to the correct field (checking types)"""
if type(field) == nescDecls.nescType and (
type(param) == int or type(param) == long or
type(param) == float or type(param) == str or
type(param) == unicode ) :
field.value = param
elif type(field) == type(param) :
field = param
else :
raise Exception("Illegal parameter type for param #%s. Requires type %s." % (
str(paramId), str(type(field))) )
def _send(self, address, *posArgs, **nameArgs) :
commArgs = ()
#posArgs and nameArgs now contain only field values.
#now assign them to the appropriate RoutingMessage fields.
#create a temporary RoutingMessage to hold the call-time parameters
thisCall = deepcopy(self)
for i in range(len(posArgs)) :
thisCall._assignParam(thisCall.value[thisCall.fields[i+1]["name"]], posArgs[i], i)
for key in nameArgs.keys() :
if not thisCall.value.has_key(key) :
raise Exception("parameter name %s non-existent" % key)
thisCall._assignParam(thisCall.value[key], nameArgs[key], key)
thisCall.parent.sendComm.send(address, thisCall, *commArgs)
def parseCallParams(self, nameArgs) :
callParams = self.getCallParams()
#parse any call-time call parameters
for param in nameArgs.keys() :
if callParams.has_key(param) :
callParams[param] = nameArgs[param]
del nameArgs[param]
return callParams
def getCallParams(self) :
"""Use the default call parameters from the parent module, but if I have the same
field with a non-None value, use it instead"""
callParams = self.parent.getCallParams()
for param in callParams.keys() :
if self.__dict__.has_key(param) and self.__getattribute__(param) != None :
callParams[param] = self.__getattribute__(param)
return callParams
def __repr__(self) :
"""full function name"""
return "%s object at %s:\n\n%s" % (self.__class__, hex(id(self)), str(self))
def register(self, listener, comm=()) :
self.parent.receiveComm.register(self, listener, *comm)
def unregister(self, listener, comm=()) :
self.parent.receiveComm.unregister(self, listener, *comm)
class Shortcut (object):
"""used to allow multiple levels of indirection w/routing messages using dots;
ie., to allow something.module.interface.RoutingMessage()"""
def __init__(self, parent, name):
self.parent = parent
self.name = name
def __getattr__(self, name) :
name = self.name + "." + name
if self.parent._messages.has_key(name) :
return self.parent._messages.get(name)
else :
for message in self.parent._messages.values() :
if message.nescType.find(name+".") == 0 :
return Shortcut(self.parent,name)
raise Exception("Cannot find %s. Check spelling." % name)
def __repr__(self):
return "%s object at %s:\n\n%s" % (self.__class__, hex(id(self)), str(self))
def __str__(self):
string = ""
funcs = ()
messageNames = self.parent._messages.keys()
messageNames.sort()
for message in messageNames :
if message.find(self.name) == 0 :
string += str(self.parent._messages[message])
string = string.replace(self.name + "." , "" )
return string
class RoutingMessages(object) :
def __init__(self, app, sendComm=None, receiveComm=None, sendChannel=None, tosbase=True) :
self.app = app
self.sendComm = sendComm
if sendComm == None :
raise Exception("You must pass something in sendComm")
elif type(sendComm) == str :
if sendChannel == None:
self.sendComm = Comm.Comm(app)
self.sendComm.connect(sendComm)
else :
self.sendComm = Drip.Drip(app, sendChannel, sendComm)
self.address=app.enums.TOS_BCAST_ADDR
self.receiveComm = receiveComm
if receiveComm == None :
receiveComm = sendComm
self.receiveComm = receiveComm
if type(receiveComm) == str :
self.returnAddress = 0xfffe
self.receiveComm = Drain.Drain(app, self.returnAddress, receiveComm)
self.receiveComm.usingTosBase=tosbase
self.receiveComm.delay=60 #rebuild the tree every 5 mins
self.receiveComm.forever=True
self.receiveComm.VERBOSE=False
self.receiveComm.maintainTree()
self._messages = {}
def initializeCallParams(self, callParams) :
for (callParam,defaultVal) in self.defaultCallParams :
if callParams.has_key(callParam) :
self.__dict__[callParam] = callParams[callParam]
elif not self.__dict__.has_key(callParam):
self.__dict__[callParam] = defaultVal
def getCallParams(self) :
callParams = {}
for (callParam,default) in self.defaultCallParams :
callParams[callParam] = self.__dict__[callParam]
return callParams
def __getattr__(self, name) :
for function in self._messages.values() :
if function.nescType.find(name + ".") == 0 :
return Shortcut(self,name)
raise AttributeError("No such attribute %s" % name)
def __repr__(self) :
return "%s object at %s:\n\n%s" % (self.__class__, hex(id(self)), str(self))
def __str__(self) :
""" Print all available RoutingMessages."""
string = ""
keys = self._messages.keys()
keys.sort()
for name in keys :
string += str( self._messages[name])
return string
--- NEW FILE: SupplementQuery.py ---
#!/usr/bin/python -i
#
# "Copyright (c) 2000-2003 The Regents of the University of California.
# 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 following
# two paragraphs and the author appear in all copies of this software.
#
# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY
# OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
#
# @author August Joki
#
# *This script pulls the tos_image.xml file of the currently running
# program off of the mote attached to the computer.
# *(Only if the program has been loaded into the flash)
# *Parses the xml file to get the supplement.tar.bz2 file
# *Extracts the supplement files to the directory provided
# *Sets up the pytos environment based on the files in the supplement
#
# TODO: work through tosbase(?)
#
# Usage:
# SupQuery.py [dir] [motecom]
#
# Where "dir" is the directory where the supplement files will be downloaded to.
# Creates directory if it doesn't exist.
# Uses the current directory if nothing is supplied.
#
# Where "motecom" is the standard comm port definition, eg "sf at localhost:9001"
# Uses MOTECOM if nothing is supplied
#
# Deluge parsing taken from read_deluge_supplement
# Thanks Gil
import sys, os, re
from xml.dom.minidom import parse
from binascii import unhexlify
# Check command line args
supDir = None
comm = os.getenv("MOTECOM")
if len(sys.argv) > 2:
supDir = sys.argv[1]
comm = sys.argv[2]
elif len(sys.argv) >1:
if sys.argv[1].find("@") != -1:
if sys.argv[1].find(":") != -1:
comm = sys.argv[1]
else:
supDir = sys.argv[1]
# Parse deluge ping response
print "Determining Running Application...."
deluge = os.popen("MOTECOM="+comm+" java net.tinyos.tools.Deluge -p",'r')
pinging = re.compile("^Pinging node ...")
connected = re.compile("^Connected to Deluge node.")
progname = re.compile("Prog Name:\\s+(.*)")
compon = re.compile("Compiled On:\\s+(.*)")
userhash = re.compile("User Hash:\\s+(.*)")
stored = re.compile("Stored Image (\\d)")
platform = re.compile("Platform:\\s+(.*)")
userid = re.compile("User ID:\\s+(.*)")
hostname = re.compile("Hostname:\\s+(.*)")
numpages = re.compile("Num Pages:\\s+(.*)")
currentProgram = {}
storedPrograms = []
deluged = -1
line = deluge.readline().rstrip()
if pinging.search(line) != None:
print line
line = deluge.readline().rstrip()
if connected.search(line) != None:
print line
dashes = deluge.readline().rstrip() #---...
print dashes
print deluge.readline().rstrip() #Curr...
st = deluge.readline().rstrip() #Prog...
print st
currentProgram["progName"] = progname.search(st).group(1)
st = deluge.readline().rstrip() #Comp...
print st
currentProgram["compOn"] = compon.search(st).group(1)
st = deluge.readline().rstrip() #User...
print st
currentProgram["userHash"] = userhash.search(st).group(1)
print dashes
# Collect image infos
eof = False
while(not eof):
st = deluge.readline().rstrip()
if stored.search(st) != None:
num = int(stored.search(st).group(1))
prog = {}
prog["progName"] = progname.search(deluge.readline().rstrip()).group(1)
prog["compOn"] = compon.search(deluge.readline().rstrip()).group(1)
prog["platform"] = platform.search(deluge.readline().rstrip()).group(1)
prog["userId"] = userid.search(deluge.readline().rstrip()).group(1)
prog["hostname"] = hostname.search(deluge.readline().rstrip()).group(1)
prog["userHash"] = userhash.search(deluge.readline().rstrip()).group(1)
prog["numPages"] = numpages.search(deluge.readline().rstrip()).group(1)
storedPrograms.insert(num, prog)
if (currentProgram["progName"] == prog["progName"] and
currentProgram["compOn"] == prog["compOn"] and
currentProgram["userHash"] == prog["userHash"]):
deluged = num
else:
eof = True
# Running program not in flash so no supplement available
if deluged == -1:
index = 0
print "Currently running program has not been Deluged.\nNo supplement to download."
print dashes
print " Stored Programs:"
for prog in storedPrograms:
if prog["progName"] != "N/A":
name = prog["progName"]
comp = prog["compOn"]
uhash = prog["userHash"]
print " "+str(index)
print " Prog Name: "+name
print " Compiled On: "+comp
print " User Hash: "+uhash
index += 1
sys.exit()
deluge.close()
# Time to download tos_image.xml off mote
if not os.access(supDir,os.F_OK):
os.makedirs(supDir)
os.chdir(supDir)
st = ''
if supDir != None:
st = supDir+"/tos_image.xml"
print "Downloading image to "+st+"."
print "This could take a while...."
os.popen("MOTECOM="+comm+" java net.tinyos.tools.Deluge -d -in="+str(deluged)+" -o=tos_image.xml",'r')
print "Done downloading image."
# Extract supplement
print "Extracting supplement."
dom = parse("tos_image.xml")
supxml = dom.getElementsByTagName("supplement")[0]
format = supxml.getAttribute("format")
sup = supxml.firstChild.data
dom.unlink()
# Parse supplement archive
print "Parsing supplement.tar.bz2."
whitespace = re.compile("\\s+")
sup = whitespace.sub('',sup)
if format == "hex":
#if supDir != None:
# os.chdir(supDir)
supfile = open("sup.hx",'w')
supfile.write(str(sup))
supfile.close()
supfile = open('sup.pl','w')
supfile.write('open(HX, "sup.hx"); my $hex = <HX>; my $bin = pack("h*", $hex); open(SUP, ">supplement.tar.bz2"); print SUP $bin;')
supfile.close()
t = os.system('perl sup.pl')
print t
# Unpack supplement file
print "Untaring suplement.tar.bz2"
os.system("tar xjf supplement.tar.bz2")
os.remove("sup.hx")
os.remove("sup.pl")
os.remove("tos_image.xml")
# Set up pytos environment like normal
print "Now setting up pytos environment...."
import pytos.tools.Rpc as Rpc
import pytos.tools.RamSymbols as RamSymbols
import pytos.util.NescApp as NescApp
app = NescApp.NescApp(supDir, comm, tosbase=False)
--- NEW FILE: Timer.py ---
#$Id: Timer.py,v 1.1 2005/09/23 10:20:33 kaminw Exp $
# "Copyright (c) 2000-2003 The Regents of the University of California.
# 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 following
# two paragraphs and the author appear in all copies of this software.
#
# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY
# OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
# @author Shawn Schaffert <sms at eecs.berkeley.edu>
import threading
class Timer( object ) :
def __init__( self , callback=None , period=0 , numFiring=0 , waitTime=0 ) :
self.period = period #must be >= 0
self.waitTime = waitTime #must be >=0
self.numFiring = numFiring # 0 = forever, 1 = one-shot , 2+ = finite repeats
self.callback = callback
def __fireNext( self ) :
if self.numFiring == 0 :
self.timer = threading.Timer( self.period , self.__callback ).start()
elif self.remainingFirings == 0 :
self.timer = None
else :
self.timer = threading.Timer( self.period , self.__callback ).start()
self.remainingFirings -= 1
def __callback( self ) :
if self.stopTimer :
self.timer = None
else :
self.__fireNext()
if self.callback:
self.callback()
def __waitOver( self ) :
self.__fireNext()
def start( self ) :
self.timer = None
self.remainingFirings = self.numFiring
self.stopTimer = False
if self.waitTime > 0 :
self.timer = threading.Timer( self.waitTime , self.__waitOver ).start()
else :
self.__fireNext()
def cancel( self ) :
self.stopTimer = True
--- NEW FILE: __init__.py ---
# "Copyright (c) 2000-2003 The Regents of the University of California.
# 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 following
# two paragraphs and the author appear in all copies of this software.
#
# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY
# OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
#
# @author Kamin Whitehouse
#
--- NEW FILE: nescDecls.py ---
# "Copyright (c) 2000-2003 The Regents of the University of California.
# 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 following
# two paragraphs and the author appear in all copies of this software.
#
# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
# OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY
# OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
# ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
#
# @author Kamin Whitehouse
#
import sys, string, math, re, os
from struct import *
from xml.dom import minidom
from jpype import jimport
from copy import deepcopy
###########
# This class can be used to hold a basic nesc type, eg uint8_t It can
# be set and get through nescType.value, and does type checking
#
###########
def findBuildFile(givenString, desiredFilename) :
"""This function will find a desiredFilename (eg. nescDecls.xml) the build directory
from a givenString (e.g 'build/pc'). Legal givenStrings are:
1. Full path, eg: /home/kamin/tinyos-1.x/...
2. relative path, eg: apps/TestRpc/build/pc
3. platform name, eg: pc or telosb
"""
#check to see if the given string contains the desiredFilename
if givenString.find(desiredFilename) >= 0 :
filename = givenString
#then check to see if it is an absolute or relative path
elif givenString.find('/') >= 0 :
filename = givenString + desiredFilename
#then check to see if it is just the platform name
elif len(givenString) > 0:
filename = 'build/' + givenString + '/' + desiredFilename
#check if a default platform environment variable is defined
elif os.environ.has_key("TINYOS_DEFAULT_PLATFORM") :
filename = 'build/' + os.environ["TINYOS_DEFAULT_PLATFORM"] + '/' + desiredFilename
#otherwise, assume the file is in './'
else :
filename = desiredFilename
#check to see if the file was successfully found
if not os.path.isfile(filename) :
raise IOError("File %s not found" % filename)
return filename
class nescType( object ) :
"""A python representation of a nesc type.
usage:
X = nescType.value
nescType.value = X
bytes = nescType.getBytes()
nescType.setBytes(bytes)
nescType
print nescType
"""
def __init__( self , nescType, cType, pythonType, xmlTag,
conversionString, size, defaultValue) :
"""create a new nescType"""
self.nescType = nescType
self.cType = cType
self.pythonType = pythonType
self._xmlTag = xmlTag
self.size = size
self._conversionString = conversionString
self.value = defaultValue
def __repr__(self) :
return "%s object at %s:\n\n%20s : %s" % (self.__class__, hex(id(self)), "value", str(self))
def __str__(self) :
if self._conversionString == "c" :
return "'" + str(self.value) + "'"
else :
return str(self.value)
# this func could be used for type checking
def __setattr__(self, name, value) :
if self.__dict__.has_key("value") and name == "value":
#use the type conversions built into pack
pack(self._conversionString, value)
self.__dict__[name] = value
def oneLineStr(self) :
return str(self)
def __deepcopy__(self, memo={}) :
result = nescType(self.nescType, self.cType, self.pythonType,
self._xmlTag, self._conversionString, self.size,
deepcopy(self.value, memo))
memo[id(self)] = result
return result
def isType(self, xmlDefinition) :
"""returns 1 if the xml definition describes this type.
Returns 0 otherwise."""
if xmlDefinition != None and xmlDefinition.tagName == self._xmlTag and \
xmlDefinition.hasAttribute("cname") and \
xmlDefinition.getAttribute("cname") == self.cType :
return 1
elif self.nescType == "void" and xmlDefinition.tagName == self._xmlTag :
#void is a special xml case that doesn't have cname defined (grr)
return 1
else :
return 0
def getBytes(self) :
"""Hexidecimal representation of a value of this type"""
if self.nescType == "void" :
return ''
try:
bytes = pack(self._conversionString, self.value)
except Exception, inst:
print inst
raise Exception("Bytes conversion error: %s %d bytes to %d" %
(self.nescType, len(bytes), self.size) )
if len(bytes) != self.size:
raise Exception("Wrong number of bytes for conversion: %s %d bytes to %d" %
(self.nescType, len(bytes), self.size))
return bytes
def setBytes(self, bytes):
"""A value of this type from a hexidecimal representation"""
if self.nescType == "void" :
return bytes
if len(bytes) < self.size:
raise Exception("Wrong number of bytes for conversion: %s %d bytes to %d" %
(self.nescType, len(bytes), self.size))
try:
self.value, = unpack( self._conversionString, bytes[:self.size])
except Exception, inst:
print inst
raise Exception("Bytes conversion error: %s %d bytes to %d" %
( self.nescType, len(bytes), self.size) )
return bytes[self.size:]
###########
# Array of basic nesc types,
###########
class nescArray( object ) :
"""A python representation of a nesc array.
usage:
array = nescArray(size, nescType)
array = nescArray(myTypes, xmlDecl)
X = array[3]
X = array[3:6] (returns a list or, if char[] array, a python string)
array[3] = X
array[3:6] [X,Y,Z] (or, if char[], \"foo\")
bytes = array.getBytes()
array.setBytes(bytes)
array
print array
"""
def __init__( self , *varargs) :
"""initialize all elements to 0"""
if len(varargs) == 0 :
return
elif len(varargs) == 2 and type(varargs[0]) == int :
(self.len,self.elementType) = varargs[:]
bracketStr = "[" + str(self.len) + "]"
elif len(varargs) == 2 :
(nescTypes, xmlDefinition) = varargs[:]
if xmlDefinition.tagName != "type-array" :
raise Exception("Not array definition")
child = getUniqueChild(xmlDefinition)
self.elementType = nescTypes.getTypeFromXML(child)
sizeStr = xmlDefinition.getAttribute("elements")[2:]
self.len = int(sizeStr)
bracketStr = "[" + sizeStr + "]"
else :
raise Exception("Illegal array params")
self.nescType = self.elementType.nescType + bracketStr
self.cType = self.elementType.cType + bracketStr
self.pythonType = self.elementType.pythonType + bracketStr
self.size = self.len * self.elementType.size
self.value = []
for i in range(self.len):
self.value.append(deepcopy(self.elementType))
def __repr__(self) :
"""A printable representation of the value"""
return "%s object at %s:\n\n\t%s" % (self.__class__, hex(id(self)), str(self))
def __str__(self) :
"""A printable representation of the value"""
string = "nescArray of type %s:\n" % self.nescType
# if self.elementType._conversionString == "c":
# string += self.oneLineStr()
# else:
for i in range(self.len) :
string += "%2d: %s\n" % (i, self.value[i].oneLineStr())
return string
def __getitem__(self, key) :
if self.elementType.__class__ == nescType :
if key.__class__ == slice:
if self.elementType._conversionString == "c":
string = ""
for item in self.value.__getitem__(key) :
string += item.value
return string
else:
return [item.value for item in self.value.__getitem__(key)]
else:
return self.value.__getitem__(key).value
else:
return self.value.__getitem__(key)
def __setitem__(self, key, value) :
if self.elementType.__class__ == nescType :
if key.__class__ == slice:
i=0;
for item in self.value.__getitem__(key) :
item.value = value[i]
i += 1
else:
self.value.__getitem__(key).value = value
else :
self.value.__setitem__(key, value)
def __delitem__(self, key) :
return self.value.__delitem__(key)
def oneLineStr(self) :
"""A one-line representation of the value"""
#maybe the string should just print like a string
#but the \x00 chars look like nothing
# if self.elementType._conversionString == "c":
# string = '\''
# for c in self.value :
# string += c.value
# string += '\''
# else:
tmpStr = str(self.elementType)
if tmpStr.find("\n") >= 0 or len(tmpStr) > 5 :
return self.nescType
else :
i = 0; string = "["
while len(string) < 40 and i < self.len :
string += str(self.value[i]) + ", "
i += 1
if i < self.len :
string += "...]"
else:
string += "\b\b]"
return string
def __deepcopy__(self, memo={}) :
result = nescArray()
memo[id(self)] = result
result.elementType = deepcopy(self.elementType, memo)
result.nescType = self.nescType
result.cType = self.cType
result.pythonType = self.pythonType
result.len = self.len
result.size = self.size
result.value = deepcopy(self.value, memo)
return result
def isType(self, xmlDefinition) :
"""returns 1 if the xml definition describes this type.
Returns 0 otherwise."""
if ( xmlDefinition != None and xmlDefinition.tagName == "type-array" and
int(xmlDefinition.getAttribute("elements")[2:]) == self.len ) :
child = getUniqueChild(xmlDefinition)
return self.elementType.isType(child)
else :
return 0
def getBytes(self) :
"""Hexidecimal representation of a value of this type"""
bytes = ""
for i in range(self.len):
bytes += self.value[i].getBytes()
if len(bytes) != self.size:
raise Exception("Byte conversion error: %s %d bytes to %d" %
( self.nescType, len(bytes), self.size))
return bytes
def setBytes(self, bytes) :
"""A value of this type from a hexidecimal representation"""
if len(bytes) < self.size:
raise Exception("Byte conversion error: %s %d bytes to %d" %
(self.nescType, len(bytes), self.size) )
for i in range(self.len) :
bytes = self.value[i].setBytes(bytes)
return bytes
###########
# Pointer to basic nesc types,
###########
class nescPointer( object ) :
"""A python representation of a nesc pointer.
usage:
pointer = nescPointer(ptrSize, nescType)
pointer = nescPointer(myTypes, xmlDecl)
nescType = pointer.value
pointer.value = nescType
bytes = pointer.getBytes()
pointer.setBytes(bytes)
pointer
print pointer
"""
def __init__( self , *varargs) :
"""initialize all elements to 0"""
if len(varargs) == 0:
return
elif len(varargs) == 2 and varargs[1].__dict__.has_key("tagName"):
(nescTypes, xmlDefinition) = varargs[:]
if xmlDefinition.tagName != "type-pointer" :
raise Exception("Not pointer definition")
child = getUniqueChild(xmlDefinition)
self.value = nescTypes.getTypeFromXML(child)
self.size = int(xmlDefinition.getAttribute("size")[2:])
elif len(varargs) == 2 :
self.size = varargs[0].types["unsigned int"].size
self.value = varargs[1]
else :
raise Exception("Illegal nescPointer constructor arguments")
self.nescType = self.value.nescType + "*"
self.cType = self.value.cType + "*"
self.pythonType = self.value.pythonType + "*"
def __repr__(self) :
return "%s object at %s:\n\n\t%s" % (self.__class__, hex(id(self)), str(self))
def __str__(self) :
"""A text representation of the value"""
return "ptr-> %s" % str(self.value)
def oneLineStr(self) :
"""A one-line representation of the value"""
return "ptr-> %s" % self.value.oneLineStr()
def __deepcopy__(self, memo={}) :
result = nescPointer()
memo[id(self)] = result
result.value = deepcopy(self.value, memo)
result.size = self.size
result.nescType = self.nescType
result.cType = self.cType
result.pythonType = self.pythonType
return result
def isType(self, xmlDefinition) :
"""returns 1 if the xml definition describes this type.
Returns 0 otherwise."""
if xmlDefinition != None and xmlDefinition.tagName == "type-pointer" :
child = getUniqueChild(xmlDefinition)
return self.value.isType(child)
else :
return 0
def getBytes(self) :
bytes = pack (str(self.size)+"s",'\x00')
if len(bytes) != self.size:
raise Exception("Byte conversion error: %s %d bytes to %d" %
(self.nescType, len(bytes), self.size) )
return bytes
def setBytes(self, bytes) :
if len(bytes) < self.size:
raise Exception("Byte conversion error: %s %d bytes to %d" %
( self.nescType, len(bytes), self.size) )
return bytes[self.size:]
###########
# Struct of basic nesc types,
###########
class nescStruct( object ) :
"""A python representation of a nesc structure.
usage:
struct = nescStruct(myTypes, xmlDecl)
struct = nescStruct(structName, (fieldName, type) (fieldName, type), ...)
X = struct.field
struct.field = X
bytes = struct.getBytes()
struct.setBytes(bytes)
struct
print struct
"""
def __init__( self, *varargs) :
"""initialize all fields to 0"""
self.__dict__["value"] = {}
self.fields = []
self.size = 0
if len(varargs) == 0 :
self.nescType = ""
#create the struct from nescType args
elif len(varargs) >= 1 and ( type(varargs[0]) == str or
type(varargs[0]) == unicode ) :
self.nescType = varargs[0]
self._parseNescTypeFields(varargs[1:])
## parse the struct def from xml
elif len(varargs) == 2 and type(varargs[1]) != tuple :
(nescTypes, xmlDefinition) = varargs[:]
if xmlDefinition.tagName != "struct" :
raise Exception("Not struct definition")
if xmlDefinition.hasAttribute("name") == False:
raise Exception("Anonymous struct")
self.nescType = xmlDefinition.getAttribute("name")
self.size = int(xmlDefinition.getAttribute("size")[2:])
self._parseXMLFields(nescTypes, xmlDefinition)
else :
raise Exception("Illegal nescStruct constructor args")
self.cType = self.nescType
self.pythonType = self.nescType
self.__initialized = True
def __getattr__(self, name) :
if self.__dict__.has_key("value") :
if self.value.has_key(name) :
if self.value[name].__class__ == nescType :
return self.value[name].value
else :
return self.value[name]
else :
raise AttributeError("No such field \"%s\" in the nescStruct \"%s\"" % (name, self.nescType))
def __setattr__(self, name, value) :
if not self.__dict__.has_key("_nescStruct__initialized") :
self.__dict__[name] = value
return
if self.value.has_key(name) :
if self.value[name].__class__ == nescType :
self.value[name].value = value;
else :
self.value[name] = value;
elif self.__dict__.has_key(name) :
self.__dict__[name] = value
else :
raise AttributeError("No such field \"%s\" in the nescStruct \"%s\"" % (name, self.nescType))
def __repr__(self) :
return "%s object at %s:\n\n\t%s" % (self.__class__, hex(id(self)), str(self))
def __str__(self) :
"""All fields and values as a readable string"""
string = self.nescType + ": \n"
for field in self.fields :
string += "%30s : %s\n" % (
"%s %s" % (self.value[field["name"]].nescType, field["name"]),
self.value[field["name"]].oneLineStr() )
return string
def oneLineStr(self) :
"""A one-line representation of the struct"""
return self.nescType
def __deepcopy__(self, memo={}) :
result = self.__class__()
memo[id(self)] = result
self._copyFields(result, memo)
return result
def _copyFields(self, other, memo=None) :
other.size = self.size
other.nescType = self.nescType
other.cType = self.cType
other.pythonType = self.pythonType
if memo == None :
other.value = deepcopy(self.value)
other.fields = deepcopy(self.fields)
else :
other.value = deepcopy(self.value, memo)
other.fields = deepcopy(self.fields, memo)
other.__initialized = True
def _parseXMLFields(self, nescTypes, xmlDefinition) :
"""Create a list of fields & values given a struct xml declaration."""
fields = [node for node in xmlDefinition.getElementsByTagName("field")]
fields.sort( lambda A, B : A - B,
lambda field: int(field.getAttribute("bit-offset")[2:]) )
for fieldDef in fields:
field = {}
field["name"] = fieldDef.getAttribute("name")
field["bitOffset"] = int(fieldDef.getAttribute("bit-offset")[2:])
if fieldDef.hasAttribute("bit-size"):
field["bitSize"] = int(fieldDef.getAttribute("bit-size")[2:])
elif fieldDef.hasAttribute("size"):
field["bitSize"] = int(fieldDef.getAttribute("size")[2:])*8
self.fields.append(field)
self.value[fieldDef.getAttribute("name")] = nescTypes.getTypeFromXML(fieldDef)
#here's a weird bug in the nesc.xml generation where the "size" attribute
#for packed structs is actually the size of the unpacked struct.
if xmlDefinition.hasAttribute("packed") :
self.size = self.packedSize()
else:
self.size = int(xmlDefinition.getAttribute("size")[2:])
def _parseNescTypeFields(self, fields) :
"""Create a list of fields & values given a tuple of
fieldname,value sequences."""
self.size = 0
for fieldDef in fields:
field = {}
(field["name"],fType) = fieldDef
field["bitOffset"] = self.size*8
field["bitSize"] = fType.size*8
self.fields.append(field)
self.value[field["name"]] = fType
self.size += fType.size
def isType(self, xmlDefinition) :
"""returns 1 if the xml definition describes this type.
Returns 0 otherwise."""
if xmlDefinition == None :
return 0
child = getUniqueChild(xmlDefinition)
if ( ( xmlDefinition.tagName == "struct" and
xmlDefinition.getAttribute("name") == self.nescType) or
( xmlDefinition.tagName == "type-tag" and child != None and
child.tagName == "struct-ref" and
child.getAttribute("name") == self.nescType ) ) :
return 1
else :
return 0
def getBytes(self) :
"""Hexidecimal representation of struct"""
# We have to be careful in here about:
# 1. bit fields (ie. bitSize shorter than nominal type size)
# 2. packing (ie. bits that are not part of any particular field)
bits = ""
for field in self.fields :
for i in range(len(bits), field["bitOffset"]) :
bits += "0"
newBits = hex2bin(self.value[field["name"]].getBytes())
bits += newBits[-field["bitSize"]:]
#the following loop is just type checking for bit fields. Can we do this on setattr?
for i in range(len(newBits)-field["bitSize"]):
if newBits[i] == "1":
print "Bit-field type error: value of %s.%s being truncated" % (self.nescType,
field["name"])
for i in range(len(bits), self.size*8) :
bits += "0"
bytes = bin2hex(bits)
if len(bytes) != self.size:
raise Exception("Byte conversion error: %s %d bytes to %d" %
( self.nescType, len(bytes), self.size))
return bytes
def setBytes(self, bytes) :
"""Set all values using hexidecimal representation"""
# We have to be careful in here about:
# 1. bit fields (ie. bitSize shorter than nominal type size)
# 2. packing (ie. bits that are not part of any particular field)
if len(bytes) < self.size:
raise Exception("Byte conversion error: %s %d bytes to %d" %
(self.nescType, len(bytes), self.size) )
bits = hex2bin(bytes)
for field in self.fields :
newBits = ""
for i in range(self.value[field["name"]].size*8) :
newBits += "0"
selectedBits=bits[field["bitOffset"]:field["bitOffset"]+field["bitSize"]]
newBits = newBits[:-field["bitSize"]] + selectedBits
newBytes = ""
for i in range(self.value[field["name"]].size) :
newBytes += '\x00'
tmpBytes = bin2hex(newBits)
newBytes = newBytes[:-len(tmpBytes)] + tmpBytes
self.value[field["name"]].setBytes(newBytes);
return bytes[self.size:]
def packedSize(self) :
if len(self.fields) == 0 :
trueSize = 0
else :
a,b,lastField = self._findLastNestedField()
trueSize = (lastField["bitOffset"] + lastField["bitSize"]) /8
return trueSize
def _findLastNestedField(self) :
lastField = self
parents = []
#find the last (possibly nested) field
while issubclass(type(lastField), nescStruct) and len(lastField.fields) > 0 :
parent = lastField
lastFieldDef = parent.fields[-1]
lastField = parent.value[lastFieldDef["name"]]
parents.append( parent )
return (lastField, parents, lastFieldDef)
class TosMsg ( nescStruct ) :
"""A python representation of a TosMsg.
Is a nescStruct object.
Can be used with
pytos.comm.send, pytos.comm.register, pytos.comm.unregister.
usage:
msg = TosMsg(amType)
msg = TosMsg(amType, nescStruct)
msg = TosMsg(amType, <nescStruct constructor args>)
print msg
msg.field = X
comm.send(msg)
comm.register(msg, f)
comm.unregister(msg, f)
migMsg = msg.createMigMsg()
msg.parseMigMsg(migMsg)
"""
def __init__(self, amType, *varargs):
self.amType = amType
self.parentMsg = None
#if this is a nescStruct argument, make myself a clone of it
if len(varargs) == 1 and issubclass(type(varargs[0]), nescStruct) :
nescStruct._copyFields(varargs[0],self)
#otherwise, make myself into a struct with the struct args
elif len(varargs) >= 1:
nescStruct.__init__(self, *varargs)
def __deepcopy__(self, memo={}) :
result = self.__class__(self.amType)
memo[id(self)] = result
self._copyFields(result, memo)
result.parentMsg = deepcopy(self.parentMsg, memo)
return result
def getParentMsg(self, amOrName) :
"""This function will get the parent message with the amType or name specified"""
if self.parentMsg == None :
return None
elif self.parentMsg.nescType == amOrName or self.parentMsg.amType == amOrName :
return self.parentMsg
else :
return self.parentMsg.getParentMsg(amOrName)
def createMigMsg(self) :
"""Returns a java BaseTOSMsg with same amType and length
and with data payload of same bytes"""
Message = jimport.net.tinyos.message.BaseTOSMsg
msg = Message(self.size)
msg.dataSet(unpack( str(self.size) + 'b', self.getBytes() ) )
msg.amTypeSet(self.amType)
# msg.set_type( self.amType )
# msg.set_length(self.size)
return msg
def parseMigMsg(self, msg) :
"""Takes a java BaseTOSMsg and creates TosMsg
with same amType and length and with data payload of same bytes"""
self.amType = msg.amType()
data = list(msg.dataGet())
self.setBytes(pack(str(len(data)) + 'b', *data))
def __repr__(self) :
return "%s object at %s:\n\n\t%s" % (self.__class__, hex(id(self)), str(self))
def __str__(self) :
"""All fields and values as a readable string"""
return "TosMsg(am=%d) " % self.amType + nescStruct.__str__(self)
def setBytes(self, bytes) :
"""Extend this msg to be longer, if necessary to accomodate extra data.
This only happens if the last field is a nescArray of length 0.
Unlike nescStructs, TosMsg objects are not nested recursively, so it is
Ok to do this."""
if len(bytes) > self.size : #trueSize() :
#print "there are more bytes than fit in this msg... trying to grow msg"
lastField, parents,b = self._findLastNestedField()
#see if it is an array of size 0
if type(lastField) == nescArray and lastField.len == 0 :
#make it bigger
#print "last field is nescArray[0]... growing"
lastFieldSize = lastField.elementType.size
numExtraBytes = len(bytes) - self.size #trueSize()
if numExtraBytes % lastFieldSize == 0:
requiredArraySize = int( numExtraBytes/lastFieldSize )
lastField = nescArray(requiredArraySize, lastField.elementType)
#print "new size is %d" % numExtraBytes
#and set it, changing the size of all parent structs
parents.reverse()
for parent in parents :
# trueSize = parent.trueSize()
parent.value[parent.fields[-1]["name"]] = lastField
parent.fields[-1]["bitSize"] = lastField.size*8
parent.size = self.packedSize()# + lastField.size
lastField = parent
else:
#print "last field is not nescArray[0]. Cannot grow. Ignoring extra data."
pass
#make sure everything worked out correctly and call parent's function
if len(bytes) != self.size :#trueSize() :
raise Exception("Incorrect number of bytes for TosMsg. Byte conversion error: %s %d bytes to %d" % ( self.nescType, len(bytes), self.size) )
#print "passing to child to set bytes."
nescStruct.setBytes(self,bytes)
def getUniqueChild(xmlDefinition) :
child = None
for childNode in xmlDefinition.childNodes :
if childNode.nodeType == 1 :
child = childNode
break
return child
def bin2hex(bits) :
bytes = ""
for i in range(0, len(bits), 8 ):
bytes += pack('B',int(bits[i:i+8],2))
return bytes
def hex2bin(bytes) :
bits = ""
for i in range(len(bytes)) :
val, = unpack('B',bytes[i])
for j in range(7,-1,-1):
if val>= pow(2,j):
bits += "1"
val -= pow(2,j)
else :
bits += "0"
return bits
def TestAppTypes() :
testRpc = appTypes('/home/kamin/tinyos-1.x/contrib/hood/apps/TestRpc/build/telosb/nesc.xml')
print testRpc
if __name__ == "__main__": TestAppTypes()
More information about the Tinyos-commits
mailing list