# HG changeset patch # User etisserant # Date 1232156206 -3600 # Node ID 87c925eaaa3aec82751d74928c32b52c79f7b3c0 # Parent 7f7912ae5ee86ce28fc6e92c829da61bd853f790 Added support for wxglade GUIs. diff -r 7f7912ae5ee8 -r 87c925eaaa3a Beremiz_service.py --- a/Beremiz_service.py Sat Jan 17 02:34:45 2009 +0100 +++ b/Beremiz_service.py Sat Jan 17 02:36:46 2009 +0100 @@ -38,7 +38,7 @@ """%sys.argv[0] try: - opts, args = getopt.getopt(sys.argv[1:], "i:p:n:x:h") + opts, argv = getopt.getopt(sys.argv[1:], "i:p:n:x:h") except getopt.GetoptError, err: # print help information and exit: print str(err) # will print something like "option -a not recognized" @@ -73,14 +73,14 @@ usage() sys.exit() -if len(args) > 1: +if len(argv) > 1: usage() sys.exit() -elif len(args) == 1: - WorkingDir = args[0] -elif len(args) == 0: +elif len(argv) == 1: + WorkingDir = argv[0] +elif len(argv) == 0: WorkingDir = os.getcwd() - args=[WorkingDir] + argv=[WorkingDir] if enablewx: try: @@ -351,20 +351,20 @@ os.mkdir(WorkingDir) class Server(): - def __init__(self, name, ip, port, workdir, args): + def __init__(self, name, ip, port, workdir, argv, statuschange=None, evaluator=eval): self.continueloop = True self.daemon = None self.name = name self.ip = ip self.port = port self.workdir = workdir - self.args = args + self.argv = argv self.plcobj = None self.servicepublisher = None - self.statuschange = None - - def Loop(self, statuschange=None): self.statuschange = statuschange + self.evaluator = evaluator + + def Loop(self): while self.continueloop: self.Start() @@ -378,7 +378,7 @@ def Start(self): pyro.initServer() self.daemon=pyro.Daemon(host=self.ip, port=self.port) - self.plcobj = PLCObject(self.workdir, self.daemon, self.args, self.statuschange) + self.plcobj = PLCObject(self.workdir, self.daemon, self.argv, self.statuschange, self.evaluator) uri = self.daemon.connect(self.plcobj,"PLCObject") print "The daemon runs on port :",self.port @@ -402,15 +402,32 @@ del self.servicepublisher self.daemon.shutdown(True) -pyroserver = Server(name, ip, port, WorkingDir, args) if havewx: + from threading import Semaphore + wx_eval_lock = Semaphore(0) app=wx.App(redirect=False) - taskbar_instance = BeremizTaskBarIcon(pyroserver) def statuschange(status): wx.CallAfter(taskbar_instance.UpdateIcon,status) - pyro_thread=Thread(target=pyroserver.Loop, args=[statuschange]) + + eval_res = None + def wx_evaluator(callable, *args, **kwargs): + global eval_res + eval_res=callable(*args,**kwargs) + #print eval_res + wx_eval_lock.release() + + def evaluator(callable, *args, **kwargs): + wx.CallAfter(wx_evaluator,callable,*args,**kwargs) + wx_eval_lock.acquire() + return eval_res + + pyroserver = Server(name, ip, port, WorkingDir, argv, statuschange, evaluator) + taskbar_instance = BeremizTaskBarIcon(pyroserver) + + pyro_thread=Thread(target=pyroserver.Loop) pyro_thread.start() app.MainLoop() else: + pyroserver = Server(name, ip, port, WorkingDir, argv) pyroserver.Loop() diff -r 7f7912ae5ee8 -r 87c925eaaa3a images/editWXGLADE.png Binary file images/editWXGLADE.png has changed diff -r 7f7912ae5ee8 -r 87c925eaaa3a images/icons.svg --- a/images/icons.svg Sat Jan 17 02:34:45 2009 +0100 +++ b/images/icons.svg Sat Jan 17 02:36:46 2009 +0100 @@ -41,9 +41,9 @@ pagecolor="#ffffff" id="base" showgrid="false" - inkscape:zoom="5.656854" - inkscape:cx="241.82787" - inkscape:cy="888.09651" + inkscape:zoom="1.9999999" + inkscape:cx="389.62633" + inkscape:cy="954.22679" inkscape:window-x="0" inkscape:window-y="25" inkscape:current-layer="svg2" @@ -82634,7 +82634,7 @@ y2="144.96741" gradientUnits="userSpaceOnUse" spreadMethod="reflect" - gradientTransform="translate(170,0)" /> + gradientTransform="translate(230,0)" /> + gradientTransform="translate(230,0)" /> + gradientTransform="translate(230,0)" /> + gradientTransform="translate(170,0)" /> + + + + + + + + + + + + + + + + %% editIECrawcode editPYTHONcode EditCfile Transfer Connect Disconnect Debug %% + x="73.295929" + y="121.52582">%% editIECrawcode editWXGLADE editPYTHONcode EditCfile Transfer Connect Disconnect Debug %% + transform="matrix(1.1031299,0.6368924,-0.6368924,1.1031299,228.02287,-226.14748)" /> + + + Wx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 7f7912ae5ee8 -r 87c925eaaa3a plugger.py --- a/plugger.py Sat Jan 17 02:34:45 2009 +0100 +++ b/plugger.py Sat Jan 17 02:36:46 2009 +0100 @@ -855,6 +855,10 @@ # define name for IEC raw code file return os.path.join(self.PlugPath(), "runtime.py") + def _getWXGLADEpath(self): + # define name for IEC raw code file + return os.path.join(self.PlugPath(), "hmi.wxg") + def GetLocations(self): locations = [] filepath = os.path.join(self._getBuildPath(),"LOCATED_VARIABLES.h") @@ -976,6 +980,14 @@ else: return None + def launch_wxglade(self,options, wait=False): + from wxglade import __file__ as fileName + path = os.path.dirname(fileName) + glade = os.path.join(path,'wxglade.py') + mode = {False:os.P_NOWAIT, True:os.P_WAIT}[wait] + print (mode,sys.executable,[sys.executable]+[glade]+options) + os.spawnv(mode,sys.executable,[sys.executable]+[glade]+options) + ####################################################################### # # C CODE GENERATION METHODS @@ -998,6 +1010,11 @@ pyfile=self._getPYTHONcodepath() if os.path.exists(pyfile): res += (("runtime.py", file(pyfile,"rb")),) + wxgfile=self._getWXGLADEpath() + if os.path.exists(wxgfile): + hmipyfile=os.path.join(self._getBuildPath(),"hmi.py") + self.launch_wxglade(['-o', hmipyfile, '-g','python', wxgfile], wait=True) + res += (("hmi.py", file(hmipyfile,"rb")),) return res @@ -1102,7 +1119,7 @@ python_eval_fb_list = [] for v in self._VariablesList : - if v["vartype"] == "FB" and v["type"] == "PYTHON_EVAL": + if v["vartype"] == "FB" and v["type"] in ["PYTHON_EVAL","PYTHON_POLL"]: python_eval_fb_list.append(v) python_eval_fb_count = max(1, len(python_eval_fb_list)) @@ -1290,6 +1307,19 @@ new_dialog.Show() + def _editWXGLADE(self): + wxg_filename = self._getWXGLADEpath() + if not os.path.exists(wxg_filename): + open(wxg_filename,"w").write(""" + + + + frame_1 + + +""") + self.launch_wxglade([wxg_filename]) + def _EditPLC(self): if self.PLCEditor is None: self.RefreshPluginsBlockLists() @@ -1700,4 +1730,8 @@ "name" : "Python code", "tooltip" : "Write Python runtime code, for use with python_eval FBs", "method" : "_editPYTHONcode"}, + {"bitmap" : opjimg("editWXGLADE"), + "name" : "WXGLADE GUI", + "tooltip" : "Edit a WxWidgets GUI with WXGlade", + "method" : "_editWXGLADE"}, ] diff -r 7f7912ae5ee8 -r 87c925eaaa3a runtime/PLCObject.py --- a/runtime/PLCObject.py Sat Jan 17 02:34:45 2009 +0100 +++ b/runtime/PLCObject.py Sat Jan 17 02:36:46 2009 +0100 @@ -24,8 +24,8 @@ import Pyro.core as pyro from threading import Timer, Thread -import ctypes, os, commands -import sys +import ctypes, os, commands, types, sys + if os.name in ("nt", "ce"): from _ctypes import LoadLibrary as dlopen @@ -46,8 +46,9 @@ class PLCObject(pyro.ObjBase): _Idxs = [] - def __init__(self, workingdir, daemon, argv, statuschange=None): + def __init__(self, workingdir, daemon, argv, statuschange=None, evaluator=eval): pyro.ObjBase.__init__(self) + self.evaluator = evaluator self.argv = [workingdir] + argv # force argv[0] to be "path" to exec... self.workingdir = workingdir self.PLCStatus = "Stopped" @@ -57,6 +58,7 @@ self.daemon = daemon self.statuschange = statuschange self.python_threads_vars = None + self.hmi_frame = None # Get the last transfered PLC if connector must be restart try: @@ -181,24 +183,40 @@ def PrepareRuntimePy(self): self.python_threads_vars = globals().copy() pyfile = os.path.join(self.workingdir, "runtime.py") + hmifile = os.path.join(self.workingdir, "hmi.py") if os.path.exists(pyfile): try: # TODO handle exceptions in runtime.py # pyfile may redefine _runtime_cleanup # or even call _PythonThreadProc itself. + if os.path.exists(hmifile): + execfile(hmifile, self.python_threads_vars) execfile(pyfile, self.python_threads_vars) + try: + # try to instanciate the first frame found. + for name, obj in self.python_threads_vars.iteritems(): + # obj is a class + if type(obj)==type(type) and issubclass(obj,self.python_threads_vars['wx'].Frame): + self.hmi_frame = obj(None) + self.python_threads_vars['_'+name] = self.hmi_frame + self.hmi_frame.Show() + break + except: + PLCprint(traceback.format_exc()) except: PLCprint(traceback.format_exc()) def BeginRuntimePy(self): runtime_begin = self.python_threads_vars.get("_runtime_begin",None) if runtime_begin is not None: - runtime_begin() + self.evaluator(runtime_begin) def FinishRuntimePy(self): runtime_cleanup = self.python_threads_vars.get("_runtime_cleanup",None) if runtime_cleanup is not None: - runtime_cleanup() + self.evaluator(runtime_cleanup) + if self.hmi_frame is not None: + self.evaluator(self.hmi_frame.Destroy) self.python_threads_vars = None def PythonThreadProc(self): @@ -212,7 +230,7 @@ if cmd is None: break try : - res = str(eval(cmd,self.python_threads_vars)) + res = str(self.evaluator(eval,cmd,self.python_threads_vars)) except Exception,e: res = "#EXCEPTION : "+str(e) PLCprint(res) @@ -227,7 +245,7 @@ self._resumeDebug() self.PLCStatus = "Started" self.StatusChange() - self.PrepareRuntimePy() + self.evaluator(self.PrepareRuntimePy) self.PythonThread = Thread(target=self.PythonThreadProc) self.PythonThread.start() return True diff -r 7f7912ae5ee8 -r 87c925eaaa3a tests/linux/python_cwiid/hmi.wxg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/linux/python_cwiid/hmi.wxg Sat Jan 17 02:36:46 2009 +0100 @@ -0,0 +1,397 @@ + + + + + + + frame_1 + + 0 + 3 + 3 + 0 + + wxEXPAND + 0 + + + 0 + 0,1 + 2 + 0 + 1 + 0 + + wxEXPAND + 0 + + + + + start_manu + + + + + wxEXPAND + 0 + + + + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + + wxEXPAND + 0 + + + 0 + 2 + 1 + 0 + + wxEXPAND + 0 + + + + + + wxEXPAND + 0 + + + 0 + 1 + 2 + 0 + + wxEXPAND + 0 + + + + + + + wxEXPAND + 0 + + + + + + + + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + + wxEXPAND + 0 + + + 0 + 2 + 1 + 0 + + wxEXPAND + 0 + + + + + + wxEXPAND + 0 + + + 0 + 1 + 2 + 0 + + wxEXPAND + 0 + + + + + + + wxEXPAND + 0 + + + + + + + + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + + 0 + + + 1 + + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + + wxEXPAND + 0 + + + 0 + 2 + 1 + 0 + + wxEXPAND + 0 + + + + + + wxEXPAND + 0 + + + 0 + 1 + 2 + 0 + + wxEXPAND + 0 + + + + + + + wxEXPAND + 0 + + + + + + + + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + + wxEXPAND + 0 + + + 0 + 2 + 1 + 0 + + wxEXPAND + 0 + + + + + + wxEXPAND + 0 + + + 0 + 1 + 2 + 0 + + wxEXPAND + 0 + + + + + + + wxEXPAND + 0 + + + + + + + + + + + + + wxEXPAND + 0 + + + wxVERTICAL + + + wxEXPAND + 0 + + + + 1 + + + + + wxEXPAND + 0 + + + + + + + wxEXPAND + 0 + + + + 1 + + + + + wxEXPAND + 0 + + + + + + + + + wxEXPAND + 0 + + + wxHORIZONTAL + + + wxEXPAND + 0 + + + 0 + 2 + 1 + 0 + + wxEXPAND + 0 + + + + + + wxEXPAND + 0 + + + 0 + 1 + 2 + 0 + + wxEXPAND + 0 + + + + + + + wxEXPAND + 0 + + + + + + + + + + + + + wxEXPAND + 0 + + + #ff0000 + STOP + + + 20 + default + + normal + 0 + + + + + + + diff -r 7f7912ae5ee8 -r 87c925eaaa3a tests/linux/python_cwiid/plc.xml --- a/tests/linux/python_cwiid/plc.xml Sat Jan 17 02:34:45 2009 +0100 +++ b/tests/linux/python_cwiid/plc.xml Sat Jan 17 02:36:46 2009 +0100 @@ -6,9 +6,9 @@ + creationDateTime="2008-12-14 16:21:19"/> + modificationDateTime="2009-01-16 21:51:43"> @@ -40,34 +40,29 @@ + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - @@ -79,7 +74,7 @@ 'last_point[0]' - + @@ -119,7 +114,7 @@ - + @@ -173,19 +168,17 @@ 'btA' - + - + - - - - - + + + @@ -277,28 +270,6 @@ - - - - - - - - - - - - - - - - - - - - - - @@ -463,96 +434,13 @@ ', y:' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - pytest_var2 - - - - - - - - - - - pytest_var2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + BOOL#TRUE + diff -r 7f7912ae5ee8 -r 87c925eaaa3a tests/linux/python_cwiid/runtime.py --- a/tests/linux/python_cwiid/runtime.py Sat Jan 17 02:34:45 2009 +0100 +++ b/tests/linux/python_cwiid/runtime.py Sat Jan 17 02:36:46 2009 +0100 @@ -17,8 +17,10 @@ ################################################################################ import cwiid - +import sys +from threading import Thread ## Configuration +wm = None wiimote_hwaddr = '' # Use your address to speed up the connection proccess #wiimote_hwaddr = '00:19:1D:5D:5D:DC' @@ -30,18 +32,19 @@ '''Wiimote callback managing method Recieves a message list, each element is different, see the libcwiid docs''' global btA, btB, last_point + #print messages #print "wiimote callback" for msg in messages: - if msg[0] == cwiid.MESG_IR: - # msg is of the form (cwiid.MESG_IR, (((x, y), size) or None * 4)) - for p in msg[1]: - if p: - pos = p['pos'][0], p['pos'][1] # point is mirrored - #s = max(p['size'], 1) - - last_point = tuple(pos) - #print "last_point",last_point - elif msg[0] == cwiid.MESG_BTN: +# if msg[0] == cwiid.MESG_IR: +# # msg is of the form (cwiid.MESG_IR, (((x, y), size) or None * 4)) +# for p in msg[1]: +# if p: +# pos = p['pos'][0], p['pos'][1] # point is mirrored +# #s = max(p['size'], 1) +# +# last_point = tuple(pos) +# #print "last_point",last_point + if msg[0] == cwiid.MESG_BTN: # msg is of the form (cwiid.MESG_BTN, cwiid.BTN_*) if msg[1] & cwiid.BTN_A: btA = 1 @@ -55,36 +58,63 @@ #print "btB = 1" else: btB = 0 + elif msg[0] == cwiid.MESG_NUNCHUK: + #sbb = msg[1]['buttons'] + last_point = msg[1]['stick'] + #ssx = msg[1]['stick'][0] + #ssy = msg[1]['stick'][1] + #msg[1]['acc'][0] + #msg[1]['acc'][1] + #msg[1]['acc'][2] #print "btB = 0" #elif msg[0] == cwiid.MESG_STATUS: # # msg is of the form (cwiid.MESG_BTN, { 'status' : value, ... }) # print msg[1] -try: -#if False: - wm = cwiid.Wiimote(wiimote_hwaddr) - if wm is not None: - # each message will contain info about ir and buttons - wm.rpt_mode = cwiid.RPT_IR | cwiid.RPT_BTN # | cwiid.RPT_STATUS - # tell cwiid to use the callback interface and allways send button events - wm.enable(cwiid.FLAG_MESG_IFC - #| cwiid.FLAG_NONBLOCK - | cwiid.FLAG_REPEAT_BTN) +def Connect_Wiimote(frameobj): + global wm,wiimote_hwaddr + try: + #if False: + print "Press 1+2 Now !!!!" + sys.stdout.flush() + wm = cwiid.Wiimote(wiimote_hwaddr) + if wm is not None: + # each message will contain info about ir and buttons + wm.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_EXT # | cwiid.RPT_STATUS | cwiid.RPT_IR | + # tell cwiid to use the callback interface and allways send button events + wm.enable(cwiid.FLAG_MESG_IFC) + #| cwiid.FLAG_NONBLOCK + #| cwiid.FLAG_REPEAT_BTN) - # specify wich function will manage messages AFTER the other settings - wm.mesg_callback = cback + # specify wich function will manage messages AFTER the other settings + wm.mesg_callback = cback - # quick check on the wiimote - print "Got Wiimote!" - st = wm.state - for e in st: - print str(e).ljust(8), ">", st[e] -except: -#else: - print "Error with wiimote " + str(wiimote_hwaddr) - + # quick check on the wiimote + print "Got Wiimote!" + frameobj.label_1.SetLabel("Got Wiimote !") + st = wm.state + for e in st: + print str(e).ljust(8), ">", st[e] + except: + #else: + print "Error with wiimote " + str(wiimote_hwaddr) + frameobj.label_1.SetLabel("Wiimote NOK") + sys.stdout.flush() + def _runtime_cleanup(): - print "_runtime_cleanup() Called" - runing = 0 if wm is not None: wm.close() + +def start_manu(self,evt): + self.label_1.SetLabel("press 1+2 now !!!") + wx.CallAfter(Connect_Wiimote, self) + evt.Skip() +HMIFrame.start_manu = start_manu + +def _runtime_begin(): + pass + #wx.CallAfter(Connect_Wiimote) +#Thread(target=Connect_Wiimote).start() + +#create_frame() +#wx.Yield() \ No newline at end of file