[Tinyos-commits] CVS: tinyos-1.x/tools/python/apps Oscope.py, NONE, 1.1 OscopeAlternate.py, NONE, 1.1 PytosShell.py, NONE, 1.1

Kamin Whitehouse kaminw at users.sourceforge.net
Fri Sep 23 03:20:35 PDT 2005


Update of /cvsroot/tinyos/tinyos-1.x/tools/python/apps
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5850/apps

Added Files:
	Oscope.py OscopeAlternate.py PytosShell.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: Oscope.py ---
#!/usr/bin/python
#$Id: Oscope.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>
# @author Kamin Whitehouse 
#
# This is the default Oscope application, which shows how a very simple
# python script should use the pytos tools.  Some other versions of Oscope
# exist, which show special cases (eg. how to use mig msgs instead of python
# msgs, or how to use event-driven programming instead of threaded apps)
#
# To debug this application, run it with the -i option passed to python
# and then close the Tk frame.

import sys, time, os
import pytos.util.nescDecls as nescDecls   #the nescTypes stuff
from pylab import *                        #the matplotlib stuff
from matplotlib.numerix import arange, sin, pi, array
from pytos.Comm import Comm         #the python comm stack
from pytos.Comm import MessageQueue        #the message queue
import Tkinter as Tk                       #the gui stuff
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
import threading
from copy import deepcopy

class Oscope( object ) :
    """Oscope is a class that opens a window and prints out data
    being passed in by a mote running the tinyos-1.x/apps/Oscilloscope
    application.  You must indicate where the build directory is

    Usage:
    Oscope.py [platform directory] [comm port]

    Both parameters can be contained in environment variables. Example usage:
    
      from the shell command line:
        python OscopeThreaded.py ~/tinyos-1.x/apps/Oscope/build/telosb serial at COM1:telos

        or

        cd ~/tinyos-1.x/apps/Oscope
        python OscopeThreaded.py telosb serial at COM1:telos

        or
        
        export MOTECOM = serial at COM1:telos
        export DEFAULT_PLATFORM
        cd ~/tinyos-1.x/apps/Oscope
        python OscopeThreaded.py

      from the python command line:
      (note, it's slow and loses packets as a module... why?)
        from OscopeThreaded import Oscope
        oscope = Oscope('serial at COM1:telos')

        or
        
        from pytos.Comm import Comm
        myComm = Comm()
        myComm.connect('serial at COM1:telos')
        oscope = Oscope(comm=myComm)

        and/or (you can use combinations of comm and tkRoot)

        import Tkinter as Tk
        root = Tk.Tk()
        oscope = Oscope(rkRoot = root)
        root.mainloop()
        """
    
    def __init__( self , buildDir="", motecom=None,  tkRoot=None, comm=None ) :

        #first, import all types, msgs, and enums from the nesc app
        self.app = nescDecls.nescApp(buildDir, "Oscope")
        #use the user's comm and tkroot, if they passed it in
        if tkRoot == None:
            self.tkRoot = Tk.Tk()
        else :
            self.tkRoot = tkRoot
        if comm == None:
            comm = Comm()
            comm.connect( motecom ) #defaults to MOTECOM env variable if undefined
        self.comm = comm

        self.initializeGui()
        #create a queue for receiving oscope messages and register it for messages
        oscopeMsgQueue = MessageQueue(1)
        self.comm.register( deepcopy(self.app.msgs.OscopeMsg) , oscopeMsgQueue )
        #start a thread to process the messages (make daemon so it dies when tk is killed)
        msgThread = threading.Thread(target=self.processMessages,
                                     args=(oscopeMsgQueue,))
        msgThread.setDaemon(True)
        msgThread.start()
        # start the GUI thread if we own it
        if tkRoot == None:
            self.tkRoot.mainloop()
            print "Oscope.py exited normally"
            
    def initializeGui(self) :

        # create the frame where all the widgets will go
        self.frame = Tk.Frame( self.tkRoot )
        self.frame.pack()
        # create the matplotlib figure for displaying the oscope msg payload
        self.fig = figure()
        self.axes = subplot(111)
        self.axes.plot([0],[0],'b')
        #we create a line that holds sensor data so that we can update it later
        self.line, = self.axes.lines
        self.line.set_data([],[])
        #remember the current axis limits
        self.xlim = self.axes.get_xlim()
        self.ylim = self.axes.get_ylim()
        # start/stop button
        self.startButton = Tk.Button( self.frame , text="start" ,
                                      command = self.toggleStart )
        self.startButton.pack( side = Tk.LEFT )
        # reset button
        self.resetButton = Tk.Button( self.frame , text="reset" ,
                                      command = self.reset )
        self.resetButton.pack( side = Tk.LEFT )
        #container object for the figure instance
        self.canvas = FigureCanvasTkAgg( self.fig , master = self.tkRoot )  
        self.canvas.show()
        self.canvas.get_tk_widget().pack( side = Tk.TOP , fill = Tk.BOTH ,
                                          expand = 1 )
        self.toolbar = NavigationToolbar2TkAgg( self.canvas , self.tkRoot )
        self.toolbar.update()
        self.canvas._tkcanvas.pack( side=Tk.TOP , fill=Tk.BOTH , expand=1)

        
    def reset( self ) :
        self.comm.send(self.app.enums.TOS_BCAST_ADDR, self.app.msgs.OscopeResetMsg )
        self.line.set_data([],[])
        self.canvas.draw()
        
    def toggleStart( self ) :
        if self.startButton["text"] == "start" :
            self.startButton["text"] = "stop"
        else :
            self.startButton["text"] = "start"

    def processMessages(self, msgQueue) :
        while True :
            (addr,msg) = msgQueue.get()
            if self.startButton["text"] == "stop" :
                self.receivedOscopeMsg(msg)

    def receivedOscopeMsg( self , msg ) :
        print "Received new data #%d from %d" % (msg.lastSampleNumber,
                                                 msg.sourceMoteID )
        #update the old line with the new data
        newData = list(msg.data)
        xdata = self.line.get_xdata().tolist()
        ydata = self.line.get_ydata().tolist()
        xdata.extend(range(len(xdata), len(xdata)+len(newData)))
        ydata.extend(newData)
        self.line.set_data(xdata, ydata)

        #now, if the user isn't zooming or something, update the axis limits
        if self.xlim == self.axes.get_xlim() and  \
           self.ylim == self.axes.get_ylim() :
            self.axes.set_xlim(min(xdata), max(xdata))
            self.axes.set_ylim(min(ydata), max(ydata)) 
            self.xlim = self.axes.get_xlim()
            self.ylim = self.axes.get_ylim()
           
        self.canvas.draw()

        
