Moved template C code to targets dir. Cleaned up some forgotten print.
--- a/plugger.py Thu Aug 21 13:21:37 2008 +0200
+++ b/plugger.py Thu Aug 21 17:17:36 2008 +0200
@@ -613,7 +613,6 @@
DebugTypes = [t for t in zip(*TypeHierarchy_list)[0] if not t.startswith("ANY")] + \
["STEP","TRANSITION","ACTION"]
-import runtime
import re
import targets
import connectors
@@ -1039,7 +1038,7 @@
self.GetIECProgramsAndVariables()
# prepare debug code
- debug_code = runtime.code("plc_debug") % {
+ debug_code = targets.code("plc_debug") % {
"programs_declarations":
"\n".join(["extern %(type)s %(C_path)s;"%p for p in self._ProgramList]),
"extern_variables_declarations":"\n".join([
@@ -1100,7 +1099,7 @@
[loc for loc,Cfiles,DoCalls in self.LocationCFilesAndCFLAGS if loc and DoCalls])
# Generate main, based on template
- plc_main_code = runtime.code("plc_common_main") % {
+ plc_main_code = targets.code("plc_common_main") % {
"calls_prototypes":"\n".join([(
"int __init_%(s)s(int argc,char **argv);\n"+
"void __cleanup_%(s)s();\n"+
@@ -1121,7 +1120,7 @@
}
target_name = self.BeremizRoot.getTargetType().getcontent()["name"]
- plc_main_code += targets.code(target_name)
+ plc_main_code += targets.targetcode(target_name)
return plc_main_code
@@ -1176,7 +1175,6 @@
os.mkdir(extrafilespath)
# Then write the files
for fname,fobject in ExtraFiles:
- print fname,fobject
fpath = os.path.join(extrafilespath,fname)
open(fpath, "wb").write(fobject.read())
# Now we can forget ExtraFiles (will close files object)
@@ -1439,9 +1437,6 @@
for name in os.listdir(extrafilespath) \
if not name=="CVS"]
- for filename, unused in extrafiles:
- print filename
-
# Send PLC on target
builder = self.GetBuilder()
if builder is not None:
--- a/runtime/PLCObject.py Thu Aug 21 13:21:37 2008 +0200
+++ b/runtime/PLCObject.py Thu Aug 21 17:17:36 2008 +0200
@@ -24,9 +24,7 @@
import Pyro.core as pyro
from threading import Timer
-import ctypes, os, dl, commands
-#, sys
-#sys.setdlopenflags(dl.RTLD_NOW | dl.RTLD_GLOBAL)
+import ctypes, os, commands
if os.name == ("nt", "ce"):
from _ctypes import LoadLibrary as dlopen
@@ -42,8 +40,9 @@
}.get(sys.platform, "")
class PLCObject(pyro.ObjBase):
- def __init__(self, workingdir, daemon):
+ def __init__(self, workingdir, daemon, argv):
pyro.ObjBase.__init__(self)
+ self.argv=argv
self.workingdir = workingdir
self.PLCStatus = "Stopped"
self.PLClibraryHandle = None
@@ -142,7 +141,7 @@
"libpan",
"libX11",
]:
- badhandle = dlopen(badlib, dl.RTLD_NOLOAD)
+ #badhandle = dlopen(badlib, dl.RTLD_NOLOAD)
print "Dirty lib detected :" + badlib
#dlclose(badhandle)
return True
@@ -153,20 +152,24 @@
print "StartPLC"
if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped":
c_argv = ctypes.c_char_p * len(sys.argv)
- if self._LoadNewPLC() and self._startPLC(len(sys.argv),c_argv(*sys.argv)) == 0:
+ if self._LoadNewPLC() and self._startPLC(len(self.argv),c_argv(*self.argv)) == 0:
self.PLCStatus = "Started"
return True
else:
print "_StartPLC did not return 0 !"
- return False
+ self._DoStopPLC()
+ return False
+
+ def _DoStopPLC(self):
+ self._stopPLC()
+ self.PLCStatus = "Stopped"
+ if self._FreePLC():
+ self.PLCStatus = "Dirty"
+ return True
def StopPLC(self):
if self.PLCStatus == "Started":
- self._stopPLC()
- self.PLCStatus = "Stopped"
- if self._FreePLC():
- self.PLCStatus = "Dirty"
- return True
+ self._DoStopPLC()
return False
def _Reload(self):
--- a/runtime/__init__.py Thu Aug 21 13:21:37 2008 +0200
+++ b/runtime/__init__.py Thu Aug 21 17:17:36 2008 +0200
@@ -2,12 +2,5 @@
import os
-def code(name):
- filename = os.path.join(os.path.split(__file__)[0],name + ".c")
- if os.path.exists(filename):
- return open(filename).read()
- else:
- return "#error %s target not implemented !!!\n"%name
-
from PLCObject import PLCObject
import ServicePublisher
--- a/runtime/plc_common_main.c Thu Aug 21 13:21:37 2008 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,177 +0,0 @@
-/*
- * Prototypes for function provided by arch-specific code (main)
- * concatained after this template
- ** /
-
-
-/*
- * Functions and variables provied by generated C softPLC
- **/
-extern int common_ticktime__;
-
-/*
- * Functions and variables provied by plc.c
- **/
-void run(long int tv_sec, long int tv_nsec);
-
-#define maxval(a,b) ((a>b)?a:b)
-
-#include "iec_types.h"
-/*#include "stdio.h" /* For debug */
-
-/*
- * Functions and variables provied by generated C softPLC
- **/
-void config_run__(int tick);
-void config_init__(void);
-
-/*
- * Functions and variables to export to generated C softPLC and plugins
- **/
-
-IEC_TIME __CURRENT_TIME;
-int __tick = 0;
-
-static int init_level = 0;
-static int Debugging = 1;
-
-/*
- * Prototypes of functions exported by plugins
- **/
-%(calls_prototypes)s
-
-/*
- * Retrieve input variables, run PLC and publish output variables
- **/
-void __run()
-{
- %(retrieve_calls)s
-
- if(Debugging) __retrieve_debug();
-
- config_run__(__tick);
-
- if(Debugging) __publish_debug();
-
- %(publish_calls)s
-
- __tick++;
-}
-
-/*
- * Initialize variables according to PLC's defalut values,
- * and then init plugins with that values
- **/
-int __init(int argc,char **argv)
-{
- int res;
- config_init__();
- %(init_calls)s
- return 0;
-}
-/*
- * Calls plugin cleanup proc.
- **/
-void __cleanup()
-{
- %(cleanup_calls)s
-}
-
-
-void PLC_GetTime(IEC_TIME *CURRENT_TIME);
-void PLC_SetTimer(long long next, long long period);
-
-#define CALIBRATED -2
-#define NOT_CALIBRATED -1
-static int calibration_count = NOT_CALIBRATED;
-static IEC_TIME cal_begin;
-static long long Tsync = 0;
-static long long FreqCorr = 0;
-static int Nticks = 0;
-static int last_tick = 0;
-static long long Ttick = 0;
-#define mod %%
-/*
- * Call this on each external sync,
- * @param sync_align_ratio 0->100 : align ratio, < 0 : no align, calibrate period
- **/
-void align_tick(int sync_align_ratio)
-{
- /*
- printf("align_tick(%%d)\n", calibrate);
- */
- if(sync_align_ratio < 0){ /* Calibration */
- if(calibration_count == CALIBRATED)
- /* Re-calibration*/
- calibration_count = NOT_CALIBRATED;
- if(calibration_count == NOT_CALIBRATED)
- /* Calibration start, get time*/
- PLC_GetTime(&cal_begin);
- calibration_count++;
- }else{ /* do alignment (if possible) */
- if(calibration_count >= 0){
- /* End of calibration */
- /* Get final time */
- IEC_TIME cal_end;
- PLC_GetTime(&cal_end);
- /*adjust calibration_count*/
- calibration_count++;
- /* compute mean of Tsync, over calibration period */
- Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 +
- (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count;
- if( (Nticks = (Tsync / Ttick)) > 0){
- FreqCorr = (Tsync mod Ttick); /* to be divided by Nticks */
- }else{
- FreqCorr = Tsync - (Ttick mod Tsync);
- }
- /*
- printf("Tsync = %%ld\n", Tsync);
- printf("calibration_count = %%d\n", calibration_count);
- printf("Nticks = %%d\n", Nticks);
- */
- calibration_count = CALIBRATED;
- }
- if(calibration_count == CALIBRATED){
- /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */
- IEC_TIME now;
- long long elapsed;
- long long Tcorr;
- long long PhaseCorr;
- long long PeriodicTcorr;
- PLC_GetTime(&now);
- elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec;
- if(Nticks > 0){
- PhaseCorr = elapsed - (Ttick + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */
- Tcorr = Ttick + (PhaseCorr + FreqCorr) / Nticks;
- if(Nticks < 2){
- /* When Sync source period is near Tick time */
- /* PhaseCorr may not be applied to Periodic time given to timer */
- PeriodicTcorr = Ttick + FreqCorr / Nticks;
- }else{
- PeriodicTcorr = Tcorr;
- }
- }else if(__tick > last_tick){
- last_tick = __tick;
- PhaseCorr = elapsed - (Tsync*sync_align_ratio/100);
- PeriodicTcorr = Tcorr = Ttick + PhaseCorr + FreqCorr;
- }else{
- /*PLC did not run meanwhile. Nothing to do*/
- return;
- }
- /* DO ALIGNEMENT */
- PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr);
- }
- }
-}
-
-int suspendDebug()
-{
- /* Prevent PLC to enter debug code */
- Debugging = 0;
-}
-
-int resumeDebug()
-{
- /* Let PLC enter debug code */
- Debugging = 1;
-}
--- a/runtime/plc_debug.c Thu Aug 21 13:21:37 2008 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
-/*
- * DEBUGGER code
- *
- * On "publish", when buffer is free, debugger stores arbitrary variables
- * content into, and mark this buffer as filled
- *
- *
- * Buffer content is read asynchronously, (from non real time part),
- * and then buffer marked free again.
- *
- *
- * */
-#include "iec_types_all.h"
-#include "POUS.h"
-/*for memcpy*/
-#include <string.h>
-
-#define BUFFER_SIZE 1024
-#define MAX_SUBSCRIBTION %(subscription_table_count)d
-
-/* Atomically accessed variable for buffer state */
-#define BUFFER_FREE 0
-#define BUFFER_BUSY 1
-static long buffer_state = BUFFER_FREE;
-
-/* The buffer itself */
-char debug_buffer[BUFFER_SIZE];
-
-/* Buffer's cursor*/
-static char* buffer_cursor = debug_buffer;
-
-typedef struct{
- void* ptrvalue;
- __IEC_types_enum type;
-}struct_plcvar;
-
-/***
- * Declare programs
- **/
-%(programs_declarations)s
-
-/***
- * Declare global variables from resources and conf
- **/
-%(extern_variables_declarations)s
-
-static int subscription_table[MAX_SUBSCRIBTION];
-static int* latest_subscription = subscription_table;
-static int* subscription_cursor = subscription_table;
-
-struct_plcvar variable_table[%(variables_pointer_type_table_count)d];
-
-void __init_debug()
-{
-%(variables_pointer_type_table_initializer)s
-};
-
-void __cleanup_debug()
-{
-}
-
-void __retrieve_debug()
-{
-}
-
-void __publish_debug()
-{
- /* Lock buffer */
- long latest_state = AtomicCompareExchange(
- &buffer_state,
- BUFFER_FREE,
- BUFFER_BUSY);
-
- /* 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;
-
- /* Trigger asynchronous transmission (returns immediately) */
- InitiateDebugTransfer(); /* size */
- }
-}
-
-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 ResetDebugVariables(void)
-{
- latest_subscription = subscription_table;
-}
-
-void FreeDebugData()
-{
- /* atomically mark buffer as free */
- long latest_state = AtomicCompareExchange(
- &buffer_state,
- BUFFER_BUSY,
- BUFFER_FREE);
-}
-
-void* IterDebugData(int* idx, const char **type_name)
-{
- if(subscription_cursor < latest_subscription){
- *idx = *subscription_cursor;
- struct_plcvar* my_var = &variable_table[*subscription_cursor++];
- *type_name = __get_type_enum_name(my_var->type);
- return my_var->ptrvalue;
- }
- return NULL;
-}
-
--- a/targets/__init__.py Thu Aug 21 13:21:37 2008 +0200
+++ b/targets/__init__.py Thu Aug 21 17:17:36 2008 +0200
@@ -64,11 +64,14 @@
for target in DictXSD_target.keys():
targetchoices += DictXSD_target[target]
-def code(target_name):
- filename = path.join(path.split(__file__)[0], target_name, "plc_%s_main.c"%target_name)
- if path.exists(filename):
- return open(filename).read()
- else:
- return "#error %s target not implemented !!!\n"%target_name
+def targetcode(target_name, code_name=None):
+ if code_name is None:
+ code_name="plc_%s_main.c"%target_name
+ filename = path.join(path.split(__file__)[0], target_name, code_name)
+ return open(filename).read()
+
+def code(name):
+ filename = path.join(path.split(__file__)[0],name + ".c")
+ return open(filename).read()
from toolchain_gcc import toolchain_gcc
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/targets/plc_common_main.c Thu Aug 21 17:17:36 2008 +0200
@@ -0,0 +1,177 @@
+/*
+ * Prototypes for function provided by arch-specific code (main)
+ * concatained after this template
+ ** /
+
+
+/*
+ * Functions and variables provied by generated C softPLC
+ **/
+extern int common_ticktime__;
+
+/*
+ * Functions and variables provied by plc.c
+ **/
+void run(long int tv_sec, long int tv_nsec);
+
+#define maxval(a,b) ((a>b)?a:b)
+
+#include "iec_types.h"
+/*#include "stdio.h" /* For debug */
+
+/*
+ * Functions and variables provied by generated C softPLC
+ **/
+void config_run__(int tick);
+void config_init__(void);
+
+/*
+ * Functions and variables to export to generated C softPLC and plugins
+ **/
+
+IEC_TIME __CURRENT_TIME;
+int __tick = 0;
+
+static int init_level = 0;
+static int Debugging = 1;
+
+/*
+ * Prototypes of functions exported by plugins
+ **/
+%(calls_prototypes)s
+
+/*
+ * Retrieve input variables, run PLC and publish output variables
+ **/
+void __run()
+{
+ %(retrieve_calls)s
+
+ if(Debugging) __retrieve_debug();
+
+ config_run__(__tick);
+
+ if(Debugging) __publish_debug();
+
+ %(publish_calls)s
+
+ __tick++;
+}
+
+/*
+ * Initialize variables according to PLC's defalut values,
+ * and then init plugins with that values
+ **/
+int __init(int argc,char **argv)
+{
+ int res;
+ config_init__();
+ %(init_calls)s
+ return 0;
+}
+/*
+ * Calls plugin cleanup proc.
+ **/
+void __cleanup()
+{
+ %(cleanup_calls)s
+}
+
+
+void PLC_GetTime(IEC_TIME *CURRENT_TIME);
+void PLC_SetTimer(long long next, long long period);
+
+#define CALIBRATED -2
+#define NOT_CALIBRATED -1
+static int calibration_count = NOT_CALIBRATED;
+static IEC_TIME cal_begin;
+static long long Tsync = 0;
+static long long FreqCorr = 0;
+static int Nticks = 0;
+static int last_tick = 0;
+static long long Ttick = 0;
+#define mod %%
+/*
+ * Call this on each external sync,
+ * @param sync_align_ratio 0->100 : align ratio, < 0 : no align, calibrate period
+ **/
+void align_tick(int sync_align_ratio)
+{
+ /*
+ printf("align_tick(%%d)\n", calibrate);
+ */
+ if(sync_align_ratio < 0){ /* Calibration */
+ if(calibration_count == CALIBRATED)
+ /* Re-calibration*/
+ calibration_count = NOT_CALIBRATED;
+ if(calibration_count == NOT_CALIBRATED)
+ /* Calibration start, get time*/
+ PLC_GetTime(&cal_begin);
+ calibration_count++;
+ }else{ /* do alignment (if possible) */
+ if(calibration_count >= 0){
+ /* End of calibration */
+ /* Get final time */
+ IEC_TIME cal_end;
+ PLC_GetTime(&cal_end);
+ /*adjust calibration_count*/
+ calibration_count++;
+ /* compute mean of Tsync, over calibration period */
+ Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 +
+ (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count;
+ if( (Nticks = (Tsync / Ttick)) > 0){
+ FreqCorr = (Tsync mod Ttick); /* to be divided by Nticks */
+ }else{
+ FreqCorr = Tsync - (Ttick mod Tsync);
+ }
+ /*
+ printf("Tsync = %%ld\n", Tsync);
+ printf("calibration_count = %%d\n", calibration_count);
+ printf("Nticks = %%d\n", Nticks);
+ */
+ calibration_count = CALIBRATED;
+ }
+ if(calibration_count == CALIBRATED){
+ /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */
+ IEC_TIME now;
+ long long elapsed;
+ long long Tcorr;
+ long long PhaseCorr;
+ long long PeriodicTcorr;
+ PLC_GetTime(&now);
+ elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec;
+ if(Nticks > 0){
+ PhaseCorr = elapsed - (Ttick + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */
+ Tcorr = Ttick + (PhaseCorr + FreqCorr) / Nticks;
+ if(Nticks < 2){
+ /* When Sync source period is near Tick time */
+ /* PhaseCorr may not be applied to Periodic time given to timer */
+ PeriodicTcorr = Ttick + FreqCorr / Nticks;
+ }else{
+ PeriodicTcorr = Tcorr;
+ }
+ }else if(__tick > last_tick){
+ last_tick = __tick;
+ PhaseCorr = elapsed - (Tsync*sync_align_ratio/100);
+ PeriodicTcorr = Tcorr = Ttick + PhaseCorr + FreqCorr;
+ }else{
+ /*PLC did not run meanwhile. Nothing to do*/
+ return;
+ }
+ /* DO ALIGNEMENT */
+ PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr);
+ }
+ }
+}
+
+int suspendDebug()
+{
+ /* Prevent PLC to enter debug code */
+ Debugging = 0;
+}
+
+int resumeDebug()
+{
+ /* Let PLC enter debug code */
+ Debugging = 1;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/targets/plc_debug.c Thu Aug 21 17:17:36 2008 +0200
@@ -0,0 +1,151 @@
+/*
+ * DEBUGGER code
+ *
+ * On "publish", when buffer is free, debugger stores arbitrary variables
+ * content into, and mark this buffer as filled
+ *
+ *
+ * Buffer content is read asynchronously, (from non real time part),
+ * and then buffer marked free again.
+ *
+ *
+ * */
+#include "iec_types_all.h"
+#include "POUS.h"
+/*for memcpy*/
+#include <string.h>
+
+#define BUFFER_SIZE 1024
+#define MAX_SUBSCRIBTION %(subscription_table_count)d
+
+/* Atomically accessed variable for buffer state */
+#define BUFFER_FREE 0
+#define BUFFER_BUSY 1
+static long buffer_state = BUFFER_FREE;
+
+/* The buffer itself */
+char debug_buffer[BUFFER_SIZE];
+
+/* Buffer's cursor*/
+static char* buffer_cursor = debug_buffer;
+
+typedef struct{
+ void* ptrvalue;
+ __IEC_types_enum type;
+}struct_plcvar;
+
+/***
+ * Declare programs
+ **/
+%(programs_declarations)s
+
+/***
+ * Declare global variables from resources and conf
+ **/
+%(extern_variables_declarations)s
+
+static int subscription_table[MAX_SUBSCRIBTION];
+static int* latest_subscription = subscription_table;
+static int* subscription_cursor = subscription_table;
+
+struct_plcvar variable_table[%(variables_pointer_type_table_count)d];
+
+void __init_debug()
+{
+%(variables_pointer_type_table_initializer)s
+};
+
+void __cleanup_debug()
+{
+}
+
+void __retrieve_debug()
+{
+}
+
+void __publish_debug()
+{
+ /* Lock buffer */
+ long latest_state = AtomicCompareExchange(
+ &buffer_state,
+ BUFFER_FREE,
+ BUFFER_BUSY);
+
+ /* 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;
+
+ /* Trigger asynchronous transmission (returns immediately) */
+ InitiateDebugTransfer(); /* size */
+ }
+}
+
+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 ResetDebugVariables(void)
+{
+ latest_subscription = subscription_table;
+}
+
+void FreeDebugData()
+{
+ /* atomically mark buffer as free */
+ long latest_state = AtomicCompareExchange(
+ &buffer_state,
+ BUFFER_BUSY,
+ BUFFER_FREE);
+}
+
+void* IterDebugData(int* idx, const char **type_name)
+{
+ if(subscription_cursor < latest_subscription){
+ *idx = *subscription_cursor;
+ struct_plcvar* my_var = &variable_table[*subscription_cursor++];
+ *type_name = __get_type_enum_name(my_var->type);
+ return my_var->ptrvalue;
+ }
+ return NULL;
+}
+