--- a/ProjectController.py Tue Jan 29 23:41:00 2013 +0100
+++ b/ProjectController.py Wed Jan 30 18:54:12 2013 +1100
@@ -25,7 +25,7 @@
from dialogs import DiscoveryDialog
from PLCControler import PLCControler
from plcopen.structures import IEC_KEYWORDS
-from targets.typemapping import DebugTypesSize
+from targets.typemapping import DebugTypesSize, LogLevelsCount, LogLevels
from ConfigTreeNode import ConfigTreeNode
base_folder = os.path.split(sys.path[0])[0]
@@ -113,7 +113,7 @@
self.DebugThread = None
self.debug_break = False
self.previous_plcstate = None
- self.previous_log_count = None
+ self.previous_log_count = [None]*LogLevelsCount
# copy ConfNodeMethods so that it can be later customized
self.StatusMethods = [dic.copy() for dic in self.StatusMethods]
@@ -1077,24 +1077,26 @@
self.CompareLocalAndRemotePLC()
def UpdatePLCLog(self, log_count):
- if log_count and self.previous_log_count != log_count:
- # XXX replace dump to console with dedicated log panel.
- to_console = ['']
- dump_end = max( # request message sent after the last one we already got
- self.previous_log_count - 1 if self.previous_log_count is not None else -1,
- log_count - 100) # 100 is purely arbitrary number
- # dedicated panel should only ask for a small range,
- # depending on how user navigate in the panel
- # and only ask for last one in follow mode
- for msgidx in xrange(log_count-1, dump_end,-1):
- msg = self._connector.GetLogMessage(msgidx)
- if msg is not None :
- to_console.insert(0, '#' + repr(msgidx) + ": " + msg)
- else:
- to_console.insert(0, 'No log before #'+repr(msgidx))
- break;
- self.logger.write("\n".join(to_console))
- self.previous_log_count = log_count
+ if log_count :
+ for level, count, prev in zip(xrange(LogLevelsCount), log_count,self.previous_log_count):
+ if count is not None and prev != count:
+ # XXX replace dump to console with dedicated log panel.
+ to_console = ['']
+ dump_end = max( # request message sent after the last one we already got
+ prev - 1 if prev is not None else -1,
+ count - 100) # 100 is purely arbitrary number
+ # dedicated panel should only ask for a small range,
+ # depending on how user navigate in the panel
+ # and only ask for last one in follow mode
+ for msgidx in xrange(count-1, dump_end,-1):
+ msg = self._connector.GetLogMessage(level, msgidx)
+ if msg is not None :
+ to_console.insert(0, LogLevels[level]+ ':#' + repr(msgidx) + ": " + msg)
+ else:
+ to_console.insert(0, LogLevels[level]+ ': No log before #'+repr(msgidx))
+ break;
+ self.logger.write("\n".join(to_console))
+ self.previous_log_count[level] = count
def UpdateMethodsFromPLCStatus(self):
status = None
@@ -1289,7 +1291,7 @@
while (not self.debug_break) and (self._connector is not None):
Trace = self._connector.GetTraceVariables()
if(Trace):
- plc_status, log_count, debug_tick, debug_vars = Trace
+ plc_status, debug_tick, debug_vars = Trace
else:
plc_status = None
debug_getvar_retry += 1
@@ -1331,7 +1333,7 @@
def _connect_debug(self):
self.previous_plcstate = None
- self.previous_log_count = None
+ self.previous_log_count = [None]*LogLevelsCount
if self.AppFrame:
self.AppFrame.ResetGraphicViewers()
self.RegisterDebugVarToConnector()
@@ -1511,7 +1513,7 @@
else:
self.logger.write_error(_("No PLC to transfer (did build succeed ?)\n"))
- self.previous_log_count = None
+ self.previous_log_count = [None]*LogLevelsCount
wx.CallAfter(self.UpdateMethodsFromPLCStatus)
--- a/connectors/PYRO/__init__.py Tue Jan 29 23:41:00 2013 +0100
+++ b/connectors/PYRO/__init__.py Wed Jan 30 18:54:12 2013 +1100
@@ -140,7 +140,7 @@
if self.RemotePLCObjectProxyCopy is None:
self.RemotePLCObjectProxyCopy = copy.copy(confnodesroot._connector.GetPyroProxy())
return self.RemotePLCObjectProxyCopy.GetTraceVariables()
- GetTraceVariables = PyroCatcher(_PyroGetTraceVariables,("Broken",-1,None,None))
+ GetTraceVariables = PyroCatcher(_PyroGetTraceVariables,("Broken",None,None))
def _PyroGetPLCstatus(self):
return RemotePLCObjectProxy.GetPLCstatus()
--- a/runtime/PLCObject.py Tue Jan 29 23:41:00 2013 +0100
+++ b/runtime/PLCObject.py Wed Jan 30 18:54:12 2013 +1100
@@ -25,7 +25,8 @@
import Pyro.core as pyro
from threading import Timer, Thread, Lock, Semaphore
import ctypes, os, commands, types, sys
-from targets.typemapping import SameEndianessTypeTranslator as TypeTranslator
+from targets.typemapping import LogLevelsDefault, LogLevelsCount, SameEndianessTypeTranslator as TypeTranslator
+
if os.name in ("nt", "ce"):
from _ctypes import LoadLibrary as dlopen
@@ -80,25 +81,29 @@
if self.statuschange is not None:
self.statuschange(self.PLCStatus)
- def LogMessage(self, msg):
- return self._LogMessage(msg, len(msg))
-
-
- def GetLogCount(self):
+ def LogMessage(self, *args):
+ if len(args) == 2:
+ level, msg = args
+ else:
+ level = LogLevelsDefault
+ msg, = args
+ return self._LogMessage(level, msg, len(msg))
+
+
+ def GetLogCount(self, level):
if self._GetLogCount is not None :
- return int(self._GetLogCount())
- elif self._loading_error is not None:
+ return int(self._GetLogCount(level))
+ elif self._loading_error is not None and level==0:
return 1;
-
- def GetLogMessage(self, msgid):
+ def GetLogMessage(self, level, msgid):
if self._GetLogMessage is not None:
maxsz = len(self._log_read_buffer)-1
- sz = self._GetLogMessage(msgid, self._log_read_buffer, maxsz)
+ sz = self._GetLogMessage(level, msgid, self._log_read_buffer, maxsz)
if sz and sz <= maxsz:
self._log_read_buffer[sz] = '\x00'
return self._log_read_buffer.value
- elif self._loading_error is not None :
+ elif self._loading_error is not None and level==0:
return self._loading_error
return None
@@ -171,15 +176,16 @@
self._GetLogCount = self.PLClibraryHandle.GetLogCount
self._GetLogCount.restype = ctypes.c_uint32
+ self._GetLogCount.argtypes = [ctypes.c_uint8]
self._LogMessage = self.PLClibraryHandle.LogMessage
self._LogMessage.restype = ctypes.c_int
- self._LogMessage.argtypes = [ctypes.c_char_p, ctypes.c_uint32]
+ self._LogMessage.argtypes = [ctypes.c_uint8, ctypes.c_char_p, ctypes.c_uint32]
self._log_read_buffer = ctypes.create_string_buffer(1<<14) #16K
self._GetLogMessage = self.PLClibraryHandle.GetLogMessage
self._GetLogMessage.restype = ctypes.c_uint32
- self._GetLogMessage.argtypes = [ctypes.c_uint32, ctypes.c_char_p, ctypes.c_uint32]
+ self._GetLogMessage.argtypes = [ctypes.c_uint8, ctypes.c_uint32, ctypes.c_char_p, ctypes.c_uint32]
self._loading_error = None
return True
@@ -206,7 +212,7 @@
self._resumeDebug = lambda:None
self._PythonIterator = lambda:""
self._GetLogCount = None
- self._LogMessage = lambda m,s:PLCprint("OFF LOG :"+m)
+ self._LogMessage = lambda l,m,s:PLCprint("OFF LOG :"+m)
self._GetLogMessage = None
self.PLClibraryHandle = None
# Unload library explicitely
@@ -293,8 +299,6 @@
self.evaluator(self.FinishRuntimePy)
def StartPLC(self):
- PLCprint("StartPLC")
- self.LogMessage("Hello Log")
if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped":
c_argv = ctypes.c_char_p * len(self.argv)
error = None
@@ -304,14 +308,15 @@
self.PythonThread = Thread(target=self.PythonThreadProc)
self.PythonThread.start()
self.StartSem.acquire()
+ self.LogMessage("PLC started")
else:
- PLCprint(_("Problem starting PLC : error %d" % res))
+ self.LogMessage(_("Problem starting PLC : error %d" % res))
self.PLCStatus = "Broken"
self.StatusChange()
def StopPLC(self):
- PLCprint("StopPLC")
if self.PLCStatus == "Started":
+ self.LogMessage("PLC stopped")
self._stopPLC()
self.PythonThread.join()
return True
@@ -330,10 +335,10 @@
return True
def GetPLCstatus(self):
- return self.PLCStatus, self.GetLogCount()
+ return self.PLCStatus, map(self.GetLogCount,xrange(LogLevelsCount))
def NewPLC(self, md5sum, data, extrafiles):
- PLCprint("NewPLC (%s)"%md5sum)
+ self.LogMessage("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")
@@ -451,10 +456,10 @@
self._FreeDebugData()
self.PLClibraryLock.release()
if offset and offset == size.value:
- return self.PLCStatus, self.GetLogCount(), tick.value, res
+ return self.PLCStatus, tick.value, res
#elif size.value:
#PLCprint("Debug error - wrong buffer unpack ! %d != %d"%(offset, size.value))
- return self.PLCStatus, self.GetLogCount(), None, []
+ return self.PLCStatus, None, []
def RemoteExec(self, script, **kwargs):
try:
--- a/targets/plc_debug.c Tue Jan 29 23:41:00 2013 +0100
+++ b/targets/plc_debug.c Wed Jan 30 18:54:12 2013 +1100
@@ -306,25 +306,31 @@
/* LOGGING
*/
+#define LOG_LEVELS 4
+#define LOG_CRITICAL 0
+#define LOG_WARNING 1
+#define LOG_INFO 2
+#define LOG_DEBUG 4
+
#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/
#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1)
-static char LogBuff[LOG_BUFFER_SIZE];
-void inline copy_to_log(uint32_t buffpos, void* buf, uint32_t size){
+static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE];
+void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){
if(buffpos + size < LOG_BUFFER_SIZE){
- memcpy(&LogBuff[buffpos], buf, size);
+ memcpy(&LogBuff[level][buffpos], buf, size);
}else{
uint32_t remaining = LOG_BUFFER_SIZE - buffpos - 1;
- memcpy(&LogBuff[buffpos], buf, remaining);
- memcpy(LogBuff, buf + remaining, size - remaining);
- }
-}
-void inline copy_from_log(uint32_t buffpos, void* buf, uint32_t size){
+ memcpy(&LogBuff[level][buffpos], buf, remaining);
+ memcpy(LogBuff[level], buf + remaining, size - remaining);
+ }
+}
+void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){
if(buffpos + size < LOG_BUFFER_SIZE){
- memcpy(buf, &LogBuff[buffpos], size);
+ memcpy(buf, &LogBuff[level][buffpos], size);
}else{
uint32_t remaining = LOG_BUFFER_SIZE - buffpos;
- memcpy(buf, &LogBuff[buffpos], remaining);
- memcpy(buf + remaining, LogBuff, size - remaining);
+ memcpy(buf, &LogBuff[level][buffpos], remaining);
+ memcpy(buf + remaining, LogBuff[level], size - remaining);
}
}
@@ -345,10 +351,10 @@
|63 ... 32|31 ... 0|
| Message | Buffer |
| counter | Index | */
-static uint64_t LogCursor = 0x0;
+static uint64_t LogCursor[LOG_LEVELS] = {0x0,0x0,0x0,0x0};
/* Store one log message of give size */
-int LogMessage(char* buf, uint32_t size){
+int LogMessage(uint8_t level, char* buf, uint32_t size){
if(size < LOG_BUFFER_SIZE - sizeof(mTail)){
uint32_t buffpos;
mTail tail;
@@ -358,34 +364,34 @@
succeeds non interrupted */
uint64_t new_cursor, old_cursor;
do{
- old_cursor = LogCursor;
+ old_cursor = LogCursor[level];
buffpos = (uint32_t)old_cursor;
tail.msgidx = (old_cursor >> 32);
new_cursor = ((uint64_t)(tail.msgidx + 1)<<32)
| (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK);
- }while(!__sync_bool_compare_and_swap(&LogCursor,old_cursor,new_cursor));
-
- copy_to_log(buffpos, buf, size);
+ }while(!__sync_bool_compare_and_swap(&LogCursor[level],old_cursor,new_cursor));
+
+ copy_to_log(level, buffpos, buf, size);
tail.msgsize = size;
/*XXX tick*/
/*XXX RTC*/
- copy_to_log((buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail));
+ copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail));
return 1; /* Success */
}else{
char mstr[] = "Logging error : message too big";
- LogMessage(mstr, sizeof(mstr));
+ LogMessage(LOG_CRITICAL, mstr, sizeof(mstr));
}
return 0;
}
-uint32_t GetLogCount(){
- return (uint64_t)LogCursor >> 32;
+uint32_t GetLogCount(uint8_t level){
+ return (uint64_t)LogCursor[level] >> 32;
}
/* Return message size and content */
-uint32_t GetLogMessage(uint32_t msgidx, char* buf, uint32_t max_size){
- uint64_t cursor = LogCursor;
+uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size){
+ uint64_t cursor = LogCursor[level];
if(cursor){
/* seach cursor */
uint32_t stailpos = (uint32_t)cursor;
@@ -398,13 +404,13 @@
do {
smsgidx = tail.msgidx;
stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK;
- copy_from_log(stailpos, &tail, sizeof(mTail));
+ copy_from_log(level, stailpos, &tail, sizeof(mTail));
}while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx));
if(tail.msgidx == msgidx){
uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK;
uint32_t totalsize = tail.msgsize; /*sizeof(mTail);*/
- copy_from_log(sbuffpos, buf, totalsize > max_size ? max_size : totalsize);
+ copy_from_log(level, sbuffpos, buf, totalsize > max_size ? max_size : totalsize);
return totalsize;
}
}
--- a/targets/typemapping.py Tue Jan 29 23:41:00 2013 +0100
+++ b/targets/typemapping.py Wed Jan 30 18:54:12 2013 +1100
@@ -76,3 +76,7 @@
# Construct debugger natively supported types
DebugTypesSize = dict([(key,sizeof(t)) for key,(t,p,u) in SameEndianessTypeTranslator.iteritems() if t is not None])
+LogLevels = ["CRITICAL","WARNING","INFO","DEBUG"]
+LogLevelsCount = len(LogLevels)
+LogLevelsDict = dict(zip(LogLevels,range(LogLevelsCount)))
+LogLevelsDefault = LogLevelsDict["DEBUG"]
--- a/tests/logging/plc.xml Tue Jan 29 23:41:00 2013 +0100
+++ b/tests/logging/plc.xml Wed Jan 30 18:54:12 2013 +1100
@@ -8,7 +8,7 @@
productVersion="1"
creationDateTime="2013-01-29T14:01:00"/>
<contentHeader name="Unnamed"
- modificationDateTime="2013-01-29T21:30:36">
+ modificationDateTime="2013-01-30T18:24:53">
<coordinateInfo>
<fbd>
<scaling x="0" y="0"/>
@@ -22,7 +22,23 @@
</coordinateInfo>
</contentHeader>
<types>
- <dataTypes/>
+ <dataTypes>
+ <dataType name="LOGLEVEL">
+ <baseType>
+ <enum>
+ <values>
+ <value name="CRITICAL"/>
+ <value name="WARNING"/>
+ <value name="INFO"/>
+ <value name="DEBUG"/>
+ </values>
+ </enum>
+ </baseType>
+ <initialValue>
+ <simpleValue value="INFO"/>
+ </initialValue>
+ </dataType>
+ </dataTypes>
<pous>
<pou name="LOGGER" pouType="functionBlock">
<interface>
@@ -37,6 +53,14 @@
<string/>
</type>
</variable>
+ <variable name="LEVEL">
+ <type>
+ <derived name="LOGLEVEL"/>
+ </type>
+ <initialValue>
+ <simpleValue value="INFO"/>
+ </initialValue>
+ </variable>
</inputVars>
<localVars>
<variable name="TRIG0">
@@ -50,7 +74,7 @@
<ST>
<![CDATA[IF TRIG AND NOT TRIG0 THEN
{{
- LogMessage(GetFbVar(MSG, .body),GetFbVar(MSG, .len));
+ LogMessage(GetFbVar(LEVEL),GetFbVar(MSG, .body),GetFbVar(MSG, .len));
}}
END_IF;
TRIG0:=TRIG;
@@ -61,54 +85,25 @@
<pou name="program0" pouType="program">
<interface>
<localVars>
+ <variable name="beat">
+ <type>
+ <BOOL/>
+ </type>
+ </variable>
+ <variable name="count">
+ <type>
+ <INT/>
+ </type>
+ </variable>
<variable name="LOGGER0">
<type>
<derived name="LOGGER"/>
</type>
</variable>
- <variable name="beat">
- <type>
- <BOOL/>
- </type>
- </variable>
- <variable name="count">
- <type>
- <INT/>
- </type>
- </variable>
</localVars>
</interface>
<body>
<FBD>
- <block localId="1" width="65" height="71" typeName="LOGGER" instanceName="LOGGER0">
- <position x="1008" y="64"/>
- <inputVariables>
- <variable formalParameter="TRIG">
- <connectionPointIn>
- <relPosition x="0" y="32"/>
- <connection refLocalId="3" formalParameter="OUT">
- <position x="1008" y="96"/>
- <position x="640" y="96"/>
- <position x="640" y="94"/>
- <position x="272" y="94"/>
- </connection>
- </connectionPointIn>
- </variable>
- <variable formalParameter="MSG">
- <connectionPointIn>
- <relPosition x="0" y="57"/>
- <connection refLocalId="8" formalParameter="OUT">
- <position x="1008" y="121"/>
- <position x="970" y="121"/>
- <position x="970" y="204"/>
- <position x="935" y="204"/>
- </connection>
- </connectionPointIn>
- </variable>
- </inputVariables>
- <inOutVariables/>
- <outputVariables/>
- </block>
<inVariable localId="2" height="27" width="85">
<position x="732" y="188"/>
<connectionPointOut>
@@ -292,6 +287,38 @@
</variable>
</outputVariables>
</block>
+ <block localId="11" width="65" height="80" typeName="LOGGER" instanceName="LOGGER0">
+ <position x="1183" y="64"/>
+ <inputVariables>
+ <variable formalParameter="TRIG">
+ <connectionPointIn>
+ <relPosition x="0" y="30"/>
+ <connection refLocalId="3" formalParameter="OUT">
+ <position x="1183" y="94"/>
+ <position x="272" y="94"/>
+ </connection>
+ </connectionPointIn>
+ </variable>
+ <variable formalParameter="MSG">
+ <connectionPointIn>
+ <relPosition x="0" y="50"/>
+ <connection refLocalId="8" formalParameter="OUT">
+ <position x="1183" y="114"/>
+ <position x="979" y="114"/>
+ <position x="979" y="204"/>
+ <position x="935" y="204"/>
+ </connection>
+ </connectionPointIn>
+ </variable>
+ <variable formalParameter="LEVEL">
+ <connectionPointIn>
+ <relPosition x="0" y="70"/>
+ </connectionPointIn>
+ </variable>
+ </inputVariables>
+ <inOutVariables/>
+ <outputVariables/>
+ </block>
</FBD>
</body>
</pou>