# HG changeset patch # User Edouard TISSERANT # Date 1259755677 -3600 # Node ID 9d5036e86c3db6466887ebe73a834832a057e569 # Parent 8ef035de86de283844a258585704269717d10cf1# Parent 1b1dc8ad2498f246817991cd96b93149d383503b merge diff -r 1b1dc8ad2498 -r 9d5036e86c3d Beremiz.py --- a/Beremiz.py Wed Dec 02 10:24:09 2009 +0100 +++ b/Beremiz.py Wed Dec 02 13:07:57 2009 +0100 @@ -28,6 +28,7 @@ import tempfile import shutil import random +import time CWD = os.path.split(os.path.realpath(__file__))[0] @@ -252,6 +253,8 @@ self.black_white = wx.TextAttr("BLACK", "WHITE") self.default_style = None self.output = output + # to prevent rapid fire on rising log panel + self.rising_timer = 0 def write(self, s, style = None): if style is None : style=self.black_white @@ -263,6 +266,10 @@ self.output.ScrollLines(s.count('\n')+1) self.output.ShowPosition(self.output.GetLastPosition()) self.output.Thaw() + newtime = time.time() + if newtime - self.rising_timer > 1: + self.output.Rise() + self.rising_timer = newtime def write_warning(self, s): self.write(s,self.red_white) @@ -376,6 +383,7 @@ self.LogConsole = wx.TextCtrl(id=ID_BEREMIZLOGCONSOLE, value='', name='LogConsole', parent=self.BottomNoteBook, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TE_MULTILINE|wx.TE_RICH2) + self.LogConsole.Rise = self.RiseLogConsole self.LogConsole.Bind(wx.EVT_LEFT_DCLICK, self.OnLogConsoleDClick) self.BottomNoteBook.AddPage(self.LogConsole, _("Log Console")) @@ -422,6 +430,13 @@ self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) + def RiseLogConsole(self): + for idx in xrange(self.BottomNoteBook.GetPageCount()): + window = self.BottomNoteBook.GetPage(idx) + if window == self.LogConsole: + self.BottomNoteBook.SetSelection(idx) + break + def RefreshTitle(self): name = _("Beremiz") if self.PluginRoot is not None: diff -r 1b1dc8ad2498 -r 9d5036e86c3d Beremiz_service.py --- a/Beremiz_service.py Wed Dec 02 10:24:09 2009 +0100 +++ b/Beremiz_service.py Wed Dec 02 13:07:57 2009 +0100 @@ -415,7 +415,7 @@ def UpdateIcon(self, plcstatus): if plcstatus is "Started" : currenticon = self.MakeIcon(starticon.GetImage()) - elif plcstatus is "Stopped" or plcstatus is "Starting": + elif plcstatus is "Stopped": currenticon = self.MakeIcon(stopicon.GetImage()) else: currenticon = self.MakeIcon(defaulticon.GetImage()) diff -r 1b1dc8ad2498 -r 9d5036e86c3d connectors/LPC/LPCObject.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/connectors/LPC/LPCObject.py Wed Dec 02 13:07:57 2009 +0100 @@ -0,0 +1,177 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#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, Thread, Lock +import ctypes, os, commands, types, sys +import traceback + +class LPCObject(): + _Idxs = [] + def __init__(self,pluginsroot): + self.PLCStatus = "Stopped" + self.pluginsroot = pluginsroot + self.PLCprint = pluginsroot.logger.write + + def StartPLC(self, debug=False): + PLCprint("StartPLC") + if self.CurrentPLCFilename is not None: + self.PLCStatus = "Started" + self.PythonThread = Thread(target=self.PythonThreadProc, args=[debug]) + self.PythonThread.start() + + def StopPLC(self): + PLCprint("StopPLC") + if self.PLCStatus == "Started": + self._stopPLC() + return True + return False + + def ForceReload(self): + # respawn python interpreter + Timer(0.1,self._Reload).start() + return True + + def GetPLCstatus(self): + return self.PLCStatus + + def NewPLC(self, md5sum, data, extrafiles): + PLCprint("NewPLC (%s)"%md5sum) + if self.PLCStatus in ["Stopped", "Empty", "Broken"]: + NewFileName = md5sum + lib_ext + extra_files_log = os.path.join(self.workingdir,"extra_files.txt") + try: + os.remove(os.path.join(self.workingdir, + self.CurrentPLCFilename)) + for filename in file(extra_files_log, "r").readlines() + [extra_files_log]: + try: + os.remove(os.path.join(self.workingdir, filename.strip())) + except: + pass + except: + pass + + try: + # Create new PLC file + open(os.path.join(self.workingdir,NewFileName), + 'wb').write(data) + + # Store new PLC filename based on md5 key + open(self._GetMD5FileName(), "w").write(md5sum) + + # Then write the files + log = file(extra_files_log, "w") + for fname,fdata in extrafiles: + fpath = os.path.join(self.workingdir,fname) + open(fpath, "wb").write(fdata) + log.write(fname+'\n') + + # Store new PLC filename + self.CurrentPLCFilename = NewFileName + except: + PLCprint(traceback.format_exc()) + return False + if self.PLCStatus == "Empty": + self.PLCStatus = "Stopped" + return True + return False + + def MatchMD5(self, MD5): + try: + last_md5 = open(self._GetMD5FileName(), "r").read() + return last_md5 == MD5 + except: + return False + + def SetTraceVariablesList(self, idxs): + """ + Call ctype imported function to append + these indexes to registred variables in PLC debugger + """ + self._suspendDebug() + # keep a copy of requested idx + self._Idxs = idxs[:] + self._ResetDebugVariables() + for idx in idxs: + self._RegisterDebugVariable(idx) + self._resumeDebug() + + class IEC_STRING(ctypes.Structure): + """ + Must be changed according to changes in iec_types.h + """ + _fields_ = [("len", ctypes.c_uint8), + ("body", ctypes.c_char * 127)] + + TypeTranslator = {"BOOL" : (ctypes.c_uint8, lambda x:x.value!=0), + "STEP" : (ctypes.c_uint8, lambda x:x.value), + "TRANSITION" : (ctypes.c_uint8, lambda x:x.value), + "ACTION" : (ctypes.c_uint8, lambda x:x.value), + "SINT" : (ctypes.c_int8, lambda x:x.value), + "USINT" : (ctypes.c_uint8, lambda x:x.value), + "BYTE" : (ctypes.c_uint8, lambda x:x.value), + "STRING" : (IEC_STRING, lambda x:x.body[:x.len]), + "INT" : (ctypes.c_int16, lambda x:x.value), + "UINT" : (ctypes.c_uint16, lambda x:x.value), + "WORD" : (ctypes.c_uint16, lambda x:x.value), + "WSTRING" : (None, None),#TODO + "DINT" : (ctypes.c_int32, lambda x:x.value), + "UDINT" : (ctypes.c_uint32, lambda x:x.value), + "DWORD" : (ctypes.c_uint32, lambda x:x.value), + "LINT" : (ctypes.c_int64, lambda x:x.value), + "ULINT" : (ctypes.c_uint64, lambda x:x.value), + "LWORD" : (ctypes.c_uint64, lambda x:x.value), + "REAL" : (ctypes.c_float, lambda x:x.value), + "LREAL" : (ctypes.c_double, lambda x:x.value), + } + + def GetTraceVariables(self): + """ + Return a list of variables, corresponding to the list of required idx + """ + if self.PLCStatus == "Started": + self.PLClibraryLock.acquire() + tick = self._WaitDebugData() + #PLCprint("Debug tick : %d"%tick) + if tick == 2**32 - 1: + tick = -1 + res = None + else: + idx = ctypes.c_int() + typename = ctypes.c_char_p() + res = [] + + for given_idx in self._Idxs: + buffer=self._IterDebugData(ctypes.byref(idx), ctypes.byref(typename)) + c_type,unpack_func = self.TypeTranslator.get(typename.value, (None,None)) + if c_type is not None and given_idx == idx.value: + res.append(unpack_func(ctypes.cast(buffer, + ctypes.POINTER(c_type)).contents)) + else: + PLCprint("Debug error idx : %d, expected_idx %d, type : %s"%(idx.value, given_idx,typename.value)) + res.append(None) + self._FreeDebugData() + self.PLClibraryLock.release() + return tick, res + return -1, None + diff -r 1b1dc8ad2498 -r 9d5036e86c3d connectors/LPC/LPCProto.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/connectors/LPC/LPCProto.py Wed Dec 02 13:07:57 2009 +0100 @@ -0,0 +1,88 @@ +import serial +from threading import Lock + +LPC_CMDS=dict(IDLE = 0x00, + START = 0x01, + STOP = 0x02, + SET_TRACE_VARIABLE = 0x04, + GET_TRACE_VARIABLES = 0x05, + SET_FORCED_VARIABLE = 0x06, + GET_PLCID = 0x07) + +WAIT_DATA = 0x04 + +LPC_STATUS=dict(STARTED = 0x01, + STOPPED = 0x02, + DEBUG = 0x03) + +class LPCError(exceptions.Exception): + """Exception class""" + def __init__(self, msg): + self.msg = msg + return + + def __str__(self): + return "LPC communication error ! " + str(self.msg) + +class LPCProto: + def __init__(self, port, rate, timeout): + # open serial port + self.serialPort = serial.Serial( port, rate, timeout = timeout ) + self.serialPort.flush() + # handshake + self.HandleTransaction(LPCTransaction("IDLE")) + # serialize access lock + self.TransactionLock = Lock() + + def HandleTransaction(self, transaction): + self.TransactionLock.acquire() + try: + transaction.SetPseudoFile(self.serialPort) + # send command, wait ack (timeout) + transaction.SendCommand() + current_plc_status = transaction.GetCommandAck() + if current_plc_status is not None: + res = transaction.ExchangeData() + else: + raise LPCError("LPC transaction error - controller did not answer as expected") + finally: + self.TransactionLock.release() + return current_plc_status, res + +class LPCTransaction: + def __init__(self, command, optdata): + self.Command = LPC_CMDS[command] + self.OptData = optdata[:] + self.serialPort = None + + def SetPseudoFile(pseudofile): + self.pseudofile = pseudofile + + def SendCommand(self): + # send command thread + self.pseudofile.write(chr(self.Command)) + + def GetCommandAck(self): + comm_status, current_plc_status = map(ord, self.pseudofile.read(2)) + # LPC returns command itself as an ack for command + if(comm_status == self.Command): + return current_plc_status + return None + + def ExchangeData(self): + if self.Command & WAIT_DATA : + length = len(self.OptData) + # transform length into a byte string + # we presuppose endianess of LPC same as PC + lengthstr = ctypes.string_at(ctypes.pointer(ctypes.c_int(length)),4) + self.pseudofile.write(lengthstr + self.OptData) + + lengthstr = self.pseudofile.read(4) + # transform a byte string into length + length = ctypes.cast(ctypes.c_char_p(lengthstr), ctypes.POINTER(ctypes.c_int)).contents.value + return self.pseudofile.read(length) + return None + +if __name__ == "__main__": + TestConnection = LPCProto() + \ No newline at end of file diff -r 1b1dc8ad2498 -r 9d5036e86c3d connectors/LPC/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/connectors/LPC/__init__.py Wed Dec 02 13:07:57 2009 +0100 @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +#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 +import traceback + + +def LPC_connector_factory(uri, pluginsroot): + """ + This returns the connector to LPC style PLCobject + """ + pluginsroot.logger.write(_("Connecting to URI : %s\n")%uri) + + servicetype, location = uri.split("://") + + # Try to get the proxy object + try : + # TODO: Open Serial Port + RemotePLCObjectProxy = LPCObject(pluginsroot) # LPC_PLCObject_Proxy + except Exception, msg: + pluginsroot.logger.write_error(_("Couldn't connect !\n")) + pluginsroot.logger.write_error(traceback.format_exc()) + return None + + def LPCCatcher(func, default=None): + """ + A function that catch a pyserial exceptions, write error to logger + and return defaul value when it happen + """ + def catcher_func(*args,**kwargs): + try: + return func(*args,**kwargs) + except Exception,e: + #pluginsroot.logger.write_error(traceback.format_exc()) + pluginsroot.logger.write_error(str(e)+"\n") + pluginsroot._connector = None + return default + return catcher_func + + # Check connection is effective. + # lambda is for getattr of GetPLCstatus to happen inside catcher + if LPCCatcher(lambda:RemotePLCObjectProxy.GetPLCstatus())() == None: + pluginsroot.logger.write_error(_("Cannot get PLC status - connection failed.\n")) + return None + + + class LPCProxy: + """ + A Serial proxy class to handle Beremiz Pyro interface specific behavior. + And to put LPC exception catcher in between caller and pyro proxy + """ + def _LPCGetTraceVariables(self): + return self.RemotePLCObjectProxy.GetTraceVariables() + GetTraceVariables = LPCCatcher(_LPCGetTraceVariables,("Broken",None,None)) + + def _LPCGetPLCstatus(self): + return RemotePLCObjectProxy.GetPLCstatus() + GetPLCstatus = LPCCatcher(_LPCGetPLCstatus, "Broken") + + def __getattr__(self, attrName): + member = self.__dict__.get(attrName, None) + if member is None: + def my_local_func(*args,**kwargs): + return RemotePLCObjectProxy.__getattr__(attrName)(*args,**kwargs) + member = LPCCatcher(my_local_func, None) + self.__dict__[attrName] = member + return member + + return LPCProxy() + + diff -r 1b1dc8ad2498 -r 9d5036e86c3d connectors/PYRO/__init__.py --- a/connectors/PYRO/__init__.py Wed Dec 02 10:24:09 2009 +0100 +++ b/connectors/PYRO/__init__.py Wed Dec 02 13:07:57 2009 +0100 @@ -112,19 +112,13 @@ """ for safe use in from debug thread, must use the copy """ - if self.RemotePLCObjectProxyCopy is not None and self.RemotePLCObjectProxyCopy.GetPLCstatus() == "Started": - return self.RemotePLCObjectProxyCopy.GetTraceVariables() - else: - return None,None - GetTraceVariables = PyroCatcher(_PyroGetTraceVariables,(None,None)) + return self.RemotePLCObjectProxyCopy.GetTraceVariables() + GetTraceVariables = PyroCatcher(_PyroGetTraceVariables,("Broken",None,None)) - def _PyroPLCIsStarting(self): - """ - for safe use in from debug thread, must use the copy - """ - return self.RemotePLCObjectProxyCopy is not None and self.RemotePLCObjectProxyCopy.GetPLCstatus() == "Starting" - PLCIsStarting = PyroCatcher(_PyroPLCIsStarting,False) - + def _PyroGetPLCstatus(self): + return RemotePLCObjectProxy.GetPLCstatus() + GetPLCstatus = PyroCatcher(_PyroGetPLCstatus, "Broken") + def __getattr__(self, attrName): member = self.__dict__.get(attrName, None) if member is None: diff -r 1b1dc8ad2498 -r 9d5036e86c3d plugger.py --- a/plugger.py Wed Dec 02 10:24:09 2009 +0100 +++ b/plugger.py Wed Dec 02 13:07:57 2009 +0100 @@ -783,8 +783,6 @@ self.DebugThread = None self.debug_break = False self.previous_plcstate = None - self.StatusPrint = {"Broken": self.logger.write_error, - None: lambda x: None} # copy PluginMethods so that it can be later customized self.PluginMethods = [dic.copy() for dic in self.PluginMethods] self.LoadSTLibrary() @@ -1541,43 +1539,38 @@ status = self._connector.GetPLCstatus() else: status = "Disconnected" - for args in { - "Starting" : [("_Run", True), - ("_Debug", True), - ("_Stop", False)], - "Started" : [("_Run", False), - ("_Debug", False), - ("_Stop", True)], - "Stopped" : [("_Run", True), - ("_Debug", True), - ("_Stop", False)], - "Empty" : [("_Run", False), - ("_Debug", False), - ("_Stop", False)], - "Broken" : [("_Run", True), - ("_Debug", True), - ("_Stop", False)], - "Disconnected" :[("_Run", False), - ("_Debug", False), - ("_Stop", False), - ("_Transfer", False), - ("_Connect", True), - ("_Disconnect", False)], - }.get(status,[]): - self.ShowMethod(*args) - return status - - def PullPLCStatusProc(self, event): + if(self.previous_plcstate != status): + for args in { + "Started" : [("_Run", False), + ("_Debug", False), + ("_Stop", True)], + "Stopped" : [("_Run", True), + ("_Debug", True), + ("_Stop", False)], + "Empty" : [("_Run", False), + ("_Debug", False), + ("_Stop", False)], + "Broken" : [], + "Disconnected" :[("_Run", False), + ("_Debug", False), + ("_Stop", False), + ("_Transfer", False), + ("_Connect", True), + ("_Disconnect", False)], + }.get(status,[]): + self.ShowMethod(*args) + self.previous_plcstate = status + return True + return False + + def PullPLCStatusProc(self, event): if self._connector is None: self.StatusTimer.Stop() - current_status = self.UpdateMethodsFromPLCStatus() - if current_status != self.previous_plcstate: - self.previous_plcstate = current_status - if current_status is not None: - status = _(current_status) - else: - status = "" - self.StatusPrint.get(current_status, self.logger.write)(_("PLC is %s\n")%status) + if self.UpdateMethodsFromPLCStatus(): + status = _(self.previous_plcstate) + {"Broken": self.logger.write_error, + None: lambda x: None}.get( + self.previous_plcstate, self.logger.write)(_("PLC is %s\n")%status) self.AppFrame.RefreshAll() def _Run(self): @@ -1693,23 +1686,21 @@ # This lock is used to avoid flooding wx event stack calling callafter self.debug_break = False while (not self.debug_break) and (self._connector is not None): - debug_tick, debug_vars = self._connector.GetTraceVariables() + plc_status, debug_tick, debug_vars = self._connector.GetTraceVariables() #print debug_tick, debug_vars self.IECdebug_lock.acquire() - if debug_vars is not None and \ - len(debug_vars) == len(self.TracedIECPath): - for IECPath,value in zip(self.TracedIECPath, debug_vars): - if value is not None: - self.CallWeakcallables(IECPath, "NewValue", debug_tick, value) - self.CallWeakcallables("__tick__", "NewDataAvailable") - elif debug_vars is not None: - wx.CallAfter(self.logger.write_warning, - _("Debug data not coherent %d != %d\n")%(len(debug_vars), len(self.TracedIECPath))) - elif debug_tick == -1: - #wx.CallAfter(self.logger.write, "Debugger unavailable\n") - pass + if debug_vars is not None: + if len(debug_vars) == len(self.TracedIECPath): + for IECPath,value in zip(self.TracedIECPath, debug_vars): + if value is not None: + self.CallWeakcallables(IECPath, "NewValue", debug_tick, value) + self.CallWeakcallables("__tick__", "NewDataAvailable") + else : + wx.CallAfter(self.logger.write_warning, + _("Debug data do not match requested variable count %d != %d\n")%(len(debug_vars), len(self.TracedIECPath))) else: - if self._connector.PLCIsStarting(): + if plc_status == "Started": + # Be patient, tollerate PLC to come up before debugging time.sleep(0.01) else: wx.CallAfter(self.logger.write, _("Debugger disabled\n")) @@ -1816,7 +1807,7 @@ self.CompareLocalAndRemotePLC() # Init with actual PLC status and print it - self.previous_plcstate = self.UpdateMethodsFromPLCStatus() + self.UpdateMethodsFromPLCStatus() if self.previous_plcstate is not None: status = _(self.previous_plcstate) else: diff -r 1b1dc8ad2498 -r 9d5036e86c3d runtime/PLCObject.py --- a/runtime/PLCObject.py Wed Dec 02 10:24:09 2009 +0100 +++ b/runtime/PLCObject.py Wed Dec 02 13:07:57 2009 +0100 @@ -256,7 +256,7 @@ def StartPLC(self, debug=False): PLCprint("StartPLC") if self.CurrentPLCFilename is not None: - self.PLCStatus = "Starting" + self.PLCStatus = "Started" self.PythonThread = Thread(target=self.PythonThreadProc, args=[debug]) self.PythonThread.start() @@ -378,16 +378,12 @@ """ if self.PLCStatus == "Started": self.PLClibraryLock.acquire() - tick = self._WaitDebugData() + tick = ctypes.c_int() #PLCprint("Debug tick : %d"%tick) - if tick == 2**32 - 1: - tick = -1 - res = None - else: + if self._WaitDebugData(ctypes.byref(tick)) != 0: idx = ctypes.c_int() typename = ctypes.c_char_p() res = [] - for given_idx in self._Idxs: buffer=self._IterDebugData(ctypes.byref(idx), ctypes.byref(typename)) c_type,unpack_func = self.TypeTranslator.get(typename.value, (None,None)) @@ -399,6 +395,6 @@ res.append(None) self._FreeDebugData() self.PLClibraryLock.release() - return tick, res - return -1, None - + return self.PLCStatus, tick, res + return self.PLCStatus, None, None + diff -r 1b1dc8ad2498 -r 9d5036e86c3d targets/Linux/plc_Linux_main.c --- a/targets/Linux/plc_Linux_main.c Wed Dec 02 10:24:09 2009 +0100 +++ b/targets/Linux/plc_Linux_main.c Wed Dec 02 13:07:57 2009 +0100 @@ -131,12 +131,12 @@ } extern unsigned long __tick; -/* from plc_debugger.c */ -unsigned long WaitDebugData() + +int WaitDebugData(unsigned long *tick) { + *tick = __debug_tick; /* Wait signal from PLC thread */ - if(pthread_mutex_lock(&debug_wait_mutex)) return -1; - return __debug_tick; + return pthread_mutex_lock(&debug_wait_mutex); } /* Called by PLC thread when debug_publish finished diff -r 1b1dc8ad2498 -r 9d5036e86c3d targets/Win32/plc_Win32_main.c --- a/targets/Win32/plc_Win32_main.c Wed Dec 02 10:24:09 2009 +0100 +++ b/targets/Win32/plc_Win32_main.c Wed Dec 02 13:07:57 2009 +0100 @@ -170,10 +170,12 @@ } /* from plc_debugger.c */ +int WaitDebugData(unsigned long *tick) unsigned long WaitDebugData() { - if(WaitForSingleObject(debug_wait_sem, INFINITE) != WAIT_OBJECT_0) return -1; - return __debug_tick; + *tick = __debug_tick; + /* Wait signal from PLC thread */ + return WaitForSingleObject(debug_wait_sem, INFINITE) != WAIT_OBJECT_0; } /* Called by PLC thread when debug_publish finished diff -r 1b1dc8ad2498 -r 9d5036e86c3d targets/Xenomai/plc_Xenomai_main.c --- a/targets/Xenomai/plc_Xenomai_main.c Wed Dec 02 10:24:09 2009 +0100 +++ b/targets/Xenomai/plc_Xenomai_main.c Wed Dec 02 13:07:57 2009 +0100 @@ -205,15 +205,16 @@ extern unsigned long __tick; /* from plc_debugger.c */ -unsigned long WaitDebugData() +int WaitDebugData(unsigned long *tick) { char message; int res; + *tick = __debug_tick; /* Wait signal from PLC thread */ if (PLC_state & PLC_STATE_DEBUG_FILE_OPENED) { res = read(WaitDebug_pipe_fd, &message, sizeof(char)); if (res == sizeof(char)) - return __debug_tick; + return 0; } return -1; } diff -r 1b1dc8ad2498 -r 9d5036e86c3d targets/plc_common_main.c --- a/targets/plc_common_main.c Wed Dec 02 10:24:09 2009 +0100 +++ b/targets/plc_common_main.c Wed Dec 02 13:07:57 2009 +0100 @@ -23,7 +23,7 @@ **/ IEC_TIME __CURRENT_TIME; IEC_BOOL __DEBUG = 0; -unsigned long __tick = -1; +unsigned long __tick = 0; /* * Variable generated by C softPLC and plugins