Preliminary accessor support for debug
authorEdouard TISSERANT <edouard.tisserant@gmail.com>
Wed, 02 Dec 2009 20:22:28 +0100
changeset 450 18583d13f0fa
parent 449 9d5036e86c3d
child 451 73b3913b6d9c
Preliminary accessor support for debug
plugger.py
runtime/PLCObject.py
targets/plc_debug.c
--- a/plugger.py	Wed Dec 02 13:07:57 2009 +0100
+++ b/plugger.py	Wed Dec 02 20:22:28 2009 +0100
@@ -1303,7 +1303,7 @@
                     # Fill in IEC<->C translation dicts
                     IEC_path=attrs["IEC_path"]
                     Idx=int(attrs["num"])
-                    self._IECPathToIdx[IEC_path]=Idx
+                    self._IECPathToIdx[IEC_path]=(Idx, attrs["type"])
             except Exception,e:
                 self.logger.write_error(_("Cannot open/parse VARIABLES.csv!\n"))
                 self.logger.write_error(traceback.format_exc())
@@ -1331,10 +1331,15 @@
                len(self._VariablesList),
            "variables_pointer_type_table_count":
                len(self._VariablesList),
-           "variables_pointer_type_table_initializer":"\n".join([
-               {"PT":"    variable_table[%(num)s].ptrvalue = (void*)(%(C_path)s);\n",
-                "VAR":"    variable_table[%(num)s].ptrvalue = (void*)(&%(C_path)s);\n"}[v["vartype"]]%v + 
-                "    variable_table[%(num)s].type = %(type)s_ENUM;\n"%v
+           "for_each_variable_do_code":"\n".join([
+               {"PT":"    (*fp)((void*)&%(C_path)s,%(type)s_P_ENUM);\n",
+                "VAR":"    (*fp)((void*)&%(C_path)s,%(type)s_ENUM);\n"}[v["vartype"]]%v
+                for v in self._VariablesList if v["vartype"] != "FB" and v["type"] in DebugTypes ]),
+           "find_variable_case_code":"\n".join([
+               "    case %(num)s:\n"%v+
+               "        varp = (void*)&%(C_path)s;\n"%v+
+               {"PT":"        return %(type)s_P_ENUM;\n",
+                "VAR":"        return %(type)s_ENUM;\n"}[v["vartype"]]%v
                 for v in self._VariablesList if v["vartype"] != "FB" and v["type"] in DebugTypes ])}
         
         return debug_code
@@ -1596,16 +1601,17 @@
                     IECPathsToPop.append(IECPath)
                 elif IECPath != "__tick__":
                     # Convert 
-                    Idx = self._IECPathToIdx.get(IECPath,None)
+                    Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None))
                     if Idx is not None:
-                        Idxs.append(Idx)
-                        self.TracedIECPath.append(IECPath)
+                        Idxs.append((Idx, IEC_Type, IECPath))
                     else:
                         self.logger.write_warning(_("Debug : Unknown variable %s\n")%IECPath)
             for IECPathToPop in IECPathsToPop:
                 self.IECdebug_datas.pop(IECPathToPop)
 
-            self._connector.SetTraceVariablesList(Idxs)
+            Idxs.sort()
+            self.TracedIECPath = zip(Idxs)[2]
+            self._connector.SetTraceVariablesList(zip(zip(Idxs)[0:1]))
             self.IECdebug_lock.release()
             
             #for IEC_path, IECdebug_data in self.IECdebug_datas.iteritems():
@@ -1629,7 +1635,7 @@
         to a WeakKeyDictionary linking 
         weakly referenced callables to optionnal args
         """
-        if IECPath != "__tick__" and self._IECPathToIdx.get(IECPath, None) is None:
+        if IECPath != "__tick__" and not self._IECPathToIdx.has_key(IECPath):
             return None
         
         self.IECdebug_lock.acquire()
--- a/runtime/PLCObject.py	Wed Dec 02 13:07:57 2009 +0100
+++ b/runtime/PLCObject.py	Wed Dec 02 20:22:28 2009 +0100
@@ -131,15 +131,12 @@
             self._RegisterDebugVariable.restype = None
             self._RegisterDebugVariable.argtypes = [ctypes.c_int]
     
-            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
             
-            self._WaitDebugData = self.PLClibraryHandle.WaitDebugData
-            self._WaitDebugData.restype = ctypes.c_int  
+            self._GetDebugData = self.PLClibraryHandle.GetDebugData
+            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
             self._suspendDebug.restype = None
@@ -165,7 +162,7 @@
         self._RegisterDebugVariable = lambda x:None
         self._IterDebugData = lambda x,y:None
         self._FreeDebugData = lambda:None
-        self._WaitDebugData = lambda:-1
+        self._GetDebugData = lambda:-1
         self._suspendDebug = lambda:None
         self._resumeDebug = lambda:None
         self._PythonIterator = lambda:""
@@ -339,7 +336,7 @@
         # keep a copy of requested idx
         self._Idxs = idxs[:]
         self._ResetDebugVariables()
-        for idx in idxs:
+        for idx,iectype in idxs:
             self._RegisterDebugVariable(idx)
         self._resumeDebug()
 
@@ -378,21 +375,21 @@
         """
         if self.PLCStatus == "Started":
             self.PLClibraryLock.acquire()
