lbessard@321: /**
lbessard@321:  * Linux specific code
greg@336:  **/
lbessard@321: 
lbessard@321: #include <stdio.h>
Edouard@615: #include <unistd.h>
lbessard@321: #include <string.h>
lbessard@321: #include <time.h>
lbessard@321: #include <signal.h>
lbessard@321: #include <stdlib.h>
lbessard@321: #include <sys/mman.h>
greg@342: #include <sys/fcntl.h>
lbessard@321: 
lbessard@321: #include <native/task.h>
lbessard@321: #include <native/timer.h>
lbessard@321: #include <native/mutex.h>
lbessard@321: #include <native/sem.h>
greg@342: #include <native/pipe.h>
lbessard@321: 
lbessard@321: unsigned int PLC_state = 0;
Edouard@615: #define PLC_STATE_TASK_CREATED                 1
Edouard@615: #define PLC_STATE_DEBUG_FILE_OPENED            2 
Edouard@615: #define PLC_STATE_DEBUG_PIPE_CREATED           4 
Edouard@615: #define PLC_STATE_PYTHON_FILE_OPENED           8 
Edouard@615: #define PLC_STATE_PYTHON_PIPE_CREATED          16   
Edouard@615: #define PLC_STATE_WAITDEBUG_FILE_OPENED        32   
Edouard@615: #define PLC_STATE_WAITDEBUG_PIPE_CREATED       64
Edouard@615: #define PLC_STATE_WAITPYTHON_FILE_OPENED       128
Edouard@615: #define PLC_STATE_WAITPYTHON_PIPE_CREATED      256
Edouard@615: 
Edouard@615: #define WAITDEBUG_PIPE_DEVICE        "/dev/rtp0"
Edouard@615: #define WAITDEBUG_PIPE_MINOR         0
Edouard@615: #define DEBUG_PIPE_DEVICE            "/dev/rtp1"
Edouard@615: #define DEBUG_PIPE_MINOR             1
Edouard@615: #define WAITPYTHON_PIPE_DEVICE       "/dev/rtp2"
Edouard@615: #define WAITPYTHON_PIPE_MINOR        2
Edouard@615: #define PYTHON_PIPE_DEVICE           "/dev/rtp3"
Edouard@615: #define PYTHON_PIPE_MINOR            3
Edouard@615: #define PIPE_SIZE                    1 
lbessard@321: 
lbessard@321: /* provided by POUS.C */
laurent@397: extern unsigned long common_ticktime__;
lbessard@321: 
lbessard@321: long AtomicCompareExchange(long* atomicvar,long compared, long exchange)
lbessard@321: {
lbessard@321:     return __sync_val_compare_and_swap(atomicvar, compared, exchange);
lbessard@321: }
lbessard@321: 
lbessard@321: void PLC_GetTime(IEC_TIME *CURRENT_TIME)
lbessard@321: {
lbessard@321:     RTIME current_time = rt_timer_read();
lbessard@321:     CURRENT_TIME->tv_sec = current_time / 1000000000;
lbessard@321:     CURRENT_TIME->tv_nsec = current_time % 1000000000;
lbessard@321: }
lbessard@321: 
lbessard@321: RT_TASK PLC_task;
greg@342: RT_PIPE WaitDebug_pipe;
Edouard@615: RT_PIPE WaitPython_pipe;
Edouard@615: RT_PIPE Debug_pipe;
Edouard@615: RT_PIPE Python_pipe;
Edouard@615: int WaitDebug_pipe_fd;
Edouard@615: int WaitPython_pipe_fd;
Edouard@615: int Debug_pipe_fd;
Edouard@615: int Python_pipe_fd;
Edouard@615: 
lbessard@321: int PLC_shutdown = 0;
lbessard@321: 
Edouard@615: void PLC_SetTimer(unsigned long long next, unsigned long long period)
lbessard@321: {
lbessard@321:   RTIME current_time = rt_timer_read();
lbessard@321:   rt_task_set_periodic(&PLC_task, current_time + next, rt_timer_ns2ticks(period));
lbessard@321: }
lbessard@321: 
lbessard@321: void PLC_task_proc(void *arg)
lbessard@321: {
lbessard@321:     PLC_SetTimer(Ttick, Ttick);
greg@336: 
lbessard@321:     while (1) {
lbessard@321:         PLC_GetTime(&__CURRENT_TIME);
lbessard@321:         __run();
lbessard@321:         if (PLC_shutdown) break;
lbessard@321:         rt_task_wait_period(NULL);
lbessard@321:     }
lbessard@321: }
lbessard@321: 
laurent@397: static unsigned long __debug_tick;
lbessard@321: 
lbessard@321: void PLC_cleanup_all(void)
lbessard@321: {
lbessard@321:     if (PLC_state & PLC_STATE_TASK_CREATED) {
lbessard@321:         rt_task_delete(&PLC_task);
lbessard@321:         PLC_state &= ~PLC_STATE_TASK_CREATED;
lbessard@321:     }
lbessard@321: 
Edouard@615:     if (PLC_state & PLC_STATE_WAITDEBUG_PIPE_CREATED) {
Edouard@615:         rt_pipe_delete(&WaitDebug_pipe);
Edouard@615:         PLC_state &= ~PLC_STATE_WAITDEBUG_PIPE_CREATED;
Edouard@615:     }
Edouard@615: 
Edouard@615:     if (PLC_state & PLC_STATE_WAITDEBUG_FILE_OPENED) {
Edouard@615:         close(WaitDebug_pipe_fd);
Edouard@615:         PLC_state &= ~PLC_STATE_WAITDEBUG_FILE_OPENED;
Edouard@615:     }
Edouard@615: 
Edouard@615:     if (PLC_state & PLC_STATE_WAITPYTHON_PIPE_CREATED) {
Edouard@615:         rt_pipe_delete(&WaitPython_pipe);
Edouard@615:         PLC_state &= ~PLC_STATE_WAITDEBUG_PIPE_CREATED;
Edouard@615:     }
Edouard@615: 
Edouard@615:     if (PLC_state & PLC_STATE_WAITPYTHON_PIPE_CREATED) {
Edouard@615:         close(WaitPython_pipe_fd);
Edouard@615:         PLC_state &= ~PLC_STATE_WAITPYTHON_FILE_OPENED;
lbessard@321:     }
greg@336: 
greg@342:     if (PLC_state & PLC_STATE_DEBUG_PIPE_CREATED) {
Edouard@615:         rt_pipe_delete(&Debug_pipe);
greg@342:         PLC_state &= ~PLC_STATE_DEBUG_PIPE_CREATED;
greg@342:     }
greg@342: 
greg@342:     if (PLC_state & PLC_STATE_DEBUG_FILE_OPENED) {
Edouard@615:         close(Debug_pipe_fd);
greg@342:         PLC_state &= ~PLC_STATE_DEBUG_FILE_OPENED;
lbessard@321:     }
lbessard@321: 
Edouard@615:     if (PLC_state & PLC_STATE_PYTHON_PIPE_CREATED) {
Edouard@615:         rt_pipe_delete(&Python_pipe);
Edouard@615:         PLC_state &= ~PLC_STATE_DEBUG_PIPE_CREATED;
Edouard@615:     }
Edouard@615: 
Edouard@615:     if (PLC_state & PLC_STATE_PYTHON_PIPE_CREATED) {
Edouard@615:         close(Python_pipe_fd);
Edouard@615:         PLC_state &= ~PLC_STATE_PYTHON_FILE_OPENED;
Edouard@615:     }
Edouard@615: 
lbessard@321: }
lbessard@321: 
lbessard@321: int stopPLC()
lbessard@321: {
lbessard@321:     PLC_shutdown = 1;
lbessard@321:     /* Stop the PLC */
lbessard@321:     PLC_SetTimer(0, 0);
greg@342:     __cleanup();
lbessard@321:     PLC_cleanup_all();
lbessard@321:     __debug_tick = -1;
Edouard@615:     return 0;
lbessard@321: }
lbessard@321: 
lbessard@321: //
lbessard@321: void catch_signal(int sig)
lbessard@321: {
lbessard@321:     stopPLC();
lbessard@321: //  signal(SIGTERM, catch_signal);
lbessard@321:     signal(SIGINT, catch_signal);
lbessard@321:     printf("Got Signal %d\n",sig);
lbessard@321:     exit(0);
lbessard@321: }
lbessard@321: 
lbessard@321: #define max_val(a,b) ((a>b)?a:b)
lbessard@321: int startPLC(int argc,char **argv)
lbessard@321: {
lbessard@321:     signal(SIGINT, catch_signal);
greg@336: 
Edouard@615:     /* no memory swapping for that process */
lbessard@321:     mlockall(MCL_CURRENT | MCL_FUTURE);
greg@336: 
laurent@397:     /* Define Ttick to 1ms if common_ticktime not defined */
laurent@397:     Ttick = common_ticktime__?common_ticktime__:1000000;
greg@336: 
Edouard@615:     /*** RT Pipes creation and opening ***/
Edouard@615:     /* create Debug_pipe */
Edouard@615:     if(rt_pipe_create(&Debug_pipe, "Debug_pipe", DEBUG_PIPE_MINOR, PIPE_SIZE)) 
Edouard@615:         goto error;
Edouard@615:     PLC_state |= PLC_STATE_DEBUG_PIPE_CREATED;
Edouard@615: 
Edouard@615:     /* open Debug_pipe*/
Edouard@615:     if((Debug_pipe_fd = open(DEBUG_PIPE_DEVICE, O_RDWR)) == -1) goto error;
Edouard@615:     PLC_state |= PLC_STATE_DEBUG_FILE_OPENED;
Edouard@615: 
Edouard@615:     /* create Python_pipe */
Edouard@615:     if(rt_pipe_create(&Python_pipe, "Python_pipe", PYTHON_PIPE_MINOR, PIPE_SIZE)) 
Edouard@615:         goto error;
Edouard@615:     PLC_state |= PLC_STATE_PYTHON_PIPE_CREATED;
Edouard@615: 
Edouard@615:     /* open Python_pipe*/
Edouard@615:     if((Python_pipe_fd = open(PYTHON_PIPE_DEVICE, O_RDWR)) == -1) goto error;
Edouard@615:     PLC_state |= PLC_STATE_PYTHON_FILE_OPENED;
greg@336: 
greg@342:     /* create WaitDebug_pipe */
Edouard@616:     if(rt_pipe_create(&WaitDebug_pipe, "WaitDebug_pipe", WAITDEBUG_PIPE_MINOR, PIPE_SIZE))
Edouard@615:         goto error;
Edouard@615:     PLC_state |= PLC_STATE_WAITDEBUG_PIPE_CREATED;
greg@342: 
greg@342:     /* open WaitDebug_pipe*/
Edouard@615:     if((WaitDebug_pipe_fd = open(WAITDEBUG_PIPE_DEVICE, O_RDWR)) == -1) goto error;
Edouard@615:     PLC_state |= PLC_STATE_WAITDEBUG_FILE_OPENED;
Edouard@615: 
Edouard@615:     /* create WaitPython_pipe */
Edouard@616:     if(rt_pipe_create(&WaitPython_pipe, "WaitPython_pipe", WAITPYTHON_PIPE_MINOR, PIPE_SIZE))
greg@342:         goto error;
Edouard@615:     PLC_state |= PLC_STATE_WAITPYTHON_PIPE_CREATED;
Edouard@615: 
Edouard@615:     /* open WaitPython_pipe*/
Edouard@615:     if((WaitPython_pipe_fd = open(WAITPYTHON_PIPE_DEVICE, O_RDWR)) == -1) goto error;
Edouard@615:     PLC_state |= PLC_STATE_WAITPYTHON_FILE_OPENED;
Edouard@615: 
Edouard@615:     /*** create PLC task ***/
Edouard@615:     if(rt_task_create(&PLC_task, "PLC_task", 0, 50, 0)) goto error;
lbessard@321:     PLC_state |= PLC_STATE_TASK_CREATED;
greg@336: 
Edouard@615:     if(__init(argc,argv)) goto error;
Edouard@615: 
Edouard@615:     /* start PLC task */
Edouard@615:     if(rt_task_start(&PLC_task, &PLC_task_proc, NULL)) goto error;
lbessard@321: 
lbessard@321:     return 0;
lbessard@321: 
lbessard@321: error:
Edouard@616: 
lbessard@321:     PLC_cleanup_all();
lbessard@321:     return 1;
lbessard@321: }
lbessard@321: 
Edouard@615: #define DEBUG_FREE 0
Edouard@615: #define DEBUG_BUSY 1
Edouard@615: static long debug_state = DEBUG_FREE;
Edouard@615: 
lbessard@321: int TryEnterDebugSection(void)
lbessard@321: {
Edouard@616:     if(AtomicCompareExchange(
Edouard@615:         &debug_state,
Edouard@615:         DEBUG_FREE,
Edouard@616:         DEBUG_BUSY) == DEBUG_FREE){
Edouard@616:         if(__DEBUG){
Edouard@616:             return 1;
Edouard@616:         }
Edouard@616:         AtomicCompareExchange( &debug_state, DEBUG_BUSY, DEBUG_FREE);
Edouard@616:     }
Edouard@616:     return 0;
Edouard@615: }
Edouard@615: 
Edouard@615: #define DEBUG_UNLOCK 1
lbessard@321: void LeaveDebugSection(void)
lbessard@321: {
Edouard@615:     if(AtomicCompareExchange( &debug_state, 
Edouard@615:         DEBUG_BUSY, DEBUG_FREE) == DEBUG_BUSY){
Edouard@615:         char msg = DEBUG_UNLOCK;
Edouard@615:         /* signal to NRT for wakeup */
Edouard@615:         rt_pipe_write(&Debug_pipe, &msg, sizeof(msg), P_NORMAL);
Edouard@615:     }
lbessard@321: }
lbessard@321: 
laurent@397: extern unsigned long __tick;
Edouard@615: 
Edouard@615: #define DEBUG_PENDING_DATA 1
ed@446: int WaitDebugData(unsigned long *tick)
lbessard@321: {
Edouard@615:     char cmd;
greg@345:     int res;
lbessard@321:     /* Wait signal from PLC thread */
Edouard@615:     res = read(WaitDebug_pipe_fd, &cmd, sizeof(cmd));
Edouard@617:     if (res == sizeof(cmd) && cmd == DEBUG_PENDING_DATA){
Edouard@617:         *tick = __debug_tick;
Edouard@615:         return 0;
Edouard@617:     }
greg@345:     return -1;
lbessard@321: }
greg@336: 
lbessard@321: /* Called by PLC thread when debug_publish finished
lbessard@321:  * This is supposed to unlock debugger thread in WaitDebugData*/
lbessard@321: void InitiateDebugTransfer()
lbessard@321: {
Edouard@615:     char msg = DEBUG_PENDING_DATA;
lbessard@321:     /* remember tick */
lbessard@321:     __debug_tick = __tick;
lbessard@321:     /* signal debugger thread it can read data */
Edouard@615:     rt_pipe_write(&WaitDebug_pipe, &msg, sizeof(msg), P_NORMAL);
Edouard@615: }
Edouard@615: 
Edouard@615: int suspendDebug(int disable)
Edouard@615: {
Edouard@615:     char cmd = DEBUG_UNLOCK;
Edouard@615:     while(AtomicCompareExchange(
Edouard@615:             &debug_state,
Edouard@615:             DEBUG_FREE,
Edouard@615:             DEBUG_BUSY) != DEBUG_FREE &&
Edouard@615:             cmd == DEBUG_UNLOCK){
Edouard@616:        if(read(Debug_pipe_fd, &cmd, sizeof(cmd)) != sizeof(cmd)){
Edouard@615:            return -1;
Edouard@615:        }
Edouard@615:     }
Edouard@615:     __DEBUG = !disable;
Edouard@617:     if (disable)
Edouard@617:         AtomicCompareExchange( &debug_state, DEBUG_BUSY, DEBUG_FREE);
Edouard@615:     return 0;
lbessard@321: }
lbessard@321: 
lbessard@321: void resumeDebug(void)
lbessard@321: {
Edouard@615:     AtomicCompareExchange( &debug_state, DEBUG_BUSY, DEBUG_FREE);
Edouard@615: }
Edouard@615: 
Edouard@615: #define PYTHON_PENDING_COMMAND 1
Edouard@615: 
Edouard@615: #define PYTHON_FREE 0
Edouard@615: #define PYTHON_BUSY 1
Edouard@615: static long python_state = PYTHON_FREE;
Edouard@615: 
lbessard@321: int WaitPythonCommands(void)
Edouard@615: { 
Edouard@615:     char cmd;
lbessard@321:     /* Wait signal from PLC thread */
Edouard@615:     if(read(WaitPython_pipe_fd, &cmd, sizeof(cmd))==sizeof(cmd) && cmd==PYTHON_PENDING_COMMAND){
Edouard@615:         return 0;
greg@345:     }
greg@345:     return -1;
lbessard@321: }
greg@336: 
lbessard@321: /* Called by PLC thread on each new python command*/
lbessard@321: void UnBlockPythonCommands(void)
lbessard@321: {
Edouard@615:     char msg = PYTHON_PENDING_COMMAND;
Edouard@615:     rt_pipe_write(&WaitPython_pipe, &msg, sizeof(msg), P_NORMAL);
lbessard@321: }
lbessard@321: 
lbessard@321: int TryLockPython(void)
lbessard@321: {
Edouard@615:     return AtomicCompareExchange(
Edouard@615:         &python_state,
Edouard@615:         PYTHON_FREE,
Edouard@615:         PYTHON_BUSY) == PYTHON_FREE;
Edouard@615: }
Edouard@615: 
Edouard@615: #define UNLOCK_PYTHON 1
Edouard@615: void LockPython(void)
Edouard@615: {
Edouard@615:     char cmd = UNLOCK_PYTHON;
Edouard@615:     while(AtomicCompareExchange(
Edouard@615:             &python_state,
Edouard@615:             PYTHON_FREE,
Edouard@615:             PYTHON_BUSY) != PYTHON_FREE &&
Edouard@615:             cmd == UNLOCK_PYTHON){
Edouard@615:        read(Python_pipe_fd, &cmd, sizeof(cmd));
Edouard@615:     }
lbessard@321: }
lbessard@321: 
lbessard@321: void UnLockPython(void)
lbessard@321: {
Edouard@615:     if(AtomicCompareExchange(
Edouard@615:             &python_state,
Edouard@615:             PYTHON_BUSY,
Edouard@615:             PYTHON_FREE) == PYTHON_BUSY){
Edouard@615:         if(rt_task_self()){/*is that the real time task ?*/
Edouard@615:            char cmd = UNLOCK_PYTHON;
Edouard@615:            rt_pipe_write(&Python_pipe, &cmd, sizeof(cmd), P_NORMAL);
Edouard@615:         }/* otherwise, no signaling from non real time */
Edouard@615:     }    /* as plc does not wait for lock. */
Edouard@615: }
Edouard@615: 
Edouard@616: int CheckRetainBuffer(void)
Edouard@616: {
Edouard@616: 	return 1;
Edouard@616: }
Edouard@616: 
Edouard@616: void ValidateRetainBuffer(void)
Edouard@616: {
Edouard@616: }
Edouard@616: 
Edouard@616: void InValidateRetainBuffer(void)
Edouard@616: {
Edouard@616: }
Edouard@616: 
Edouard@616: void Retain(unsigned int offset, unsigned int count, void *p)
Edouard@616: {
Edouard@616: }
Edouard@616: 
Edouard@616: void Remind(unsigned int offset, unsigned int count, void *p)
Edouard@616: {
Edouard@616: }
Edouard@616: