37 buf_set, |
37 buf_set, |
38 buf_tosend |
38 buf_tosend |
39 } buf_state_t; |
39 } buf_state_t; |
40 |
40 |
41 static int global_write_dirty = 0; |
41 static int global_write_dirty = 0; |
|
42 static long hmitree_rlock = 0; |
|
43 static long hmitree_wlock = 0; |
42 |
44 |
43 typedef struct { |
45 typedef struct { |
44 void *ptr; |
46 void *ptr; |
45 __IEC_types_enum type; |
47 __IEC_types_enum type; |
46 uint32_t buf_index; |
48 uint32_t buf_index; |
47 |
49 |
48 /* publish/write/send */ |
50 /* publish/write/send */ |
49 long wlock; |
|
50 buf_state_t wstate[MAX_CONNECTIONS]; |
51 buf_state_t wstate[MAX_CONNECTIONS]; |
51 |
52 |
52 /* zero means not subscribed */ |
53 /* zero means not subscribed */ |
53 uint16_t refresh_period_ms[MAX_CONNECTIONS]; |
54 uint16_t refresh_period_ms[MAX_CONNECTIONS]; |
54 uint16_t age_ms[MAX_CONNECTIONS]; |
55 uint16_t age_ms[MAX_CONNECTIONS]; |
55 |
56 |
56 /* retrieve/read/recv */ |
57 /* retrieve/read/recv */ |
57 long rlock; |
|
58 buf_state_t rstate; |
58 buf_state_t rstate; |
59 |
59 |
60 } hmi_tree_item_t; |
60 } hmi_tree_item_t; |
61 |
61 |
62 static hmi_tree_item_t hmi_tree_item[] = { |
62 static hmi_tree_item_t hmi_tree_item[] = { |
81 |
81 |
82 %(var_access_code)s |
82 %(var_access_code)s |
83 |
83 |
84 static int write_iterator(uint32_t index, hmi_tree_item_t *dsc) |
84 static int write_iterator(uint32_t index, hmi_tree_item_t *dsc) |
85 { |
85 { |
86 uint32_t session_index = 0; |
86 { |
87 int value_changed = 0; |
87 uint32_t session_index = 0; |
88 if(AtomicCompareExchange(&dsc->wlock, 0, 1) == 0) { |
88 int value_changed = 0; |
89 void *dest_p = &wbuf[dsc->buf_index]; |
89 void *dest_p = NULL; |
90 void *real_value_p = NULL; |
90 void *real_value_p = NULL; |
91 char flags = 0; |
91 void *visible_value_p = NULL; |
92 void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags); |
92 USINT sz = 0; |
93 USINT sz = __get_type_enum_size(dsc->type); |
|
94 if(__Is_a_string(dsc)){ |
|
95 sz = ((STRING*)visible_value_p)->len + 1; |
|
96 } |
|
97 while(session_index < MAX_CONNECTIONS) { |
93 while(session_index < MAX_CONNECTIONS) { |
98 if(dsc->wstate[session_index] == buf_set){ |
94 if(dsc->wstate[session_index] == buf_set){ |
99 /* if being subscribed */ |
95 /* if being subscribed */ |
100 if(dsc->refresh_period_ms[session_index]){ |
96 if(dsc->refresh_period_ms[session_index]){ |
101 if(dsc->age_ms[session_index] + ticktime_ms < dsc->refresh_period_ms[session_index]){ |
97 if(dsc->age_ms[session_index] + ticktime_ms < dsc->refresh_period_ms[session_index]){ |
105 global_write_dirty = 1; |
101 global_write_dirty = 1; |
106 } |
102 } |
107 } |
103 } |
108 } |
104 } |
109 |
105 |
110 if(dsc->wstate[session_index] == buf_new /* just subscribed |
106 /* variable is sample only if just subscribed |
111 or already subscribed having value change */ |
107 or already subscribed and having value change */ |
112 || (dsc->refresh_period_ms[session_index] > 0 |
108 int do_sample = 0; |
113 && (value_changed || (value_changed=memcmp(dest_p, visible_value_p, sz))) != 0)){ |
109 int just_subscribed = dsc->wstate[session_index] == buf_new; |
114 /* if not already marked/signaled, do it */ |
110 if(!just_subscribed){ |
|
111 int already_subscribed = dsc->refresh_period_ms[session_index] > 0; |
|
112 if(already_subscribed){ |
|
113 if(!value_changed){ |
|
114 if(!visible_value_p){ |
|
115 char flags = 0; |
|
116 visible_value_p = UnpackVar(dsc, &real_value_p, &flags); |
|
117 if(__Is_a_string(dsc)){ |
|
118 sz = ((STRING*)visible_value_p)->len + 1; |
|
119 } else { |
|
120 sz = __get_type_enum_size(dsc->type); |
|
121 } |
|
122 dest_p = &wbuf[dsc->buf_index]; |
|
123 } |
|
124 value_changed = memcmp(dest_p, visible_value_p, sz) != 0; |
|
125 do_sample = value_changed; |
|
126 }else{ |
|
127 do_sample = 1; |
|
128 } |
|
129 } |
|
130 } else { |
|
131 do_sample = 1; |
|
132 } |
|
133 |
|
134 |
|
135 if(do_sample){ |
115 if(dsc->wstate[session_index] != buf_set && dsc->wstate[session_index] != buf_tosend) { |
136 if(dsc->wstate[session_index] != buf_set && dsc->wstate[session_index] != buf_tosend) { |
116 if(dsc->wstate[session_index] == buf_new || ticktime_ms > dsc->refresh_period_ms[session_index]){ |
137 if(dsc->wstate[session_index] == buf_new \ |
|
138 || ticktime_ms > dsc->refresh_period_ms[session_index]){ |
117 dsc->wstate[session_index] = buf_tosend; |
139 dsc->wstate[session_index] = buf_tosend; |
118 global_write_dirty = 1; |
140 global_write_dirty = 1; |
119 } else { |
141 } else { |
120 dsc->wstate[session_index] = buf_set; |
142 dsc->wstate[session_index] = buf_set; |
121 } |
143 } |
126 session_index++; |
148 session_index++; |
127 } |
149 } |
128 /* copy value if changed (and subscribed) */ |
150 /* copy value if changed (and subscribed) */ |
129 if(value_changed) |
151 if(value_changed) |
130 memcpy(dest_p, visible_value_p, sz); |
152 memcpy(dest_p, visible_value_p, sz); |
131 AtomicCompareExchange(&dsc->wlock, 1, 0); |
|
132 } |
153 } |
133 // else ... : PLC can't wait, variable will be updated next turn |
154 // else ... : PLC can't wait, variable will be updated next turn |
134 return 0; |
155 return 0; |
135 } |
156 } |
136 |
157 |
137 static uint32_t send_session_index; |
158 static uint32_t send_session_index; |
138 static int send_iterator(uint32_t index, hmi_tree_item_t *dsc) |
159 static int send_iterator(uint32_t index, hmi_tree_item_t *dsc) |
139 { |
160 { |
140 while(AtomicCompareExchange(&dsc->wlock, 0, 1)) |
|
141 nRT_reschedule(); |
|
142 |
|
143 if(dsc->wstate[send_session_index] == buf_tosend) |
161 if(dsc->wstate[send_session_index] == buf_tosend) |
144 { |
162 { |
145 uint32_t sz = __get_type_enum_size(dsc->type); |
163 uint32_t sz = __get_type_enum_size(dsc->type); |
146 if(sbufidx + sizeof(uint32_t) + sz <= sizeof(sbuf)) |
164 if(sbufidx + sizeof(uint32_t) + sz <= sizeof(sbuf)) |
147 { |
165 { |
157 sbufidx += sizeof(uint32_t) /* index */ + sz; |
175 sbufidx += sizeof(uint32_t) /* index */ + sz; |
158 } |
176 } |
159 else |
177 else |
160 { |
178 { |
161 printf("BUG!!! %%d + %%ld + %%d > %%ld \n", sbufidx, sizeof(uint32_t), sz, sizeof(sbuf)); |
179 printf("BUG!!! %%d + %%ld + %%d > %%ld \n", sbufidx, sizeof(uint32_t), sz, sizeof(sbuf)); |
162 AtomicCompareExchange(&dsc->wlock, 1, 0); |
|
163 return EOVERFLOW; |
180 return EOVERFLOW; |
164 } |
181 } |
165 } |
182 } |
166 |
183 |
167 AtomicCompareExchange(&dsc->wlock, 1, 0); |
|
168 return 0; |
184 return 0; |
169 } |
185 } |
170 |
186 |
171 static int read_iterator(uint32_t index, hmi_tree_item_t *dsc) |
187 static int read_iterator(uint32_t index, hmi_tree_item_t *dsc) |
172 { |
188 { |
173 if(AtomicCompareExchange(&dsc->rlock, 0, 1) == 0) |
189 if(dsc->rstate == buf_set) |
174 { |
190 { |
175 if(dsc->rstate == buf_set) |
191 void *src_p = &rbuf[dsc->buf_index]; |
176 { |
192 void *real_value_p = NULL; |
177 void *src_p = &rbuf[dsc->buf_index]; |
193 char flags = 0; |
178 void *real_value_p = NULL; |
194 void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags); |
179 char flags = 0; |
195 memcpy(real_value_p, src_p, __get_type_enum_size(dsc->type)); |
180 void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags); |
196 dsc->rstate = buf_free; |
181 memcpy(real_value_p, src_p, __get_type_enum_size(dsc->type)); |
197 } |
182 dsc->rstate = buf_free; |
|
183 } |
|
184 AtomicCompareExchange(&dsc->rlock, 1, 0); |
|
185 } |
|
186 // else ... : PLC can't wait, variable will be updated next turn |
|
187 return 0; |
198 return 0; |
188 } |
199 } |
189 |
200 |
190 void update_refresh_period(hmi_tree_item_t *dsc, uint32_t session_index, uint16_t refresh_period_ms) |
201 void update_refresh_period(hmi_tree_item_t *dsc, uint32_t session_index, uint16_t refresh_period_ms) |
191 { |
202 { |
192 while(AtomicCompareExchange(&dsc->wlock, 0, 1)) |
|
193 nRT_reschedule(); |
|
194 |
|
195 if(refresh_period_ms) { |
203 if(refresh_period_ms) { |
196 if(!dsc->refresh_period_ms[session_index]) |
204 if(!dsc->refresh_period_ms[session_index]) |
197 { |
205 { |
198 dsc->wstate[session_index] = buf_new; |
206 dsc->wstate[session_index] = buf_new; |
199 } |
207 } |
200 } else { |
208 } else { |
201 dsc->wstate[session_index] = buf_free; |
209 dsc->wstate[session_index] = buf_free; |
202 } |
210 } |
203 dsc->refresh_period_ms[session_index] = refresh_period_ms; |
211 dsc->refresh_period_ms[session_index] = refresh_period_ms; |
204 AtomicCompareExchange(&dsc->wlock, 1, 0); |
|
205 } |
212 } |
206 |
213 |
207 static uint32_t reset_session_index; |
214 static uint32_t reset_session_index; |
208 static int reset_iterator(uint32_t index, hmi_tree_item_t *dsc) |
215 static int reset_iterator(uint32_t index, hmi_tree_item_t *dsc) |
209 { |
216 { |
248 delete_RT_to_nRT_signal(svghmi_handle); |
255 delete_RT_to_nRT_signal(svghmi_handle); |
249 } |
256 } |
250 |
257 |
251 void __retrieve_svghmi() |
258 void __retrieve_svghmi() |
252 { |
259 { |
253 traverse_hmi_tree(read_iterator); |
260 if(AtomicCompareExchange(&hmitree_rlock, 0, 1) == 0) { |
|
261 traverse_hmi_tree(read_iterator); |
|
262 AtomicCompareExchange(&hmitree_rlock, 1, 0); |
|
263 } |
254 } |
264 } |
255 |
265 |
256 void __publish_svghmi() |
266 void __publish_svghmi() |
257 { |
267 { |
258 global_write_dirty = 0; |
268 global_write_dirty = 0; |
259 traverse_hmi_tree(write_iterator); |
269 if(AtomicCompareExchange(&hmitree_wlock, 0, 1) == 0) { |
|
270 traverse_hmi_tree(write_iterator); |
|
271 AtomicCompareExchange(&hmitree_wlock, 1, 0); |
|
272 } |
260 if(global_write_dirty) { |
273 if(global_write_dirty) { |
261 SVGHMI_WakeupFromRTThread(); |
274 SVGHMI_WakeupFromRTThread(); |
262 } |
275 } |
263 } |
276 } |
264 |
277 |
272 |
285 |
273 if(svghmi_continue_collect) { |
286 if(svghmi_continue_collect) { |
274 int res; |
287 int res; |
275 sbufidx = HMI_HASH_SIZE; |
288 sbufidx = HMI_HASH_SIZE; |
276 send_session_index = session_index; |
289 send_session_index = session_index; |
|
290 |
|
291 while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){ |
|
292 nRT_reschedule(); |
|
293 } |
|
294 |
277 if((res = traverse_hmi_tree(send_iterator)) == 0) |
295 if((res = traverse_hmi_tree(send_iterator)) == 0) |
278 { |
296 { |
279 if(sbufidx > HMI_HASH_SIZE){ |
297 if(sbufidx > HMI_HASH_SIZE){ |
280 memcpy(&sbuf[0], &hmi_hash[0], HMI_HASH_SIZE); |
298 memcpy(&sbuf[0], &hmi_hash[0], HMI_HASH_SIZE); |
281 *ptr = &sbuf[0]; |
299 *ptr = &sbuf[0]; |
282 *size = sbufidx; |
300 *size = sbufidx; |
|
301 AtomicCompareExchange(&hmitree_wlock, 1, 0); |
283 return 0; |
302 return 0; |
284 } |
303 } |
|
304 AtomicCompareExchange(&hmitree_wlock, 1, 0); |
285 return ENODATA; |
305 return ENODATA; |
286 } |
306 } |
287 // printf("collected BAD result %%d\n", res); |
307 // printf("collected BAD result %%d\n", res); |
|
308 AtomicCompareExchange(&hmitree_wlock, 1, 0); |
288 return res; |
309 return res; |
289 } |
310 } |
290 else |
311 else |
291 { |
312 { |
292 return EINTR; |
313 return EINTR; |
293 } |
314 } |
294 } |
315 } |
295 |
316 |
296 typedef enum { |
317 typedef enum { |
|
318 unset = -1, |
297 setval = 0, |
319 setval = 0, |
298 reset = 1, |
320 reset = 1, |
299 subscribe = 2 |
321 subscribe = 2 |
300 } cmd_from_JS; |
322 } cmd_from_JS; |
301 |
323 |
348 } |
389 } |
349 |
390 |
350 if((valptr + sz) <= end) |
391 if((valptr + sz) <= end) |
351 { |
392 { |
352 // rescheduling spinlock until free |
393 // rescheduling spinlock until free |
353 while(AtomicCompareExchange(&dsc->rlock, 0, 1)) |
394 if(!got_rlock){ |
354 nRT_reschedule(); |
395 while(AtomicCompareExchange(&hmitree_rlock, 0, 1)){ |
|
396 nRT_reschedule(); |
|
397 } |
|
398 got_rlock=1; |
|
399 } |
355 |
400 |
356 memcpy(dst_p, valptr, sz); |
401 memcpy(dst_p, valptr, sz); |
357 dsc->rstate = buf_set; |
402 dsc->rstate = buf_set; |
358 |
403 |
359 AtomicCompareExchange(&dsc->rlock, 1, 0); |
|
360 progress = sz + sizeof(uint32_t) /* index */; |
404 progress = sz + sizeof(uint32_t) /* index */; |
361 } |
405 } |
362 else |
406 else |
363 { |
407 { |
364 return -EINVAL; |
408 ret = -EINVAL; |
|
409 goto exit_free; |
365 } |
410 } |
366 } |
411 } |
367 else |
412 else |
368 { |
413 { |
369 return -EINVAL; |
414 ret = -EINVAL; |
|
415 goto exit_free; |
370 } |
416 } |
371 } |
417 } |
372 break; |
418 break; |
373 |
419 |
374 case reset: |
420 case reset: |
375 { |
421 { |
376 progress = 0; |
422 progress = 0; |
377 reset_session_index = session_index; |
423 reset_session_index = session_index; |
|
424 if(!got_wlock){ |
|
425 while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){ |
|
426 nRT_reschedule(); |
|
427 } |
|
428 got_wlock = 1; |
|
429 } |
378 traverse_hmi_tree(reset_iterator); |
430 traverse_hmi_tree(reset_iterator); |
379 } |
431 } |
380 break; |
432 break; |
381 |
433 |
382 case subscribe: |
434 case subscribe: |
384 uint32_t index = *(uint32_t*)(cursor); |
436 uint32_t index = *(uint32_t*)(cursor); |
385 uint16_t refresh_period_ms = *(uint32_t*)(cursor + sizeof(uint32_t)); |
437 uint16_t refresh_period_ms = *(uint32_t*)(cursor + sizeof(uint32_t)); |
386 |
438 |
387 if(index < HMI_ITEM_COUNT) |
439 if(index < HMI_ITEM_COUNT) |
388 { |
440 { |
|
441 if(!got_wlock){ |
|
442 while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){ |
|
443 nRT_reschedule(); |
|
444 } |
|
445 got_wlock = 1; |
|
446 } |
389 hmi_tree_item_t *dsc = &hmi_tree_item[index]; |
447 hmi_tree_item_t *dsc = &hmi_tree_item[index]; |
390 update_refresh_period(dsc, session_index, refresh_period_ms); |
448 update_refresh_period(dsc, session_index, refresh_period_ms); |
391 } |
449 } |
392 else |
450 else |
393 { |
451 { |
394 return -EINVAL; |
452 ret = -EINVAL; |
|
453 goto exit_free; |
395 } |
454 } |
396 |
455 |
397 progress = sizeof(uint32_t) /* index */ + |
456 progress = sizeof(uint32_t) /* index */ + |
398 sizeof(uint16_t) /* refresh period */; |
457 sizeof(uint16_t) /* refresh period */; |
399 } |
458 } |