16 #include <alchemy/sem.h> |
16 #include <alchemy/sem.h> |
17 #include <alchemy/pipe.h> |
17 #include <alchemy/pipe.h> |
18 |
18 |
19 unsigned int PLC_state = 0; |
19 unsigned int PLC_state = 0; |
20 #define PLC_STATE_TASK_CREATED 1 |
20 #define PLC_STATE_TASK_CREATED 1 |
21 #define PLC_STATE_DEBUG_FILE_OPENED 2 |
21 #define PLC_STATE_DEBUG_PIPE_CREATED 2 |
22 #define PLC_STATE_DEBUG_PIPE_CREATED 4 |
22 #define PLC_STATE_PYTHON_PIPE_CREATED 8 |
23 #define PLC_STATE_PYTHON_FILE_OPENED 8 |
23 #define PLC_STATE_WAITDEBUG_PIPE_CREATED 16 |
24 #define PLC_STATE_PYTHON_PIPE_CREATED 16 |
24 #define PLC_STATE_WAITPYTHON_PIPE_CREATED 32 |
25 #define PLC_STATE_WAITDEBUG_FILE_OPENED 32 |
25 |
26 #define PLC_STATE_WAITDEBUG_PIPE_CREATED 64 |
|
27 #define PLC_STATE_WAITPYTHON_FILE_OPENED 128 |
|
28 #define PLC_STATE_WAITPYTHON_PIPE_CREATED 256 |
|
29 #define PLC_STATE_SVGHMI_FILE_OPENED 512 |
|
30 #define PLC_STATE_SVGHMI_PIPE_CREATED 1024 |
|
31 |
|
32 #define WAITDEBUG_PIPE_DEVICE "/dev/rtp0" |
|
33 #define WAITDEBUG_PIPE_MINOR 0 |
|
34 #define DEBUG_PIPE_DEVICE "/dev/rtp1" |
|
35 #define DEBUG_PIPE_MINOR 1 |
|
36 #define WAITPYTHON_PIPE_DEVICE "/dev/rtp2" |
|
37 #define WAITPYTHON_PIPE_MINOR 2 |
|
38 #define PYTHON_PIPE_DEVICE "/dev/rtp3" |
|
39 #define PYTHON_PIPE_MINOR 3 |
|
40 #define SVGHMI_PIPE_DEVICE "/dev/rtp4" |
|
41 #define SVGHMI_PIPE_MINOR 4 |
|
42 #define PIPE_SIZE 1 |
26 #define PIPE_SIZE 1 |
43 |
27 |
44 // rt-pipes commands |
28 // rt-pipes commands |
45 |
29 |
46 #define PYTHON_PENDING_COMMAND 1 |
30 #define PYTHON_PENDING_COMMAND 1 |
66 CURRENT_TIME->tv_sec = current_time / 1000000000; |
50 CURRENT_TIME->tv_sec = current_time / 1000000000; |
67 CURRENT_TIME->tv_nsec = current_time % 1000000000; |
51 CURRENT_TIME->tv_nsec = current_time % 1000000000; |
68 } |
52 } |
69 |
53 |
70 RT_TASK PLC_task; |
54 RT_TASK PLC_task; |
71 RT_PIPE WaitDebug_pipe; |
55 void *WaitDebug_handle; |
72 RT_PIPE WaitPython_pipe; |
56 void *WaitPython_handle; |
73 RT_PIPE Debug_pipe; |
57 void *Debug_handle; |
74 RT_PIPE Python_pipe; |
58 void *Python_handle; |
75 RT_PIPE svghmi_pipe; |
59 void *svghmi_handle; |
76 int WaitDebug_pipe_fd; |
60 |
77 int WaitPython_pipe_fd; |
61 struct RT_to_nRT_signal_s { |
78 int Debug_pipe_fd; |
62 int used; |
79 int Python_pipe_fd; |
63 RT_PIPE pipe; |
80 int svghmi_pipe_fd; |
64 int pipe_fd; |
|
65 char *name; |
|
66 }; |
|
67 typedef struct RT_to_nRT_signal_s RT_to_nRT_signal_t; |
|
68 |
|
69 #define max_RT_to_nRT_signals 16 |
|
70 |
|
71 static RT_to_nRT_signal_t RT_to_nRT_signal_pool[max_RT_to_nRT_signals]; |
|
72 |
|
73 int recv_RT_to_nRT_signal(void* handle, char* payload){ |
|
74 RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle; |
|
75 if(!sig->used) return -EINVAL; |
|
76 return read(sig->pipe_fd, payload, 1); |
|
77 } |
|
78 |
|
79 int send_RT_to_nRT_signal(void* handle, char payload){ |
|
80 RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle; |
|
81 if(!sig->used) return -EINVAL; |
|
82 return rt_pipe_write(&sig->pipe, &payload, 1, P_NORMAL); |
|
83 } |
|
84 |
81 |
85 |
82 int PLC_shutdown = 0; |
86 int PLC_shutdown = 0; |
83 |
87 |
84 void PLC_SetTimer(unsigned long long next, unsigned long long period) |
88 void PLC_SetTimer(unsigned long long next, unsigned long long period) |
85 { |
89 { |
100 /* since xenomai 3 it is not enough to close() |
104 /* since xenomai 3 it is not enough to close() |
101 file descriptor to unblock read()... */ |
105 file descriptor to unblock read()... */ |
102 { |
106 { |
103 /* explicitely finish python thread */ |
107 /* explicitely finish python thread */ |
104 char msg = PYTHON_FINISH; |
108 char msg = PYTHON_FINISH; |
105 rt_pipe_write(&WaitPython_pipe, &msg, sizeof(msg), P_NORMAL); |
109 send_RT_to_nRT_signal(WaitPython_handle, msg); |
106 } |
110 } |
107 { |
111 { |
108 /* explicitely finish debug thread */ |
112 /* explicitely finish debug thread */ |
109 char msg = DEBUG_FINISH; |
113 char msg = DEBUG_FINISH; |
110 rt_pipe_write(&WaitDebug_pipe, &msg, sizeof(msg), P_NORMAL); |
114 send_RT_to_nRT_signal(WaitDebug_handle, msg); |
111 } |
115 } |
112 } |
116 } |
113 |
117 |
114 static unsigned long __debug_tick; |
118 static unsigned long __debug_tick; |
|
119 |
|
120 #define _LogAndReturnNull(text) \ |
|
121 {\ |
|
122 char mstr[256] = text " for ";\ |
|
123 strncat(mstr, name, 255);\ |
|
124 LogMessage(LOG_CRITICAL, mstr, strlen(mstr));\ |
|
125 return NULL;\ |
|
126 } |
|
127 |
|
128 void *create_RT_to_nRT_signal(char* name){ |
|
129 int new_index = -1; |
|
130 RT_to_nRT_signal_t *sig; |
|
131 char pipe_dev[64]; |
|
132 |
|
133 /* find a free slot */ |
|
134 for(int i=0; i < max_RT_to_nRT_signals; i++){ |
|
135 sig = &RT_to_nRT_signal_pool[i]; |
|
136 if(!sig->used){ |
|
137 new_index = i; |
|
138 break; |
|
139 } |
|
140 } |
|
141 |
|
142 /* fail if none found */ |
|
143 if(new_index == -1) { |
|
144 _LogAndReturnNull("Maximum count of RT-PIPE reached while creating pipe"); |
|
145 } |
|
146 |
|
147 /* create rt pipe */ |
|
148 if(rt_pipe_create(&sig->pipe, name, new_index, PIPE_SIZE) < 0){ |
|
149 _LogAndReturnNull("Failed opening real-time end of RT-PIPE"); |
|
150 } |
|
151 |
|
152 /* open pipe's userland */ |
|
153 snprintf(pipe_dev, 64, "/dev/rtp%d", new_index); |
|
154 if((sig->pipe_fd = open(pipe_dev, O_RDWR)) == -1){ |
|
155 rt_pipe_delete(&sig->pipe); |
|
156 _LogAndReturnNull("Failed opening non-real-time end of RT-PIPE"); |
|
157 } |
|
158 |
|
159 sig->used = 1; |
|
160 sig->name = name; |
|
161 |
|
162 return sig; |
|
163 } |
|
164 |
|
165 void delete_RT_to_nRT_signal(void* handle){ |
|
166 RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle; |
|
167 |
|
168 if(!sig->used) return; |
|
169 |
|
170 rt_pipe_delete(&sig->pipe); |
|
171 |
|
172 close(sig->pipe_fd); |
|
173 |
|
174 sig->used = 0; |
|
175 } |
|
176 |
|
177 int wait_RT_to_nRT_signal(void* handle){ |
|
178 char cmd; |
|
179 int ret = recv_RT_to_nRT_signal(handle, &cmd); |
|
180 return (ret == 1) ? 0 : ((ret == 0) ? ENODATA : -ret); |
|
181 } |
|
182 |
|
183 int unblock_RT_to_nRT_signal(void* handle){ |
|
184 int ret = send_RT_to_nRT_signal(handle, 0); |
|
185 return (ret == 1) ? 0 : ((ret == 0) ? EINVAL : -ret); |
|
186 } |
115 |
187 |
116 void PLC_cleanup_all(void) |
188 void PLC_cleanup_all(void) |
117 { |
189 { |
118 if (PLC_state & PLC_STATE_TASK_CREATED) { |
190 if (PLC_state & PLC_STATE_TASK_CREATED) { |
119 rt_task_delete(&PLC_task); |
191 rt_task_delete(&PLC_task); |
120 PLC_state &= ~PLC_STATE_TASK_CREATED; |
192 PLC_state &= ~PLC_STATE_TASK_CREATED; |
121 } |
193 } |
122 |
194 |
123 if (PLC_state & PLC_STATE_SVGHMI_PIPE_CREATED) { |
|
124 rt_pipe_delete(&svghmi_pipe); |
|
125 PLC_state &= ~PLC_STATE_SVGHMI_PIPE_CREATED; |
|
126 } |
|
127 |
|
128 if (PLC_state & PLC_STATE_SVGHMI_FILE_OPENED) { |
|
129 close(svghmi_pipe_fd); |
|
130 PLC_state &= ~PLC_STATE_SVGHMI_FILE_OPENED; |
|
131 } |
|
132 |
|
133 if (PLC_state & PLC_STATE_WAITDEBUG_PIPE_CREATED) { |
195 if (PLC_state & PLC_STATE_WAITDEBUG_PIPE_CREATED) { |
134 rt_pipe_delete(&WaitDebug_pipe); |
196 delete_RT_to_nRT_signal(WaitDebug_handle); |
135 PLC_state &= ~PLC_STATE_WAITDEBUG_PIPE_CREATED; |
197 PLC_state &= ~PLC_STATE_WAITDEBUG_PIPE_CREATED; |
136 } |
198 } |
137 |
199 |
138 if (PLC_state & PLC_STATE_WAITDEBUG_FILE_OPENED) { |
|
139 close(WaitDebug_pipe_fd); |
|
140 PLC_state &= ~PLC_STATE_WAITDEBUG_FILE_OPENED; |
|
141 } |
|
142 |
|
143 if (PLC_state & PLC_STATE_WAITPYTHON_PIPE_CREATED) { |
200 if (PLC_state & PLC_STATE_WAITPYTHON_PIPE_CREATED) { |
144 rt_pipe_delete(&WaitPython_pipe); |
201 delete_RT_to_nRT_signal(WaitPython_handle); |
145 PLC_state &= ~PLC_STATE_WAITPYTHON_PIPE_CREATED; |
202 PLC_state &= ~PLC_STATE_WAITPYTHON_PIPE_CREATED; |
146 } |
203 } |
147 |
204 |
148 if (PLC_state & PLC_STATE_WAITPYTHON_FILE_OPENED) { |
|
149 close(WaitPython_pipe_fd); |
|
150 PLC_state &= ~PLC_STATE_WAITPYTHON_FILE_OPENED; |
|
151 } |
|
152 |
|
153 if (PLC_state & PLC_STATE_DEBUG_PIPE_CREATED) { |
205 if (PLC_state & PLC_STATE_DEBUG_PIPE_CREATED) { |
154 rt_pipe_delete(&Debug_pipe); |
206 delete_RT_to_nRT_signal(Debug_handle); |
155 PLC_state &= ~PLC_STATE_DEBUG_PIPE_CREATED; |
207 PLC_state &= ~PLC_STATE_DEBUG_PIPE_CREATED; |
156 } |
208 } |
157 |
209 |
158 if (PLC_state & PLC_STATE_DEBUG_FILE_OPENED) { |
|
159 close(Debug_pipe_fd); |
|
160 PLC_state &= ~PLC_STATE_DEBUG_FILE_OPENED; |
|
161 } |
|
162 |
|
163 if (PLC_state & PLC_STATE_PYTHON_PIPE_CREATED) { |
210 if (PLC_state & PLC_STATE_PYTHON_PIPE_CREATED) { |
164 rt_pipe_delete(&Python_pipe); |
211 delete_RT_to_nRT_signal(Python_handle); |
165 PLC_state &= ~PLC_STATE_PYTHON_PIPE_CREATED; |
212 PLC_state &= ~PLC_STATE_PYTHON_PIPE_CREATED; |
166 } |
213 } |
167 |
|
168 if (PLC_state & PLC_STATE_PYTHON_FILE_OPENED) { |
|
169 close(Python_pipe_fd); |
|
170 PLC_state &= ~PLC_STATE_PYTHON_FILE_OPENED; |
|
171 } |
|
172 |
|
173 } |
214 } |
174 |
215 |
175 int stopPLC() |
216 int stopPLC() |
176 { |
217 { |
177 /* Stop the PLC */ |
218 /* Stop the PLC */ |
211 signal(SIGINT, catch_signal); |
252 signal(SIGINT, catch_signal); |
212 |
253 |
213 /* no memory swapping for that process */ |
254 /* no memory swapping for that process */ |
214 mlockall(MCL_CURRENT | MCL_FUTURE); |
255 mlockall(MCL_CURRENT | MCL_FUTURE); |
215 |
256 |
|
257 |
|
258 /* memory initialization */ |
216 PLC_shutdown = 0; |
259 PLC_shutdown = 0; |
217 |
260 bzero(RT_to_nRT_signal_pool, sizeof(RT_to_nRT_signal_pool)); |
218 /*** RT Pipes creation and opening ***/ |
261 |
|
262 /*** RT Pipes ***/ |
219 /* create Debug_pipe */ |
263 /* create Debug_pipe */ |
220 if(rt_pipe_create(&Debug_pipe, "Debug_pipe", DEBUG_PIPE_MINOR, PIPE_SIZE) < 0) |
264 if(Debug_handle = create_RT_to_nRT_signal("Debug_pipe")) goto error; |
221 _startPLCLog(FO "Debug_pipe real-time end"); |
|
222 PLC_state |= PLC_STATE_DEBUG_PIPE_CREATED; |
265 PLC_state |= PLC_STATE_DEBUG_PIPE_CREATED; |
223 |
266 |
224 /* open Debug_pipe*/ |
|
225 if((Debug_pipe_fd = open(DEBUG_PIPE_DEVICE, O_RDWR)) == -1) |
|
226 _startPLCLog(FO DEBUG_PIPE_DEVICE); |
|
227 PLC_state |= PLC_STATE_DEBUG_FILE_OPENED; |
|
228 |
|
229 /* create Python_pipe */ |
267 /* create Python_pipe */ |
230 if(rt_pipe_create(&Python_pipe, "Python_pipe", PYTHON_PIPE_MINOR, PIPE_SIZE) < 0) |
268 if(Python_handle = create_RT_to_nRT_signal("Python_pipe")) goto error; |
231 _startPLCLog(FO "Python_pipe real-time end"); |
|
232 PLC_state |= PLC_STATE_PYTHON_PIPE_CREATED; |
269 PLC_state |= PLC_STATE_PYTHON_PIPE_CREATED; |
233 |
270 |
234 /* open Python_pipe*/ |
|
235 if((Python_pipe_fd = open(PYTHON_PIPE_DEVICE, O_RDWR)) == -1) |
|
236 _startPLCLog(FO PYTHON_PIPE_DEVICE); |
|
237 PLC_state |= PLC_STATE_PYTHON_FILE_OPENED; |
|
238 |
|
239 /* create WaitDebug_pipe */ |
271 /* create WaitDebug_pipe */ |
240 if(rt_pipe_create(&WaitDebug_pipe, "WaitDebug_pipe", WAITDEBUG_PIPE_MINOR, PIPE_SIZE) < 0) |
272 if(WaitDebug_handle = create_RT_to_nRT_signal("WaitDebug_pipe")) goto error; |
241 _startPLCLog(FO "WaitDebug_pipe real-time end"); |
|
242 PLC_state |= PLC_STATE_WAITDEBUG_PIPE_CREATED; |
273 PLC_state |= PLC_STATE_WAITDEBUG_PIPE_CREATED; |
243 |
274 |
244 /* open WaitDebug_pipe*/ |
|
245 if((WaitDebug_pipe_fd = open(WAITDEBUG_PIPE_DEVICE, O_RDWR)) == -1) |
|
246 _startPLCLog(FO WAITDEBUG_PIPE_DEVICE); |
|
247 PLC_state |= PLC_STATE_WAITDEBUG_FILE_OPENED; |
|
248 |
|
249 /* create WaitPython_pipe */ |
275 /* create WaitPython_pipe */ |
250 if(rt_pipe_create(&WaitPython_pipe, "WaitPython_pipe", WAITPYTHON_PIPE_MINOR, PIPE_SIZE) < 0) |
276 if(WaitPython_handle = create_RT_to_nRT_signal("WaitPython_pipe")) goto error; |
251 _startPLCLog(FO "WaitPython_pipe real-time end"); |
|
252 PLC_state |= PLC_STATE_WAITPYTHON_PIPE_CREATED; |
277 PLC_state |= PLC_STATE_WAITPYTHON_PIPE_CREATED; |
253 |
|
254 /* open WaitPython_pipe*/ |
|
255 if((WaitPython_pipe_fd = open(WAITPYTHON_PIPE_DEVICE, O_RDWR)) == -1) |
|
256 _startPLCLog(FO WAITPYTHON_PIPE_DEVICE); |
|
257 PLC_state |= PLC_STATE_WAITPYTHON_FILE_OPENED; |
|
258 |
|
259 /* create svghmi_pipe */ |
|
260 if(rt_pipe_create(&svghmi_pipe, "svghmi_pipe", SVGHMI_PIPE_MINOR, PIPE_SIZE) < 0) |
|
261 _startPLCLog(FO "svghmi_pipe real-time end"); |
|
262 PLC_state |= PLC_STATE_SVGHMI_PIPE_CREATED; |
|
263 |
|
264 /* open svghmi_pipe*/ |
|
265 if((svghmi_pipe_fd = open(SVGHMI_PIPE_DEVICE, O_RDWR)) == -1) |
|
266 _startPLCLog(FO SVGHMI_PIPE_DEVICE); |
|
267 PLC_state |= PLC_STATE_SVGHMI_FILE_OPENED; |
|
268 |
278 |
269 /*** create PLC task ***/ |
279 /*** create PLC task ***/ |
270 if(rt_task_create(&PLC_task, "PLC_task", 0, 50, T_JOINABLE)) |
280 if(rt_task_create(&PLC_task, "PLC_task", 0, 50, T_JOINABLE)) |
271 _startPLCLog("Failed creating PLC task"); |
281 _startPLCLog("Failed creating PLC task"); |
272 PLC_state |= PLC_STATE_TASK_CREATED; |
282 PLC_state |= PLC_STATE_TASK_CREATED; |
371 int WaitPythonCommands(void) |
381 int WaitPythonCommands(void) |
372 { |
382 { |
373 char cmd; |
383 char cmd; |
374 if (PLC_shutdown) return -1; |
384 if (PLC_shutdown) return -1; |
375 /* Wait signal from PLC thread */ |
385 /* Wait signal from PLC thread */ |
376 if(read(WaitPython_pipe_fd, &cmd, sizeof(cmd))==sizeof(cmd) && cmd==PYTHON_PENDING_COMMAND){ |
386 if(recv_RT_to_nRT_signal(WaitPython_handle, &cmd) == 1 && cmd==PYTHON_PENDING_COMMAND){ |
377 return 0; |
387 return 0; |
378 } |
388 } |
379 return -1; |
389 return -1; |
380 } |
390 } |
381 |
391 |
382 /* Called by PLC thread on each new python command*/ |
392 /* Called by PLC thread on each new python command*/ |
383 void UnBlockPythonCommands(void) |
393 void UnBlockPythonCommands(void) |
384 { |
394 { |
385 char msg = PYTHON_PENDING_COMMAND; |
395 char msg = PYTHON_PENDING_COMMAND; |
386 rt_pipe_write(&WaitPython_pipe, &msg, sizeof(msg), P_NORMAL); |
396 send_RT_to_nRT_signal(WaitPython_handle, msg); |
387 } |
397 } |
388 |
398 |
389 int TryLockPython(void) |
399 int TryLockPython(void) |
390 { |
400 { |
391 return AtomicCompareExchange( |
401 return AtomicCompareExchange( |
414 &python_state, |
424 &python_state, |
415 PYTHON_BUSY, |
425 PYTHON_BUSY, |
416 PYTHON_FREE) == PYTHON_BUSY){ |
426 PYTHON_FREE) == PYTHON_BUSY){ |
417 if(rt_task_self()){/*is that the real time task ?*/ |
427 if(rt_task_self()){/*is that the real time task ?*/ |
418 char cmd = UNLOCK_PYTHON; |
428 char cmd = UNLOCK_PYTHON; |
419 rt_pipe_write(&Python_pipe, &cmd, sizeof(cmd), P_NORMAL); |
429 send_RT_to_nRT_signal(Python_handle, cmd); |
420 }/* otherwise, no signaling from non real time */ |
430 }/* otherwise, no signaling from non real time */ |
421 } /* as plc does not wait for lock. */ |
431 } /* as plc does not wait for lock. */ |
422 } |
432 } |
423 |
433 |
424 void SVGHMI_SuspendFromPythonThread(void) |
|
425 { |
|
426 char cmd = 1; /*whatever*/ |
|
427 read(svghmi_pipe_fd, &cmd, sizeof(cmd)); |
|
428 } |
|
429 |
|
430 void SVGHMI_WakeupFromRTThread(void) |
|
431 { |
|
432 char cmd; |
|
433 rt_pipe_write(&svghmi_pipe, &cmd, sizeof(cmd), P_NORMAL); |
|
434 } |
|
435 |
|
436 #ifndef HAVE_RETAIN |
434 #ifndef HAVE_RETAIN |
437 int CheckRetainBuffer(void) |
435 int CheckRetainBuffer(void) |
438 { |
436 { |
439 return 1; |
437 return 1; |
440 } |
438 } |