321
|
1 |
/**
|
|
2 |
* Linux specific code
|
|
3 |
**/
|
|
4 |
|
|
5 |
#include <stdio.h>
|
|
6 |
#include <string.h>
|
|
7 |
#include <time.h>
|
|
8 |
#include <signal.h>
|
|
9 |
#include <stdlib.h>
|
|
10 |
#include <sys/mman.h>
|
|
11 |
|
|
12 |
#include <native/task.h>
|
|
13 |
#include <native/timer.h>
|
|
14 |
#include <native/mutex.h>
|
|
15 |
#include <native/sem.h>
|
|
16 |
|
|
17 |
unsigned int PLC_state = 0;
|
|
18 |
#define PLC_STATE_TASK_CREATED 1
|
|
19 |
#define PLC_STATE_PYTHON_MUTEX_CREATED 2
|
|
20 |
#define PLC_STATE_PYTHON_WAIT_SEM_CREATED 4
|
|
21 |
#define PLC_STATE_DEBUG_MUTEX_CREATED 8
|
|
22 |
#define PLC_STATE_DEBUG_WAIT_SEM_CREATED 16
|
|
23 |
|
|
24 |
/* provided by POUS.C */
|
|
25 |
extern int common_ticktime__;
|
|
26 |
|
|
27 |
long AtomicCompareExchange(long* atomicvar,long compared, long exchange)
|
|
28 |
{
|
|
29 |
return __sync_val_compare_and_swap(atomicvar, compared, exchange);
|
|
30 |
}
|
|
31 |
|
|
32 |
void PLC_GetTime(IEC_TIME *CURRENT_TIME)
|
|
33 |
{
|
|
34 |
RTIME current_time = rt_timer_read();
|
|
35 |
CURRENT_TIME->tv_sec = current_time / 1000000000;
|
|
36 |
CURRENT_TIME->tv_nsec = current_time % 1000000000;
|
|
37 |
}
|
|
38 |
|
|
39 |
RT_TASK PLC_task;
|
|
40 |
RT_TASK WaitDebug_task;
|
|
41 |
RT_TASK WaitPythonCommand_task;
|
|
42 |
RT_TASK UnLockPython_task;
|
|
43 |
RT_TASK LockPython_task;
|
|
44 |
int PLC_shutdown = 0;
|
|
45 |
|
|
46 |
void PLC_SetTimer(long long next, long long period)
|
|
47 |
{
|
|
48 |
RTIME current_time = rt_timer_read();
|
|
49 |
rt_task_set_periodic(&PLC_task, current_time + next, rt_timer_ns2ticks(period));
|
|
50 |
}
|
|
51 |
|
|
52 |
void PLC_task_proc(void *arg)
|
|
53 |
{
|
|
54 |
PLC_SetTimer(Ttick, Ttick);
|
|
55 |
|
|
56 |
while (1) {
|
|
57 |
PLC_GetTime(&__CURRENT_TIME);
|
|
58 |
__run();
|
|
59 |
if (PLC_shutdown) break;
|
|
60 |
rt_task_wait_period(NULL);
|
|
61 |
}
|
|
62 |
}
|
|
63 |
|
|
64 |
static int __debug_tick;
|
|
65 |
|
|
66 |
RT_SEM python_wait_sem;
|
|
67 |
RT_MUTEX python_mutex;
|
|
68 |
RT_SEM debug_wait_sem;
|
|
69 |
RT_MUTEX debug_mutex;
|
|
70 |
|
|
71 |
void PLC_cleanup_all(void)
|
|
72 |
{
|
|
73 |
if (PLC_state & PLC_STATE_TASK_CREATED) {
|
|
74 |
rt_task_delete(&PLC_task);
|
|
75 |
PLC_state &= ~PLC_STATE_TASK_CREATED;
|
|
76 |
}
|
|
77 |
|
|
78 |
if (PLC_state & PLC_STATE_PYTHON_WAIT_SEM_CREATED) {
|
|
79 |
rt_sem_delete(&python_wait_sem);
|
|
80 |
PLC_state &= ~ PLC_STATE_PYTHON_WAIT_SEM_CREATED;
|
|
81 |
}
|
|
82 |
|
|
83 |
if (PLC_state & PLC_STATE_PYTHON_MUTEX_CREATED) {
|
|
84 |
rt_mutex_delete(&python_mutex);
|
|
85 |
PLC_state &= ~ PLC_STATE_PYTHON_MUTEX_CREATED;
|
|
86 |
}
|
|
87 |
|
|
88 |
if (PLC_state & PLC_STATE_DEBUG_WAIT_SEM_CREATED) {
|
|
89 |
rt_sem_delete(&debug_wait_sem);
|
|
90 |
PLC_state &= ~ PLC_STATE_DEBUG_WAIT_SEM_CREATED;
|
|
91 |
}
|
|
92 |
|
|
93 |
if (PLC_state & PLC_STATE_DEBUG_MUTEX_CREATED) {
|
|
94 |
rt_mutex_delete(&debug_mutex);
|
|
95 |
PLC_state &= ~ PLC_STATE_DEBUG_MUTEX_CREATED;
|
|
96 |
}
|
|
97 |
}
|
|
98 |
|
|
99 |
int stopPLC()
|
|
100 |
{
|
|
101 |
PLC_shutdown = 1;
|
|
102 |
/* Stop the PLC */
|
|
103 |
PLC_SetTimer(0, 0);
|
|
104 |
PLC_cleanup_all();
|
|
105 |
__cleanup();
|
|
106 |
__debug_tick = -1;
|
|
107 |
rt_sem_v(&debug_wait_sem);
|
|
108 |
rt_sem_v(&python_wait_sem);
|
|
109 |
}
|
|
110 |
|
|
111 |
//
|
|
112 |
void catch_signal(int sig)
|
|
113 |
{
|
|
114 |
stopPLC();
|
|
115 |
// signal(SIGTERM, catch_signal);
|
|
116 |
signal(SIGINT, catch_signal);
|
|
117 |
printf("Got Signal %d\n",sig);
|
|
118 |
exit(0);
|
|
119 |
}
|
|
120 |
|
|
121 |
#define max_val(a,b) ((a>b)?a:b)
|
|
122 |
int startPLC(int argc,char **argv)
|
|
123 |
{
|
|
124 |
int ret = 0;
|
|
125 |
|
|
126 |
signal(SIGINT, catch_signal);
|
|
127 |
|
|
128 |
/* ne-memory-swapping for this program */
|
|
129 |
mlockall(MCL_CURRENT | MCL_FUTURE);
|
|
130 |
|
|
131 |
/* Translate PLC's microseconds to Ttick nanoseconds */
|
|
132 |
Ttick = 1000000 * max_val(common_ticktime__,1);
|
|
133 |
|
|
134 |
/* create python_wait_sem */
|
|
135 |
ret = rt_sem_create(&python_wait_sem, "python_wait_sem", 0, S_FIFO);
|
|
136 |
if (ret) goto error;
|
|
137 |
PLC_state |= PLC_STATE_PYTHON_WAIT_SEM_CREATED;
|
|
138 |
|
|
139 |
/* create python_mutex */
|
|
140 |
ret = rt_mutex_create(&python_mutex, "python_mutex");
|
|
141 |
if (ret) goto error;
|
|
142 |
PLC_state |= PLC_STATE_PYTHON_MUTEX_CREATED;
|
|
143 |
|
|
144 |
/* create debug_wait_sem */
|
|
145 |
ret = rt_sem_create(&debug_wait_sem, "debug_wait_sem", 0, S_FIFO);
|
|
146 |
if (ret) goto error;
|
|
147 |
PLC_state |= PLC_STATE_DEBUG_WAIT_SEM_CREATED;
|
|
148 |
|
|
149 |
/* create debug_mutex */
|
|
150 |
ret = rt_mutex_create(&debug_mutex, "debug_mutex");
|
|
151 |
if (ret) goto error;
|
|
152 |
PLC_state |= PLC_STATE_DEBUG_MUTEX_CREATED;
|
|
153 |
|
|
154 |
/* create can_driver_task */
|
|
155 |
ret = rt_task_create(&PLC_task, "PLC_task", 0, 50, 0);
|
|
156 |
if (ret) goto error;
|
|
157 |
PLC_state |= PLC_STATE_TASK_CREATED;
|
|
158 |
|
|
159 |
ret = __init(argc,argv);
|
|
160 |
if (ret) goto error;
|
|
161 |
|
|
162 |
/* start can_driver_task */
|
|
163 |
ret = rt_task_start(&PLC_task, &PLC_task_proc, NULL);
|
|
164 |
if (ret) goto error;
|
|
165 |
|
|
166 |
return 0;
|
|
167 |
|
|
168 |
error:
|
|
169 |
PLC_cleanup_all();
|
|
170 |
return 1;
|
|
171 |
}
|
|
172 |
|
|
173 |
int TryEnterDebugSection(void)
|
|
174 |
{
|
|
175 |
return rt_mutex_acquire(&debug_mutex, TM_NONBLOCK) == 0;
|
|
176 |
}
|
|
177 |
|
|
178 |
void LeaveDebugSection(void)
|
|
179 |
{
|
|
180 |
rt_mutex_release(&debug_mutex);
|
|
181 |
}
|
|
182 |
|
|
183 |
extern int __tick;
|
|
184 |
/* from plc_debugger.c */
|
|
185 |
int WaitDebugData()
|
|
186 |
{
|
|
187 |
rt_task_shadow(&WaitDebug_task, "WaitDebug_task", 0, 0);
|
|
188 |
/* Wait signal from PLC thread */
|
|
189 |
rt_sem_p(&debug_wait_sem, TM_INFINITE);
|
|
190 |
return __debug_tick;
|
|
191 |
}
|
|
192 |
|
|
193 |
/* Called by PLC thread when debug_publish finished
|
|
194 |
* This is supposed to unlock debugger thread in WaitDebugData*/
|
|
195 |
void InitiateDebugTransfer()
|
|
196 |
{
|
|
197 |
/* remember tick */
|
|
198 |
__debug_tick = __tick;
|
|
199 |
/* signal debugger thread it can read data */
|
|
200 |
rt_sem_v(&debug_wait_sem);
|
|
201 |
}
|
|
202 |
|
|
203 |
void suspendDebug(void)
|
|
204 |
{
|
|
205 |
__DEBUG = 0;
|
|
206 |
/* Prevent PLC to enter debug code */
|
|
207 |
rt_mutex_acquire(&debug_mutex, TM_INFINITE);
|
|
208 |
}
|
|
209 |
|
|
210 |
void resumeDebug(void)
|
|
211 |
{
|
|
212 |
__DEBUG = 1;
|
|
213 |
/* Let PLC enter debug code */
|
|
214 |
rt_mutex_release(&debug_mutex);
|
|
215 |
}
|
|
216 |
|
|
217 |
/* from plc_python.c */
|
|
218 |
int WaitPythonCommands(void)
|
|
219 |
{
|
|
220 |
rt_task_shadow(&WaitPythonCommand_task, "WaitPythonCommand_task", 0, 0);
|
|
221 |
/* Wait signal from PLC thread */
|
|
222 |
rt_sem_p(&python_wait_sem, TM_INFINITE);
|
|
223 |
}
|
|
224 |
|
|
225 |
/* Called by PLC thread on each new python command*/
|
|
226 |
void UnBlockPythonCommands(void)
|
|
227 |
{
|
|
228 |
/* signal debugger thread it can read data */
|
|
229 |
rt_sem_v(&python_wait_sem);
|
|
230 |
}
|
|
231 |
|
|
232 |
int TryLockPython(void)
|
|
233 |
{
|
|
234 |
return rt_mutex_acquire(&python_mutex, TM_NONBLOCK) == 0;
|
|
235 |
}
|
|
236 |
|
|
237 |
void UnLockPython(void)
|
|
238 |
{
|
|
239 |
rt_task_shadow(&UnLockPython_task, "UnLockPython_task", 0, 0);
|
|
240 |
rt_mutex_release(&python_mutex);
|
|
241 |
}
|
|
242 |
|
|
243 |
void LockPython(void)
|
|
244 |
{
|
|
245 |
rt_task_shadow(&LockPython_task, "LockPython_task", 0, 0);
|
|
246 |
rt_mutex_acquire(&python_mutex, TM_INFINITE);
|
|
247 |
}
|