[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