if __name__ == "__main__":
    #if the user is running this as a script as opposed to an imported module
    if len(sys.argv) == 3 :
        oscope = Oscope(buildDir = sys.argv[1], motecom = sys.argv[2], )
    elif len(sys.argv) == 2 :
        oscope = Oscope(buildDir = sys.argv[1], )
    else:
        oscope = Oscope()


--- NEW FILE: OscopeAlternate.py ---
#!/usr/bin/python

#$Id: OscopeAlternate.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>
# @author Kamin Whitehouse 
#
# This application is an alternate implementation of the main Oscope application.
# The differences are:
# 1.  this application uses java MIG messages instead of python TosMsg objects
# 2.  This application uses event-driven message processing instead of threads
#

import sys, time, os
from pylab import *                 #the matplotlib stuff
from matplotlib.numerix import arange, sin, pi, array
from pytos.Comm import Comm  #the python comm stack
from jpype import jimport           #java messages
import Tkinter as Tk                #the gui stuff
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg

tinyos = jimport.net.tinyos

class Oscope( object ) :
    """Oscope is a class that opens a window and prints out data
    being passed in by a mote running the tinyos-1.x/apps/Oscilloscope
    application.

    Usage:
      from the shell command line:
        python Oscope.py serial at COM1:telos

        or
        
        export MOTECOM = serial at COM1:telos
        python Oscope.py

      from the python command line:
      (note, it's slow and loses packets as a module... why?)
        from Oscope import Oscope
        oscope = Oscope('serial at COM1:telos')

        or
        
        from pytos.Comm import Comm
        myComm = Comm()
        myComm.connect('serial at COM1:telos')
        oscope = Oscope(comm=myComm)

        and/or (you can use combinations of comm and tkRoot)

        import Tkinter as Tk
        root = Tk.Tk()
        oscope = Oscope(rkRoot = root)
        root.mainloop()
        """
    
    def __init__( self , motecom=None,  tkRoot=None, comm=None ) :

        #use the user's tk root, if they passed it in
        if tkRoot == None:
            self.tkRoot = Tk.Tk()
        else:
            self.tkRoot = tkRoot
            
        #use the user's comm, if they passed it in
        if comm != None:
            self.comm = comm
        #if no comm passed, create one
        else:
            # connect using motecom first, then MOTECOM environment var
            self.comm = Comm()
            if motecom != None :
                self.comm.connect( motecom )
            elif "MOTECOM" in os.environ :
                self.comm.connect( os.environ["MOTECOM"] )
            else:
                sys.stderr.write("No serial port specified\n")
    
        #register a listener for my message
        self.comm.register( tinyos.oscope.OscopeMsg() , self )
        
        # start/stop state
        self.started = False

        # create the frame where all the widgets will go
        self.frame = Tk.Frame( self.tkRoot )
        self.frame.pack()

        # create the matplotlib figure for displaying the oscope msg payload
        #self.fig = Figure()
        #self.axes = self.fig.add_subplot(111)
        self.fig = figure()
        self.axes = subplot(111)
        self.axes.plot([0],[0],'b')

        #we create a line that holds sensor data
        #so that we can update it later
        self.line, = self.axes.lines
        self.line.set_data([],[])

        #remember the current axis limits
        self.xlim = self.axes.get_xlim()
        self.ylim = self.axes.get_ylim()

        # start/stop button
        self.startButton = Tk.Button( self.frame , text="start" ,
                                      command = self.toggleStart )
        self.startButton.pack( side = Tk.LEFT )

        # reset button
        self.resetButton = Tk.Button( self.frame , text="reset" ,
                                      command = self.reset )
        self.resetButton.pack( side = Tk.LEFT )

        #container object for the figure instance
        self.canvas = FigureCanvasTkAgg( self.fig , master = self.tkRoot )  
        self.canvas.show()
        self.canvas.get_tk_widget().pack( side = Tk.TOP , fill = Tk.BOTH ,
                                          expand = 1 )

        self.toolbar = NavigationToolbar2TkAgg( self.canvas , self.tkRoot )
        self.toolbar.update()
        self.canvas._tkcanvas.pack( side=Tk.TOP , fill=Tk.BOTH , expand=1)

        # start the GUI if I created it
        if tkRoot == None:
            self.tkRoot.mainloop()


    def reset( self ) :
        self.comm.send(65535, tinyos.oscope.OscopeResetMsg() )
        self.line.set_data([],[])
        self.canvas.draw()
        
    def toggleStart( self ) :
        self.started = not self.started
        if self.started :
            self.startButton["text"] = "stop"
        else :
            self.startButton["text"] = "start"

    def messageReceived( self , addr , msg ) :

        # Because callbacks via jpype give awful errors, catch
        # and print errors here
        try:
            if self.started :
                if isinstance( msg , tinyos.oscope.OscopeMsg ) :
                    self.receivedOscopeMsg( msg )
                else :
                    sys.stderr.write("message of unknown type received\n")
        except Exception,inst :
            print inst
            sys.exit(1)

    def receivedOscopeMsg( self , msg ) :
        print "Received new data #%d from %d" % (msg.get_lastSampleNumber(),
                                                 msg.get_sourceMoteID() )
        #update the old line with the new data
        newData = list(msg.get_data())
        xdata = self.line.get_xdata().tolist()
        ydata = self.line.get_ydata().tolist()
        xdata.extend(range(len(xdata), len(xdata)+len(newData)))
        ydata.extend(newData)
        self.line.set_data(xdata, ydata)

        #now, if the user isn't zooming or something, update the axis limits
        if self.xlim == self.axes.get_xlim() and  \
           self.ylim == self.axes.get_ylim() :
            self.axes.set_xlim(min(xdata), max(xdata))
            self.axes.set_ylim(min(ydata), max(ydata)) 
            self.xlim = self.axes.get_xlim()
            self.ylim = self.axes.get_ylim()
           
        self.canvas.draw()

        
if __name__ == "__main__":
    #if the user is running this as a script
    if len(sys.argv) == 2 :
        oscope = Oscope(motecom = sys.argv[1])
    else:
        oscope = Oscope()


--- NEW FILE: PytosShell.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 Kamin Whitehouse 
#

# This script loads the basic pytos environment for a specific application.
#
# The script must be run in the application directory or told where it is,
# and must be told which platform to import (first parameter).  It will then import all
# nesc types, enums, and messages defined in the application.
#
# If the user has a node running this application and indicates how to connect to
# that node (second parameter), the script will also load any rpc functions and ram symbols
# in the application and present them to the user.
#
# In lieu of the first and second parameters, the TINYOS_DEFAULT_PLATFORM and MOTECOM
# environment variables can be used.
#
# usage:
# $     Pytos.py [buildDir] [motecom]
#
# Where "buildDir" is
# 1.  only a platform name, eg "pc" or "telosb"
# 2.  a path to the build dir, eg. "../../TestRpc/build/telosb"
#
# And where motecom is the standard comm port definition, eg "sf at localhost:9001"
#
# Once the application is loaded, the "app" variable will be available, from which you
# can access all imported enums, types, messages, rpc functions or ram symbols.
#
# Be sure to set the tosbase variable below if you are using a TosBase

import sys
import pytos.tools.Rpc as Rpc
import pytos.tools.RamSymbols as RamSymbols
import pytos.util.NescApp as NescApp

buildDir = None
if len(sys.argv) > 1:
    buildDir = sys.argv[1]

port = None
if len(sys.argv) > 2:
    port = sys.argv[2]

# import the enums and types in the nesc app that I am working with
app = NescApp.NescApp(buildDir, port, tosbase=True)




More information about the Tinyos-commits mailing list