etisserant@280: /**
etisserant@280:  * Linux specific code
greg@329:  **/
etisserant@280: 
greg@205: #include <stdio.h>
greg@205: #include <string.h>
greg@205: #include <time.h>
greg@205: #include <signal.h>
greg@205: #include <stdlib.h>
greg@329: #include <pthread.h>
edouard@568: #include <locale.h>
Laurent@876: #include <semaphore.h>
greg@205: 
Laurent@876: static sem_t Run_PLC;
etisserant@280: 
etisserant@236: long AtomicCompareExchange(long* atomicvar,long compared, long exchange)
greg@205: {
greg@205:     return __sync_val_compare_and_swap(atomicvar, compared, exchange);
greg@205: }
Edouard@954: long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange)
Edouard@954: {
Edouard@954:     return __sync_val_compare_and_swap(atomicvar, compared, exchange);
Edouard@954: }
greg@205: 
greg@205: void PLC_GetTime(IEC_TIME *CURRENT_TIME)
greg@205: {
Edouard@592:     struct timespec tmp;
Edouard@592:     clock_gettime(CLOCK_REALTIME, &tmp);
Edouard@592:     CURRENT_TIME->tv_sec = tmp.tv_sec;
Edouard@592:     CURRENT_TIME->tv_nsec = tmp.tv_nsec;
greg@205: }
greg@205: 
greg@205: void PLC_timer_notify(sigval_t val)
greg@205: {
greg@205:     PLC_GetTime(&__CURRENT_TIME);
Laurent@876:     sem_post(&Run_PLC);
greg@205: }
greg@205: 
greg@205: timer_t PLC_timer;
greg@205: 
edouard@518: void PLC_SetTimer(unsigned long long next, unsigned long long period)
greg@205: {
greg@205:     struct itimerspec timerValues;
greg@205: 	/*
greg@205: 	printf("SetTimer(%lld,%lld)\n",next, period);
greg@205: 	*/
greg@205:     memset (&timerValues, 0, sizeof (struct itimerspec));
greg@205: 	{
greg@205: #ifdef __lldiv_t_defined
greg@205: 		lldiv_t nxt_div = lldiv(next, 1000000000);
greg@205: 		lldiv_t period_div = lldiv(period, 1000000000);
greg@205: 	    timerValues.it_value.tv_sec = nxt_div.quot;
greg@205: 	    timerValues.it_value.tv_nsec = nxt_div.rem;
greg@205: 	    timerValues.it_interval.tv_sec = period_div.quot;
greg@205: 	    timerValues.it_interval.tv_nsec = period_div.rem;
greg@205: #else
greg@205: 	    timerValues.it_value.tv_sec = next / 1000000000;
greg@205: 	    timerValues.it_value.tv_nsec = next % 1000000000;
greg@205: 	    timerValues.it_interval.tv_sec = period / 1000000000;
greg@205: 	    timerValues.it_interval.tv_nsec = period % 1000000000;
greg@205: #endif
greg@329: 	}
greg@205:     timer_settime (PLC_timer, 0, &timerValues, NULL);
greg@205: }
greg@205: //
greg@205: void catch_signal(int sig)
greg@205: {
greg@205: //  signal(SIGTERM, catch_signal);
greg@205:   signal(SIGINT, catch_signal);
greg@205:   printf("Got Signal %d\n",sig);
greg@205:   exit(0);
greg@205: }
greg@205: 
etisserant@239: 
laurent@397: static unsigned long __debug_tick;
etisserant@239: 
Laurent@876: pthread_t PLC_thread;
etisserant@280: static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER;
etisserant@280: static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER;
etisserant@280: static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER;
etisserant@239: static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
etisserant@239: 
Laurent@876: int PLC_shutdown = 0;
Laurent@876: 
Laurent@876: void PLC_thread_proc(void *arg)
Laurent@876: {
Laurent@876:     while (!PLC_shutdown) {
Laurent@876:         sem_wait(&Run_PLC);
Laurent@876:         __run();
Laurent@876:     }
Laurent@876:     pthread_exit(0);
Laurent@876: }
Laurent@876: 
etisserant@280: #define maxval(a,b) ((a>b)?a:b)
greg@205: int startPLC(int argc,char **argv)
greg@205: {
greg@205:     struct sigevent sigev;
edouard@568:     setlocale(LC_NUMERIC, "C");
greg@329: 
Laurent@876:     PLC_shutdown = 0;
Laurent@876: 
Laurent@876:     sem_init(&Run_PLC, 0, 0);
Laurent@876: 
Laurent@876:     pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL);
Laurent@876: 
greg@205:     memset (&sigev, 0, sizeof (struct sigevent));
greg@205:     sigev.sigev_value.sival_int = 0;
greg@205:     sigev.sigev_notify = SIGEV_THREAD;
greg@205:     sigev.sigev_notify_attributes = NULL;
greg@205:     sigev.sigev_notify_function = PLC_timer_notify;
greg@205: 
lbessard@333:     pthread_mutex_init(&debug_wait_mutex, NULL);
edouard@462:     pthread_mutex_init(&debug_mutex, NULL);
lbessard@333:     pthread_mutex_init(&python_wait_mutex, NULL);
edouard@462:     pthread_mutex_init(&python_mutex, NULL);
greg@329: 
etisserant@280:     pthread_mutex_lock(&debug_wait_mutex);
etisserant@280:     pthread_mutex_lock(&python_wait_mutex);
etisserant@239: 
greg@205:     timer_create (CLOCK_REALTIME, &sigev, &PLC_timer);
greg@205:     if(  __init(argc,argv) == 0 ){
greg@205:         PLC_SetTimer(Ttick,Ttick);
greg@329: 
greg@205:         /* install signal handler for manual break */
greg@205:         signal(SIGINT, catch_signal);
greg@205:     }else{
greg@205:         return 1;
greg@205:     }
greg@205:     return 0;
greg@205: }
greg@205: 
etisserant@239: int TryEnterDebugSection(void)
etisserant@239: {
edouard@462:     if (pthread_mutex_trylock(&debug_mutex) == 0){
edouard@462:         /* Only enter if debug active */
edouard@462:         if(__DEBUG){
edouard@462:             return 1;
edouard@462:         }
edouard@483:         pthread_mutex_unlock(&debug_mutex);
edouard@462:     }
edouard@462:     return 0;
etisserant@239: }
etisserant@235: 
etisserant@239: void LeaveDebugSection(void)
etisserant@235: {
etisserant@239:     pthread_mutex_unlock(&debug_mutex);
etisserant@235: }
etisserant@235: 
greg@205: int stopPLC()
greg@205: {
greg@205:     /* Stop the PLC */
Laurent@876:     PLC_shutdown = 1;
Laurent@876:     sem_post(&Run_PLC);
greg@205:     PLC_SetTimer(0,0);
Laurent@876: 	pthread_join(PLC_thread, NULL);
Laurent@876: 	sem_destroy(&Run_PLC);
greg@205:     timer_delete (PLC_timer);
greg@205:     __cleanup();
greg@329:     pthread_mutex_destroy(&debug_wait_mutex);
edouard@483:     pthread_mutex_destroy(&debug_mutex);
greg@329:     pthread_mutex_destroy(&python_wait_mutex);
edouard@483:     pthread_mutex_destroy(&python_mutex);
laurent@386:     return 0;
greg@205: }
greg@205: 
laurent@397: extern unsigned long __tick;
ed@446: 
ed@446: int WaitDebugData(unsigned long *tick)
greg@205: {
Edouard@617:     int res;
Laurent@876:     if (PLC_shutdown) return 1;
Edouard@617:     /* Wait signal from PLC thread */
Edouard@617:     res = pthread_mutex_lock(&debug_wait_mutex);
ed@446:     *tick = __debug_tick;
Edouard@617:     return res;
greg@205: }
greg@329: 
greg@205: /* Called by PLC thread when debug_publish finished
greg@205:  * This is supposed to unlock debugger thread in WaitDebugData*/
greg@205: void InitiateDebugTransfer()
greg@205: {
etisserant@239:     /* remember tick */
etisserant@227:     __debug_tick = __tick;
etisserant@239:     /* signal debugger thread it can read data */
etisserant@280:     pthread_mutex_unlock(&debug_wait_mutex);
greg@205: }
etisserant@239: 
Edouard@614: int suspendDebug(int disable)
edouard@462: {
etisserant@239:     /* Prevent PLC to enter debug code */
etisserant@239:     pthread_mutex_lock(&debug_mutex);
edouard@462:     /*__DEBUG is protected by this mutex */
edouard@462:     __DEBUG = !disable;
laurent@485:     if (disable)
laurent@485:     	pthread_mutex_unlock(&debug_mutex);
Edouard@614:     return 0;
etisserant@239: }
etisserant@239: 
etisserant@280: void resumeDebug(void)
etisserant@239: {
etisserant@290:     __DEBUG = 1;
etisserant@239:     /* Let PLC enter debug code */
etisserant@239:     pthread_mutex_unlock(&debug_mutex);
etisserant@239: }
etisserant@239: 
etisserant@280: /* from plc_python.c */
etisserant@280: int WaitPythonCommands(void)
etisserant@280: {
etisserant@280:     /* Wait signal from PLC thread */
greg@329:     return pthread_mutex_lock(&python_wait_mutex);
etisserant@280: }
greg@329: 
etisserant@280: /* Called by PLC thread on each new python command*/
etisserant@280: void UnBlockPythonCommands(void)
etisserant@280: {
etisserant@280:     /* signal debugger thread it can read data */
etisserant@280:     pthread_mutex_unlock(&python_wait_mutex);
etisserant@280: }
etisserant@280: 
etisserant@280: int TryLockPython(void)
etisserant@280: {
etisserant@280:     return pthread_mutex_trylock(&python_mutex) == 0;
etisserant@280: }
etisserant@280: 
etisserant@280: void UnLockPython(void)
etisserant@280: {
etisserant@280:     pthread_mutex_unlock(&python_mutex);
etisserant@280: }
etisserant@280: 
etisserant@280: void LockPython(void)
etisserant@280: {
etisserant@280:     pthread_mutex_lock(&python_mutex);
etisserant@280: }
edouard@483: 
laurent@522: int CheckRetainBuffer(void)
laurent@522: {
laurent@522: 	return 1;
laurent@522: }
laurent@522: 
edouard@580: void ValidateRetainBuffer(void)
edouard@580: {
edouard@580: }
edouard@580: 
edouard@580: void InValidateRetainBuffer(void)
edouard@580: {
edouard@580: }
edouard@580: 
edouard@483: void Retain(unsigned int offset, unsigned int count, void *p)
edouard@483: {
edouard@483: }
edouard@483: 
edouard@483: void Remind(unsigned int offset, unsigned int count, void *p)
edouard@483: {
edouard@483: }