# HG changeset patch # User etisserant # Date 1219411809 -7200 # Node ID f3eb35df4d87b2aad85da44f353dd193ca68d59d # Parent 11124e129a287f77f0e36241d3144af1e266c0ef Now, Beremiz launch Beremiz_service at startup, with a one-time workin dir diff -r 11124e129a28 -r f3eb35df4d87 Beremiz.py --- a/Beremiz.py Fri Aug 22 15:27:37 2008 +0200 +++ b/Beremiz.py Fri Aug 22 15:30:09 2008 +0200 @@ -25,8 +25,13 @@ __version__ = "$Revision$" import os, sys, getopt, wx - -CWD = os.path.split(os.path.realpath(__file__))[0] +import tempfile +import shutil +from signal import SIGKILL + +_local_path = os.path.split(os.path.realpath(__file__))[0] +def Bpath(*args): + return os.path.join(_local_path,*args) if __name__ == '__main__': def usage(): @@ -56,13 +61,14 @@ app = wx.PySimpleApp() wx.InitAllImageHandlers() - bmp = wx.Image(os.path.join(CWD,"images","splash.png")).ConvertToBitmap() + bmp = wx.Image(Bpath("images","splash.png")).ConvertToBitmap() splash=wx.SplashScreen(bmp,wx.SPLASH_CENTRE_ON_SCREEN, 1000, None) wx.Yield() import wx.lib.buttons, wx.lib.statbmp import types, time, re, platform, time, traceback, commands from plugger import PluginsRoot +from wxPopen import ProcessLogger base_folder = os.path.split(sys.path[0])[0] sys.path.append(base_folder) @@ -130,7 +136,7 @@ style = 0, name = "genstatbmp"): - bitmappath = os.path.join(CWD, "images", bitmapname) + bitmappath = Bpath( "images", bitmapname) if os.path.isfile(bitmappath): bitmap = wx.Bitmap(bitmappath) else: @@ -354,8 +360,16 @@ self.Log = LogPseudoFile(self.LogConsole) +# self.local_runtime = ProcessLogger(self.Log, +# "bash -c 'while true; do echo coucou; sleep 1; done'") + self.local_runtime_tmpdir = tempfile.mkdtemp() + self.local_runtime = ProcessLogger(self.Log, + "%s %s -i localhost %s"%(sys.executable, + Bpath("Beremiz_service.py"), + self.local_runtime_tmpdir)) + # Add beremiz's icon in top left corner of the frame - self.SetIcon(wx.Icon(os.path.join(CWD, "images", "brz.ico"), wx.BITMAP_TYPE_ICO)) + self.SetIcon(wx.Icon(Bpath( "images", "brz.ico"), wx.BITMAP_TYPE_ICO)) self.PluginRoot = PluginsRoot(self, self.Log) self.DisableEvents = False @@ -397,13 +411,17 @@ (int(last_line), int(last_column))) def OnCloseFrame(self, event): + # shutdown local runtime + self.local_runtime.kill(SIGKILL) + # clear temp dir + shutil.rmtree(self.local_runtime_tmpdir) + if self.PluginRoot.HasProjectOpened(): - if self.PluginRoot.runningPLC is not None: - wx.MessageBox("Please stop any running PLC before closing") - event.Veto() - return if self.PluginRoot.ProjectTestModified(): - dialog = wx.MessageDialog(self, "There are changes, do you want to save?", "Close Application", wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) + dialog = wx.MessageDialog(self, + "Save changes ?", + "Close Application", + wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) answer = dialog.ShowModal() dialog.Destroy() if answer == wx.ID_YES: @@ -479,7 +497,7 @@ plcwindowsizer.AddWindow(st, 0, border=5, flag=wx.ALL|wx.ALIGN_CENTER) addbutton_id = wx.NewId() - addbutton = wx.lib.buttons.GenBitmapButton(id=addbutton_id, bitmap=wx.Bitmap(os.path.join(CWD, 'images', 'Add.png')), + addbutton = wx.lib.buttons.GenBitmapButton(id=addbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Add.png')), name='AddPluginButton', parent=plcwindow, pos=wx.Point(0, 0), size=wx.Size(16, 16), style=wx.NO_BORDER) addbutton.SetToolTipString("Add a sub plugin") @@ -509,11 +527,11 @@ paramswindow.Hide() minimizebutton_id = wx.NewId() - minimizebutton = wx.lib.buttons.GenBitmapToggleButton(id=minimizebutton_id, bitmap=wx.Bitmap(os.path.join(CWD, 'images', 'Maximize.png')), + minimizebutton = wx.lib.buttons.GenBitmapToggleButton(id=minimizebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Maximize.png')), name='MinimizeButton', parent=plcwindow, pos=wx.Point(0, 0), size=wx.Size(24, 24), style=wx.NO_BORDER) make_genbitmaptogglebutton_flat(minimizebutton) - minimizebutton.SetBitmapSelected(wx.Bitmap(os.path.join(CWD, 'images', 'Minimize.png'))) + minimizebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Minimize.png'))) plcwindowbuttonsizer.AddWindow(minimizebutton, 0, border=5, flag=wx.ALL) # if len(self.PluginRoot.PlugChildsTypes) > 0: @@ -575,7 +593,7 @@ if "method" in plugin_method and plugin_method.get("shown",True): id = wx.NewId() button = GenBitmapTextButton(id=id, parent=parent, - bitmap=wx.Bitmap(os.path.join(CWD, "%s.png"%plugin_method.get("bitmap", os.path.join("images", "Unknown")))), label=plugin_method["name"], + bitmap=wx.Bitmap(Bpath( "%s.png"%plugin_method.get("bitmap", os.path.join("images", "Unknown")))), label=plugin_method["name"], name=plugin_method["name"], pos=wx.DefaultPosition, style=wx.NO_BORDER) button.SetToolTipString(plugin_method["tooltip"]) button.Bind(wx.EVT_BUTTON, self.GetButtonCallBackFunction(plugin, plugin_method["method"]), id=id) @@ -668,11 +686,11 @@ leftsizer.AddSizer(rolesizer, 0, border=0, flag=wx.GROW|wx.RIGHT) enablebutton_id = wx.NewId() - enablebutton = wx.lib.buttons.GenBitmapToggleButton(id=enablebutton_id, bitmap=wx.Bitmap(os.path.join(CWD, 'images', 'Disabled.png')), + enablebutton = wx.lib.buttons.GenBitmapToggleButton(id=enablebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Disabled.png')), name='EnableButton', parent=leftwindow, size=wx.Size(16, 16), pos=wx.Point(0, 0), style=0)#wx.NO_BORDER) enablebutton.SetToolTipString("Enable/Disable this plugin") make_genbitmaptogglebutton_flat(enablebutton) - enablebutton.SetBitmapSelected(wx.Bitmap(os.path.join(CWD, 'images', 'Enabled.png'))) + enablebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Enabled.png'))) enablebutton.SetToggle(plugin.MandatoryParams[1].getEnabled()) def toggleenablebutton(event): res = self.SetPluginParamsAttribute(plugin, "BaseParams.Enabled", enablebutton.GetToggle()) @@ -700,14 +718,14 @@ if plugin_IECChannel > 0: ieccdownbutton_id = wx.NewId() - ieccdownbutton = wx.lib.buttons.GenBitmapButton(id=ieccdownbutton_id, bitmap=wx.Bitmap(os.path.join(CWD, 'images', 'IECCDown.png')), + ieccdownbutton = wx.lib.buttons.GenBitmapButton(id=ieccdownbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'IECCDown.png')), name='IECCDownButton', parent=leftwindow, pos=wx.Point(0, 0), size=wx.Size(16, 16), style=wx.NO_BORDER) ieccdownbutton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(plugin, plugin_IECChannel - 1), id=ieccdownbutton_id) updownsizer.AddWindow(ieccdownbutton, 0, border=0, flag=wx.ALIGN_LEFT) ieccupbutton_id = wx.NewId() - ieccupbutton = wx.lib.buttons.GenBitmapTextButton(id=ieccupbutton_id, bitmap=wx.Bitmap(os.path.join(CWD, 'images', 'IECCUp.png')), + ieccupbutton = wx.lib.buttons.GenBitmapTextButton(id=ieccupbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'IECCUp.png')), name='IECCUpButton', parent=leftwindow, pos=wx.Point(0, 0), size=wx.Size(16, 16), style=wx.NO_BORDER) ieccupbutton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(plugin, plugin_IECChannel + 1), id=ieccupbutton_id) @@ -717,7 +735,7 @@ iecsizer.AddSizer(adddeletesizer, 0, border=5, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL) deletebutton_id = wx.NewId() - deletebutton = wx.lib.buttons.GenBitmapButton(id=deletebutton_id, bitmap=wx.Bitmap(os.path.join(CWD, 'images', 'Delete.png')), + deletebutton = wx.lib.buttons.GenBitmapButton(id=deletebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Delete.png')), name='DeletePluginButton', parent=leftwindow, pos=wx.Point(0, 0), size=wx.Size(16, 16), style=wx.NO_BORDER) deletebutton.SetToolTipString("Delete this plugin") @@ -726,7 +744,7 @@ if len(plugin.PlugChildsTypes) > 0: addbutton_id = wx.NewId() - addbutton = wx.lib.buttons.GenBitmapButton(id=addbutton_id, bitmap=wx.Bitmap(os.path.join(CWD, 'images', 'Add.png')), + addbutton = wx.lib.buttons.GenBitmapButton(id=addbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Add.png')), name='AddPluginButton', parent=leftwindow, pos=wx.Point(0, 0), size=wx.Size(16, 16), style=wx.NO_BORDER) addbutton.SetToolTipString("Add a sub plugin") @@ -734,13 +752,13 @@ adddeletesizer.AddWindow(addbutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER) expandbutton_id = wx.NewId() - expandbutton = wx.lib.buttons.GenBitmapToggleButton(id=expandbutton_id, bitmap=wx.Bitmap(os.path.join(CWD, 'images', 'plus.png')), + expandbutton = wx.lib.buttons.GenBitmapToggleButton(id=expandbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'plus.png')), name='ExpandButton', parent=leftwindow, pos=wx.Point(0, 0), size=wx.Size(13, 13), style=wx.NO_BORDER) expandbutton.labelDelta = 0 expandbutton.SetBezelWidth(0) expandbutton.SetUseFocusIndicator(False) - expandbutton.SetBitmapSelected(wx.Bitmap(os.path.join(CWD, 'images', 'minus.png'))) + expandbutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'minus.png'))) expandbutton.SetToggle(self.PluginInfos[plugin]["expanded"]) if len(self.PluginInfos[plugin]["children"]) > 0: @@ -767,11 +785,11 @@ leftminimizebutton_id = wx.NewId() - leftminimizebutton = wx.lib.buttons.GenBitmapToggleButton(id=leftminimizebutton_id, bitmap=wx.Bitmap(os.path.join(CWD, 'images', 'ShowVars.png')), + leftminimizebutton = wx.lib.buttons.GenBitmapToggleButton(id=leftminimizebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'ShowVars.png')), name='MinimizeButton', parent=leftwindow, pos=wx.Point(0, 0), size=wx.Size(24, 24), style=wx.NO_BORDER) make_genbitmaptogglebutton_flat(leftminimizebutton) - leftminimizebutton.SetBitmapSelected(wx.Bitmap(os.path.join(CWD, 'images', 'HideVars.png'))) + leftminimizebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'HideVars.png'))) leftminimizebutton.SetToggle(self.PluginInfos[plugin]["left_visible"]) def toggleleftwindow(event): if leftminimizebutton.GetToggle(): @@ -829,11 +847,11 @@ paramswindow.Hide() middleminimizebutton_id = wx.NewId() - middleminimizebutton = wx.lib.buttons.GenBitmapToggleButton(id=middleminimizebutton_id, bitmap=wx.Bitmap(os.path.join(CWD, 'images', 'Maximize.png')), + middleminimizebutton = wx.lib.buttons.GenBitmapToggleButton(id=middleminimizebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Maximize.png')), name='MinimizeButton', parent=middlewindow, pos=wx.Point(0, 0), size=wx.Size(24, 24), style=wx.NO_BORDER) make_genbitmaptogglebutton_flat(middleminimizebutton) - middleminimizebutton.SetBitmapSelected(wx.Bitmap(os.path.join(CWD, 'images', 'Minimize.png'))) + middleminimizebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Minimize.png'))) middleminimizebutton.SetToggle(self.PluginInfos[plugin]["middle_visible"]) middleparamssizer.AddWindow(middleminimizebutton, 0, border=5, flag=wx.ALL) @@ -1177,11 +1195,11 @@ event.Skip() def OnBeremizMenu(self, event): - open_pdf(os.path.join(CWD, "doc", "manual_beremiz.pdf")) + open_pdf(Bpath( "doc", "manual_beremiz.pdf")) event.Skip() def OnAboutMenu(self, event): - OpenHtmlFrame(self,"About Beremiz", os.path.join(CWD, "doc","about.html"), wx.Size(550, 500)) + OpenHtmlFrame(self,"About Beremiz", Bpath("doc","about.html"), wx.Size(550, 500)) event.Skip() def OnAddButton(self, event): diff -r 11124e129a28 -r f3eb35df4d87 Beremiz_service.py --- a/Beremiz_service.py Fri Aug 22 15:27:37 2008 +0200 +++ b/Beremiz_service.py Fri Aug 22 15:30:09 2008 +0200 @@ -22,20 +22,22 @@ #License along with this library; if not, write to the Free Software #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -import os, sys, getopt, socket +import os, sys, getopt def usage(): print """ Usage of Beremiz PLC execution service :\n -%s {[-a ip] [-d path] [-p port]|-h|--help} - -a, --address - authorized ip to connect (x.x.x.x) - -d, --directory path - set the working directory - -p, --port port number - set the port number - -h, --help - print this help text and quit +%s {[-n name] [-i ip] [-p port]|-h|--help} working_dir + -n - zeroconf service name + -i - ip of interface to bind to (x.x.x.x) + -p - port number + -h - print this help text and quit + + working_dir - directory where are stored PLC files """%sys.argv[0] try: - opts, args = getopt.getopt(sys.argv[1:], "a:p:h", ["help"]) + opts, args = getopt.getopt(sys.argv[1:], "i:p:n:h") except getopt.GetoptError, err: # print help information and exit: print str(err) # will print something like "option -a not recognized" @@ -45,17 +47,23 @@ # default values ip = "" port = 3000 -print opts +name = os.environ[{ + "linux2":"USER", + "win32":"USERNAME", + }.get(sys.platform, "USER")] + for o, a in opts: - if o in ("-h", "--help"): + if o == "-h": usage() sys.exit() - elif o in ("-a", "--address"): + elif o == "-i": if len(a.split(".")) == 4 or a == "localhost": ip = a - elif o in ("-p", "--port"): + elif o == "-p": # port: port that the service runs on port = int(a) + elif o == "-n": + name = a else: usage() sys.exit() @@ -67,9 +75,7 @@ WorkingDir = args[0] elif len(args) == 0: WorkingDir = os.getcwd() -else: - usage() - sys.exit() + args=[WorkingDir] from runtime import PLCObject, ServicePublisher import Pyro.core as pyro @@ -77,26 +83,6 @@ if not os.path.isdir(WorkingDir): os.mkdir(WorkingDir) -# type: fully qualified service type name -type = '_PYRO._tcp.local.' -# name: fully qualified service name -name = 'First test.%s'%(type) -# address: IP address as unsigned short, network byte order - -def gethostaddr(dst = '224.0.1.41'): - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - try: - s.connect((dst, 7)) - (host, port) = s.getsockname() - s.close() - if host != '0.0.0.0': - return host - except error: - pass - return socket.gethostbyname(socket.gethostname()) - -# properties: dictionary of properties (or a string holding the bytes for the text field) -serviceproperties = {'description':'Remote control for PLC'} pyro.initServer() daemon=pyro.Daemon(host=ip, port=port) @@ -109,14 +95,9 @@ # Configure and publish service # Not publish service if localhost in address params if ip != "localhost" and ip != "127.0.0.1": - # No ip params -> get host ip - if ip == "": - ip_32b = socket.inet_aton(gethostaddr(ip)) - else: - ip_32b = ip print "Publish service on local network" - service = ServicePublisher.PublishService() - service.ConfigureService(type, name, ip_32b, port, serviceproperties) - service.PublishService() + service = ServicePublisher.ServicePublisher(name, ip, port) + +sys.stdout.flush() daemon.requestLoop() diff -r 11124e129a28 -r f3eb35df4d87 plugger.py --- a/plugger.py Fri Aug 22 15:27:37 2008 +0200 +++ b/plugger.py Fri Aug 22 15:30:09 2008 +0200 @@ -683,8 +683,6 @@ self.PLCEditor = None # copy PluginMethods so that it can be later customized self.PluginMethods = [dic.copy() for dic in self.PluginMethods] - # special root member for handlig PLC execution - self.runningPLC = None def PlugTestModified(self): return self.ChangesToSave or not self.ProjectIsSaved() diff -r 11124e129a28 -r f3eb35df4d87 runtime/ServicePublisher.py --- a/runtime/ServicePublisher.py Fri Aug 22 15:27:37 2008 +0200 +++ b/runtime/ServicePublisher.py Fri Aug 22 15:30:09 2008 +0200 @@ -22,20 +22,48 @@ #License along with this library; if not, write to the Free Software #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -import Zeroconf +import Zeroconf, socket -class PublishService(): - def __init__(self): - self.server = Zeroconf.Zeroconf() +# type: fully qualified service type name +service_type = '_PYRO._tcp.local.' - def ConfigureService(self, type, name, address, port, description): - self.newservice = Zeroconf.ServiceInfo(type, - name, - address, +# properties: dictionary of properties (or a string holding the bytes for the text field) +serviceproperties = {'description':'Beremiz remote PLC'} + +def gethostaddr(dst = '224.0.1.41'): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.connect((dst, 7)) + (host, port) = s.getsockname() + s.close() + if host != '0.0.0.0': + return host + except error: + pass + return socket.gethostbyname(socket.gethostname()) + + +def ServicePublisher(name, ip, port): + + # name: fully qualified service name + service_name = 'Beremiz_%s.%s'%(name,service_type) + + # No ip params -> get host ip + if ip == "": + ip = gethostaddr() + + print "Mon IP est :"+ip + + server = Zeroconf.Zeroconf(ip) + + # address: IP address as unsigned short, network byte order + ip_32b = socket.inet_aton(ip) + + server.registerService( + Zeroconf.ServiceInfo(service_type, + service_name, + ip_32b, port, - weight = 0, # weight: weight of the service - priority= 0, # priority: priority of the service - properties = description) - - def PublishService(self): - self.server.registerService(self.newservice) \ No newline at end of file + properties = serviceproperties)) + + return server \ No newline at end of file diff -r 11124e129a28 -r f3eb35df4d87 wxPopen.py --- a/wxPopen.py Fri Aug 22 15:27:37 2008 +0200 +++ b/wxPopen.py Fri Aug 22 15:30:09 2008 +0200 @@ -28,7 +28,7 @@ import subprocess, ctypes import threading import os -import signal +from signal import SIGTERM, SIGKILL class outputThread(threading.Thread): @@ -139,7 +139,7 @@ if self.finish_callback is not None: self.finish_callback(self,ecode,pid) - def kill(self): + def kill(self,signal=SIGTERM): self.outt.killed = True self.errt.killed = True if wx.Platform == '__WXMSW__': @@ -149,7 +149,7 @@ ctypes.windll.kernel32.CloseHandle(handle) else: try: - os.kill(self.Proc.pid, signal.SIGTERM) + os.kill(self.Proc.pid, signal) except: pass