[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

gEDA-cvs: CVS update: pcbmanager.py



  User: pcjc2   
  Date: 06/10/05 18:19:45

  Modified:    .        pcbmanager.py
  Log:
  Rework of pcbmanager.py to interface with a D-Bus enabled PCB instance. 
  
  Removed old stdout parser. Updated configure.ac to reflect dependancies 
  
  on some dbus python modules. 
  
  
  
  
  Revision  Changes    Path
  1.2       +74 -259   eda/geda/xgsch2pcb/lib/xgsch2pcb/pcbmanager.py
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: pcbmanager.py
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/xgsch2pcb/lib/xgsch2pcb/pcbmanager.py,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -b -r1.1 -r1.2
  --- pcbmanager.py	19 Sep 2006 09:42:42 -0000	1.1
  +++ pcbmanager.py	5 Oct 2006 22:19:45 -0000	1.2
  @@ -20,7 +20,8 @@
   # TODO: Is this needed? What version of python do we depend on?
   from __future__ import generators
   
  -import commands, shutil, re, gobject, os, sys
  +import commands, shutil, re, gobject, os, sys, time
  +import dbus, dbus.glib, dbus.service
   
   # i18n
   import gettext
  @@ -33,8 +34,7 @@
   from funcs import *
   
   # Define PCB action return codes
  -PCB_RC_OK      = 001
  -PCB_RC_ERROR   = 002
  +PCB_RC_OK      = 0
   
   class PCBManager( gobject.GObject ):
   
  @@ -53,7 +53,11 @@
           self.project_dir = self.project.filename.rsplit('.', 1)[0]
           self.output_name = self.project.output_name
   
  -        self.pipes = None
  +        self.pcb = None
  +        self.pcb_obj = None
  +        self.pcb_iface = None
  +        self.pcb_actions_iface = None
  +        
           self.cofunc = None
           
           self.toolpath = find_tool_path( 'pcb' )
  @@ -69,83 +73,72 @@
                       _("\nCouldn't find 'gsch2pcb' executable")
               raise Exception, exception_txt
   
  +        # Setup the D-Bus connection
  +        # TODO: Graceful error handling
  +        self.session_bus = dbus.SessionBus()
  +        self.dbus_obj = self.session_bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
  +        self.dbus_iface = dbus.Interface(self.dbus_obj, 'org.freedesktop.DBus')
   
  +        self.empty_char_array = dbus.Array( '', signature="s" )
   
  -    def __del__(self):
          
  +    def __del__(self):       
           if self.pcb_stdin:
               self.pcb_stdin.close()
   
           if self.pcb_stdout:
               self.pcb_stdout.close()
   
  -        # TODO: Close pipe, kill PCB and call parent class del
  -        if not self.pipes == None:
  -            self.pipes == None
  -
  -        # TODO: Do we need to call our parent's destructor?
  -        #gobject.GObject.__del__(self)
  -
       def close_layout(self):
  -
           # TODO: Fixme
  -        self.pcb_write( "Quit()\n" )
  -        
  -        # TODO: Block until the pipe dies, or timeout?
  -        pass
  +        self.pcb_actions_iface.ExecAction( "Quit", self.empty_char_array )
   
       def open_layout(self):
  -        
           if self.is_layout_open():
               # TODO: Is there some clever way to bring PCB to front?
               # Possibly send it an action which does a window-manager request?
               return
  -        
  -        pcbargs = (self.toolpath, '--listen', self.output_name + ".pcb" )
  -        self.pipes = Popen(pcbargs, stdin=PIPE, stdout=PIPE)
  -        self.pcb_stdout = self.pipes.stdout
  -        self.pcb_stdin = self.pipes.stdin
  -        
  -        # TODO: Wait until PCB confirms layout loaded
  -        
  -        ## Call fnctl to set non-blocking IO on the input stream
  -        #child_in = pcbpipe.stdout.fileno()
  -        #flags = fcntl.fcntl(child_in, fcntl.F_GETFL)
  -        #fcntl.fcntl(child_in, fcntl.F_SETFL, flags | os.O_NONBLOCK)
  -        
  -        # Setup callback for data ready on PCB's stdout pipe
  -        self.parser = pcb_output_parser( self.pcb_stdout )
  -        self.parser.connect("return-code", self.parser_return_code_cb)
  -        self.parser.connect("pipe-died", self.parser_pipe_died_cb)
  -
  +        Popen([self.toolpath, self.output_name + ".pcb"])
  +        while not self.is_layout_open():
  +            time.sleep( 0.1 )
           assert self.is_layout_open()
   
  +
       def is_layout_open(self):
          
  -        if self.pipes == None or self.pipes.poll() != None:
  +        try:
  +            pcb_instances = self.dbus_iface.ListQueuedOwners('org.seul.geda.pcb')
  +        except:
  +            print "is_layout_open(): DEBUG: Couldn't find any PCB instances"
               return False
   
  -        # TODO: Check to see if the layout is actually open, not just pipe alive?
  -        return True
  +        found_our_file = False
   
  -    def update_layout(self, schematics):
  +        for pcb in pcb_instances:
  +            print 'is_layout_open(): DEBUG: Found PCB instance at unique name ' + pcb
   
  -        # First check the layout is open
  -        if not self.is_layout_open():
  -            self.open_layout()
  +            pcb_obj = self.session_bus.get_object(pcb, '/org/seul/geda/pcb')
  +            pcb_iface = dbus.Interface(pcb_obj, 'org.seul.geda.pcb')
  +            filename = pcb_iface.GetFilename()
  +            print 'is_layout_open(): DEBUG: Filename is ' + filename
   
  -        if self.cofunc == None:
  -            self.cofunc = self.cofunction_update( schematics )
  -        else:
  -            print _("Already in the middle of an update")
  -            # TODO: Some further exception?
  -            return
  +            if filename == os.path.abspath( self.output_name ) + ".pcb":
  +                found_our_file = True
  +                continue
           
  -        try:
  -            self.cofunc.next()
  +        if not found_our_file: 
  +            return False
                   
  -        except StopIteration:
  -            self.cofunc = None
  +        pcb_actions_iface = dbus.Interface(pcb_obj, 'org.seul.geda.pcb.actions')
  +
  +        # TODO: FIXME: Seems unclean to update these here
  +        self.pcb = pcb
  +        self.pcb_obj = pcb_obj
  +        self.pcb_iface = pcb_iface
  +        self.pcb_actions_iface = pcb_actions_iface
  +
  +        # TODO: Check to see if the layout is actually open, not just pipe alive?
  +        return True
       
           
       def needs_updating(self, schematics):
  @@ -170,34 +163,8 @@
   
           return (layout_mtime < schematic_mtime)
   
  -    def pcb_write( self, string ):
  -        self.pcb_stdin.write( string )
  -        print ">pcb<: ", string,
  -
  -    def cofunction_update( self, schematics ):
  -
  -        # NOTE TO HACKERS:
  -        #
  -        # This function (rightly or wrongly) is implemeted as a python generator.
  -        # It uses the generator function "yield", to return out of this function
  -        # whilst allowing re-entry at that point after a suitable signal is handled.
  -        #
  -        # After every yield statement, we should check the status-codes from the
  -        # parser class. This is done by calling self.parser.consume_retcode().
  -        #
  -        # For convenience, call "error_occurred()", which returns True if an error
  -        # condition was met.
  -
  -        def error_occurred( ):
  -            retcode = self.parser.consume_retcode()
  -            error = False
  -            if retcode == None:
  -                error = True
  -                print _("error_occurred: no retcode from pcb parser")
  -            elif retcode == PCB_RC_ERROR:
  -                error = True
  -                print _("error_occurred: Error response, retcode=%s") % retcode
  -            return error
  +
  +    def update_layout( self, schematics ):
   
           def error_restore_backup():
               # Deliberatly leave (self.output_name + ".savedbackup.pcb") incase it is useful
  @@ -237,18 +204,11 @@
                   pass
   
   
  -        print _("********START UPDATING********")
  -        
  -        # Send 'hello' to PCB
  -        self.pcb_write("Hello()\n")
  -        
  -        # Wait to re-enter with a response
  -        yield None
  +        # First check the layout is open
  +        if not self.is_layout_open():
  +            self.open_layout()
   
  -        if error_occurred():
  -            # PCB is not responding happily to its "Hello" action
  -            # TODO: ERROR MESSAGE TO THE USER
  -            return
  +        print _("********START UPDATING********")
               
           # TODO: TELL PCB TO IGNORE USER ACTIONS
   
  @@ -257,12 +217,7 @@
               shutil.move(self.output_name + ".pcb", self.output_name + ".backup.pcb")
           
           # Save layout
  -        self.pcb_write("SaveTo(Layout, %s)\n" % (self.output_name + ".pcb"))
  -        
  -        # Wait to re-enter with a response
  -        yield None
  -        
  -        if error_occurred():
  +        if self.pcb_actions_iface.ExecAction( "SaveTo", [ "Layout", self.output_name + ".pcb" ] ):
               error_restore_backup()
               # TODO: TELL PCB TO ALLOW USER ACTIONS
               # TODO: ERROR MESSAGE TO USER
  @@ -285,60 +240,48 @@
           # TODO: HANDLE ERROR OUTPUT FROM gsch2pcb!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
           
           # Load layout
  -        self.pcb_write("LoadFrom(Revert, %s)\n" % (self.output_name + ".pcb"))
  -        
  -        # Wait to re-enter with a response
  -        yield None
  -        
  -        if error_occurred():
  +        if self.pcb_actions_iface.ExecAction("LoadFrom", [ "Revert", self.output_name + ".pcb" ]):
               error_restore_backup()
               # TODO: TELL PCB TO ALLOW USER ACTIONS
               # TODO: ERROR MESSAGE TO USER
               return
           
           # Delete rats
  -        self.pcb_write("DeleteRats(AllRats)\n")
  +        if self.pcb_actions_iface.ExecAction("DeleteRats", ["AllRats"]):
  +            # TODO: WARNING TO USER?
  +            pass
           
           # Load netlist
  -        self.pcb_write("LoadFrom(Netlist, %s)\n" % (self.output_name + ".net"))
  -
  -        # Wait to re-enter with a response
  -        yield None
  -        
  -        if error_occurred():
  +        if self.pcb_actions_iface.ExecAction("LoadFrom", ["Netlist", self.output_name + ".net"]):
               # TODO: WARNING TO THE USER?
               pass
           
           # If new elements exist, put them in the paste-buffer
           newparts = self.output_name + ".new.pcb"
           if os.path.exists (newparts):
  -            self.pcb_write("LoadFrom(LayoutToBuffer, %s)\n" % newparts)
  -            
  -            # Wait to re-enter with a response
  -            yield None
  -            
  -            if error_occurred():
  +            if self.pcb_actions_iface.ExecAction("LoadFrom", ["LayoutToBuffer", newparts]):
                   # TODO: WARN USER?
                   pass
          
               # Paste the new components near the origin
  -            self.pcb_write("PasteBuffer(ToLayout,10,10,mil)\n")
  +            if self.pcb_actions_iface.ExecAction("PasteBuffer", ["ToLayout","10","10","mil"]):
  +                # TODO: WARN USER?
  +                pass
               
               # Change back to the "none" (select) tool
  -            self.pcb_write("Mode(None)\n")
  +            if self.pcb_actions_iface.ExecAction("Mode", ["None"]):
  +                # TODO: WARN USER?
  +                pass
           
           # Run the .cmd file
  -        self.pcb_write("ExecuteFile(%s)\n" % (self.output_name + ".cmd"))
  -        
  -        # Wait to re-enter with a response
  -        yield None
  -        
  -        if error_occurred():
  +        if self.pcb_actions_iface.ExecAction("ExecuteFile", [self.output_name + ".cmd"]):
               # TODO: WARN USER?
               pass
               
           # Add the rat-lines
  -        self.pcb_write("AddRats(AllRats)\n")
  +        if self.pcb_actions_iface.ExecAction("AddRats", ["AllRats"]):
  +            # TODO: WARN USER?
  +            pass
           
           # Move original layout backup back in place, delete intermediate files
           cleanup_files()
  @@ -346,133 +289,5 @@
           print _("********DONE UPDATING********")
               
       
  -    def parser_return_code_cb( self, parser, retcode ):
  -     
  -        # If running, advance the function which is communicating with PCB
  -
  -        if self.cofunc == None:
  -            # print _("Ignoring return code out of cofunc execution")
  -            return
  -            
  -        try:
  -            self.cofunc.next()
  -                
  -        except StopIteration:
  -            self.cofunc = None
  -
  -    ## TODO: Use this timeout handler somewhere?
  -    #def pcb_timeout_cb( self ):
  -    #
  -    #    if self.cofunc == None:
  -    #        return True
  -    #
  -    #    try:
  -    #        self.cofunc.next()
  -    #
  -    #    except StopIteration:
  -    #        self.cofunc = None
  -    #
  -    #    ## OR, should we just:
  -    #    #self.parser_return_code_cb( self.parser, 'TIMEOUT' )
  -    #    ## as this gives a definate indication of re-entry cause
  -
  -
  -    def parser_pipe_died_cb( self, parser ):
  -        
  -        # Close the pipe
  -        self.pcb_stdin.close()
  -        self.pcb_stdin = None
  -
  -        # Close the corresponding pipe outputting to PCB
  -        self.pcb_stdout.close()
  -        self.pcb_stdout = None
  -
  -        # Close any remaining attachment to the process
  -        # TODO: Check there isn't an equivelant to "Pclose"
  -        self.pipes = None
  -            
   gobject.type_register( PCBManager )
   
  -class pcb_output_parser(gobject.GObject):
  -    # Register signals which we may emit
  -    __gsignals__ = { "return-code": ( gobject.SIGNAL_NO_RECURSE,
  -                                      gobject.TYPE_NONE,
  -                                      (gobject.TYPE_INT, ) ),
  -                     "pipe-died": ( gobject.SIGNAL_NO_RECURSE,
  -                                      gobject.TYPE_NONE,
  -                                      () ) }
  -                                    
  -
  -    def __init__(self, file):
  -        gobject.GObject.__init__(self)
  -        
  -        self.atnewline = True
  -        self.file = file
  -
  -        # Hardcode these for now
  -        self.out_prefix = "<pcb>: "
  -        self.out_echo = True
  -
  -        self.last_retcode = None
  -
  -        # Compile a regular expression to get any numerical 
  -        # return code from a PCB output string
  -        self.retcode_re = re.compile( '([0-9]{3,3}) - ' )
  -        
  -        self.watch_handle = gobject.io_add_watch(self.file, 
  -                             gobject.IO_IN | gobject.IO_ERR | gobject.IO_HUP,
  -                             self.pcb_read_cb )
  -    
  -    def __del__(self):
  -        gobject.source_remove(self.watch_handle);
  -        gobject.GObject.__del__(self)
  -    
  -    def consume_retcode(self):
  -        retval = self.last_retcode
  -        self.last_retcode = None
  -        return retval
  -        
  -    def get_last_retcode(self):
  -        return self.last_retcode
  -        
  -    def pcb_read_cb (self, source, condition ):
  -        
  -        # Check if the connection has died
  -        if condition & gobject.IO_HUP:
  -
  -            # Callback signal to inform the program
  -            self.emit( "pipe-died" );
  -
  -            # Return False, so the io_watch will not re-run
  -            return False
  -        
  -        # Attempt reading from the pipe
  -        try:
  -
  -            data = self.file.readline ()
  -
  -        except IOError:
  -
  -            print >> sys.stderr, _("pcb_read_cb: IOError whilst in readline()")
  -
  -            # Callback signal to inform the program
  -            self.emit( "pipe-died" );
  -
  -            # Return False, so the io_watch will not re-run
  -            return False
  -        
  -        if self.out_echo:
  -            print self.out_prefix, data,
  -
  -        # TODO: Decide if we just want to signal directly with the line read from PCB?
  -
  -        re_match = self.retcode_re.match( data )
  -        
  -        if re_match:
  -            self.last_retcode = int( re_match.group(1) )
  -            self.emit ( "return-code", self.last_retcode )
  -        
  -        return True
  -
  -gobject.type_register( pcb_output_parser )
  - 
  
  
  


_______________________________________________
geda-cvs mailing list
geda-cvs@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-cvs