targets/OSX/plc_OSX_main.c
branchpython3
changeset 3778 296e459efdfb
child 3781 25195da82745
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/targets/OSX/plc_OSX_main.c	Wed Nov 09 17:29:59 2022 +0800
@@ -0,0 +1,295 @@
+/**
+ * Mac OSX specific code
+ **/
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <locale.h>
+#include <semaphore.h>
+#include <dispatch/dispatch.h>
+
+static sem_t Run_PLC;
+
+long AtomicCompareExchange(long *atomicvar, long compared, long exchange)
+{
+    return __sync_val_compare_and_swap(atomicvar, compared, exchange);
+}
+
+long long AtomicCompareExchange64(long long *atomicvar, long long compared,
+                                  long long exchange)
+{
+    return __sync_val_compare_and_swap(atomicvar, compared, exchange);
+}
+
+void PLC_GetTime(IEC_TIME * CURRENT_TIME)
+{
+    struct timespec tmp;
+    clock_gettime(CLOCK_REALTIME, &tmp);
+    CURRENT_TIME->tv_sec = tmp.tv_sec;
+    CURRENT_TIME->tv_nsec = tmp.tv_nsec;
+}
+
+dispatch_queue_t queue;
+dispatch_source_t PLC_timer;
+
+static inline void PLC_timer_cancel(void *arg)
+{
+    dispatch_release(PLC_timer);
+    dispatch_release(queue);
+    exit(0);
+}
+
+static inline void PLC_timer_notify(void *arg)
+{
+    PLC_GetTime(&__CURRENT_TIME);
+    sem_post(&Run_PLC);
+}
+
+void PLC_SetTimer(unsigned long long next, unsigned long long period)
+{
+    if (next == period && next == 0) {
+        dispatch_suspend(PLC_timer);
+    } else {
+        dispatch_time_t start;
+        start = dispatch_time(DISPATCH_TIME_NOW, next);
+        dispatch_source_set_timer(PLC_timer, start, period, 0);
+        dispatch_resume(PLC_timer);
+    }
+}
+
+void catch_signal(int sig)
+{
+    signal(SIGINT, catch_signal);
+    printf("Got Signal %d\n", sig);
+    dispatch_source_cancel(PLC_timer);
+    exit(0);
+}
+
+static unsigned long __debug_tick;
+
+pthread_t PLC_thread;
+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;
+
+int PLC_shutdown = 0;
+
+int ForceSaveRetainReq(void)
+{
+    return PLC_shutdown;
+}
+
+void PLC_thread_proc(void *arg)
+{
+    while (!PLC_shutdown) {
+        sem_wait(&Run_PLC);
+        __run();
+    }
+    pthread_exit(0);
+}
+
+#define maxval(a,b) ((a>b)?a:b)
+int startPLC(int argc, char **argv)
+{
+    setlocale(LC_NUMERIC, "C");
+
+    PLC_shutdown = 0;
+
+    sem_init(&Run_PLC, 0, 0);
+
+    pthread_create(&PLC_thread, NULL, (void *)&PLC_thread_proc, NULL);
+
+    pthread_mutex_init(&debug_wait_mutex, NULL);
+    pthread_mutex_init(&debug_mutex, NULL);
+    pthread_mutex_init(&python_wait_mutex, NULL);
+    pthread_mutex_init(&python_mutex, NULL);
+
+    pthread_mutex_lock(&debug_wait_mutex);
+    pthread_mutex_lock(&python_wait_mutex);
+
+    queue = dispatch_queue_create("timerQueue", 0);
+    PLC_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+
+    dispatch_set_context(PLC_timer, &PLC_timer);
+    dispatch_source_set_event_handler_f(PLC_timer, PLC_timer_notify);
+    dispatch_source_set_cancel_handler_f(PLC_timer, PLC_timer_cancel);
+
+    if (__init(argc, argv) == 0) {
+        PLC_SetTimer(common_ticktime__, common_ticktime__);
+
+        /* install signal handler for manual break */
+        signal(SIGINT, catch_signal);
+    } else {
+        return 1;
+    }
+    return 0;
+}
+
+int TryEnterDebugSection(void)
+{
+    if (pthread_mutex_trylock(&debug_mutex) == 0) {
+        /* Only enter if debug active */
+        if (__DEBUG) {
+            return 1;
+        }
+        pthread_mutex_unlock(&debug_mutex);
+    }
+    return 0;
+}
+
+void LeaveDebugSection(void)
+{
+    pthread_mutex_unlock(&debug_mutex);
+}
+
+int stopPLC()
+{
+    /* Stop the PLC */
+    PLC_shutdown = 1;
+    sem_post(&Run_PLC);
+    PLC_SetTimer(0, 0);
+    pthread_join(PLC_thread, NULL);
+    sem_destroy(&Run_PLC);
+    dispatch_source_cancel(PLC_timer);
+    __cleanup();
+    pthread_mutex_destroy(&debug_wait_mutex);
+    pthread_mutex_destroy(&debug_mutex);
+    pthread_mutex_destroy(&python_wait_mutex);
+    pthread_mutex_destroy(&python_mutex);
+    return 0;
+}
+
+extern unsigned long __tick;
+
+int WaitDebugData(unsigned long *tick)
+{
+    int res;
+    if (PLC_shutdown)
+        return 1;
+    /* Wait signal from PLC thread */
+    res = pthread_mutex_lock(&debug_wait_mutex);
+    *tick = __debug_tick;
+    return res;
+}
+
+/* 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 */
+    pthread_mutex_unlock(&debug_wait_mutex);
+}
+
+int suspendDebug(int disable)
+{
+    /* Prevent PLC to enter debug code */
+    pthread_mutex_lock(&debug_mutex);
+    /*__DEBUG is protected by this mutex */
+    __DEBUG = !disable;
+    if (disable)
+        pthread_mutex_unlock(&debug_mutex);
+    return 0;
+}
+
+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 */
+    return pthread_mutex_lock(&python_wait_mutex);
+}
+
+/* Called by PLC thread on each new python command*/
+void UnBlockPythonCommands(void)
+{
+    /* signal python 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);
+}
+
+struct RT_to_nRT_signal_s {
+    pthread_cond_t WakeCond;
+    pthread_mutex_t WakeCondLock;
+};
+
+typedef struct RT_to_nRT_signal_s RT_to_nRT_signal_t;
+
+#define _LogAndReturnNull(text) \
+    {\
+    	char mstr[256] = text " for ";\
+        strncat(mstr, name, 255);\
+        LogMessage(LOG_CRITICAL, mstr, strlen(mstr));\
+        return NULL;\
+    }
+
+void *create_RT_to_nRT_signal(char *name)
+{
+    RT_to_nRT_signal_t *sig =
+        (RT_to_nRT_signal_t *) malloc(sizeof(RT_to_nRT_signal_t));
+
+    if (!sig)
+        _LogAndReturnNull("Failed allocating memory for RT_to_nRT signal");
+
+    pthread_cond_init(&sig->WakeCond, NULL);
+    pthread_mutex_init(&sig->WakeCondLock, NULL);
+
+    return (void *)sig;
+}
+
+void delete_RT_to_nRT_signal(void *handle)
+{
+    RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t *) handle;
+
+    pthread_cond_destroy(&sig->WakeCond);
+    pthread_mutex_destroy(&sig->WakeCondLock);
+
+    free(sig);
+}
+
+int wait_RT_to_nRT_signal(void *handle)
+{
+    int ret;
+    RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t *) handle;
+    pthread_mutex_lock(&sig->WakeCondLock);
+    ret = pthread_cond_wait(&sig->WakeCond, &sig->WakeCondLock);
+    pthread_mutex_unlock(&sig->WakeCondLock);
+    return ret;
+}
+
+int unblock_RT_to_nRT_signal(void *handle)
+{
+    RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t *) handle;
+    return pthread_cond_signal(&sig->WakeCond);
+}
+
+void nRT_reschedule(void)
+{
+    sched_yield();
+}