Now python files provided by extentions have init, start, stop and cleanup hooks
authorEdouard Tisserant
Thu, 04 Apr 2013 11:13:28 +0900
changeset 1014 e2f7d6c95db0
parent 1013 d54ca1ec9090
child 1018 6b7ba640f49e
Now python files provided by extentions have init, start, stop and cleanup hooks
runtime/PLCObject.py
svgui/svgui.py
tests/logging/plc.xml
tests/logging/py_ext_0@py_ext/py_ext.xml
wxglade_hmi/wxglade_hmi.py
--- a/runtime/PLCObject.py	Thu Apr 04 11:12:30 2013 +0900
+++ b/runtime/PLCObject.py	Thu Apr 04 11:13:28 2013 +0900
@@ -67,7 +67,7 @@
         self.hmi_frame = None
         self.website = website
         self._loading_error = None
-        self.python_threads_vars = None
+        self.python_runtime_vars = None
         
         # Get the last transfered PLC if connector must be restart
         try:
@@ -231,49 +231,63 @@
         self.PLClibraryLock.release()
         return False
 
-    def PrepareRuntimePy(self):
-        self.python_threads_vars = globals().copy()
-        self.python_threads_vars["WorkingDir"] = self.workingdir
-        self.python_threads_vars["website"] = self.website
-        self.python_threads_vars["_runtime_begin"] = []
-        self.python_threads_vars["_runtime_cleanup"] = []
-        self.python_threads_vars["PLCObject"] = self
-        self.python_threads_vars["PLCBinary"] = self.PLClibraryHandle
+    def PythonRuntimeCall(self, methodname):
+        """ 
+        Calls init, start, stop or cleanup method provided by 
+        runtime python files, loaded when new PLC uploaded
+        """
+        try :
+            for method in self.python_runtime_vars.get("_runtime_%s"%methodname, []):
+                res,exp = self.evaluator(method)
+                if exp is not None: raise(exp)
+        except:
+            self.LogMessage(0,traceback.format_exc())
+            raise
+
+    def PythonRuntimeInit(self):
+        MethodNames = ["init", "start", "stop", "cleanup"]
+        self.python_runtime_vars = globals().copy()
+        self.python_runtime_vars["WorkingDir"] = self.workingdir
+        self.python_runtime_vars["website"] = self.website
+        for methodname in MethodNames :
+            self.python_runtime_vars["_runtime_%s"%methodname] = []
+        self.python_runtime_vars["PLCObject"] = self
+        self.python_runtime_vars["PLCBinary"] = self.PLClibraryHandle
         
         try:
             for filename in os.listdir(self.workingdir):
                 name, ext = os.path.splitext(filename)
                 if name.upper().startswith("RUNTIME") and ext.upper() == ".PY":
-                    execfile(os.path.join(self.workingdir, filename), self.python_threads_vars)
-                    runtime_begin = self.python_threads_vars.get("_%s_begin" % name, None)
-                    if runtime_begin is not None:
-                        self.python_threads_vars["_runtime_begin"].append(runtime_begin)
-                    runtime_cleanup = self.python_threads_vars.get("_%s_cleanup" % name, None)
-                    if runtime_cleanup is not None:
-                        self.python_threads_vars["_runtime_cleanup"].append(runtime_cleanup)
-            
-            for runtime_begin in self.python_threads_vars.get("_runtime_begin", []):
-                runtime_begin()
+                    execfile(os.path.join(self.workingdir, filename), self.python_runtime_vars)
+                    for methodname in MethodNames: 
+                        method = self.python_runtime_vars.get("_%s_%s" % (name, methodname), None)
+                        if method is not None:
+                            self.python_runtime_vars["_runtime_%s"%methodname].append(method)
+            
         except:
             self.LogMessage(0,traceback.format_exc())
             raise
             
+        self.PythonRuntimeCall("init")
+
         if self.website is not None:
             self.website.PLCStarted()
 
-    def FinishRuntimePy(self):
-        for runtime_cleanup in self.python_threads_vars.get("_runtime_cleanup", []):
-            runtime_cleanup()    
+
+    def PythonRuntimeCleanup(self):
+        if self.python_runtime_vars is not None:
+            self.PythonRuntimeCall("cleanup")
+
         if self.website is not None:
             self.website.PLCStopped()
-        self.python_threads_vars = None
+
+        self.python_runtime_vars = None
 
     def PythonThreadProc(self):
         self.PLCStatus = "Started"
         self.StatusChange()
         self.StartSem.release()
-        res,exp = self.evaluator(self.PrepareRuntimePy)
-        if exp is not None: raise(exp)
+        self.PythonRuntimeCall("start")
         res,cmd,blkid = "None","None",ctypes.c_void_p()
         compile_cache={}
         while True:
@@ -284,24 +298,23 @@
             if cmd is None:
                 break
             try :
