Now logging have 4 levels
authorEdouard Tisserant
Wed, 30 Jan 2013 18:54:12 +1100
changeset 917 401e44bae7c0
parent 916 697d8b77d716
child 918 aa136ef12506
Now logging have 4 levels
ProjectController.py
connectors/PYRO/__init__.py
runtime/PLCObject.py
targets/plc_debug.c
targets/typemapping.py
tests/logging/plc.xml
--- 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>