etisserant@280: /**
etisserant@280:  * Win32 specific code
greg@329:  **/
etisserant@280: 
greg@205: #include <stdio.h>
greg@205: #include <sys/timeb.h>
greg@205: #include <time.h>
greg@205: #include <windows.h>
edouard@568: #include <locale.h>
greg@205: 
etisserant@280: 
greg@244: long AtomicCompareExchange(long* atomicvar, long compared, long exchange)
greg@205: {
greg@205:     return InterlockedCompareExchange(atomicvar, exchange, compared);
greg@205: }
Edouard@954: CRITICAL_SECTION Atomic64CS; 
Edouard@954: long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange)
Edouard@954: {
Edouard@954:     long long res;
Edouard@954:     EnterCriticalSection(&Atomic64CS);
Edouard@954:     res=*atomicvar;
Edouard@954:     if(*atomicvar == compared){
Edouard@954:         *atomicvar = exchange;
Edouard@954:     }
Edouard@954:     LeaveCriticalSection(&Atomic64CS);
Edouard@954:     return res;
Edouard@954: }
greg@205: 
edouard@3296: struct timeb timetmp;
greg@205: void PLC_GetTime(IEC_TIME *CURRENT_TIME)
greg@205: {
edouard@3296: 	ftime(&timetmp);
greg@329: 
greg@205: 	(*CURRENT_TIME).tv_sec = timetmp.time;
greg@205: 	(*CURRENT_TIME).tv_nsec = timetmp.millitm * 1000000;
greg@205: }
greg@205: 
greg@205: HANDLE PLC_timer = NULL;
edouard@518: void PLC_SetTimer(unsigned long long next, unsigned long long period)
greg@205: {
greg@229: 	LARGE_INTEGER liDueTime;
greg@205: 	/* arg 2 of SetWaitableTimer take 100 ns interval*/
greg@205: 	liDueTime.QuadPart =  next / (-100);
greg@329: 
Edouard@685: 	if (!SetWaitableTimer(PLC_timer, &liDueTime, period<1000000?1:period/1000000, NULL, NULL, 0))
greg@205:     {
greg@205:         printf("SetWaitableTimer failed (%d)\n", GetLastError());
greg@205:     }
greg@229: }
greg@229: 
andrej@2174: int PLC_shutdown;
andrej@2174: 
andrej@2174: int ForceSaveRetainReq(void) {
andrej@2174:     return PLC_shutdown;
andrej@2174: }
andrej@2174: 
greg@229: /* Variable used to stop plcloop thread */
greg@229: void PlcLoop()
greg@229: {
andrej@2174:     PLC_shutdown = 0;
andrej@2174:     while(!PLC_shutdown) {
edouard@3850:         if (WaitForSingleObject(PLC_timer, INFINITE) != WAIT_OBJECT_0){
andrej@2174:             PLC_shutdown = 1;
edouard@3850:             break;
edouard@3850:         }
edouard@3850:         PLC_GetTime(&__CURRENT_TIME);
edouard@3850:         __run();
edouard@483:     }
greg@205: }
greg@205: 
greg@229: HANDLE PLC_thread;
greg@244: HANDLE debug_sem;
greg@329: HANDLE debug_wait_sem;
etisserant@280: HANDLE python_sem;
greg@329: HANDLE python_wait_sem;
etisserant@280: 
etisserant@280: #define maxval(a,b) ((a>b)?a:b)
greg@229: int startPLC(int argc,char **argv)
greg@205: {
greg@229: 	unsigned long thread_id = 0;
Edouard@954:     BOOL tmp;
greg@205: 
edouard@483:     debug_sem = CreateSemaphore(
edouard@483:                             NULL,           // default security attributes
edouard@483:                             1,  			// initial count
edouard@483:                             1,  			// maximum count
edouard@483:                             NULL);          // unnamed semaphore
greg@329:     if (debug_sem == NULL)
greg@244:     {
etisserant@280:         printf("startPLC CreateSemaphore debug_sem error: %d\n", GetLastError());
ewald@1573:         return 1;
greg@244:     }
greg@329: 
edouard@483:     debug_wait_sem = CreateSemaphore(
edouard@483:                             NULL,           // default security attributes
edouard@483:                             0,  			// initial count
edouard@483:                             1,  			// maximum count
edouard@483:                             NULL);          // unnamed semaphore
etisserant@280: 
greg@329:     if (debug_wait_sem == NULL)
etisserant@280:     {
etisserant@280:         printf("startPLC CreateSemaphore debug_wait_sem error: %d\n", GetLastError());
ewald@1573:         return 1;
etisserant@280:     }
etisserant@280: 
edouard@483:     python_sem = CreateSemaphore(
edouard@483:                             NULL,           // default security attributes
edouard@483:                             1,  			// initial count
edouard@483:                             1,  			// maximum count
edouard@483:                             NULL);          // unnamed semaphore
etisserant@280: 
greg@329:     if (python_sem == NULL)
etisserant@280:     {
etisserant@280:         printf("startPLC CreateSemaphore python_sem error: %d\n", GetLastError());
ewald@1573:         return 1;
etisserant@280:     }
edouard@483:     python_wait_sem = CreateSemaphore(
edouard@483:                             NULL,           // default security attributes
edouard@483:                             0,  			// initial count
edouard@483:                             1,  			// maximum count
edouard@483:                             NULL);          // unnamed semaphore
etisserant@280: 
etisserant@280: 
greg@329:     if (python_wait_sem == NULL)
etisserant@280:     {
etisserant@280:         printf("startPLC CreateSemaphore python_wait_sem error: %d\n", GetLastError());
ewald@1573:         return 1;
etisserant@280:     }
etisserant@280: 
greg@329: 
edouard@483:     /* Create a waitable timer */
Edouard@685:     timeBeginPeriod(1);
greg@205:     PLC_timer = CreateWaitableTimer(NULL, FALSE, "WaitableTimer");
greg@205:     if(NULL == PLC_timer)
greg@205:     {
greg@205:         printf("CreateWaitableTimer failed (%d)\n", GetLastError());
greg@205:         return 1;
greg@205:     }
greg@205:     if( __init(argc,argv) == 0 )
greg@205:     {
Edouard@1428:         PLC_SetTimer(common_ticktime__,common_ticktime__);
edouard@483:         PLC_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlcLoop, NULL, 0, &thread_id);
greg@205:     }
greg@229:     else{
edouard@483:         return 1;
greg@229:     }
greg@205:     return 0;
greg@205: }
edouard@3947: static unsigned int __debug_tick;
greg@244: 
greg@244: int TryEnterDebugSection(void)
greg@244: {
greg@244: 	//printf("TryEnterDebugSection\n");
edouard@469:     if(WaitForSingleObject(debug_sem, 0) == WAIT_OBJECT_0){
edouard@469:         /* Only enter if debug active */
edouard@469:         if(__DEBUG){
edouard@469:             return 1;
edouard@469:         }
edouard@483:         ReleaseSemaphore(debug_sem, 1, NULL);
edouard@483:     }
edouard@469:     return 0;
greg@244: }
greg@244: 
greg@244: void LeaveDebugSection(void)
greg@244: {
greg@244: 	ReleaseSemaphore(debug_sem, 1, NULL);
greg@244:     //printf("LeaveDebugSection\n");
greg@244: }
greg@229: 
greg@229: int stopPLC()
greg@229: {
edouard@3850:  	
edouard@3850:     PLC_shutdown = 1;
edouard@3850:     // force last wakeup of PLC thread
edouard@3850:     SetWaitableTimer(PLC_timer, 0, 0, NULL, NULL, 0);
edouard@3850:     // wait end of PLC thread
edouard@3850:     WaitForSingleObject(PLC_thread, INFINITE);
edouard@3850: 
edouard@3850:     __cleanup();
edouard@3850: 
edouard@483:     CloseHandle(PLC_timer);
edouard@483:     CloseHandle(debug_wait_sem);
edouard@483:     CloseHandle(debug_sem);
edouard@483:     CloseHandle(python_wait_sem);
edouard@483:     CloseHandle(python_sem);
edouard@483:     CloseHandle(PLC_thread);
greg@229: }
greg@229: 
greg@229: /* from plc_debugger.c */
edouard@3947: int WaitDebugData(unsigned int *tick)
greg@229: {
laurent@709: 	DWORD res;
laurent@709: 	res = WaitForSingleObject(debug_wait_sem, INFINITE);
ed@446:     *tick = __debug_tick;
ed@446:     /* Wait signal from PLC thread */
laurent@709: 	return res != WAIT_OBJECT_0;
greg@229: }
greg@329: 
etisserant@280: /* Called by PLC thread when debug_publish finished
greg@229:  * This is supposed to unlock debugger thread in WaitDebugData*/
greg@229: void InitiateDebugTransfer()
greg@229: {
greg@244:     /* remember tick */
greg@244:     __debug_tick = __tick;
greg@244:     /* signal debugger thread it can read data */
etisserant@280:     ReleaseSemaphore(debug_wait_sem, 1, NULL);
greg@229: }
greg@244: 
Edouard@614: int suspendDebug(int disable)
edouard@469: {
greg@244:     /* Prevent PLC to enter debug code */
edouard@483:     WaitForSingleObject(debug_sem, INFINITE);
edouard@469:     __DEBUG = !disable;
Lolitech@484:     if(disable)
Lolitech@484:         ReleaseSemaphore(debug_sem, 1, NULL);
Edouard@614:     return 0;
greg@244: }
greg@244: 
greg@244: void resumeDebug()
greg@244: {
etisserant@290: 	__DEBUG = 1;
greg@244:     /* Let PLC enter debug code */
greg@244: 	ReleaseSemaphore(debug_sem, 1, NULL);
greg@244: }
etisserant@280: 
etisserant@280: /* from plc_python.c */
etisserant@280: int WaitPythonCommands(void)
etisserant@280: {
etisserant@280:     /* Wait signal from PLC thread */
greg@329: 	return WaitForSingleObject(python_wait_sem, INFINITE);
greg@329: }
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: 	ReleaseSemaphore(python_wait_sem, 1, NULL);
etisserant@280: }
etisserant@280: 
etisserant@280: int TryLockPython(void)
etisserant@280: {
etisserant@280: 	return WaitForSingleObject(python_sem, 0) == WAIT_OBJECT_0;
etisserant@280: }
etisserant@280: 
etisserant@280: void UnLockPython(void)
etisserant@280: {
etisserant@280: 	ReleaseSemaphore(python_sem, 1, NULL);
etisserant@280: }
etisserant@280: 
etisserant@280: void LockPython(void)
etisserant@280: {
etisserant@280: 	WaitForSingleObject(python_sem, INFINITE);
etisserant@280: }
etisserant@280: 
Edouard@1465: static void __attribute__((constructor))
Edouard@1465: beremiz_dll_init(void)
Edouard@1465: {
Edouard@1465:     InitializeCriticalSection(&Atomic64CS);
Edouard@1465: 
Edouard@1465: }
Edouard@1465: 
Edouard@1465: static void __attribute__((destructor))
Edouard@1465: beremiz_dll_destroy(void)
Edouard@1465: {
Edouard@1465:     DeleteCriticalSection(&Atomic64CS);
Edouard@1465: }
Edouard@1465: 
edouard@3295: struct RT_to_nRT_signal_s {
edouard@3295:     HANDLE sem;
edouard@3295: };
edouard@3295: 
edouard@3295: typedef struct RT_to_nRT_signal_s RT_to_nRT_signal_t;
edouard@3295: 
edouard@3295: #define _LogAndReturnNull(text) \
edouard@3295:     {\
edouard@3295:     	char mstr[256] = text " for ";\
edouard@3295:         strncat(mstr, name, 255);\
edouard@3295:         LogMessage(LOG_CRITICAL, mstr, strlen(mstr));\
edouard@3295:         return NULL;\
edouard@3295:     }
edouard@3295: 
edouard@3295: void *create_RT_to_nRT_signal(char* name){
edouard@3295:     RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)malloc(sizeof(RT_to_nRT_signal_t));
edouard@3295: 
edouard@3295:     if(!sig) 
edouard@3295:     	_LogAndReturnNull("Failed allocating memory for RT_to_nRT signal");
edouard@3295: 
edouard@3295:     sig->sem = CreateSemaphore(
edouard@3295:                             NULL,           // default security attributes
edouard@3295:                             1,  			// initial count
edouard@3295:                             1,  			// maximum count
edouard@3295:                             NULL);          // unnamed semaphore
edouard@3295: 
edouard@3295:     if(sig->sem == NULL)
edouard@3295:     {
edouard@3295:     	char mstr[256];
edouard@3295:         snprintf(mstr, 255, "startPLC CreateSemaphore %s error: %d\n", name, GetLastError());
edouard@3295:         LogMessage(LOG_CRITICAL, mstr, strlen(mstr));
edouard@3295:         return NULL;
edouard@3295:     }
edouard@3295: 
edouard@3295:     return (void*)sig;
edouard@3295: }
edouard@3295: 
edouard@3295: void delete_RT_to_nRT_signal(void* handle){
edouard@3295:     RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle;
edouard@3295: 
edouard@3295:     CloseHandle(python_sem);
edouard@3295: 
edouard@3295:     free(sig);
edouard@3295: }
edouard@3295: 
edouard@3295: int wait_RT_to_nRT_signal(void* handle){
edouard@3295:     int ret;
edouard@3295:     RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle;
edouard@3295: 	return WaitForSingleObject(sig->sem, INFINITE);
edouard@3295: }
edouard@3295: 
edouard@3295: int unblock_RT_to_nRT_signal(void* handle){
edouard@3295:     RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle;
edouard@3295: 	return ReleaseSemaphore(sig->sem, 1, NULL);
edouard@3295: }
edouard@3295: 
edouard@3295: void nRT_reschedule(void){
edouard@3295:     SwitchToThread();
edouard@3295: }
edouard@3295: