# ieee802154.py

Go to the documentation of this file.

    00001 #   Copyright (c) 2008 Axel Wachtler
    00002 #   All rights reserved.
    00003 #
    00004 #   Redistribution and use in source and binary forms, with or without
    00005 #   modification, are permitted provided that the following conditions
    00006 #   are met:
    00007 #
    00008 #   * Redistributions of source code must retain the above copyright
    00009 #     notice, this list of conditions and the following disclaimer.
    00010 #   * Redistributions in binary form must reproduce the above copyright
    00011 #     notice, this list of conditions and the following disclaimer in the
    00012 #     documentation and/or other materials provided with the distribution.
    00013 #   * Neither the name of the authors nor the names of its contributors
    00014 #     may be used to endorse or promote products derived from this software
    00015 #     without specific prior written permission.
    00016 #
    00017 #   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    00018 #   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    00019 #   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    00020 #   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    00021 #   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    00022 #   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    00023 #   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    00024 #   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    00025 #   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    00026 #   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    00027 #   POSSIBILITY OF SUCH DAMAGE.
    00028
    00029 # $Id: ieee802154.py,v 1.21 2010/02/22 20:44:32 awachtler Exp $
    00030
    00031 ##
    00032 # @page pgCCUCap Application Description
    00033 #
    00034 # (@ref pgContribCapture "back")
    00035 #
    00036 # @section secCapSyn Synopsis
    00037 #
    00038 #   <tt>python ieee802154.py -p PORT|-r FILE [OPTIONS]</tt>
    00039 #
    00040 # @section secCapOpt Options
    00041 #
    00042 # @par General IO Options
    00043 #
    00044 # - @opt2{-p,portname}\n  Name of the port which is read, e.g. @c /dev/ttyUSB0
    00045 # - @opt2{-r,capfile}\n   Name of the capture file which is read @c mytrace.dat
    00046 # - @opt2{-i,pipename}\n  Name of the pipe
    00047 #
    00048 # @par Options for use with -p
    00049 #
    00050 # - @opt2{-c,channel}\n set IEEE802.15.4 channel number.
    00051 # - @opt2{-R, <r>} \n set IEEE802.15.4 data rate.
    00052 #
    00053 # @par General Options
    00054 #
    00055 # - @opt2{-N,pkgcnt}\n    Stop after @c <pkgcnt> packages are received.
    00056 # - @opt{-v}\n            Set verbose output, multiple @c -v options
    00057 #                         increase the message details.
    00058 #
    00059 # @section secCapCmd Online Commands
    00060 #
    00061 # At the prompt @c "cmd:" the following commands are available:
    00062 #
    00063 #    - @opt{reopen} - reopens the named pipe and places a pcap header,
    00064 #                 so that wireshark can reconnect.
    00065 #    - @opt2{chan,<n>} \n set new channel to sniff.
    00066 #    - @opt2{rate, <r>} \n set new data rate.
    00067 #    - @opt{devrst}   \n reinitialize the sniffer device
    00068 #    - @opt{debug}    \n start python debugger
    00069 #    - @opt{info}     \n show status of sniffer DEVIN
    00070 #    - @opt{quit}     \n end session and terminate all threads
    00071 #    - @opt{help}     \n show command help
    00072 #
    00073 # <hr/>
    00074
    00075 ##
    00076 # @file
    00077 # @ingroup grpContribCapture
    00078 # @brief Capture converter script
    00079 #
    00080 # This script implements a bridge between a file or a serial port
    00081 # to a socket. This socket is the interface for wireshark/libpcap
    00082 # in order to do a live capture.
    00083 #
    00084 # How the script is used is described @ref pgContribCapture "here".
    00085 #
    00086
    00087 # === import ==================================================================
    00088 import sys, os, pdb, atexit
    00089 import traceback, getopt
    00090
    00091 # === import local moduls =====================================================
    00092 from ieee802154_base import ProgramContext
    00093 from ieee802154_io import FileIn, PortIn
    00094 from ieee802154_socket import SocketOut
    00095 from ieee802154_pipe import PipeOut
    00096 from ieee802154_gui import *
    00097
    00098 # === globals =================================================================
    00099 VERSION = "0.1"
    00100 CTX = ProgramContext()
    00101 DEVOUT = PipeOut()
    00102 DEVIN = None
    00103 # === classes =================================================================
    00104
    00105 # === functions ===============================================================
    00106
    00107 ##
    00108 # Terminate all instances of the IO classes
    00109 #
    00110 def do_quit(exclude=[]):
    00111     global CTX,DEVIN,DEVOUT,gui
    00112     print "quit: exclude:",exclude
    00113     if gui != None and 'gui' not in exclude:
    00114         print "quit_gui"
    00115         gui.cancel()
    00116         gui = None
    00117     if DEVIN != None:
    00118         print "quit_DEVIN"
    00119         DEVIN.reset()
    00120         DEVIN.close()
    00121         DEVIN = None
    00122     if DEVOUT != None:
    00123         print "quit_socket"
    00124         DEVOUT.close()
    00125         DEVOUT = None
    00126
    00127 def print_options():
    00128     print """\
    00129 Usage:
    00130   %s [OPTIONS]
    00131   Options:
    00132    -p PORT     Name of the serial port where the sniffer plattform
    00133                is connected, e.g. /dev/ttyUSB0 or COM1.
    00134    -r CAPFILE  Name of a capture file which is read @c mytrace.dat.
    00135    -i PIPE     Name of the named pipe.
    00136                 On a Linux system, PIPE can be a absolut path name, e.g.
    00137                 /tmp/ieee802154. On a Windows system PIPE is a name in a
    00138                 special pipe directory, e.g. foo maps to \\\\.\\pipe\\foo.
    00139                 [ieee802154]
    00140    -c CHAN     IEEE802.15.4 channel number
    00141    -R RATE     IEEE802.15.4 data rate
    00142    -v          increase verbose level
    00143    -h          show help and exit.
    00144    -V          print version and exit.
    00145
    00146   Note:
    00147    * -r and -p can be used only exclusively,
    00148    * -c works only with -p.
    00149 """ % sys.argv[0]
    00150
    00151
    00152 ##
    00153 # print a list of the commands available on the
    00154 # "cmd:" prompt
    00155 def print_help():
    00156     print """\
    00157 Commands:
    00158    reopen   - reopens the named pipe and places a pcap header,
    00159               so that wireshark can reconnect.
    00160    chan <n> - set IEEE 802.15.4 channel.
    00161    rate <r> - set IEEE 802.15.4 data rate (e.g. BPSK20, OQPSK100, ...)
    00162    devrst   - reinitialize the sniffer device
    00163    debug    - start python debugger
    00164    info     - show status of sniffer DEVIN
    00165    verbose  - verbose command
    00166    quit     - end session and terminate all threads
    00167    help     - show command help
    00168 """
    00169
    00170 ##
    00171 # print startup message with some essential information about
    00172 # the current configuration.
    00173 #
    00174 def print_banner():
    00175     global VERSION, DEVIN
    00176     fmtstr = {'file':'%(file)s, frames: %(frames)s',
    00177               'port':'%(port)s, %(platform)s, channel=%(chan)s, rate=%(crate)s',
    00178              }
    00179     print "\nuracoli sniffer to wireshark bridge V%s" % VERSION
    00180     inf = DEVIN.info()
    00181     fmt = fmtstr.get(inf['type'],"UNKNOWN INTERFACE TYPE")
    00182     print ' OPTS:  ', " ".join(sys.argv[1:])
    00183     print ' INPUT: ', fmt % inf
    00184     print ' OUTPUT:', str(DEVOUT.TxPipe),'\n'
    00185 ##
    00186 # Interpretation of command line options.
    00187 # @param argv  list with command line elements.
    00188 #
    00189 def process_command_line_args(argv):
    00190     global CTX
    00191     opts,args = getopt.getopt(argv,"i:hp:r:vVNR::c:x")
    00192     for o,v in opts:
    00193         if o == "-i":
    00194             v = v.strip()
    00195             if os.path.isfile(v) or os.path.islink(v):
    00196                 print "Can't overwrite existing file or link with a pipe"
    00197                 sys.exit(1)
    00198             CTX.SOCKNAME = v
    00199         if o == "-r":
    00200             CTX.CAPFILE = v.strip()
    00201             CTX.PORT = None
    00202         if o == "-p":
    00203             CTX.CAPFILE = None
    00204             CTX.PORT = v.strip()
    00205         if o == "-v":
    00206             CTX.VERBOSE += 1
    00207         if o == "-N":
    00208             CTX.MAXPACKETS = eval(v)
    00209         if o == "-c":
    00210             CTX.CHANNEL = eval(v)
    00211         if o == "-R":
    00212             CTX.RATE = v.strip()
    00213         if o == "-x":
    00214             CTX.GUI = True
    00215         if o == "-h":
    00216             print_options()
    00217             print_help()
    00218             sys.exit(0)
    00219         if o == "-V":
    00220             print "%s V%s" % (sys.argv[0],VERSION)
    00221             sys.exit(0)
    00222
    00223     if not CTX.CAPFILE and not CTX.PORT:
    00224         CTX.PORT = raw_input('Enter Capture Port:')
    00225
    00226 ##
    00227 # process interactive command
    00228 #
    00229 def process_command(cmd):
    00230     ret = 1
    00231     cmd = cmd.strip()
    00232     if len(cmd) == 0:
    00233         pass
    00234     elif cmd == "help":
    00235         print_help()
    00236     elif cmd == "quit":
    00237         do_quit()
    00238         ret = 0
    00239     elif cmd == "info":
    00240         inf = DEVIN.info()
    00241         ks = inf.keys()
    00242         ks.sort()
    00243         fmt = " % 9s : %s"
    00244         print "INPUT:"
    00245         for k in ks:
    00246             print fmt  % (k,inf[k])
    00247         print "OUTPUT:"
    00248         print fmt % ("pipe",DEVOUT.TxPipe)
    00249     elif cmd == "reopen":
    00250         DEVOUT.reopen()
    00251     elif cmd.find("chan")>=0:
    00252         try:
    00253             CTX.CHANNEL = eval(cmd.split(" ")[1])
    00254         except:
    00255             CTX.CHANNEL = eval(raw_input("channel:"))
    00256         DEVIN.set_channel(CTX.CHANNEL)
    00257     elif cmd.find("rate")>=0:
    00258         CTX.RATE = cmd.split(" ")[1].strip()
    00259         DEVIN.set_rate(CTX.RATE)
    00260     elif cmd.find("debug")>=0:
    00261         pdb.set_trace()
    00262     elif cmd.find("N")>=0:
    00263         CTX.MAXPACKETS = eval(cmd.split(" ")[1])
    00264         DEVIN.FCNT=0
    00265     elif cmd.find("devrst")>=0:
    00266         DEVIN.init()
    00267         DEVIN.set_channel(CTX.CHANNEL)
    00268     elif cmd.find("verbose") == 0:
    00269         try:
    00270             lvl = eval(cmd.split(" ")[1].strip())
    00271         except:
    00272             print "command '%s' was ignored" % cmd
    00273         else:
    00274             setverbose(lvl)
    00275             print "verbose level is now %d" % CTX.VERBOSE
    00276     else:
    00277         print "\n  Unknown Command: \"%s\"," %cmd
    00278         print "  type \"help\" to see a list of available commands.\n"
    00279     return ret
    00280
    00281 def setverbose(level):
    00282     CTX.VERBOSE = level
    00283     DEVOUT.setverbose(CTX.VERBOSE)
    00284     DEVIN.setverbose(CTX.VERBOSE)
    00285
    00286 ##
    00287 # exit handler, prompts on all Non-*NIX systems for "ENTER" in
    00288 # order to see the last error message in the terminal.
    00289 def do_exit(*argv,**argd):
    00290     do_quit()
    00291     if os.name != 'posix':
    00292         raw_input("Type Enter to Exit...")
    00293
    00294 # === init ====================================================================
    00295 if __name__ == "__main__":
    00296     try:
    00297         import rlcompleter
    00298         import readline
    00299         readline.parse_and_bind("tab:complete")
    00300     except:
    00301         pass
    00302
    00303     atexit.register(do_exit)
    00304
    00305     ## This class instance stores the global programm context
    00306     process_command_line_args(sys.argv[1:])
    00307
    00308     # create input reader classes
    00309     if CTX.CAPFILE:
    00310         DEVIN = FileIn()
    00311         DEVIN.open(CTX.CAPFILE)
    00312     elif CTX.PORT:
    00313         DEVIN = PortIn()
    00314         DEVIN.open(CTX.PORT)
    00315         if CTX.CHANNEL != None:
    00316             DEVIN.set_channel(CTX.CHANNEL)
    00317         if CTX.RATE != None:
    00318             DEVIN.set_rate(CTX.RATE)
    00319     else:
    00320         raise Exception, 'no port or capture file given'
    00321
    00322     #DEVOUT = PcapSocket(CTX.SOCKNAME, DEVIN)
    00323     DEVOUT.open(CTX.SOCKNAME, DEVIN)
    00324     setverbose(CTX.VERBOSE)
    00325     DEVIN.maxpackets = CTX.MAXPACKETS
    00326
    00327     if CTX.GUI:
    00328         gui = CtrlGui(lambda : do_quit(['gui']))
    00329         gui.start()
    00330         gui.setDEVIN(DEVIN)
    00331     else:
    00332         gui = None
    00333
    00334     run = 1
    00335     print_banner()
    00336     while run:
    00337         try:
    00338             cmd = raw_input("cmd:")
    00339             run = process_command(cmd)
    00340         except:
    00341             traceback.print_exc()
    00342             break