-            tick = ctypes.c_int()
-            #PLCprint("Debug tick : %d"%tick)
-            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))
-                    if c_type is not None and given_idx == idx.value:
-                        res.append(unpack_func(ctypes.cast(buffer,
+            tick = ctypes.c_uint32()
+            size = ctypes.c_uint32()
+            buffer = ctypes.c_void_p()
+            if self._GetDebugData(ctypes.byref(tick),ctypes.byref(size),ctypes.byref(buffer)) == 0 :
+                offset = 0
+                for idx, iectype in self._Idxs:
+                    cursor = ctypes.c_void_p(buffer.value + offset)
+                    c_type,unpack_func = self.TypeTranslator.get(iectype, (None,None))
+                    if c_type is not None and offset < size:
+                        res.append(unpack_func(ctypes.cast(cursor,
                                                            ctypes.POINTER(c_type)).contents))
+                        offset += ctypes.sizeof(c_type) 
                     else:
-                        PLCprint("Debug error idx : %d, expected_idx %d, type : %s"%(idx.value, given_idx,typename.value))
-                        res.append(None)
+                        PLCprint("Debug error !")
+                        break
             self._FreeDebugData()
             self.PLClibraryLock.release()
             return self.PLCStatus, tick, res
--- a/targets/plc_debug.c	Wed Dec 02 13:07:57 2009 +0100
+++ b/targets/plc_debug.c	Wed Dec 02 20:22:28 2009 +0100
@@ -30,11 +30,6 @@
 /* Buffer's cursor*/
 static char* buffer_cursor = debug_buffer;
 
-typedef struct{
-    void* ptrvalue;
-    __IEC_types_enum type;
-}struct_plcvar;
-
 /***
  * Declare programs 
  **/
@@ -45,15 +40,23 @@
  **/
 %(extern_variables_declarations)s
 
-static int subscription_table[MAX_SUBSCRIBTION];
-static int* latest_subscription = subscription_table;
-static int* subscription_cursor = subscription_table;
+typedef void(*__for_each_variable_do_fp)(void*, __IEC_types_enum);
+__for_each_variable_do(__for_each_variable_do_fp fp)
+{
+%(for_each_variable_do_code)s
+}
 
-struct_plcvar variable_table[%(variables_pointer_type_table_count)d];
+__IEC_types_enum __find_variable(unsigned int varindex, void ** varp)
+{
+    switch(varindex){
+%(find_variable_case_code)s
+    }
+    *varp = NULL;
+    return UNKNOWN_ENUM;
+}
 
 void __init_debug(void)
 {
-%(variables_pointer_type_table_initializer)s
     buffer_state = BUFFER_FREE;
 }
 
@@ -71,6 +74,44 @@
 extern void InitiateDebugTransfer(void);
 
 extern unsigned long __tick;
+
+#define __BufferDebugDataIterator_case_t(TYPENAME) \
+        case TYPENAME##_ENUM :\
+            flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\
+            ptrvalue = &((__IEC_##TYPENAME##_t *)varp)->value;
+
+#define __BufferDebugDataIterator_case_p(TYPENAME)\
+        case TYPENAME##_P_ENUM :\
+            flags = ((__IEC_##TYPENAME##_p *)varp)->flags;\
+            ptrvalue = ((__IEC_##TYPENAME##_p *)varp)->value;
+
+void BufferDebugDataIterator(void* varp, __IEC_types_enum vartype)
+{
+    void *ptrvalue = NULL;
+    char flags = 0;
+    /* find data to copy*/
+    switch(vartype){
+        ANY(__BufferDebugDataIterator_case_t)
+        ANY(__BufferDebugDataIterator_case_p)
+    }
+    if(flags && __IEC_DEBUG_FLAG){
+        USINT size = __get_type_enum_size(vartype);
+        /* compute next cursor positon*/
+        char* next_cursor = buffer_cursor + size;
+        /* if buffer not full */
+        if(next_cursor <= debug_buffer + BUFFER_SIZE)
+        {
+            /* copy data to the buffer */
+            memcpy(buffer_cursor, ptrvalue, size);
+            /* increment cursor according size*/
+            buffer_cursor = next_cursor;
+        }else{
+            /*TODO : signal overflow*/
+        }
+    }
+}
+
+
 void __publish_debug(void)
 {
     /* Check there is no running debugger re-configuration */
@@ -84,38 +125,10 @@
         /* If buffer was free */
         if(latest_state == BUFFER_FREE)
         {
-            int* subscription;
-            
             /* Reset buffer cursor */
             buffer_cursor = debug_buffer;
-            
-            /* iterate over subscriptions */
-            for(subscription=subscription_table;
-                subscription < latest_subscription;
-                subscription++)
-            {
-                /* get variable descriptor */
-                struct_plcvar* my_var = &variable_table[*subscription];
-                char* next_cursor;
-                /* get variable size*/
-                USINT size = __get_type_enum_size(my_var->type);
-                /* compute next cursor positon*/
-                next_cursor = buffer_cursor + size;
-                /* if buffer not full */
-                if(next_cursor <= debug_buffer + BUFFER_SIZE)
-                {
-                    /* copy data to the buffer */
-                    memcpy(buffer_cursor, my_var->ptrvalue, size);
-                    /* increment cursor according size*/
-                    buffer_cursor = next_cursor;
-                }else{
-                    /*TODO : signal overflow*/
-                }
-            }
-    
-            /* Reset buffer cursor again (for IterDebugData)*/
-            buffer_cursor = debug_buffer;
-            subscription_cursor = subscription_table;
+            /* Iterate over all variables to fill debug buffer */
+            __for_each_variable_do(BufferDebugDataIterator);
             
             /* Leave debug section,
              * Trigger asynchronous transmission 
@@ -126,21 +139,41 @@
     }
 }
 
+#define __RegisterDebugVariable_case_t(TYPENAME) \
+        case TYPENAME##_ENUM :\
+            ((__IEC_##TYPENAME##_t *)varp)->flags |= __IEC_DEBUG_FLAG;
+#define __RegisterDebugVariable_case_p(TYPENAME)\
+        case TYPENAME##_P_ENUM :\
+            ((__IEC_##TYPENAME##_p *)varp)->flags |= __IEC_DEBUG_FLAG;
 void RegisterDebugVariable(int idx)
 {
-    /*If subscription table not full */
-    if(latest_subscription - subscription_table < MAX_SUBSCRIBTION)
-    {
-        *(latest_subscription++) = idx;
-        /* TODO pre-calc buffer size and signal overflow*/
-    }else{
-        /*TODO : signal subscription overflow*/
+    void *varp;
+    switch(__find_variable(idx, varp)){
+        ANY(__RegisterDebugVariable_case_t)
+        ANY(__RegisterDebugVariable_case_p)
+    }
+}
+
+#define __ResetDebugVariablesIterator_case_t(TYPENAME) \
+        case TYPENAME##_ENUM :\
+            ((__IEC_##TYPENAME##_t *)varp)->flags &= ~__IEC_DEBUG_FLAG;
+
+#define __ResetDebugVariablesIterator_case_p(TYPENAME)\
+        case TYPENAME##_P_ENUM :\
+            ((__IEC_##TYPENAME##_p *)varp)->flags &= ~__IEC_DEBUG_FLAG;\
+
+void ResetDebugVariablesIterator(void* varp, __IEC_types_enum vartype)
+{
+    /* force debug flag to 0*/
+    switch(vartype){
+        ANY(__ResetDebugVariablesIterator_case_t)
+        ANY(__ResetDebugVariablesIterator_case_p)
     }
 }
 
 void ResetDebugVariables(void)
 {
-    latest_subscription = subscription_table;
+    __for_each_variable_do(ResetDebugVariablesIterator);
 }
 
 void FreeDebugData(void)
@@ -153,29 +186,11 @@
         BUFFER_FREE);
 }
 
-void* IterDebugData(int* idx, const char **type_name)
-{
-	struct_plcvar* my_var;
-	USINT size;
-    if(subscription_cursor < latest_subscription){
-        char* old_cursor = buffer_cursor;
-        *idx = *subscription_cursor;
-        my_var = &variable_table[*(subscription_cursor++)];
-        *type_name = __get_type_enum_name(my_var->type);
-        /* get variable size*/
-        size = __get_type_enum_size(my_var->type);
-        /* compute next cursor position*/
-        buffer_cursor = buffer_cursor + size;
-        if(old_cursor < debug_buffer + BUFFER_SIZE)
-        {
-            return old_cursor;
-        }else{
-            //printf("%%d > %%d\n", old_cursor - debug_buffer, BUFFER_SIZE);
-            return NULL;
-        } 
-    }
-    *idx = -1;
-    *type_name = NULL;
-    return NULL;
+/* Wait until debug data ready and return pointer to it */
+int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){
+    int res = WaitDebugData(tick);
+    *size = buffer_cursor - debug_buffer;
+    *buffer = NULL;
+    return res;
 }