23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 |
24 |
25 import Pyro.core as pyro |
25 import Pyro.core as pyro |
26 from threading import Timer, Thread |
26 from threading import Timer, Thread |
27 import ctypes, os, commands |
27 import ctypes, os, commands |
|
28 import sys |
28 |
29 |
29 if os.name in ("nt", "ce"): |
30 if os.name in ("nt", "ce"): |
30 from _ctypes import LoadLibrary as dlopen |
31 from _ctypes import LoadLibrary as dlopen |
31 from _ctypes import FreeLibrary as dlclose |
32 from _ctypes import FreeLibrary as dlclose |
32 elif os.name == "posix": |
33 elif os.name == "posix": |
36 |
37 |
37 lib_ext ={ |
38 lib_ext ={ |
38 "linux2":".so", |
39 "linux2":".so", |
39 "win32":".dll", |
40 "win32":".dll", |
40 }.get(sys.platform, "") |
41 }.get(sys.platform, "") |
|
42 |
|
43 def PLCprint(message): |
|
44 sys.stdout.write("PLCobject : "+message+"\n") |
|
45 sys.stdout.flush() |
41 |
46 |
42 class PLCObject(pyro.ObjBase): |
47 class PLCObject(pyro.ObjBase): |
43 _Idxs = [] |
48 _Idxs = [] |
44 def __init__(self, workingdir, daemon, argv, statuschange=None): |
49 def __init__(self, workingdir, daemon, argv, statuschange=None): |
45 pyro.ObjBase.__init__(self) |
50 pyro.ObjBase.__init__(self) |
76 def _LoadNewPLC(self): |
81 def _LoadNewPLC(self): |
77 """ |
82 """ |
78 Load PLC library |
83 Load PLC library |
79 Declare all functions, arguments and return values |
84 Declare all functions, arguments and return values |
80 """ |
85 """ |
81 print "Load PLC" |
86 PLCprint("Load PLC") |
82 try: |
87 try: |
83 self._PLClibraryHandle = dlopen(self._GetLibFileName()) |
88 self._PLClibraryHandle = dlopen(self._GetLibFileName()) |
84 self.PLClibraryHandle = ctypes.CDLL(self.CurrentPLCFilename, handle=self._PLClibraryHandle) |
89 self.PLClibraryHandle = ctypes.CDLL(self.CurrentPLCFilename, handle=self._PLClibraryHandle) |
85 |
90 |
86 self._startPLC = self.PLClibraryHandle.startPLC |
91 self._startPLC = self.PLClibraryHandle.startPLC |
139 self._resumeDebug = lambda:None |
144 self._resumeDebug = lambda:None |
140 self._PythonIterator = lambda:"" |
145 self._PythonIterator = lambda:"" |
141 self.PLClibraryHandle = None |
146 self.PLClibraryHandle = None |
142 # Unload library explicitely |
147 # Unload library explicitely |
143 if getattr(self,"_PLClibraryHandle",None) is not None: |
148 if getattr(self,"_PLClibraryHandle",None) is not None: |
144 print "Unload PLC" |
149 PLCprint("Unload PLC") |
145 dlclose(self._PLClibraryHandle) |
150 dlclose(self._PLClibraryHandle) |
146 res = self._DetectDirtyLibs() |
151 res = self._DetectDirtyLibs() |
147 else: |
152 else: |
148 res = False |
153 res = False |
149 |
154 |
166 "libatk", |
171 "libatk", |
167 "libpan", |
172 "libpan", |
168 "libX11", |
173 "libX11", |
169 ]: |
174 ]: |
170 #badhandle = dlopen(badlib, dl.RTLD_NOLOAD) |
175 #badhandle = dlopen(badlib, dl.RTLD_NOLOAD) |
171 print "Dirty lib detected :" + badlib |
176 PLCprint("Dirty lib detected :" + badlib) |
172 #dlclose(badhandle) |
177 #dlclose(badhandle) |
173 return True |
178 return True |
174 return False |
179 return False |
175 |
180 |
176 def PythonThreadProc(self): |
181 def ExecRuntimePy(self): |
177 print "PythonThreadProc started" |
|
178 self.python_threads_vars = globals().copy() |
182 self.python_threads_vars = globals().copy() |
179 pyfile = os.path.join(self.workingdir, "runtime.py") |
183 pyfile = os.path.join(self.workingdir, "runtime.py") |
180 if os.path.exists(pyfile): |
184 if os.path.exists(pyfile): |
181 # TODO handle exceptions in runtime.py |
185 # TODO handle exceptions in runtime.py |
182 # pyfile may redefine _runtime_cleanup |
186 # pyfile may redefine _runtime_cleanup |
183 # or even call _PythonThreadProc itself. |
187 # or even call _PythonThreadProc itself. |
184 execfile(pyfile, self.python_threads_vars) |
188 execfile(pyfile, self.python_threads_vars) |
|
189 |
|
190 def FinishRuntimePy(self): |
|
191 if self.python_threads_vars.get("_runtime_cleanup",None) is not None: |
|
192 self.python_threads_vars["_runtime_cleanup"]() |
|
193 self.python_threads_vars = None |
|
194 |
|
195 def PythonThreadProc(self): |
|
196 PLCprint("PythonThreadProc started") |
185 res,cmd = "None","None" |
197 res,cmd = "None","None" |
186 while self.PLCStatus == "Started": |
198 while self.PLCStatus == "Started": |
187 #print "_PythonIterator(", res, ")", |
199 #print "_PythonIterator(", res, ")", |
188 cmd = self._PythonIterator(res) |
200 cmd = self._PythonIterator(res) |
189 #print " -> ", cmd |
201 #print " -> ", cmd |
191 break |
203 break |
192 try : |
204 try : |
193 res = str(eval(cmd,self.python_threads_vars)) |
205 res = str(eval(cmd,self.python_threads_vars)) |
194 except Exception,e: |
206 except Exception,e: |
195 res = "#EXCEPTION : "+str(e) |
207 res = "#EXCEPTION : "+str(e) |
196 print res |
208 PLCprint(res) |
197 print "PythonThreadProc interrupted" |
209 PLCprint("PythonThreadProc interrupted") |
198 if self.python_threads_vars.get("_runtime_cleanup",None) is not None: |
|
199 self.python_threads_vars["_runtime_cleanup"]() |
|
200 self.python_threads_vars = None |
|
201 print "PythonThreadProc cleaned up" |
|
202 |
210 |
203 def StartPLC(self, debug=False): |
211 def StartPLC(self, debug=False): |
204 print "StartPLC" |
212 PLCprint("StartPLC") |
205 if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped": |
213 if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped": |
206 c_argv = ctypes.c_char_p * len(self.argv) |
214 c_argv = ctypes.c_char_p * len(self.argv) |
207 if self._LoadNewPLC() and self._startPLC(len(self.argv),c_argv(*self.argv)) == 0: |
215 if self._LoadNewPLC() and self._startPLC(len(self.argv),c_argv(*self.argv)) == 0: |
208 if debug: |
216 if debug: |
209 self._resumeDebug() |
217 self._resumeDebug() |
210 self.PLCStatus = "Started" |
218 self.PLCStatus = "Started" |
211 self.StatusChange() |
219 self.StatusChange() |
|
220 self.ExecRuntimePy() |
212 self.PythonThread = Thread(target=self.PythonThreadProc) |
221 self.PythonThread = Thread(target=self.PythonThreadProc) |
213 self.PythonThread.start() |
222 self.PythonThread.start() |
214 return True |
223 return True |
215 else: |
224 else: |
216 print "_StartPLC did not return 0 !" |
225 PLCprint("Problem starting PLC") |
217 self._DoStopPLC() |
226 self._DoStopPLC() |
218 return False |
227 return False |
219 |
228 |
220 def _DoStopPLC(self): |
229 def _DoStopPLC(self): |
221 self._stopPLC() |
230 self._stopPLC() |
222 self.PLCStatus = "Stopped" |
231 self.PLCStatus = "Stopped" |
223 self.PythonThread.join(timeout=1) |
232 self.PythonThread.join(timeout=1) |
224 if self.PythonThread.isAlive(): |
233 if self.PythonThread.isAlive(): |
225 print "Python thread couldn't be killed" |
234 PLCprint("Python thread couldn't be killed") |
|
235 self.FinishRuntimePy() |
226 if self._FreePLC(): |
236 if self._FreePLC(): |
227 self.PLCStatus = "Dirty" |
237 self.PLCStatus = "Dirty" |
228 self.StatusChange() |
238 self.StatusChange() |
229 return True |
239 return True |
230 |
240 |
248 |
258 |
249 def GetPLCstatus(self): |
259 def GetPLCstatus(self): |
250 return self.PLCStatus |
260 return self.PLCStatus |
251 |
261 |
252 def NewPLC(self, md5sum, data, extrafiles): |
262 def NewPLC(self, md5sum, data, extrafiles): |
253 print "NewPLC (%s)"%md5sum |
263 PLCprint("NewPLC (%s)"%md5sum) |
254 if self.PLCStatus in ["Stopped", "Empty", "Dirty"]: |
264 if self.PLCStatus in ["Stopped", "Empty", "Dirty"]: |
255 NewFileName = md5sum + lib_ext |
265 NewFileName = md5sum + lib_ext |
256 extra_files_log = os.path.join(self.workingdir,"extra_files.txt") |
266 extra_files_log = os.path.join(self.workingdir,"extra_files.txt") |
257 try: |
267 try: |
258 os.remove(os.path.join(self.workingdir, |
268 os.remove(os.path.join(self.workingdir, |
281 log.write(fname+'\n') |
291 log.write(fname+'\n') |
282 |
292 |
283 # Store new PLC filename |
293 # Store new PLC filename |
284 self.CurrentPLCFilename = NewFileName |
294 self.CurrentPLCFilename = NewFileName |
285 except: |
295 except: |
286 print traceback.format_exc() |
296 PLCprint(traceback.format_exc()) |
287 return False |
297 return False |
288 if self.PLCStatus == "Empty": |
298 if self.PLCStatus == "Empty": |
289 self.PLCStatus = "Stopped" |
299 self.PLCStatus = "Stopped" |
290 return True |
300 return True |
291 return False |
301 return False |
357 c_type,unpack_func = self.TypeTranslator.get(typename.value, (None,None)) |
367 c_type,unpack_func = self.TypeTranslator.get(typename.value, (None,None)) |
358 if c_type is not None and given_idx == idx.value: |
368 if c_type is not None and given_idx == idx.value: |
359 res.append(unpack_func(ctypes.cast(buffer, |
369 res.append(unpack_func(ctypes.cast(buffer, |
360 ctypes.POINTER(c_type)).contents)) |
370 ctypes.POINTER(c_type)).contents)) |
361 else: |
371 else: |
362 print "Debug error idx : %d, expected_idx %d, type : %s"%(idx.value, given_idx,typename.value) |
372 PLCprint("Debug error idx : %d, expected_idx %d, type : %s"%(idx.value, given_idx,typename.value)) |
363 res.append(None) |
373 res.append(None) |
364 self._FreeDebugData() |
374 self._FreeDebugData() |
365 return tick, res |
375 return tick, res |
366 return -1, None |
376 return -1, None |
367 |
377 |