-                self.python_threads_vars["FBID"]=FBID
+                self.python_runtime_vars["FBID"]=FBID
                 ccmd,AST =compile_cache.get(FBID, (None,None))
                 if ccmd is None or ccmd!=cmd:
                     AST = compile(cmd, '<plc>', 'eval')
                     compile_cache[FBID]=(cmd,AST)
-                result,exp = self.evaluator(eval,cmd,self.python_threads_vars)
+                result,exp = self.evaluator(eval,cmd,self.python_runtime_vars)
                 if exp is not None: 
                     raise(exp)
                 else:
                     res=str(result)
-                self.python_threads_vars["FBID"]=None
+                self.python_runtime_vars["FBID"]=None
             except Exception,e:
                 res = "#EXCEPTION : "+str(e)
                 self.LogMessage(1,('PyEval@0x%x(Code="%s") Exception "%s"')%(FBID,cmd,str(e)))
         self.PLCStatus = "Stopped"
         self.StatusChange()
-        exp,res = self.evaluator(self.FinishRuntimePy)
-        if exp is not None: raise(exp)
+        self.PythonRuntimeCall("stop")
     
     def StartPLC(self):
         if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped":
@@ -347,6 +360,8 @@
             NewFileName = md5sum + lib_ext
             extra_files_log = os.path.join(self.workingdir,"extra_files.txt")
 
+            self.PythonRuntimeCleanup()
+
             self._FreePLC()
             self.LogMessage("NewPLC (%s)"%md5sum)
             self.PLCStatus = "Empty"
@@ -387,6 +402,10 @@
 
             if self._LoadNewPLC():
                 self.PLCStatus = "Stopped"
+                try:
+                    self.PythonRuntimeInit()
+                except:
+                    self.PLCStatus = "Broken"
             else:
                 self._FreePLC()
             self.StatusChange()
--- a/svgui/svgui.py	Thu Apr 04 11:12:30 2013 +0900
+++ b/svgui/svgui.py	Thu Apr 04 11:13:28 2013 +0900
@@ -72,10 +72,10 @@
         runtimefile = open(runtimefile_path, 'w')
         runtimefile.write(svguiservercode % {"svgfile" : "gui.svg"})
         runtimefile.write("""
-def _runtime_%(location)s_begin():
+def _runtime_%(location)s_start():
     website.LoadHMI(%(svgui_class)s, %(jsmodules)s)
     
-def _runtime_%(location)s_cleanup():
+def _runtime_%(location)s_stop():
     website.UnLoadHMI()
     
 """ % {"location": location_str,
--- a/tests/logging/plc.xml	Thu Apr 04 11:12:30 2013 +0900
+++ b/tests/logging/plc.xml	Thu Apr 04 11:13:28 2013 +0900
@@ -8,7 +8,7 @@
               productVersion="1"
               creationDateTime="2013-01-29T14:01:00"/>
   <contentHeader name="Unnamed"
-                 modificationDateTime="2013-02-26T16:22:11">
+                 modificationDateTime="2013-04-04T11:06:06">
     <coordinateInfo>
       <fbd>
         <scaling x="0" y="0"/>
--- a/tests/logging/py_ext_0@py_ext/py_ext.xml	Thu Apr 04 11:12:30 2013 +0900
+++ b/tests/logging/py_ext_0@py_ext/py_ext.xml	Thu Apr 04 11:13:28 2013 +0900
@@ -1,23 +1,26 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <Python xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="py_ext_xsd.xsd">
-<![CDATA[import threading
+<![CDATA[import threading, time
 
 MyT = None
 Stop = False
 
+def StartLog():
+    global MyT
+    MyT=threading.Thread(target = DoLog)
+    MyT.start()
+
 def DoLog():
-    global MyT,Stop
-    MyT=threading.Timer(0.3, DoLog)
-    if not Stop : MyT.start()
-    Stop = False
-    PLCObject.LogMessage("Python side Logging")
+    global Stop
+    while not Stop:
+        PLCObject.LogMessage("Python side Logging (PLC is %s)"%PLCObject.PLCStatus)
+        time.sleep(0.3)
 
 def StopLog():
     global MyT,Stop
     Stop=True
-    if MyT is not None: MyT.cancel()
 
-_runtime_begin.append(DoLog)
+_runtime_init.append(StartLog)
 _runtime_cleanup.append(StopLog)
 ]]>
 </Python>
--- a/wxglade_hmi/wxglade_hmi.py	Thu Apr 04 11:12:30 2013 +0900
+++ b/wxglade_hmi/wxglade_hmi.py	Thu Apr 04 11:13:28 2013 +0900
@@ -73,7 +73,7 @@
         runtimefile.write("""
 %(declare)s
 
-def _runtime_%(location)s_begin():
+def _runtime_%(location)s_start():
     global %(global)s
     
     def OnCloseFrame(evt):
@@ -81,7 +81,7 @@
     
     %(init)s
     
-def _runtime_%(location)s_cleanup():
+def _runtime_%(location)s_stop():
     global %(global)s
     
     %(cleanup)s