[Tinyos-commits] CVS: tinyos-1.x/tools/python/pytos/tools Drain.py,
NONE, 1.1 Drip.py, NONE, 1.1 RamSymbols.py, NONE, 1.1 Rpc.py,
NONE, 1.1 __init__.py, NONE, 1.1
Kamin Whitehouse
kaminw at users.sourceforge.net
Fri Sep 23 03:20:35 PDT 2005
- Previous message: [Tinyos-commits] CVS: tinyos-1.x/tools/make hood.extra, NONE,
1.1 nescDecls.extra, NONE, 1.1 registry.extra, NONE,
1.1 rpc.extra, NONE, 1.1
- Next message: [Tinyos-commits] CVS: tinyos-1.x/tools/python/pytos Comm.py, NONE,
1.1 __init__.py, NONE, 1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /cvsroot/tinyos/tinyos-1.x/tools/python/pytos/tools
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5850/pytos/tools
Added Files:
Drain.py Drip.py RamSymbols.py Rpc.py __init__.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: Drain.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 jpype import jimport, JProxy, JavaException, JException
from pytos.util.JavaInheritor import JavaInheritor
import pytos.Comm as Comm
import struct, types
import thread
import pytos.util.nescDecls as nescDecls
from copy import deepcopy
drain = jimport.net.tinyos.drain
class Drain( JavaInheritor ) :
"""The Drain object inherits from both the Drain.java and
the DrainConnector.java objects, in that order. It overrides the
constructors to construct both objects from the same comm objects and
provides register/unregister methods to handle python TosMsg objects.
usage:
drain = Drain(app, spAddr, 'sf at localhost:9001')
drain = Drain(app, spAddr, moteif)
drain.register(myTosMsg, myMsgQueue)
drain.unregister(myTosMsg, myMsgQueue)
... (plus all other functions inherited from the java objects)
"""
def __init__( self , app, spAddr, moteIF ) :
if type(moteIF) == str :
moteIF = Comm.openMoteIF(moteIF, app)
drainObj = drain.Drain(spAddr, moteIF)
drainConnectorObj = drain.DrainConnector(spAddr, moteIF)
self.app = app #save for later use
JavaInheritor.__init__(self, (drainObj, drainConnectorObj) )
def register( self , msg , callback, *comm ) :
(num, callback) = self._wrapCallbackAndTosMsg(msg, callback)
self.registerListener( num , callback )
def unregister( self , msg , callback , *comm ) :
(num, callback) = self._wrapCallbackAndTosMsg(msg, callback)
self.deregisterListener( num , callback )
def _wrapCallbackAndTosMsg(self, msg, callback) :
callback = DrainMsgPeeler(self.app, msg, callback)
callback = Comm.createJavaMessageListener(callback)
num = msg.amType
return (num, callback)
class DrainMsgPeeler( Comm.Mig2TosMsgConverter ) :
"""This is a wrapper callback object that peels the Drain headers out
of a DrainMsg mig object and creates a python TosMsg with the remaining data """
def __init__(self, app, msg, callback) :
self.drainMsg = nescDecls.TosMsg(app.enums.AM_DRAINMSG, app.types.DrainMsg)
Comm.Mig2TosMsgConverter.__init__(self, msg, callback )
def messageReceived( self , addr , migMsg ) :
try:
drainMsg = deepcopy(self.drainMsg)
drainMsg.parseMigMsg(migMsg)
msg = deepcopy(self.msg)
bytes = drainMsg.data.getBytes()
msg.setBytes( bytes )
msg.parentMsg = drainMsg
self.callback( addr, msg )
except Exception, inst:
print inst
raise
--- NEW FILE: Drip.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 jpype import jimport, JInt
from pytos.util.JavaInheritor import JavaInheritor
import pytos.Comm as Comm
drip = jimport.net.tinyos.drip
class Drip( JavaInheritor ) :
"""The Drip object inherits from the Drip.java object. It overrides the
constructor, and the send and sendwakeup commands to handle python TosMsg objects.
usage:
drip = Drip(app, Channel, 'sf at localhost:9001')
drip = Drip(app, Channel, moteif)
drip.send(myTosMsg)
drip.sendWakeup(myTosMsg)
... (plus all other functions inherited from the java object)
For interface-compatbility with comm, you can also send a dest address, which is ignored:
drip.send(addr, myTosMsg)
"""
def __init__( self , app, channel, moteIF ) :
if type(moteIF) == str :
moteIF = Comm.openMoteIF(moteIF, app)
dripObj = drip.Drip(channel, moteIF)
JavaInheritor.__init__(self, (dripObj,) )
def send( self , msg, *comm ) :
#For interface-compatbility with comm, you can also send a dest address, which is ignored:
if type(msg) == int and len(comm) > 0:
msg = comm[0]
migMsg = msg.createMigMsg()
self.migMsgSend(migMsg, msg.size)
def sendWakeup( self , msg, *comm ) :
migMsg = msg.createMigMsg()
self.migMsgSendWakeup(migMsg, msg.size)
def migMsgSend( self , msg, size, *comm ) :
self._javaParents[0].send(msg, JInt(size))
def migMsgSendWakeup( self , msg, size, *comm ) :
self._javaParents[0].sendWakeup(msg, size)
--- NEW FILE: RamSymbols.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
#
"""\
RamSymbols.py -- a tool for poking and peeking ram symbols on motes.
To be used in conjunction with tinyos-1.x/contrib/nestfe/nesc/lib/RamSymbols
"""
import sys, string, time, types
from xml.dom import minidom
import pytos.util.nescDecls as nescDecls
import pytos.util.RoutingMessages as RoutingMessages
import pytos.Comm as Comm
from copy import deepcopy
class RamSymbol( RoutingMessages.RoutingMessage ) :
#this is the variable the determines, on a blocking rpc call, how
#many messages will be queued up. Should perhaps be bigger for large
#networks, but will generally be the same number for all rpc
#functions that use the same send and receive comm stacks.
msgQueueSize = 10
def __init__(self, xmlDefinition=None, parent=None) :
if xmlDefinition==None :
return
self.pokeResponseMsg = None
self.memAddress = int(xmlDefinition.getAttribute("address"))
length = int(xmlDefinition.getAttribute("length"))
typeDef = xmlDefinition.getElementsByTagName("type")[0]
self.isPointer = typeDef.getAttribute("typeClass") == "pointer"
self.isArray = xmlDefinition.hasAttribute("array")
symbolType = parent.app.types[typeDef.getAttribute("typeName")]
#if symbolType.size > parent.app.enums.MAX_RAM_SYMBOL_SIZE :
if self.isPointer :
symbolType = nescDecls.nescPointer(parent.app, symbolType)
if self.isArray :
if length % symbolType.size == 0 :
numElements = length // symbolType.size
else :
raise Exception("Could not discern ram symbol array length")
symbolType = nescDecls.nescArray(numElements, symbolType)
structArgs = []
if type(symbolType) == nescDecls.nescStruct :
self.isStruct = True
structArgs.append(symbolType)
else :
structArgs.append(xmlDefinition.getAttribute("name"))
structArgs.append( ("value", symbolType) )
#now initialize this command as a TosMsg object (which is really a nescStruct)
RoutingMessages.RoutingMessage.__init__(self, parent, 0, *structArgs)
if self.isStruct :
self.__dict__["name"] = xmlDefinition.getAttribute("name")
if length != self.size :
raise Exception("Ram symbol size incorrect")
self.pokeResponseMsg = nescDecls.TosMsg(self.memAddress, "PokeResponseMsg",
("value", parent.app.types.result_t))
def poke(self, value=None, arrayIndex = None, dereference=False, **nameArgs) :
if not self.parent.app.__dict__.has_key("RamSymbolsM") :
raise Exception("You must include the contrib/hood/tos/lib/RamSymbols/RamSymbolsM module in your nesc application in order to poke or peek at ram symbols")
func = self.parent.app.RamSymbolsM.poke
if arrayIndex != None :
if self.isArray :
if dereference == True :
if self.isPointer:
ptr = self.value["value"].elementType
newValue = deepcopy(ptr.value)
func.symbol.memAddress = self.memAddress + ptr.size * arrayIndex
func.symbol.length = newValue.size
else :
raise Exception("Dereferencing is only allowed for pointer types")
else :
newValue = deepcopy(self.value["value"].elementType)
func.symbol.memAddress = self.memAddress + newValue.size * arrayIndex
func.symbol.length = newValue.size
else :
raise Exception("Indexing a poke is only supported for arrays")
elif dereference == True :
if self.isPointer and self.isArray :
raise Exception("Poke cannot be used to dereference an entire array of pointers")
elif not self.isPointer :
raise Exception("Dereferencing is only allowed for pointer types")
newValue = deepcopy(self.value["value"].value)
func.symbol.memAddress = self.memAddress
func.symbol.length = newValue.size
else :
if self.isArray and self.size > self.parent.app.ramSymbol_t.data.size :
raise Exception("Array is too large for poking. You must index the poke")
if self.isStruct :
newValue = deepcopy(self)
elif self.isPointer :
newValue = self.parent.app.types["unsigned int"]
else :
newValue = deepcopy(self.value["value"])
func.symbol.memAddress = self.memAddress
func.symbol.length = newValue.size
if func.symbol.length > self.parent.app.types.ramSymbol_t.data.size :
raise Exception("Ram symbol size too large for msg buffer")
if value != None :
self._assignParam(newValue, value, "value")
newBytes = newValue.getBytes()
oldBytes = func.symbol.data.getBytes()
newBytes = oldBytes.replace(oldBytes[:func.symbol.length], newBytes, 1)
func.symbol.data.setBytes(newBytes)
func.symbol.dereference = dereference
result = func(**nameArgs)
return map(self.parsePokeResponse, result)
def parsePokeResponse(self, msg) :
response = deepcopy(self.pokeResponseMsg)
if msg.nescType == "RpcResponseMsg":
response.value=0
addr = msg.sourceAddress
else :
if msg.value["value"].value != self.memAddress and (not self.isArray or
(msg.value["value"].value -self.memAddress) % self.value["value"].elementType.size !=0) :
raise Exception("Memory address mismatch in poke response")
response.value = 1
addr = msg.parentMsg.sourceAddress
response.parentMsg = msg
response.nescType = "".join( [response.nescType, ", nodeID=%d"%addr] )
return response
def peek(self, arrayIndex = None, dereference=False, **nameArgs) :
if not self.parent.app.__dict__.has_key("RamSymbolsM") :
raise Exception("You must include the contrib/hood/tos/lib/RamSymbols/RamSymbolsM module in your nesc application in order to poke or peek at ram symbols")
func = self.parent.app.RamSymbolsM.peek
if arrayIndex != None :
#change memaddress to memAddres + array index
if self.isArray :
if dereference :
if self.isPointer :
func.memAddress = self.memAddress + self.value["value"].elementType.size * arrayIndex
#set length of memcpy to ptr dereferenced value
func.length = self.value["value"].elementType.value.size
else :
raise Exception("Dereferencing a peek is only allowed for pointers")
else :
func.memAddress = self.memAddress + self.value["value"].elementType.size * arrayIndex
func.length = self.value["value"].elementType.size
else :
raise Exception("Indexing a peek is only allowed for arrays")
elif dereference :
#if this is an array or ptrs, fail
if self.isArray :
raise Exception("peek cannot be used to dereference an array of pointers")
func.memAddress = self.memAddress
func.length = self.value["value"].size
else :
#if this is an array check if the whole thing will fit in the return msg
if self.isArray and self.size > self.parent.app.types.ramSymbol_t.data.size :
raise Exception("Array is too large for peeking. You must index the peek")
func.memAddress = self.memAddress
func.length = self.size
if func.length > self.parent.app.types.ramSymbol_t.data.size :
raise Exception("Ram symbol size too large for msg buffer")
func.dereference = dereference
result = func(**nameArgs)
return map(self.parsePeekResponse, result)
def parsePeekResponse(self, msg) :
#create the response message depending on if was rpc error or not
if msg.nescType == "RpcResponseMsg":
response = nescDecls.TosMsg(self.memAddress, "PeekErrorMsg",
("value", self.parent.app.types.result_t))
response.value=0
addr = msg.sourceAddress
else:
#choose the type depending on if the ramSymbol is the entire symbol or element of array
if msg.length == self.size and msg.memAddress == self.memAddress :
if self.isStruct :
value = deepcopy(self)
else :
value = deepcopy(self.value["value"])
elif (self.isArray and msg.length == self.value["value"].elementType.size and
(msg.memAddress -self.memAddress) % self.value["value"].elementType.size ==0):
value = deepcopy(self.value["value"].elementType)
elif (self.isArray and self.isPointer
and msg.length == self.value["value"].elementType.value.size and
(msg.memAddress -self.memAddress) % self.value["value"].elementType.value.size ==0):
value = deepcopy(self.value["value"].elementType.value)
elif (self.isPointer
and msg.length == self.value["value"].value.size and
(msg.memAddress -self.memAddress) % self.value["value"].value.size ==0):
value = deepcopy(self.value["value"].value)
else :
raise Exception("Memory address mismatch in peek response")
#choose the type depending on whether calling func was peek or ptrPeek
if self.isPointer :
if msg.dereference :
value = value.value
else :
value = self.parent.app.types["unsigned int"]
#create the return message from type depending if it is a struct already or must be created
if issubclass(type(value), nescDecls.nescStruct) :
response = nescDecls.TosMsg(self.memAddress, value)
else :
response = nescDecls.TosMsg(self.memAddress, value.nescType,
("value", value))
bytes = msg.data.getBytes()
response.setBytes(bytes[:response.size])
addr = msg.parentMsg.sourceAddress
response.parentMsg = msg
response.nescType = "".join( [response.nescType, ", nodeID=%d"%addr])
return response
def __str__(self) :
if self.isStruct :
return "%20s : %s\n" % (self.nescType,self.name)
else:
return "%20s : %s\n" % (self.value["value"].nescType,self.nescType)
def __deepcopy__(self, memo={}) :
result = self.__class__()
memo[id(self)] = result
result.parent = self.parent
for (callParam, defaultVal) in self.parent.defaultCallParams :
result.__dict__[callParam] = deepcopy(self.__dict__[callParam], memo)
nescDecls.TosMsg.__init__(result, self.amType, self)
return result
class RamSymbols( RoutingMessages.RoutingMessages) :
"""A container class from which to find all ram symbols.
"""
def __init__(self, app, buildDir, sendComm=None, receiveComm=None, tosbase=True, **callParams) :
""" Find function defs in rpcSchema.xml file and create function objects."""
if not "ramSymbol_t" in app.types._types :
print "The contrib/hood/tos/lib/RamSymbols/RamSymbolsM module was not included. No ram symbols will be imported."
RoutingMessages.RoutingMessages.__init__(self, app, sendComm, receiveComm,
app.enums.AM_RPCCOMMANDMSG, tosbase)
self.defaultCallParams = ( ("address", None), ("returnAddress", None),
("timeout", 1), ("blocking", True), ("responseDesired", True) )
self.initializeCallParams(callParams)
self.tooLarge = []
self.sizeIncorrect = []
self.noType = []
self.arraySizeIncorrect = []
nescDeclsXml = nescDecls.findBuildFile(buildDir, "nescDecls.xml")
schema = minidom.parse(nescDeclsXml)
symbols, = schema.childNodes[0].getElementsByTagName("ramSymbols")
symbols = [node for node in symbols.childNodes if node.nodeType == 1]
for symbolDef in symbols:
try :
self._messages[symbolDef.getAttribute("name")] = RamSymbol(symbolDef, self)
except Exception, e:
if len(e.args) > 0 and e.args[0].find("No type") == 0:
self.noType.append(symbolDef)
elif len(e.args) > 0 and e.args[0].find("Could not discern") == 0:
self.arraySizeIncorrect.append(symbolDef)
elif len(e.args) > 0 and e.args[0].find("Ram symbol size too large") == 0:
self.tooLarge.append(symbolDef)
elif len(e.args) > 0 and e.args[0].find("Ram symbol size incorrect") == 0:
self.sizeIncorrect.append(symbolDef)
else :
raise
#self.printSkippedSymbols()
def printSkippedSymbols(self) :
err = ""
if len(self.tooLarge) >0 :
err += "\nWarning: %d ram symbols were too large for %d byte packet.\n" % (len(self.tooLarge), self.app.types.ramSymbol_t.data.size )
for symbol in self.tooLarge :
err += "\t%s\n" % symbol.getAttribute("name")
if len(self.sizeIncorrect) >0 :
err += "\nWarning: The size of the following ram symbols does not match the size of the discovered type:\n"
for symbol in self.sizeIncorrect :
err += "\t%s\n" % symbol.getAttribute("name")
if len(self.noType) >0 :
err += "\nWarning: No type was found for the following ram symbols:\n"
for symbol in self.noType :
err += "\t%s\n" % symbol.getAttribute("name")
if len(self.arraySizeIncorrect) >0 :
err += "\nWarning: The following ram symbols are arrays with length not a multiple of the type size:\n"
for symbol in self.arraySizeIncorrect :
err += "\t%s\n" % symbol.getAttribute("name")
if len(err) > 0 : print err
--- NEW FILE: Rpc.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
#
"""\
Rpc.py -- a tool for calling rpc functions on motes.
To be used in conjunction with tinyos-1.x/contrib/hood/tos/lib/Rpc.
rpc = Rpc(\"./apps/TestRpc/build/pc/foo.xml\")
rpc.redOn()
rpc.redOff()
rpc.myfunc(101,'abc')
or
f=rpc.myfunc
f.firstParam = 101
f.secondParam = 'abc'
f()
"""
import sys, string, time, types
from xml.dom import minidom
import pytos.util.nescDecls as nescDecls
import pytos.util.RoutingMessages as RoutingMessages
import pytos.Comm as Comm
from copy import deepcopy
class RpcFunction( RoutingMessages.RoutingMessage ) :
"""a callable TosMsg used to interact with the rpc.nc module. On
being called, either with positional or named arguments, this
object will fill in the params given, pack up a message and send
it off using comm.send. Named arguments can have the names of the
param names. Any params not specified will have default values as
specified by the initialization semantics of nescDecls.nescStruct
(zero). Optional named parameter \"comm\" can be used to pass
arguments to the comm.send function.
usage:
rpcFunction.param = X
rpcFunction()
rpcFunction(X, Y, Z)
rpcFunction(p1=X, p2=Y, p3=Z)
rpcFunction(X, p3=Z, p2=Y)
rpcFunction(X, p3=Z, p2=Y, comm=['COM1','COM2',...])
"""
#this is the variable the determines, on a blocking rpc call, how
#many messages will be queued up. Should perhaps be bigger for large
#networks, but will generally be the same number for all rpc
#functions that use the same send and receive comm stacks.
msgQueueSize = 10
def __init__(self, xmlDefinition=None, parent=None) :
if xmlDefinition==None :
return
self.responseMsg = None
#start creating the arguments to the nescStruct constructor.
#first, add the command msg name and the rpc headers
structArgs = []
structArgs.append(xmlDefinition.tagName)
structArgs.append( ("rpcHeader", parent.app.types.RpcCommandMsg) )
#then, add each parameter as a new msg field
for i in range(int(xmlDefinition.getAttribute("numParams"))) :
param = xmlDefinition.getElementsByTagName("param%d" % i)
paramName = param[0].getAttribute("name")
paramType = parent.app.types[
param[0].getElementsByTagName("type")[0].getAttribute("typeName")]
structArgs.append( (paramName, paramType) )
#now initialize this command as a TosMsg object (which is really a nescStruct)
RoutingMessages.RoutingMessage.__init__(self, parent,
parent.app.enums.AM_RPCCOMMANDMSG, *structArgs)
#fill in the header fields once and for all
self.rpcHeader.commandID = int(xmlDefinition.getAttribute("commandID"))
self.rpcHeader.dataLength = self.size - self.rpcHeader.size
#turn the response type into a response msg (to be received by the user)
responseType = parent.app.types[
xmlDefinition.getElementsByTagName("returnType")[0].getAttribute("typeName")]
if issubclass(type(responseType), nescDecls.nescStruct) :
self.responseMsg = nescDecls.TosMsg(self.rpcHeader.commandID, responseType)
else :
self.responseMsg = nescDecls.TosMsg(self.rpcHeader.commandID, responseType.nescType,
("value", responseType))
def __call__(self, *posArgs, **nameArgs) :
if not self.parent.app.__dict__.has_key("RpcM") :
raise Exception("You must include the contrib/hood/tos/lib/Rpc/RpcM module in your nesc application in order to use rpc commands")
commArgs = ()
callParams = self.parseCallParams(nameArgs)
self.rpcHeader.transactionID+=1
thisCall = deepcopy(self)
thisCall.rpcHeader.address = callParams["address"]
thisCall.rpcHeader.returnAddress = callParams["returnAddress"]
thisCall.rpcHeader.responseDesired = callParams["responseDesired"]
#If this is a blocking call, get ready to process response msgs for timeout time
if callParams["blocking"] \
and callParams["timeout"] > 0 \
and callParams["responseDesired"]==True:
responseQueue = Comm.MessageQueue(self.msgQueueSize)
self.register(responseQueue)
processMsgs = True
thisCall._send(callParams["address"], *posArgs, **nameArgs)
if processMsgs :
startTime = time.time()
responses = []
while time.time() - startTime <= callParams["timeout"] :
try:
(addr,msg) = responseQueue.get(True, 0.1) #why 0.1?
if msg.nescType == "RpcResponseMsg" :
rxdTransactionID = msg.transactionID
else :
rxdTransactionID = msg.parentMsg.transactionID
if rxdTransactionID == thisCall.rpcHeader.transactionID :
responses.append(msg)
print '.',
except Exception, e:
if len(e.args) >0 :
print "rpc error: %s" % str(e)
print ' '
self.unregister(responseQueue)
return responses
def __str__(self) :
"""print function signature"""
string = "%21s %s( " % (self.responseMsg.nescType, self.nescType)
for field in self.fields[1:] :
string += " %s %s," % ( self.value[field["name"]].nescType,
field["name"] )
if len(self.fields) >0 :
string += "\b"
string += " )\n"
return string
def __deepcopy__(self, memo={}) :
result = self.__class__()
memo[id(self)] = result
# result.rpcHeader = deepcopy(self.rpcHeader, memo)
result.responseMsg = deepcopy(self.responseMsg, memo)
result.parent = self.parent
for (callParam, defaultVal) in self.parent.defaultCallParams :
result.__dict__[callParam] = deepcopy(self.__dict__[callParam], memo)
nescDecls.TosMsg.__init__(result, self.amType, self)
return result
def printCurrentValues(self) :
print nescDecls.TosMsg.__str__(self)
def register(self, listener, comm=()) :
self.parent.receiveComm.register(self.parent.app.msgs.RpcResponseMsg,
RpcResponseListener(self.parent.app, self.responseMsg, listener), *comm)
def unregister(self, listener, comm=()) :
self.parent.receiveComm.unregister(self.parent.app.msgs.RpcResponseMsg,
RpcResponseListener(self.parent.app, self.responseMsg, listener), *comm)
class RpcResponseListener( Comm.MessageListener ):
def __init__(self, app, responseMsg, callback ):
self.app = app
self.responseMsg = responseMsg
Comm.MessageListener.__init__(self, callback)
def messageReceived( self , addr , msg ) :
if msg.commandID == self.responseMsg.amType :
if msg.errorCode == self.app.enums.RPC_SUCCESS :
response = deepcopy(self.responseMsg)
response.setBytes( msg.data.getBytes() )
response.parentMsg = msg
response.nescType = "".join( [response.nescType,
", nodeID=%d"%response.parentMsg.sourceAddress] )
self.callback( addr, response )
else :
self.callback( addr, msg)
class Rpc( RoutingMessages.RoutingMessages) :
"""A container class from which to call all rpc functions.
usage:
rpc = Rpc(sendComm, receiveComm, '/path/to/rpcSchema.xml')
print rpc
rpc.module.interface.function(args)
rpc.module.function(args)
"""
def __init__(self, app, buildDir, sendComm=None, receiveComm=None, tosbase=True, **callParams) :
""" Find function defs in rpcSchema.xml file and create function objects."""
RoutingMessages.RoutingMessages.__init__(self, app, sendComm, receiveComm,
app.enums.AM_RPCCOMMANDMSG, tosbase)
self.defaultCallParams = ( ("address", None), ("returnAddress", None),
("timeout", 1), ("blocking", True), ("responseDesired", True) )
self.initializeCallParams(callParams)
rpcSchema = nescDecls.findBuildFile(buildDir, "rpcSchema.xml")
schema = minidom.parse(rpcSchema)
functions, = schema.childNodes[0].getElementsByTagName("rpcFunctions")
functions = [node for node in functions.childNodes if node.nodeType == 1]
for funcDef in functions:
self._messages[funcDef.tagName] = RpcFunction(funcDef, self)
--- 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
#
- Previous message: [Tinyos-commits] CVS: tinyos-1.x/tools/make hood.extra, NONE,
1.1 nescDecls.extra, NONE, 1.1 registry.extra, NONE,
1.1 rpc.extra, NONE, 1.1
- Next message: [Tinyos-commits] CVS: tinyos-1.x/tools/python/pytos Comm.py, NONE,
1.1 __init__.py, NONE, 1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the Tinyos-commits
mailing list