#This file is part of Beremiz, a Integrated Development Environment for
#programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
#See COPYING file for copyrights details.
#This library is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public
#License as published by the Free Software Foundation; either
#version 2.1 of the License, or (at your option) any later version.
#This library is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#General Public License for more details.
#You should have received a copy of the GNU General Public
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
from threading import Timer
import ctypes, os, dl, commands
#sys.setdlopenflags(dl.RTLD_NOW | dl.RTLD_GLOBAL)
if os.name == ("nt", "ce"):
from _ctypes import LoadLibrary as dlopen
from _ctypes import FreeLibrary as dlclose
from _ctypes import dlopen, dlclose
class PLCObject(pyro.ObjBase):
def __init__(self, workingdir, daemon):
pyro.ObjBase.__init__(self)
self.workingdir = workingdir
self.PLCStatus = "Stopped"
self.PLClibraryHandle = None
# Creates fake C funcs proxies
# Get the last transfered PLC if connector must be restart
self.CurrentPLCFilename=open(
"r").read().strip() + lib_ext
self.CurrentPLCFilename=None
def _GetMD5FileName(self):
return os.path.join(self.workingdir, "lasttransferedPLC.md5")
def _GetLibFileName(self):
return os.path.join(self.workingdir,self.CurrentPLCFilename)
Declare all functions, arguments and return values
self._PLClibraryHandle = dlopen(self._GetLibFileName())
self.PLClibraryHandle = ctypes.CDLL(self.CurrentPLCFilename, handle=self._PLClibraryHandle)
self._startPLC = self.PLClibraryHandle.startPLC
self._startPLC.restype = ctypes.c_int
self._startPLC.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_char_p)]
self._stopPLC = self.PLClibraryHandle.stopPLC
self._stopPLC.restype = None
self._ResetDebugVariables = self.PLClibraryHandle.ResetDebugVariables
self._ResetDebugVariables.restype = None
self._RegisterDebugVariable = self.PLClibraryHandle.ResetDebugVariables
self._RegisterDebugVariable.restype = None
self._IterDebugData = self.PLClibraryHandle.IterDebugData
self._IterDebugData.restype = ctypes.c_void_p
self._IterDebugData.argtypes = [ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_char_p)]
self._FreeDebugData = self.PLClibraryHandle.FreeDebugData
self._FreeDebugData.restype = None
print traceback.format_exc()
This is also called by __init__ to create dummy C func proxies
# Forget all refs to library
self._startPLC = lambda:None
self._stopPLC = lambda:None
self._ResetDebugVariables = lambda:None
self._RegisterDebugVariable = lambda x:None
self._IterDebugData = lambda x,y:None
self._FreeDebugData = lambda:None
self.PLClibraryHandle = None
# Unload library explicitely
if getattr(self,"_PLClibraryHandle",None) is not None:
dlclose(self._PLClibraryHandle)
res = self._DetectDirtyLibs()
self._PLClibraryHandle = None
def _DetectDirtyLibs(self):
# Get lib dependencies (for dirty lib detection)
# parasiting libs listed with ldd
badlibs = [ toks.split()[0] for toks in commands.getoutput(
"ldd "+self._GetLibFileName()).splitlines() ]
if badlib[:6] in ["libwx_",
badhandle = dlopen(badlib, dl.RTLD_NOLOAD)
print "Dirty lib detected :" + badlib
if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped":
c_argv = ctypes.c_char_p * len(sys.argv)
if self._LoadNewPLC() and self._startPLC(len(sys.argv),c_argv(*sys.argv)) == 0:
self.PLCStatus = "Started"
print "_StartPLC did not return 0 !"
if self.PLCStatus == "Started":
self.PLCStatus = "Stopped"
self.daemon.shutdown(True)
os.execv(sys.executable,[sys.executable]+sys.argv[:])
# respawn python interpreter
Timer(0.1,self._Reload).start()
def NewPLC(self, md5sum, data, extrafiles):
print "NewPLC (%s)"%md5sum
if self.PLCStatus in ["Stopped", "Empty", "Dirty"]:
NewFileName = md5sum + lib_ext
extra_files_log = os.path.join(self.workingdir,"extra_files.txt")
os.remove(os.path.join(self.workingdir,
self.CurrentPLCFilename))
for filename in file(extra_files_log, "r").readlines() + extra_files_log:
os.remove(os.path.join(self.workingdir, filename))
open(os.path.join(self.workingdir,NewFileName),
# Store new PLC filename based on md5 key
open(self._GetMD5FileName(), "w").write(md5sum)
log = file(extra_files_log, "w")
for fname,fdata in extrafiles:
fpath = os.path.join(self.workingdir,fname)
open(fpath, "wb").write(fdata)
self.CurrentPLCFilename = NewFileName
print traceback.format_exc()
if self.PLCStatus == "Empty":
self.PLCStatus = "Stopped"
last_md5 = open(self._GetMD5FileName(), "r").read()
def SetTraceVariablesList(self, idxs):
Call ctype imported function to append
these indexes to registred variables in PLC debugger
# keep a copy of requested idx
self._ResetDebugVariables()
self._RegisterDebugVariable(idx)
def GetTraceVariables(self):
Return a list of variables, corresponding to the list of requiered idx
buffer=self._IterDebugData()