--- a/ProjectController.py Thu Jan 29 19:11:34 2015 +0100
+++ b/ProjectController.py Fri Jan 30 10:45:11 2015 +0100
@@ -13,6 +13,7 @@
from time import localtime
from datetime import datetime
from weakref import WeakKeyDictionary
+from itertools import izip @@ -28,6 +29,7 @@
from PLCControler import PLCControler
from plcopen.structures import IEC_KEYWORDS
from targets.typemapping import DebugTypesSize, LogLevelsCount, LogLevels
+from targets.typemapping import UnpackDebugBuffer from ConfigTreeNode import ConfigTreeNode, XSDSchemaErrorMessage
base_folder = os.path.split(sys.path[0])[0]
@@ -736,6 +738,7 @@
+ self.TracedIECTypes = [] def GetIECProgramsAndVariables(self):
@@ -1213,7 +1216,7 @@
def SnapshotAndResetDebugValuesBuffers(self):
buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers,
- [list() for iec_path in self.TracedIECPath])
+ [list() for n in xrange(len(self.TracedIECPath))]) ticks, self.DebugTicks = self.DebugTicks, []
@@ -1221,6 +1224,7 @@
+ self.TracedIECTypes = [] if self._connector is not None:
self.IECdebug_lock.acquire()
@@ -1245,8 +1249,10 @@
- self.TracedIECPath = zip(*Idxs)[3]
- self._connector.SetTraceVariablesList(zip(*zip(*Idxs)[0:3]))
+ self.TracedIECPath = IdxsT[3] + self.TracedIECTypes = IdxsT[1] + self._connector.SetTraceVariablesList(zip(*IdxsT[0:3])) self._connector.SetTraceVariablesList([])
@@ -1388,21 +1394,24 @@
while (not self.debug_break) and (self._connector is not None):
Trace = self._connector.GetTraceVariables()
- plc_status, debug_tick, debug_vars = Trace
+ plc_status, debug_tick, debug_buff = Trace #print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()]
- if plc_status == "Started":
+ if plc_status == "Started" and debug_buff is not None: self.IECdebug_lock.acquire()
- if (debug_tick is not None and
- len(debug_vars) == len(self.DebugValuesBuffers) and
+ debug_vars = UnpackDebugBuffer(debug_buff, self.TracedIECTypes) + if (debug_tick is not None and debug_vars is not None and len(debug_vars) == len(self.TracedIECPath)):
if debug_getvar_retry > DEBUG_RETRIES_WARN:
self.logger.write(_("... debugger recovered\n"))
- for IECPath, values_buffer, value in zip(self.TracedIECPath, self.DebugValuesBuffers, debug_vars):
- IECdebug_data = self.IECdebug_datas.get(IECPath, None)
+ for IECPath, values_buffer, value in izip( + self.DebugValuesBuffers, + IECdebug_data = self.IECdebug_datas.get(IECPath, None) #FIXME get if IECdebug_data is not None and value is not None:
forced = IECdebug_data[2:4] == ["Forced", value]
if not IECdebug_data[4] and len(values_buffer) > 0:
@@ -1432,7 +1441,7 @@
self.IECdebug_lock.release()
if len(self.TracedIECPath) == len(buffers):
- for IECPath, values in zip(self.TracedIECPath, buffers):
+ for IECPath, values in izip(self.TracedIECPath, buffers): self.CallWeakcallables(IECPath, "NewValues", debug_ticks, values)
--- a/runtime/PLCObject.py Thu Jan 29 19:11:34 2015 +0100
+++ b/runtime/PLCObject.py Fri Jan 30 10:45:11 2015 +0100
@@ -2,7 +2,7 @@
#This file is part of Beremiz, a Integrated Development Environment for
-#programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
+#programming IEC 61131-3 automates supporting plcopen standard and CanFestival. #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
@@ -68,7 +68,7 @@
self._loading_error = None
self.python_runtime_vars = None
# Get the last transfered PLC if connector must be restart
self.CurrentPLCFilename=open(
@@ -107,7 +107,7 @@
tv_nsec = ctypes.c_uint32()
if self._GetLogMessage is not None:
maxsz = len(self._log_read_buffer)-1
- sz = self._GetLogMessage(level, msgid,
+ sz = self._GetLogMessage(level, msgid, self._log_read_buffer, maxsz,
@@ -134,23 +134,23 @@
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_real = self.PLClibraryHandle.stopPLC
self._stopPLC_real.restype = None
self._PythonIterator = getattr(self.PLClibraryHandle, "PythonIterator", None)
if self._PythonIterator is not None:
self._PythonIterator.restype = ctypes.c_char_p
self._PythonIterator.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_void_p)]
self._stopPLC = self._stopPLC_real
# If python confnode is not enabled, we reuse _PythonIterator
- # as a call that block pythonthread until StopPLC
+ # as a call that block pythonthread until StopPLC self.PythonIteratorLock = Lock()
self.PythonIteratorLock.acquire()
def PythonIterator(res, blkid):
@@ -158,25 +158,25 @@
self.PythonIteratorLock.release()
self._PythonIterator = PythonIterator
self.PythonIteratorLock.release()
self._stopPLC = __StopPLC
self._ResetDebugVariables = self.PLClibraryHandle.ResetDebugVariables
self._ResetDebugVariables.restype = None
self._RegisterDebugVariable = self.PLClibraryHandle.RegisterDebugVariable
self._RegisterDebugVariable.restype = None
self._RegisterDebugVariable.argtypes = [ctypes.c_int, ctypes.c_void_p]
self._FreeDebugData = self.PLClibraryHandle.FreeDebugData
self._FreeDebugData.restype = None
self._GetDebugData = self.PLClibraryHandle.GetDebugData
- self._GetDebugData.restype = ctypes.c_int
+ self._GetDebugData.restype = ctypes.c_int self._GetDebugData.argtypes = [ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_void_p)]
self._suspendDebug = self.PLClibraryHandle.suspendDebug
@@ -233,7 +233,7 @@
self._suspendDebug = lambda x:-1
self._resumeDebug = lambda:None
self._PythonIterator = lambda:""
- self._GetLogCount = None
+ self._GetLogCount = None self._LogMessage = lambda l,m,s:PLCprint("OFF LOG :"+m)
self._GetLogMessage = None
self.PLClibraryHandle = None
@@ -241,18 +241,18 @@
if getattr(self,"_PLClibraryHandle",None) is not None:
dlclose(self._PLClibraryHandle)
self._PLClibraryHandle = None
self.PLClibraryLock.release()
def PythonRuntimeCall(self, methodname):
- Calls init, start, stop or cleanup method provided by
+ Calls init, start, stop or cleanup method provided by runtime python files, loaded when new PLC uploaded
for method in self.python_runtime_vars.get("_runtime_%s"%methodname, []):
res,exp = self.evaluator(method)
self.LogMessage(0,'\n'.join(traceback.format_exception(*exp)))
def PythonRuntimeInit(self):
@@ -286,14 +286,14 @@
name, ext = os.path.splitext(filename)
if name.upper().startswith("RUNTIME") and ext.upper() == ".PY":
execfile(os.path.join(self.workingdir, filename), self.python_runtime_vars)
- for methodname in MethodNames:
+ for methodname in MethodNames: method = self.python_runtime_vars.get("_%s_%s" % (name, methodname), None)
self.python_runtime_vars["_runtime_%s"%methodname].append(method)
self.LogMessage(0,traceback.format_exc())
self.PythonRuntimeCall("init")
if self.website is not None:
@@ -319,7 +319,7 @@
# print "_PythonIterator(", res, ")",
cmd = self._PythonIterator(res,blkid)
# print " -> ", cmd, blkid
@@ -330,7 +330,7 @@
AST = compile(cmd, '<plc>', 'eval')
compile_cache[FBID]=(cmd,AST)
result,exp = self.evaluator(eval,AST,self.python_runtime_vars)
res = "#EXCEPTION : "+str(exp[1])
self.LogMessage(1,('PyEval@0x%x(Code="%s") Exception "%s"')%(FBID,cmd,
'\n'.join(traceback.format_exception(*exp))))
@@ -343,7 +343,7 @@
self.PLCStatus = "Stopped"
self.PythonRuntimeCall("stop")
if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped":
c_argv = ctypes.c_char_p * len(self.argv)
@@ -359,7 +359,7 @@
self.LogMessage(0,_("Problem starting PLC : error %d" % res))
self.PLCStatus = "Broken"
if self.PLCStatus == "Started":
self.LogMessage("PLC stopped")
@@ -382,7 +382,7 @@
return self.PLCStatus, map(self.GetLogCount,xrange(LogLevelsCount))
def NewPLC(self, md5sum, data, extrafiles):
if self.PLCStatus in ["Stopped", "Empty", "Broken"]:
NewFileName = md5sum + lib_ext
@@ -403,15 +403,15 @@
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:
@@ -443,12 +443,10 @@
def SetTraceVariablesList(self, idxs):
- Call ctype imported function to append
+ Call ctype imported function to append these indexes to registred variables in PLC debugger
@@ -462,7 +460,7 @@
c_type,unpack_func, pack_func = \
TypeTranslator.get(iectype,
- force = ctypes.byref(pack_func(c_type,force))
+ force = ctypes.byref(pack_func(c_type,force)) self._RegisterDebugVariable(idx, force)
@@ -477,18 +475,18 @@
if self.PLClibraryLock.acquire(False):
if self._GetDebugData(ctypes.byref(tick),
ctypes.byref(buff)) == 0:
- TraceVariables = UnpackDebugBuffer(buff, size.value, self._Idxs)
+ TraceBuffer = ctypes.string_at(buff.value, size.value) self.PLClibraryLock.release()
- if TraceVariables is not None:
- return self.PLCStatus, tick.value, TraceVariables
- return self.PLCStatus, None, []
+ if TraceBuffer is not None: + return self.PLCStatus, tick.value, TraceBuffer + return self.PLCStatus, None, None def RemoteExec(self, script, **kwargs):
@@ -496,8 +494,8 @@
e_type, e_value, e_traceback = sys.exc_info()
line_no = traceback.tb_lineno(get_last_traceback(e_traceback))
- return (-1, "RemoteExec script failed!\n\nLine %d: %s\n\t%s" %
+ return (-1, "RemoteExec script failed!\n\nLine %d: %s\n\t%s" % (line_no, e_value, script.splitlines()[line_no - 1]))
return (0, kwargs.get("returnVal", None))
--- a/targets/typemapping.py Thu Jan 29 19:11:34 2015 +0100
+++ b/targets/typemapping.py Fri Jan 30 10:45:11 2015 +0100
@@ -19,6 +19,11 @@
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ctypes.pythonapi.PyString_AsString.argtypes = (ctypes.c_void_p,) +ctypes.pythonapi.PyString_AsString.restype = ctypes.POINTER(ctypes.c_char) from datetime import timedelta as td
@@ -27,7 +32,7 @@
Must be changed according to changes in iec_types.h
_fields_ = [("len", c_uint8),
- ("body", c_char * 126)]
+ ("body", c_char * 126)] class IEC_TIME(Structure):
@@ -37,8 +42,8 @@
def _t(t, u=lambda x:x.value, p=lambda t,x:t(x)): return (t, u, p)
-def _ttime(): return (IEC_TIME,
- lambda x:td(0, x.s, x.ns/1000),
+def _ttime(): return (IEC_TIME, + lambda x:td(0, x.s, x.ns/1000), lambda t,x:t(x.days * 24 * 3600 + x.seconds, x.microseconds*1000))
SameEndianessTypeTranslator = {
@@ -49,8 +54,8 @@
- "STRING" : (IEC_STRING,
- lambda x:x.body[:x.len],
+ "STRING" : (IEC_STRING, + lambda x:x.body[:x.len], @@ -67,38 +72,35 @@
SwapedEndianessTypeTranslator = {
TypeTranslator=SameEndianessTypeTranslator
# Construct debugger natively supported types
DebugTypesSize = dict([(key,sizeof(t)) for key,(t,p,u) in SameEndianessTypeTranslator.iteritems() if t is not None])
-def UnpackDebugBuffer(buff, size, indexes):
- for idx, iectype, forced in indexes:
- cursor = c_void_p(buff.value + offset)
+def UnpackDebugBuffer(buff, indexes): + buffptr = cast(ctypes.pythonapi.PyString_AsString(id(buff)),c_void_p).value + for iectype in indexes: c_type,unpack_func, pack_func = \
TypeTranslator.get(iectype,
- if c_type is not None and offset < size:
- res.append(unpack_func(
- POINTER(c_type)).contents))
- offset += sizeof(c_type) if iectype != "STRING" else len(res[-1])+1
+ if c_type is not None and buffoffset < buffsize: + cursor = c_void_p( buffptr + buffoffset) + value = unpack_func( cast(cursor, + POINTER(c_type)).contents) + buffoffset += sizeof(c_type) if iectype != "STRING" else len(value)+1
- # PLCprint("Debug error - " + iectype +
- # PLCprint("Debug error - buffer too small ! %d != %d"%(offset, size))
- if offset and offset == size:
+ if buffoffset and buffoffset == buffsize: