diff -r 6be032177e2a -r ecf4d203c4d4 confnodes/python/plc_python.c --- a/confnodes/python/plc_python.c Tue May 08 16:31:12 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,216 +0,0 @@ -/* - * 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 - -/* The fifo (fixed size, as number of FB is fixed) */ -static PYTHON_EVAL* EvalFBs[%(python_eval_fb_count)d]; -/* Producer and consumer cursors */ -static int Current_PLC_EvalFB; -static int 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 -#define PYTHON_FINISHED 4 - -/* 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); - -int __init_%(location)s() -{ - 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; - return 0; -} - -void __cleanup_%(location)s() -{ - PythonState = PYTHON_FINISHED; - UnBlockPythonCommands(); -} - -void __retrieve_%(location)s() -{ - /* 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_%(location)s() -{ - 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(int poll, PYTHON_EVAL* data__) -{ - /* detect rising edge on TRIG to trigger evaluation */ - if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || - /* polling is equivalent to trig on value rather than on rising edge*/ - (poll && __GET_VAR(data__->TRIG) )) && - /* trig only if not already trigged */ - __GET_VAR(data__->TRIGGED) == 0){ - /* mark as trigged */ - __SET_VAR(data__->, TRIGGED, 1); - /* make a safe copy of the code */ - __SET_VAR(data__->, PREBUFFER, __GET_VAR(data__->CODE)); - } - /* retain value for next rising edge detection */ - __SET_VAR(data__->, TRIGM1, __GET_VAR(data__->TRIG)); - - /* python thread is not in ? */ - if( PythonState & PYTHON_LOCKED_BY_PLC){ - /* if some answer are waiting, publish*/ - if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ - /* Copy buffer content into result*/ - __SET_VAR(data__->, RESULT, __GET_VAR(data__->BUFFER)); - /* signal result presece to PLC*/ - __SET_VAR(data__->, ACK, 1); - /* Mark as free */ - __SET_VAR(data__->, STATE, PYTHON_FB_FREE); - /* mark as not trigged */ - if(!poll) - __SET_VAR(data__->, TRIGGED, 0); - /*printf("__PythonEvalFB pop %%d - %%*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ - }else if(poll){ - /* when in polling, no answer == ack down */ - __SET_VAR(data__->, ACK, 0); - } - /* got the order to act ?*/ - if(__GET_VAR(data__->TRIGGED) == 1 && - /* and not already being processed */ - __GET_VAR(data__->STATE) == PYTHON_FB_FREE) - { - /* 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 into BUFFER local*/ - __SET_VAR(data__->, BUFFER, __GET_VAR(data__->PREBUFFER)); - /* Set ACK pin to low so that we can set a rising edge on result */ - if(!poll){ - /* when not polling, a new answer imply reseting ack*/ - __SET_VAR(data__->, ACK, 0); - }else{ - /* when in polling, acting reset trigger */ - __SET_VAR(data__->, TRIGGED, 0); - } - /* Mark FB busy */ - __SET_VAR(data__->, STATE, PYTHON_FB_REQUESTED); - /* Have to wakeup python thread in case he was asleep */ - PythonState |= PYTHON_MUSTWAKEUP; - /*printf("__PythonEvalFB push %%d - %%*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ - /* Get a new line */ - Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) %% %(python_eval_fb_count)d; - } - } -} - -char* PythonIterator(char* result) -{ - char* next_command; - PYTHON_EVAL* data__; - //printf("PythonIterator result %%s\n", result); - /*emergency exit*/ - if(PythonState & PYTHON_FINISHED) return NULL; - /* 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 */ - __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ - /* If result not None */ - if(result){ - /* Get results len */ - __SET_VAR(data__->, BUFFER, strlen(result), .len); - /* prevent results overrun */ - if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) - { - __SET_VAR(data__->, BUFFER, STR_MAX_LEN, .len ); - /* TODO : signal error */ - } - /* Copy results to buffer */ - strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); - }else{ - __SET_VAR(data__->, BUFFER, 0, .len); - } - /* remove block from fifo*/ - EvalFBs[Current_Python_EvalFB] = NULL; - /* Mark block as answered */ - __SET_VAR(data__->, STATE, PYTHON_FB_ANSWERED); - /* Get a new line */ - Current_Python_EvalFB = (Current_Python_EvalFB + 1) %% %(python_eval_fb_count)d; - //printf("PythonIterator ++ Current_Python_EvalFB %%d\n", Current_Python_EvalFB); - } - /* while next slot is empty */ - while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || - /* or doesn't contain command */ - __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) - { - UnLockPython(); - /* wait next FB to eval */ - //printf("PythonIterator wait\n"); - if(WaitPythonCommands()) return NULL; - /*emergency exit*/ - if(PythonState & PYTHON_FINISHED) return NULL; - LockPython(); - } - /* Mark block as processing */ - __SET_VAR(data__->, STATE, PYTHON_FB_PROCESSING); - //printf("PythonIterator\n"); - /* make BUFFER a null terminated string */ - __SET_VAR(data__->, BUFFER, 0, .body[__GET_VAR(data__->BUFFER, .len)]); - /* next command is BUFFER */ - next_command = (char*)__GET_VAR(data__->BUFFER, .body); - /* free python mutex */ - UnLockPython(); - /* return the next command to eval */ - return next_command; -} -