Added native (not a plugin) asynchronous python eval function block - Beta. Code cleanup in C code templates.
--- a/plugger.py Tue Dec 23 19:31:28 2008 +0100
+++ b/plugger.py Tue Dec 23 19:37:44 2008 +0100
@@ -1078,6 +1078,23 @@
return debug_code
+ def Generate_plc_python(self):
+ """
+ Generate trace/debug code out of PLC variable list
+ """
+ self.GetIECProgramsAndVariables()
+
+ python_eval_fb_list = []
+ for v in self._VariablesList :
+ if v["vartype"] == "FB" and v["type"] == "PYTHON_EVAL":
+ python_eval_fb_list.append(v)
+ python_eval_fb_count = len(python_eval_fb_list)
+
+ # prepare debug code
+ python_code = targets.code("plc_python") % {
+ "python_eval_fb_count": python_eval_fb_count}
+ return python_code
+
def Generate_plc_common_main(self):
"""
Use plugins layout given in LocationCFilesAndCFLAGS to
@@ -1175,6 +1192,8 @@
for generator, filename, name in [
# debugger code
(self.Generate_plc_debugger, "plc_debugger.c", "Debugger"),
+ # IEC<->python gateway code
+ (self.Generate_plc_python, "plc_python.c", "IEC-Python gateway"),
# init/cleanup/retrieve/publish, run and align code
(self.Generate_plc_common_main,"plc_common_main.c","Common runtime")]:
try:
@@ -1408,7 +1427,7 @@
# This will block thread if more than one call is waiting
elif debug_vars is not None:
wx.CallAfter(self.logger.write_warning,
- "debug data not coherent %d != %d"%(len(debug_vars), len(self.TracedIECPath)))
+ "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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pous.xml Tue Dec 23 19:37:44 2008 +0100
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://www.plcopen.org/xml/tc6.xsd"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+ xsi:schemaLocation="http://www.plcopen.org/xml/tc6.xsd">
+ <fileHeader companyName="LOLITECH"
+ productName="Beremiz"
+ productVersion="0.0"
+ creationDateTime="2008-12-14T16:53:26"/>
+ <contentHeader name="Beremiz non-standard POUs library"
+ modificationDateTime="2008-12-18T18:41:34">
+ <coordinateInfo>
+ <fbd>
+ <scaling x="0" y="0"/>
+ </fbd>
+ <ld>
+ <scaling x="0" y="0"/>
+ </ld>
+ <sfc>
+ <scaling x="0" y="0"/>
+ </sfc>
+ </coordinateInfo>
+ </contentHeader>
+ <types>
+ <dataTypes/>
+ <pous>
+ <pou name="python_eval" pouType="functionBlock">
+ <interface>
+ <inputVars>
+ <variable name="TRIG">
+ <type>
+ <BOOL/>
+ </type>
+ </variable>
+ <variable name="CODE">
+ <type>
+ <string/>
+ </type>
+ </variable>
+ </inputVars>
+ <outputVars>
+ <variable name="ACK">
+ <type>
+ <BOOL/>
+ </type>
+ </variable>
+ <variable name="RESULT">
+ <type>
+ <string/>
+ </type>
+ </variable>
+ </outputVars>
+ <localVars>
+ <variable name="STATE">
+ <type>
+ <DWORD/>
+ </type>
+ </variable>
+ <variable name="BUFFER">
+ <type>
+ <string/>
+ </type>
+ </variable>
+ <variable name="TRIGM1">
+ <type>
+ <BOOL/>
+ </type>
+ </variable>
+ </localVars>
+ </interface>
+ <body>
+ <ST>
+<![CDATA[{extern void __PythonEvalFB(PYTHON_EVAL*);__PythonEvalFB(data__);}]]>
+ </ST>
+ </body>
+ </pou>
+ </pous>
+ </types>
+ <instances>
+ <configurations/>
+ </instances>
+</project>
--- a/runtime/PLCObject.py Tue Dec 23 19:31:28 2008 +0100
+++ b/runtime/PLCObject.py Tue Dec 23 19:37:44 2008 +0100
@@ -23,8 +23,9 @@
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import Pyro.core as pyro
-from threading import Timer
+from threading import Timer, Thread
import ctypes, os, commands
+import time
if os.name in ("nt", "ce"):
from _ctypes import LoadLibrary as dlopen
@@ -107,6 +108,10 @@
self._resumeDebug = self.PLClibraryHandle.resumeDebug
self._resumeDebug.restype = None
+
+ self._PythonIterator = self.PLClibraryHandle.PythonIterator
+ self._PythonIterator.restype = ctypes.c_char_p
+ self._PythonIterator.argtypes = [ctypes.c_char_p]
return True
except:
@@ -128,6 +133,7 @@
self._WaitDebugData = lambda:-1
self._suspendDebug = lambda:None
self._resumeDebug = lambda:None
+ self._PythonIterator = lambda:""
self.PLClibraryHandle = None
# Unload library explicitely
if getattr(self,"_PLClibraryHandle",None) is not None:
@@ -163,6 +169,18 @@
return True
return False
+ def PythonThreadProc(self):
+ res = ""
+ print "PythonThreadProc started"
+ while self.PLCStatus == "Started":
+ cmd = self._PythonIterator(res)
+ print "_PythonIterator(", res, ") -> ", cmd
+ try :
+ res = eval(cmd)
+ except Exception,e:
+ res = "#EXCEPTION : "+str(e)
+ print res
+ print "PythonThreadProc finished"
def StartPLC(self, debug=False):
print "StartPLC"
@@ -174,6 +192,8 @@
self.PLCStatus = "Started"
if self.statuschange is not None:
self.statuschange(self.PLCStatus)
+ self.PythonThread = Thread(target=self.PythonThreadProc)
+ self.PythonThread.start()
return True
else:
print "_StartPLC did not return 0 !"
@@ -270,6 +290,13 @@
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 * 40)]
TypeTranslator = {"BOOL" : (ctypes.c_uint8, lambda x:x.value!=0),
"STEP" : (ctypes.c_uint8, lambda x:x.value),
@@ -278,7 +305,7 @@
"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" : (None, None),#TODO
+ "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),
--- a/targets/Linux/plc_Linux_main.c Tue Dec 23 19:31:28 2008 +0100
+++ b/targets/Linux/plc_Linux_main.c Tue Dec 23 19:37:44 2008 +0100
@@ -1,3 +1,7 @@
+/**
+ * Linux specific code
+ **/
+
#include <stdio.h>
#include <string.h>
#include <time.h>
@@ -5,16 +9,14 @@
#include <stdlib.h>
#include <pthread.h>
+/* provided by POUS.C */
+extern int common_ticktime__;
+
long AtomicCompareExchange(long* atomicvar,long compared, long exchange)
{
return __sync_val_compare_and_swap(atomicvar, compared, exchange);
}
-//long AtomicExchange(long* atomicvar,long exchange)
-//{
-// return __sync_lock_test_and_set(atomicvar, exchange);
-//}
-
void PLC_GetTime(IEC_TIME *CURRENT_TIME)
{
clock_gettime(CLOCK_REALTIME, CURRENT_TIME);
@@ -64,9 +66,12 @@
static int __debug_tick;
-static pthread_mutex_t wait_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
+#define maxval(a,b) ((a>b)?a:b)
int startPLC(int argc,char **argv)
{
struct sigevent sigev;
@@ -79,7 +84,8 @@
sigev.sigev_notify_attributes = NULL;
sigev.sigev_notify_function = PLC_timer_notify;
- pthread_mutex_lock(&wait_mutex);
+ pthread_mutex_lock(&debug_wait_mutex);
+ pthread_mutex_lock(&python_wait_mutex);
timer_create (CLOCK_REALTIME, &sigev, &PLC_timer);
if( __init(argc,argv) == 0 ){
@@ -111,7 +117,7 @@
timer_delete (PLC_timer);
__cleanup();
__debug_tick = -1;
- pthread_mutex_unlock(&wait_mutex);
+ pthread_mutex_unlock(&debug_wait_mutex);
}
extern int __tick;
@@ -119,7 +125,7 @@
int WaitDebugData()
{
/* Wait signal from PLC thread */
- pthread_mutex_lock(&wait_mutex);
+ pthread_mutex_lock(&debug_wait_mutex);
return __debug_tick;
}
@@ -127,25 +133,49 @@
* This is supposed to unlock debugger thread in WaitDebugData*/
void InitiateDebugTransfer()
{
- /* Leave debugger section */
- pthread_mutex_unlock(&debug_mutex);
/* remember tick */
__debug_tick = __tick;
/* signal debugger thread it can read data */
- pthread_mutex_unlock(&wait_mutex);
+ pthread_mutex_unlock(&debug_wait_mutex);
}
-void suspendDebug()
+void suspendDebug(void)
{
- __DEBUG = 0;
/* Prevent PLC to enter debug code */
pthread_mutex_lock(&debug_mutex);
}
-void resumeDebug()
+void resumeDebug(void)
{
- __DEBUG = 1;
/* Let PLC enter debug code */
pthread_mutex_unlock(&debug_mutex);
}
+/* from plc_python.c */
+int WaitPythonCommands(void)
+{
+ /* Wait signal from PLC thread */
+ pthread_mutex_lock(&python_wait_mutex);
+}
+
+/* Called by PLC thread on each new python command*/
+void UnBlockPythonCommands(void)
+{
+ /* signal debugger thread it can read data */
+ pthread_mutex_unlock(&python_wait_mutex);
+}
+
+int TryLockPython(void)
+{
+ return pthread_mutex_trylock(&python_mutex) == 0;
+}
+
+void UnLockPython(void)
+{
+ pthread_mutex_unlock(&python_mutex);
+}
+
+void LockPython(void)
+{
+ pthread_mutex_lock(&python_mutex);
+}
--- a/targets/Win32/plc_Win32_main.c Tue Dec 23 19:31:28 2008 +0100
+++ b/targets/Win32/plc_Win32_main.c Tue Dec 23 19:37:44 2008 +0100
@@ -1,18 +1,20 @@
+/**
+ * Win32 specific code
+ **/
+
#include <stdio.h>
#include <sys/timeb.h>
#include <time.h>
#include <windows.h>
+/* provided by POUS.C */
+extern int common_ticktime__;
+
long AtomicCompareExchange(long* atomicvar, long compared, long exchange)
{
return InterlockedCompareExchange(atomicvar, exchange, compared);
}
-//long AtomicExchange(long* atomicvar,long exchange)
-//{
-// return InterlockedExchange(atomicvar, exchange);
-//}
-
struct _timeb timetmp;
void PLC_GetTime(IEC_TIME *CURRENT_TIME)
{
@@ -64,9 +66,11 @@
HANDLE PLC_thread;
HANDLE debug_sem;
-HANDLE wait_sem;
-#define MAX_SEM_COUNT 1
-
+HANDLE debug_wait_sem;
+HANDLE python_sem;
+HANDLE python_wait_sem;
+
+#define maxval(a,b) ((a>b)?a:b)
int startPLC(int argc,char **argv)
{
unsigned long thread_id = 0;
@@ -76,25 +80,50 @@
debug_sem = CreateSemaphore(
NULL, // default security attributes
1, // initial count
- MAX_SEM_COUNT, // maximum count
+ 1, // maximum count
NULL); // unnamed semaphore
if (debug_sem == NULL)
{
- printf("CreateMutex error: %d\n", GetLastError());
+ printf("startPLC CreateSemaphore debug_sem error: %d\n", GetLastError());
return;
}
- wait_sem = CreateSemaphore(
+ debug_wait_sem = CreateSemaphore(
NULL, // default security attributes
0, // initial count
- MAX_SEM_COUNT, // maximum count
- NULL); // unnamed semaphore
-
- if (wait_sem == NULL)
- {
- printf("CreateMutex error: %d\n", GetLastError());
- return;
- }
+ 1, // maximum count
+ NULL); // unnamed semaphore
+
+ if (debug_wait_sem == NULL)
+ {
+ printf("startPLC CreateSemaphore debug_wait_sem error: %d\n", GetLastError());
+ return;
+ }
+
+ python_sem = CreateSemaphore(
+ NULL, // default security attributes
+ 1, // initial count
+ 1, // maximum count
+ NULL); // unnamed semaphore
+
+ if (python_sem == NULL)
+ {
+ printf("startPLC CreateSemaphore python_sem error: %d\n", GetLastError());
+ return;
+ }
+ python_wait_sem = CreateSemaphore(
+ NULL, // default security attributes
+ 0, // initial count
+ 1, // maximum count
+ NULL); // unnamed semaphore
+
+
+ if (python_wait_sem == NULL)
+ {
+ printf("startPLC CreateSemaphore python_wait_sem error: %d\n", GetLastError());
+ return;
+ }
+
/* Create a waitable timer */
PLC_timer = CreateWaitableTimer(NULL, FALSE, "WaitableTimer");
@@ -133,9 +162,9 @@
WaitForSingleObject(PLC_thread, INFINITE);
__cleanup();
__debug_tick = -1;
- ReleaseSemaphore(wait_sem, 1, NULL);
+ ReleaseSemaphore(debug_wait_sem, 1, NULL);
CloseHandle(debug_sem);
- CloseHandle(wait_sem);
+ CloseHandle(debug_wait_sem);
CloseHandle(PLC_timer);
CloseHandle(PLC_thread);
}
@@ -143,30 +172,58 @@
/* from plc_debugger.c */
int WaitDebugData()
{
- WaitForSingleObject(wait_sem, INFINITE);
+ WaitForSingleObject(debug_wait_sem, INFINITE);
return __debug_tick;
}
-/* Called by PLC thread when debug_pu//blish finished
+/* Called by PLC thread when debug_publish finished
* This is supposed to unlock debugger thread in WaitDebugData*/
void InitiateDebugTransfer()
{
/* remember tick */
__debug_tick = __tick;
/* signal debugger thread it can read data */
- ReleaseSemaphore(wait_sem, 1, NULL);
+ ReleaseSemaphore(debug_wait_sem, 1, NULL);
}
void suspendDebug()
{
- __DEBUG = 0;
/* Prevent PLC to enter debug code */
WaitForSingleObject(debug_sem, INFINITE);
}
void resumeDebug()
{
- __DEBUG = 1;
/* Let PLC enter debug code */
ReleaseSemaphore(debug_sem, 1, NULL);
}
+
+/* from plc_python.c */
+int WaitPythonCommands(void)
+{
+ /* Wait signal from PLC thread */
+ WaitForSingleObject(python_wait_sem, INFINITE);
+}
+
+/* Called by PLC thread on each new python command*/
+void UnBlockPythonCommands(void)
+{
+ /* signal debugger thread it can read data */
+ ReleaseSemaphore(python_wait_sem, 1, NULL);
+}
+
+int TryLockPython(void)
+{
+ return WaitForSingleObject(python_sem, 0) == WAIT_OBJECT_0;
+}
+
+void UnLockPython(void)
+{
+ ReleaseSemaphore(python_sem, 1, NULL);
+}
+
+void LockPython(void)
+{
+ WaitForSingleObject(python_sem, INFINITE);
+}
+
--- a/targets/plc_common_main.c Tue Dec 23 19:31:28 2008 +0100
+++ b/targets/plc_common_main.c Tue Dec 23 19:37:44 2008 +0100
@@ -1,41 +1,35 @@
-/*
- * Prototypes for function provided by arch-specific code (main)
- * concatained after this template
- ** /
+/**
+ * Code common to all C targets
+ **/
+#include "iec_types.h"
/*
- * 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
+ * Prototypes of functions provied by generated C softPLC
**/
void config_run__(int tick);
void config_init__(void);
+
+/*
+ * Prototypes of functions provied by generated target C code
+ * */
void __init_debug(void);
void __cleanup_debug(void);
+/*void __retrieve_debug(void);*/
+void __publish_debug(void);
+void __init_python(void);
+void __cleanup_python(void);
+void __retrieve_python(void);
+void __publish_python(void);
/*
- * Functions and variables to export to generated C softPLC and plugins
+ * Variables used by generated C softPLC and plugins
**/
-
IEC_TIME __CURRENT_TIME;
-IEC_BOOL __DEBUG;
int __tick = -1;
+/* Help to quit cleanly when init fail at a certain level */
static int init_level = 0;
/*
@@ -52,10 +46,14 @@
%(retrieve_calls)s
+ __retrieve_python();
+
/*__retrieve_debug();*/
config_run__(__tick);
+ __publish_python();
+
__publish_debug();
%(publish_calls)s
@@ -169,3 +167,8 @@
}
}
}
+
+/**
+ * Prototypes for function provided by arch-specific code (main)
+ * is concatained hereafter
+ **/
\ No newline at end of file
--- a/targets/plc_debug.c Tue Dec 23 19:31:28 2008 +0100
+++ b/targets/plc_debug.c Tue Dec 23 19:37:44 2008 +0100
@@ -53,10 +53,7 @@
void __init_debug()
{
%(variables_pointer_type_table_initializer)s
-AtomicCompareExchange(
- &buffer_state,
- BUFFER_BUSY,
- BUFFER_FREE);
+ buffer_state = BUFFER_FREE;
}
void __cleanup_debug()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/targets/plc_python.c Tue Dec 23 19:37:44 2008 +0100
@@ -0,0 +1,179 @@
+/*
+ * Python Asynchronous execution code
+ *
+ * PLC put python commands in a fifo, respecting execution order
+ * with the help of C pragmas inserted in python_eval FB code
+ *
+ * Buffer content is read asynchronously, (from non real time part),
+ * commands are executed and result stored for later use by PLC.
+ *
+ * In this implementation, fifo is a list of pointer to python_eval
+ * function blocks structures. Some local variables have been added in
+ * python_eval interface. We use those local variables as buffer and state
+ * flags.
+ *
+ * */
+
+#include "iec_types_all.h"
+#include "POUS.h"
+#include <string.h>
+
+/* The fifo (fixed size, as number of FB is fixed) */
+static PYTHON_EVAL* EvalFBs[%(python_eval_fb_count)d];
+/* Producer and consumer cursors */
+static long Current_PLC_EvalFB;
+static long Current_Python_EvalFB;
+
+/* A global IEC-Python gateway state, for use inside python_eval FBs*/
+static int PythonState;
+#define PYTHON_LOCKED_BY_PYTHON 0
+#define PYTHON_LOCKED_BY_PLC 1
+#define PYTHON_MUSTWAKEUP 2
+
+/* Each python_eval FunctionBlock have it own state */
+#define PYTHON_FB_FREE 0
+#define PYTHON_FB_REQUESTED 1
+#define PYTHON_FB_PROCESSING 2
+#define PYTHON_FB_ANSWERED 3
+
+int WaitPythonCommands(void);
+void UnBlockPythonCommands(void);
+int TryLockPython(void);
+void UnLockPython(void);
+void LockPython(void);
+
+void __init_python()
+{
+ int i;
+ /* Initialize cursors */
+ Current_Python_EvalFB = 0;
+ Current_PLC_EvalFB = 0;
+ PythonState = PYTHON_LOCKED_BY_PYTHON;
+ for(i = 0; i < %(python_eval_fb_count)d; i++)
+ EvalFBs[i] = NULL;
+}
+
+void __cleanup_python()
+{
+}
+
+void __retrieve_python()
+{
+ /* Check Python thread is not being
+ * modifying internal python_eval data */
+ PythonState = TryLockPython() ?
+ PYTHON_LOCKED_BY_PLC :
+ PYTHON_LOCKED_BY_PYTHON;
+ /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON
+ * and python_eval will no do anything */
+}
+
+void __publish_python()
+{
+ if(PythonState & PYTHON_LOCKED_BY_PLC){
+ /* If runnig PLC did push something in the fifo*/
+ if(PythonState & PYTHON_MUSTWAKEUP){
+ /* WakeUp python thread */
+ UnBlockPythonCommands();
+ }
+ UnLockPython();
+ }
+}
+/**
+ * Called by the PLC, each time a python_eval
+ * FB instance is executed
+ */
+void __PythonEvalFB(PYTHON_EVAL* data__)
+{
+ /* python thread is not in ? */
+ if( PythonState & PYTHON_LOCKED_BY_PLC){
+ /* Rising edge on TRIG */
+ if(data__->TRIG && !data__->TRIGM1 &&
+ /* and not already being processed */
+ data__->STATE == PYTHON_FB_FREE)
+ {
+ /* Get a new line */
+ Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) %% %(python_eval_fb_count)d;
+ /* Enter the block in the fifo
+ /* Don't have to check if fifo cell is free
+ * as fifo size == FB count, and a FB cannot
+ * be requested twice */
+ EvalFBs[Current_PLC_EvalFB] = data__;
+ /* copy CODE in variable into BUFFER local*/
+ data__->BUFFER = data__->CODE;
+ /* Set ACK pin to low so that we can set a rising edge on result */
+ data__->ACK = 0;
+ /* Mark FB busy */
+ data__->STATE = PYTHON_FB_REQUESTED;
+ /* Have to wakeup python thread in case he was asleep */
+ PythonState |= PYTHON_MUSTWAKEUP;
+ //printf("__PythonEvalFB push %%*s\n",data__->BUFFER.len, data__->BUFFER.body);
+ }else if(data__->STATE == PYTHON_FB_ANSWERED){
+ data__->RESULT = data__->BUFFER;
+ data__->ACK = 1;
+ data__->STATE = PYTHON_FB_FREE;
+ //printf("__PythonEvalFB pop %%*s\n",data__->BUFFER.len, data__->BUFFER.body);
+ }
+ /* retain value for trig
+ * do this only when PYTHON_LOCKED_BY_PLC
+ * to avoid missed rising edge due to asynchronism */
+ data__->TRIGM1 = data__->TRIG;
+ }
+}
+
+char* PythonIterator(char* result)
+{
+ char* next_command;
+ PYTHON_EVAL* data__;
+ //printf("PythonIterator result %%s\n", result);
+ /* take python mutex to prevent changing PLC data while PLC running */
+ LockPython();
+ /* Get current FB */
+ data__ = EvalFBs[Current_Python_EvalFB];
+ if(data__ && /* may be null at first run */
+ data__->STATE == PYTHON_FB_PROCESSING){ /* some answer awaited*/
+ /* If result not None */
+ if(result){
+ /* Get results len */
+ data__->BUFFER.len = strlen(result);
+ /* prevent results overrun */
+ if(data__->BUFFER.len > STR_MAX_LEN)
+ {
+ data__->BUFFER.len = STR_MAX_LEN;
+ /* TODO : signal error */
+ }
+ /* Copy results to buffer */
+ strncpy(data__->BUFFER.body, result, data__->BUFFER.len);
+ }else{
+ data__->BUFFER.len = 0;
+ }
+ /* remove block from fifo*/
+ EvalFBs[Current_Python_EvalFB] = NULL;
+ /* Mark block as answered */
+ data__->STATE = PYTHON_FB_ANSWERED;
+ /* Get a new line */
+ Current_Python_EvalFB = (Current_Python_EvalFB + 1) %% %(python_eval_fb_count)d;
+ }
+ /* while next slot is empty */
+ while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) ||
+ /* or doesn't contain command */
+ data__->STATE != PYTHON_FB_REQUESTED)
+ {
+ UnLockPython();
+ /* wait next FB to eval */
+ WaitPythonCommands();
+ LockPython();
+ }
+ /* Mark block as processing */
+ data__->STATE = PYTHON_FB_PROCESSING;
+ //printf("PythonIterator\n");
+ /* make BUFFER a null terminated string */
+ data__->BUFFER.body[data__->BUFFER.len] = 0;
+ /* next command is BUFFER */
+ next_command = data__->BUFFER.body;
+ /* free python mutex */
+ UnLockPython();
+ /* return the next command to eval */
+ return next_command;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/python/beremiz.xml Tue Dec 23 19:37:44 2008 +0100
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BeremizRoot URI_location="PYRO://127.0.0.1:3000">
+ <TargetType>
+ <Linux CFLAGS="-g" LDFLAGS="-g"/>
+ </TargetType>
+</BeremizRoot>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/python/plc.xml Tue Dec 23 19:37:44 2008 +0100
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://www.plcopen.org/xml/tc6.xsd"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+ xsi:schemaLocation="http://www.plcopen.org/xml/tc6.xsd">
+ <fileHeader companyName="LOLITECH"
+ productName="Beremiz"
+ productVersion="0.0"
+ creationDateTime="2008-12-14T16:21:19"/>
+ <contentHeader name="Beremiz Python Support Tests"
+ modificationDateTime="2008-12-22T23:58:02">
+ <coordinateInfo>
+ <pageSize x="1024" y="1024"/>
+ <fbd>
+ <scaling x="5" y="5"/>
+ </fbd>
+ <ld>
+ <scaling x="5" y="5"/>
+ </ld>
+ <sfc>
+ <scaling x="5" y="5"/>
+ </sfc>
+ </coordinateInfo>
+ </contentHeader>
+ <types>
+ <dataTypes/>
+ <pous>
+ <pou name="main_pytest" pouType="program">
+ <interface>
+ <localVars>
+ <variable name="pytest_var1">
+ <type>
+ <string/>
+ </type>
+ <initialValue>
+ <simpleValue value="time.sleep(1)"/>
+ </initialValue>
+ </variable>
+ <variable name="pytest_var2">
+ <type>
+ <BOOL/>
+ </type>
+ </variable>
+ <variable name="pytest_var3">
+ <type>
+ <string/>
+ </type>
+ </variable>
+ <variable name="pytest_var4">
+ <type>
+ <BOOL/>
+ </type>
+ </variable>
+ <variable name="py1">
+ <type>
+ <derived name="python_eval"/>
+ </type>
+ </variable>
+ </localVars>
+ </interface>
+ <body>
+ <FBD>
+ <outVariable localId="2" height="30" width="120">
+ <position x="760" y="150"/>
+ <connectionPointIn>
+ <relPosition x="0" y="15"/>
+ <connection refLocalId="5" formalParameter="RESULT">
+ <position x="760" y="165"/>
+ <position x="515" y="165"/>
+ </connection>
+ </connectionPointIn>
+ <expression>pytest_var3</expression>
+ </outVariable>
+ <inVariable localId="4" height="30" width="120">
+ <position x="35" y="150"/>
+ <connectionPointOut>
+ <relPosition x="120" y="15"/>
+ </connectionPointOut>
+ <expression>pytest_var1</expression>
+ </inVariable>
+ <block localId="5" width="125" height="80" typeName="python_eval" instanceName="py1">
+ <position x="390" y="100"/>
+ <inputVariables>
+ <variable formalParameter="TRIG">
+ <connectionPointIn>
+ <relPosition x="0" y="35"/>
+ <connection refLocalId="7" formalParameter="OUT">
+ <position x="390" y="135"/>
+ <position x="190" y="135"/>
+ <position x="190" y="55"/>
+ <position x="130" y="55"/>
+ </connection>
+ </connectionPointIn>
+ </variable>
+ <variable formalParameter="CODE">
+ <connectionPointIn>
+ <relPosition x="0" y="65"/>
+ <connection refLocalId="4">
+ <position x="390" y="165"/>
+ <position x="155" y="165"/>
+ </connection>
+ </connectionPointIn>
+ </variable>
+ </inputVariables>
+ <inOutVariables/>
+ <outputVariables>
+ <variable formalParameter="ACK">
+ <connectionPointOut>
+ <relPosition x="125" y="35"/>
+ </connectionPointOut>
+ </variable>
+ <variable formalParameter="RESULT">
+ <connectionPointOut>
+ <relPosition x="125" y="65"/>
+ </connectionPointOut>
+ </variable>
+ </outputVariables>
+ </block>
+ <outVariable localId="6" height="30" width="120">
+ <position x="760" y="120"/>
+ <connectionPointIn>
+ <relPosition x="0" y="15"/>
+ <connection refLocalId="5" formalParameter="ACK">
+ <position x="760" y="135"/>
+ <position x="515" y="135"/>
+ </connection>
+ </connectionPointIn>
+ <expression>pytest_var4</expression>
+ </outVariable>
+ <block localId="7" width="70" height="45" typeName="NOT">
+ <position x="60" y="25"/>
+ <inputVariables>
+ <variable formalParameter="IN">
+ <connectionPointIn>
+ <relPosition x="0" y="30"/>
+ <connection refLocalId="3">
+ <position x="60" y="55"/>
+ <position x="45" y="55"/>
+ <position x="45" y="85"/>
+ <position x="165" y="85"/>
+ <position x="165" y="120"/>
+ <position x="155" y="120"/>
+ </connection>
+ </connectionPointIn>
+ </variable>
+ </inputVariables>
+ <inOutVariables/>
+ <outputVariables>
+ <variable formalParameter="OUT">
+ <connectionPointOut>
+ <relPosition x="70" y="30"/>
+ </connectionPointOut>
+ </variable>
+ </outputVariables>
+ </block>
+ <inOutVariable localId="3" height="30" width="120">
+ <position x="35" y="105"/>
+ <connectionPointIn>
+ <relPosition x="0" y="15"/>
+ <connection refLocalId="7" formalParameter="OUT">
+ <position x="35" y="120"/>
+ <position x="25" y="120"/>
+ <position x="25" y="15"/>
+ <position x="210" y="15"/>
+ <position x="210" y="55"/>
+ <position x="130" y="55"/>
+ </connection>
+ </connectionPointIn>
+ <connectionPointOut>
+ <relPosition x="120" y="15"/>
+ </connectionPointOut>
+ <expression>pytest_var2</expression>
+ </inOutVariable>
+ </FBD>
+ </body>
+ </pou>
+ </pous>
+ </types>
+ <instances>
+ <configurations>
+ <configuration name="conf_pytest">
+ <resource name="res_pytest">
+ <task name="pytest_task" interval="00:00:00.100000" priority="0"/>
+ <pouInstance name="pytest_instance" type="main_pytest"/>
+ </resource>
+ </configuration>
+ </configurations>
+ </instances>
+</project>