]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - support/sdk/python/tinyos/tossim/TossimApp.py
Merge devel code into the trunk.
[tinyos-2.x.git] / support / sdk / python / tinyos / tossim / TossimApp.py
diff --git a/support/sdk/python/tinyos/tossim/TossimApp.py b/support/sdk/python/tinyos/tossim/TossimApp.py
new file mode 100644 (file)
index 0000000..1b191a1
--- /dev/null
@@ -0,0 +1,517 @@
+# "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) 2005 Stanford University. All rights reserved.
+#
+# Permission to use, copy, modify, and distribute this software and
+# its documentation for any purpose, without fee, and without written
+# agreement is hereby granted, provided that the above copyright
+# notice, the following two paragraphs and the author appear in all
+# copies of this software.
+#
+# IN NO EVENT SHALL STANFORD UNIVERSITY 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 STANFORD UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# STANFORD UNIVERSITY 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 STANFORD UNIVERSITY
+# HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+# ENHANCEMENTS, OR MODIFICATIONS."
+#
+# @author Kamin Whitehouse 
+# @author Philip Levis
+
+from tinyos.tossim.TossimNescDecls import *
+
+class NescVariables(object) :
+  def __init__( self, applicationName="Unknown App", xmlFilename=None ) :
+    self.applicationName = applicationName
+    self._varNames = []
+    self._vars = []
+
+    dom = minidom.parse(xmlFilename)
+    variableList = [node for node in dom.getElementsByTagName("variables")]
+    while len(variableList) > 0:
+      variables = variableList.pop(0).getElementsByTagName("variable")
+      while len(variables) > 0:
+        cVariable = 0
+        isArray = 0
+
+        variable = variables.pop(0)
+        name = variable.getAttribute("name")
+        component = variable.getElementsByTagName("component-ref")
+
+        if (len(component) > 0):
+          name = component[0].getAttribute("qname") + "." + name
+        else:  # It's in a C file
+          cVariable = 1
+          fileName = variable.getAttribute("loc")
+          index = fileName.rfind("/") # First check for a UNIX path
+          if (index == -1):
+            index = fileName.rfind("\\") # Then a windows path
+            if (index == -1):
+              index = fileName.rfind(":") # Then if it's in the local dir
+
+          if (index != -1):
+            fileName = fileName[index+1:]
+            index = fileName.rfind(".")
+            if (index != -1):
+              fileName = fileName[0:index]
+              name = fileName + "." + name
+
+        varType = "unknown"
+        varTypes = variable.getElementsByTagName("type-float")
+        if (len(varTypes) == 0):
+          varTypes = variable.getElementsByTagName("type-int")
+
+        if (len(variable.getElementsByTagName("type-array")) > 0):
+          isArray = 1
+          
+        if (len(varTypes) > 0):
+          varTypeEntry = varTypes[0]
+          varType = varTypeEntry.getAttribute("cname")
+
+        if (cVariable == 0):
+          self._varNames.append(str(name))
+          self._vars.append(str(name))
+          if (isArray):
+            self._vars.append("array")
+          else:
+            self._vars.append("simple")
+          self._vars.append(str(varType))
+             
+  def __str__(self) :
+    """ Print all available variables."""
+    string = "\n"
+    name = 1
+    for val in self._varNames :
+      if (name):
+        string += "\t" + val
+        name = 0
+      else:
+        string += ": " + val + "\n"
+        name = 1
+        
+    return string
+     
+  def variables(self):
+    return self._vars
+  
+
+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, applicationName="Unknown App", xmlFilename = None) :
+    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+?)\"')
+    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, applicationName="Unknown App", xmlFilename = None ) :
+    self.applicationName = applicationName
+    self._enums = []
+    if type(xmlFilename) == str:
+      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 NescApp( object ) :
+  """A class that holds all types, enums, msgs, rpc commands and ram
+  symbol definitions as defined for a specific nesc application.
+
+  usage:
+  myApp = nescApp('/path/to/nescDecls.xml')
+  print myApp
+  var = myApp.enums.enumName
+  var = myApp.types.typeName
+  """
+  def __init__( self, applicationName="Unknown App", xmlFile="app.xml" ) :
+    """This function creates the NescEnums, NescTypes, and NescMsgs
+    objects for a particular application."""
+    
+    #first, import all enums, types, msgs, rpc functions, and ram symbols
+    self.applicationName = applicationName
+    self.xmlFile = xmlFile
+    
+    # Check for the nescDecls.xml file
+    if not os.path.isfile(xmlFile):
+      raise Exception("""\nERROR: cannot find file \"%s\".
+
+Your nesC app cannot be imported.  Be sure that you compiled with the \"nescDecls\" option.\n\n""" % xmlFile)
+
+    # Import enums, types, and msgs
+    self.enums = NescEnums(applicationName, xmlFile)
+    self.types = NescTypes(applicationName, xmlFile)
+    self.variables = NescVariables(applicationName, xmlFile)
+    self.messages = NescMsgs(self.types, self.enums, applicationName)
+
+  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.messages._msgNames))
+    string += "%20s : %d\n" % ("Variables", len(self.variables._varNames))
+    return string
+
+  def configureTossim(self):
+    for var in variables:
+      Mote.var