1 /* |
|
2 * (c) 2003 Mario de Sousa |
|
3 * |
|
4 * Offered to the public under the terms of the GNU General Public License |
|
5 * as published by the Free Software Foundation; either version 2 of the |
|
6 * License, or (at your option) any later version. |
|
7 * |
|
8 * This program is distributed in the hope that it will be useful, but |
|
9 * WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|
11 * Public License for more details. |
|
12 * |
|
13 * This code is made available on the understanding that it will not be |
|
14 * used in safety-critical situations without a full and competent review. |
|
15 */ |
|
16 |
|
17 /* |
|
18 * An IEC 61131-3 IL and ST compiler. |
|
19 * |
|
20 * Based on the |
|
21 * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) |
|
22 * |
|
23 */ |
|
24 |
|
25 |
|
26 /* |
|
27 * Code to be included into the code generated by the 4th stage. |
|
28 * |
|
29 * This is part of the 4th stage that generates |
|
30 * a c++ source program equivalent to the IL and ST |
|
31 * code. |
|
32 */ |
|
33 |
|
34 |
|
35 #ifndef __PLCIEC_H |
|
36 #define __PLCIEC_H |
|
37 |
|
38 //#include <stdio.h> |
|
39 #include "plc.h" |
|
40 #include <math.h> |
|
41 #include <time.h> |
|
42 |
|
43 |
|
44 |
|
45 /* function that generates an IEC runtime error */ |
|
46 void IEC_error(void) { |
|
47 /* TODO... */ |
|
48 fprintf(stderr, "IEC 61131-3 runtime error.\n"); |
|
49 exit(1); |
|
50 } |
|
51 |
|
52 |
|
53 |
|
54 typedef bool BOOL; |
|
55 #define TRUE true |
|
56 #define FALSE false |
|
57 |
|
58 typedef i8 SINT; |
|
59 typedef i16 INT; |
|
60 typedef i32 DINT; |
|
61 typedef i64 LINT; |
|
62 |
|
63 typedef u8 USINT; |
|
64 typedef u16 UINT; |
|
65 typedef u32 UDINT; |
|
66 typedef u64 ULINT; |
|
67 |
|
68 typedef u8 BYTE; |
|
69 typedef u16 WORD; |
|
70 typedef u32 DWORD; |
|
71 typedef u64 LWORD; |
|
72 |
|
73 typedef f32 REAL; |
|
74 typedef f64 LREAL; |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 /*********************************************/ |
|
82 /* TIME AND DATE data trypes */ |
|
83 /*********************************************/ |
|
84 |
|
85 /* NOTE: All the time and date data types use a struct timespec |
|
86 * internally to store the time and date. This is so as to ease all the |
|
87 * operations (add, subtract, multiply and division) the standard defines |
|
88 * on these same data types. |
|
89 * However, in order to ease the implementation of the comparison operators |
|
90 * (==, =>, <=, <, >, <>), the two elements in the timespec structure |
|
91 * must be handled in such a way as to guarantee the following: |
|
92 * - The stored time is always the result of the operation tv_sec + tv_nsec*1e-9 |
|
93 * - tv_sec and tv_nsec will always have the same sign |
|
94 * (i.e. either both positive or both negative) |
|
95 * - tv_nsec always holds a value in the range ]-1, +1[ seconds. |
|
96 * (note that -1 and +1 are excluded form the range) |
|
97 */ |
|
98 |
|
99 |
|
100 /* NOTE: According to the C++ standard, the result of the % and / operations is implementation dependent |
|
101 * when the at least one of the operands is negative! However, whatever the result of the operations, we are |
|
102 * guaranteed that (a/b)*b + (a%b) is always equal to a. |
|
103 * This means that, even knowing that both tv_sec and tv_sec always have the same sign (we make it so this is true), |
|
104 * we must still re-normailze the result for both the addition and subtraction operations! |
|
105 */ |
|
106 |
|
107 static inline void __normalizesign_timespec (struct timespec *ts) { |
|
108 if ((ts->tv_sec > 0) && (ts->tv_nsec < 0)) { |
|
109 ts->tv_sec--; |
|
110 ts->tv_nsec += 1000000000; |
|
111 } |
|
112 if ((ts->tv_sec < 0) && (ts->tv_nsec > 0)) { |
|
113 ts->tv_sec++; |
|
114 ts->tv_nsec -= 1000000000; |
|
115 } |
|
116 } |
|
117 |
|
118 |
|
119 static inline struct timespec __add_timespec (const struct timespec &t1, const struct timespec &t2) { |
|
120 /* NOTE the following sum works correctly because a long can hold a litle more than 2 seconds expressed in nano seconds! */ |
|
121 long nsec; |
|
122 nsec = t1.tv_nsec + t2.tv_nsec; |
|
123 struct timespec ts; |
|
124 ts.tv_sec = t1.tv_sec + t2.tv_sec + (nsec / 1000000000); |
|
125 ts.tv_nsec = nsec % 1000000000; |
|
126 |
|
127 __normalizesign_timespec(&ts); |
|
128 |
|
129 return ts; |
|
130 } |
|
131 |
|
132 |
|
133 static inline struct timespec __sub_timespec (const struct timespec &t1, const struct timespec &t2) { |
|
134 /* NOTE the following subtraction works correctly because a long can hold a litle more than 2 seconds expressed in nano seconds! */ |
|
135 long nsec = t1.tv_nsec - t2.tv_nsec; |
|
136 struct timespec ts; |
|
137 ts.tv_sec = t1.tv_sec - t2.tv_sec + nsec / 1000000000; |
|
138 ts.tv_nsec = nsec % 1000000000; |
|
139 |
|
140 __normalizesign_timespec(&ts); |
|
141 |
|
142 return ts; |
|
143 } |
|
144 |
|
145 |
|
146 static inline struct timespec __mul_timespec (const struct timespec &t1, const long double value) { |
|
147 #if 0 |
|
148 /* A simple implementation that risks reducing the precision of the TIME value */ |
|
149 long double sec_d1 = t1.tv_nsec / (long double)1e9 * value; |
|
150 long double sec_d2 = t1.tv_sec * value; |
|
151 long int sec = (long int)truncl(sec_d1 + sec_d2); |
|
152 struct timespec ts; |
|
153 ts.tv_sec = sec; |
|
154 ts.tv_nsec = (long int)((sec_d1 + sec_d2 - sec)*1e9); |
|
155 return ts; |
|
156 #else |
|
157 /* A more robust implementation that reduces the loss of precision of the TIME value */ |
|
158 /* NOTE: The following assumes that the value stored in tv_nsec is never larger than 1 sec |
|
159 * and is also based on the fact that tv_nsec can safely store slighlty more thanb 2 sec. |
|
160 */ |
|
161 long double sec_d1 = t1.tv_nsec / (long double)1e9 * value; |
|
162 long double sec_d2 = t1.tv_sec * value; |
|
163 long int sec1 = (long int)sec_d1; |
|
164 long int sec2 = (long int)sec_d2; |
|
165 struct timespec ts; |
|
166 ts.tv_sec = sec1 + sec2; |
|
167 ts.tv_nsec = (long int)(((sec_d1 - sec1) + (sec_d2 - sec2))*1e9); |
|
168 /* re-normalize the value of tv_nsec */ |
|
169 /* i.e. guarantee that it falls in the range ]-1, +1[ seconds. */ |
|
170 if (ts.tv_nsec >= 1000000000) {ts.tv_nsec -= 1000000000; ts.tv_sec += 1;} |
|
171 if (ts.tv_nsec <= -1000000000) {ts.tv_nsec += 1000000000; ts.tv_sec -= 1;} |
|
172 /* We don't need to re-normalize the sign, since we are guaranteed that tv_sec and tv_nsec |
|
173 * will still both have the same sign after being multiplied by the same value. |
|
174 */ |
|
175 return ts; |
|
176 #endif |
|
177 } |
|
178 |
|
179 /* Helper Macro for the comparison operators... */ |
|
180 #define __compare_timespec(CMP, t1, t2) ((t1.tv_sec == t2.tv_sec)? t1.tv_nsec CMP t2.tv_nsec : t1.tv_sec CMP t2.tv_sec) |
|
181 |
|
182 |
|
183 |
|
184 /* Some necessary forward declarations... */ |
|
185 /* |
|
186 class TIME; |
|
187 class TOD; |
|
188 class DT; |
|
189 class DATE; |
|
190 |
|
191 typedef struct timespec __timebase_t; |
|
192 */ |
|
193 |
|
194 typedef struct TIME timespec; |
|
195 typedef struct TOD timespec; |
|
196 typedef struct DT timespec; |
|
197 typedef struct DATE timespec; |
|
198 |
|
199 static inline struct timespec __time_to_timespec(int sign, double mseconds, double seconds, double minutes, double hours, double days) { |
|
200 struct timespec ts; |
|
201 |
|
202 /* sign is 1 for positive values, -1 for negative time... */ |
|
203 long double total_sec = ((days*24 + hours)*60 + minutes)*60 + seconds + mseconds/1e3; |
|
204 if (sign >= 0) sign = 1; else sign = -1; |
|
205 ts.tv_sec = sign * (long int)total_sec; |
|
206 ts.tv_nsec = sign * (long int)((total_sec - ts.tv_sec)*1e9); |
|
207 |
|
208 return ts; |
|
209 } |
|
210 |
|
211 |
|
212 static inline struct timespec __tod_to_timespec(double seconds, double minutes, double hours) { |
|
213 struct timespec ts; |
|
214 |
|
215 long double total_sec = (hours*60 + minutes)*60 + seconds; |
|
216 ts.tv_sec = (long int)total_sec; |
|
217 ts.tv_nsec = (long int)((total_sec - ts.tv_sec)*1e9); |
|
218 |
|
219 return ts; |
|
220 } |
|
221 |
|
222 static inline struct timespec __date_to_timespec(int day, int month, int year) { |
|
223 struct timespec ts; |
|
224 struct tm broken_down_time; |
|
225 |
|
226 broken_down_time.tm_sec = 0; |
|
227 broken_down_time.tm_min = 0; |
|
228 broken_down_time.tm_hour = 0; |
|
229 broken_down_time.tm_mday = day; /* day of month, from 1 to 31 */ |
|
230 broken_down_time.tm_mon = month - 1; /* month since January, in the range 0 to 11 */ |
|
231 broken_down_time.tm_year = year - 1900; /* number of years since 1900 */ |
|
232 |
|
233 time_t epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */ |
|
234 |
|
235 if ((time_t)(-1) == epoch_seconds) |
|
236 IEC_error(); |
|
237 |
|
238 ts.tv_sec = epoch_seconds; |
|
239 ts.tv_nsec = 0; |
|
240 |
|
241 return ts; |
|
242 } |
|
243 |
|
244 static inline struct timespec __dt_to_timespec(double seconds, double minutes, double hours, int day, int month, int year) { |
|
245 struct timespec ts; |
|
246 |
|
247 long double total_sec = (hours*60 + minutes)*60 + seconds; |
|
248 ts.tv_sec = (long int)total_sec; |
|
249 ts.tv_nsec = (long int)((total_sec - ts.tv_sec)*1e9); |
|
250 |
|
251 struct tm broken_down_time; |
|
252 broken_down_time.tm_sec = 0; |
|
253 broken_down_time.tm_min = 0; |
|
254 broken_down_time.tm_hour = 0; |
|
255 broken_down_time.tm_mday = day; /* day of month, from 1 to 31 */ |
|
256 broken_down_time.tm_mon = month - 1; /* month since January, in the range 0 to 11 */ |
|
257 broken_down_time.tm_year = year - 1900; /* number of years since 1900 */ |
|
258 |
|
259 time_t epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */ |
|
260 if ((time_t)(-1) == epoch_seconds) |
|
261 IEC_error(); |
|
262 |
|
263 ts.tv_sec += epoch_seconds; |
|
264 if (ts.tv_sec < epoch_seconds) |
|
265 /* since the TOD is always positive, if the above happens then we had an overflow */ |
|
266 IEC_error(); |
|
267 |
|
268 return ts; |
|
269 } |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 |
|
275 |
|
276 |
|
277 |
|
278 #ifdef 0 |
|
279 class TIME{ |
|
280 private: |
|
281 /* private variable that contains the value of time. */ |
|
282 /* NOTE: The stored value is _always_ (time.tv_sec + time.tv_nsec), |
|
283 no matter whether tv_sec is positive or negative, or tv_nsec is positive or negative. |
|
284 */ |
|
285 __timebase_t time; |
|
286 |
|
287 public: |
|
288 /* conversion to __timebase_t */ |
|
289 operator __timebase_t(void) {return time;} |
|
290 |
|
291 /* constructors... */ |
|
292 TIME (void) {time.tv_sec = 0; time.tv_nsec = 0;} |
|
293 TIME (__timebase_t time) {this->time = time;} |
|
294 TIME (const TIME &time) {this->time = time.time;} /* copy constructor */ |
|
295 TIME(int sign, double mseconds, double seconds=0, double minutes=0, double hours=0, double days=0) { |
|
296 /* sign is 1 for positive values, -1 for negative time... */ |
|
297 long double total_sec = ((days*24 + hours)*60 + minutes)*60 + seconds + mseconds/1e3; |
|
298 if (sign >= 0) sign = 1; else sign = -1; |
|
299 time.tv_sec = sign * (long int)total_sec; |
|
300 time.tv_nsec = sign * (long int)((total_sec - time.tv_sec)*1e9); |
|
301 } |
|
302 |
|
303 /* used in plciec.cc to set the value of the __CURRENT_TIME variable without having to call a |
|
304 * TIME((__timebase_t time) constructor followed by the copy constructor. |
|
305 */ |
|
306 void operator= (__timebase_t time) {this->time = time;} |
|
307 |
|
308 /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */ |
|
309 TIME operator+ (const TIME &time) {return TIME(__add_timespec(this->time, time.time));} |
|
310 TIME operator- (const TIME &time) {return TIME(__sub_timespec(this->time, time.time));} |
|
311 |
|
312 friend TOD operator+ (const TIME &time, const TOD &tod); |
|
313 friend TOD operator+ (const TOD &tod, const TIME &time); |
|
314 friend TOD operator- (const TOD &tod, const TIME &time); |
|
315 |
|
316 friend DT operator+ (const TIME &time, const DT &dt); |
|
317 friend DT operator+ (const DT &dt, const TIME &time); |
|
318 friend DT operator- (const DT &dt, const TIME &time); |
|
319 |
|
320 friend TIME operator* (const TIME &time, const long double value); |
|
321 friend TIME operator* (const long double value, const TIME &time); |
|
322 friend TIME operator/ (const TIME &time, const long double value); |
|
323 |
|
324 /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */ |
|
325 BOOL operator> (const TIME &time) {return __compare_timespec(>, this->time, time.time);} |
|
326 BOOL operator>= (const TIME &time) {return __compare_timespec(>=, this->time, time.time);} |
|
327 BOOL operator< (const TIME &time) {return __compare_timespec(<, this->time, time.time);} |
|
328 BOOL operator<= (const TIME &time) {return __compare_timespec(<=, this->time, time.time);} |
|
329 BOOL operator== (const TIME &time) {return __compare_timespec(==, this->time, time.time);} |
|
330 BOOL operator!= (const TIME &time) {return !__compare_timespec(==, this->time, time.time);} |
|
331 }; |
|
332 |
|
333 |
|
334 |
|
335 /* Time of Day */ |
|
336 class TOD { |
|
337 private: |
|
338 __timebase_t time; |
|
339 |
|
340 public: |
|
341 /* conversion to __timebase_t */ |
|
342 operator __timebase_t(void) {return time;} |
|
343 |
|
344 /* constructors... */ |
|
345 TOD (void) {time.tv_sec = 0; time.tv_nsec = 0;} |
|
346 TOD (__timebase_t time) {this->time = time;} |
|
347 TOD (const TOD &tod) {this->time = tod.time;} /* copy constructor */ |
|
348 TOD (double seconds, double minutes=0, double hours=0) { |
|
349 long double total_sec = (hours*60 + minutes)*60 + seconds; |
|
350 time.tv_sec = (long int)total_sec; |
|
351 time.tv_nsec = (long int)((total_sec - time.tv_sec)*1e9); |
|
352 } |
|
353 |
|
354 /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */ |
|
355 TIME operator- (const TOD &tod) {return TIME(__sub_timespec(this->time, tod.time));} |
|
356 |
|
357 friend TOD operator+ (const TIME &time, const TOD &tod); |
|
358 friend TOD operator+ (const TOD &tod, const TIME &time); |
|
359 friend TOD operator- (const TOD &tod, const TIME &time); |
|
360 |
|
361 /* The following operation is not in the standard, |
|
362 * but will ease the implementation of the default function CONCAT_DATE_TOD |
|
363 */ |
|
364 friend DT operator+ (const DATE &date, const TOD &tod); |
|
365 friend DT operator+ (const TOD &tod, const DATE &date); |
|
366 |
|
367 /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */ |
|
368 BOOL operator> (const TOD &tod) {return __compare_timespec(>, this->time, tod.time);} |
|
369 BOOL operator>= (const TOD &tod) {return __compare_timespec(>=, this->time, tod.time);} |
|
370 BOOL operator< (const TOD &tod) {return __compare_timespec(<, this->time, tod.time);} |
|
371 BOOL operator<= (const TOD &tod) {return __compare_timespec(<=, this->time, tod.time);} |
|
372 BOOL operator== (const TOD &tod) {return __compare_timespec(==, this->time, tod.time);} |
|
373 BOOL operator!= (const TOD &tod) {return !__compare_timespec(==, this->time, tod.time);} |
|
374 }; |
|
375 |
|
376 |
|
377 |
|
378 //typedef DATE; |
|
379 class DATE { |
|
380 private: |
|
381 __timebase_t time; |
|
382 |
|
383 public: |
|
384 /* conversion to __timebase_t */ |
|
385 operator __timebase_t(void) {return time;} |
|
386 |
|
387 /* constructors... */ |
|
388 DATE (void) {time.tv_sec = 0; time.tv_nsec = 0;} |
|
389 DATE (__timebase_t time) {this->time = time;} |
|
390 DATE (const DATE &date) {this->time = date.time;} /* copy constructor */ |
|
391 DATE (int day, int month, int year) { |
|
392 struct tm broken_down_time; |
|
393 |
|
394 broken_down_time.tm_sec = 0; |
|
395 broken_down_time.tm_min = 0; |
|
396 broken_down_time.tm_hour = 0; |
|
397 broken_down_time.tm_mday = day; /* day of month, from 1 to 31 */ |
|
398 broken_down_time.tm_mon = month - 1; /* month since January, in the range 0 to 11 */ |
|
399 broken_down_time.tm_year = year - 1900; /* number of years since 1900 */ |
|
400 |
|
401 time_t epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */ |
|
402 |
|
403 if ((time_t)(-1) == epoch_seconds) |
|
404 IEC_error(); |
|
405 |
|
406 time.tv_sec = epoch_seconds; |
|
407 time.tv_nsec = 0; |
|
408 } |
|
409 |
|
410 /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */ |
|
411 TIME operator- (const DATE &date) {return TIME(__sub_timespec(this->time, date.time));} |
|
412 /* The following operation is not in the standard, |
|
413 * but will ease the implementation of the default function CONCAT_DATE_TOD |
|
414 */ |
|
415 friend DT operator+ (const DATE &date, const TOD &tod); |
|
416 friend DT operator+ (const TOD &tod, const DATE &date); |
|
417 |
|
418 /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */ |
|
419 BOOL operator> (const DATE &date) {return __compare_timespec(>, this->time, date.time);} |
|
420 BOOL operator>= (const DATE &date) {return __compare_timespec(>=, this->time, date.time);} |
|
421 BOOL operator< (const DATE &date) {return __compare_timespec(<, this->time, date.time);} |
|
422 BOOL operator<= (const DATE &date) {return __compare_timespec(<=, this->time, date.time);} |
|
423 BOOL operator== (const DATE &date) {return __compare_timespec(==, this->time, date.time);} |
|
424 BOOL operator!= (const DATE &date) {return !__compare_timespec(==, this->time, date.time);} |
|
425 }; |
|
426 |
|
427 |
|
428 |
|
429 |
|
430 |
|
431 class DT { |
|
432 private: |
|
433 __timebase_t time; |
|
434 |
|
435 public: |
|
436 /* conversion to __timebase_t */ |
|
437 operator __timebase_t(void) {return time;} |
|
438 |
|
439 /* constructors... */ |
|
440 DT (void) {time.tv_sec = 0; time.tv_nsec = 0;} |
|
441 DT (__timebase_t time) {this->time = time;} |
|
442 DT (const DT &dt) {this->time = dt.time;} /* copy constructor */ |
|
443 DT (double seconds, double minutes, double hours, int day, int month, int year) { |
|
444 long double total_sec = (hours*60 + minutes)*60 + seconds; |
|
445 time.tv_sec = (long int)total_sec; |
|
446 time.tv_nsec = (long int)((total_sec - time.tv_sec)*1e9); |
|
447 |
|
448 struct tm broken_down_time; |
|
449 broken_down_time.tm_sec = 0; |
|
450 broken_down_time.tm_min = 0; |
|
451 broken_down_time.tm_hour = 0; |
|
452 broken_down_time.tm_mday = day; /* day of month, from 1 to 31 */ |
|
453 broken_down_time.tm_mon = month - 1; /* month since January, in the range 0 to 11 */ |
|
454 broken_down_time.tm_year = year - 1900; /* number of years since 1900 */ |
|
455 |
|
456 time_t epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */ |
|
457 if ((time_t)(-1) == epoch_seconds) |
|
458 IEC_error(); |
|
459 |
|
460 time.tv_sec += epoch_seconds; |
|
461 if (time.tv_sec < epoch_seconds) |
|
462 /* since the TOD is always positive, if the above happens then we had an overflow */ |
|
463 IEC_error(); |
|
464 } |
|
465 |
|
466 /* Helpers to conversion operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */ |
|
467 DATE __to_DATE(void) { |
|
468 #if 0 |
|
469 /* slow version */ |
|
470 struct tm broken_down_time; |
|
471 time_t seconds = time.tv_sec; |
|
472 if (NULL == gmtime_r(seconds, &broken_down_time)) /* get the UTC (GMT) broken down time */ |
|
473 IEC_error(); |
|
474 return DATE(broken_down_time.tm_mday, broken_down_time.tm_mon, broken_down_time.tm_year); |
|
475 #else |
|
476 /* Faster version, based on the fact that the date will always be a multiple of 60*60*24 seconds, |
|
477 * and that the value of tv_nsec falls in the range ]-1, +1[ |
|
478 */ |
|
479 /* The above is true since the Unix function mktime() seems to ignore all leap seconds! */ |
|
480 struct timespec date_time = {time.tv_sec - (time.tv_sec % (24*60*60)), 0}; |
|
481 return DATE(date_time); |
|
482 #endif |
|
483 } |
|
484 |
|
485 TOD __to_TOD(void) { |
|
486 #if 0 |
|
487 /* slow version */ |
|
488 struct tm broken_down_time; |
|
489 time_t seconds = time.tv_sec; |
|
490 if (NULL == gmtime_r(seconds, &broken_down_time)) /* get the UTC (GMT) broken down time */ |
|
491 IEC_error(); |
|
492 return TOD(broken_down_time.tm_sec, broken_down_time.tm_min, broken_down_time.tm_hour); |
|
493 #else |
|
494 /* Faster version, based on the fact that the date will always be a multiple of 60*60*24 seconds |
|
495 * and that the value of tv_nsec falls in the range ]-1, +1[ |
|
496 */ |
|
497 /* The above is true since the Unix function mktime() seems to ignore all leap seconds! */ |
|
498 struct timespec time_time = {time.tv_sec % (24*60*60), time.tv_nsec}; |
|
499 return TOD(time_time); |
|
500 #endif |
|
501 } |
|
502 |
|
503 /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */ |
|
504 TIME operator- (const DT &dt) {return TIME(__sub_timespec(this->time, dt.time));} |
|
505 |
|
506 friend DT operator+ (const TIME &time, const DT &dt); |
|
507 friend DT operator+ (const DT &dt, const TIME &time); |
|
508 friend DT operator- (const DT &dt, const TIME &time); |
|
509 |
|
510 /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */ |
|
511 BOOL operator> (const DT &dt) {return __compare_timespec(>, this->time, dt.time);} |
|
512 BOOL operator>= (const DT &dt) {return __compare_timespec(>=, this->time, dt.time);} |
|
513 BOOL operator< (const DT &dt) {return __compare_timespec(<, this->time, dt.time);} |
|
514 BOOL operator<= (const DT &dt) {return __compare_timespec(<=, this->time, dt.time);} |
|
515 BOOL operator== (const DT &dt) {return __compare_timespec(==, this->time, dt.time);} |
|
516 BOOL operator!= (const DT &dt) {return !__compare_timespec(==, this->time, dt.time);} |
|
517 }; |
|
518 |
|
519 |
|
520 /* The operations on time and data types... */ |
|
521 TOD operator+ (const TIME &time, const TOD &tod) {return TOD(__add_timespec(tod.time, time.time));}; |
|
522 TOD operator+ (const TOD &tod, const TIME &time) {return TOD(__add_timespec(tod.time, time.time));}; |
|
523 TOD operator- (const TOD &tod, const TIME &time) {return TOD(__sub_timespec(tod.time, time.time));}; |
|
524 |
|
525 DT operator+ (const TIME &time, const DT &dt) {return DT(__add_timespec(dt.time, time.time));}; |
|
526 DT operator+ (const DT &dt, const TIME &time) {return DT(__add_timespec(dt.time, time.time));}; |
|
527 DT operator- (const DT &dt, const TIME &time) {return DT(__sub_timespec(dt.time, time.time));}; |
|
528 |
|
529 TIME operator* (const TIME &time, const long double value) {return TIME(__mul_timespec(time.time, value));} |
|
530 TIME operator* (const long double value, const TIME &time) {return TIME(__mul_timespec(time.time, value));} |
|
531 TIME operator/ (const TIME &time, const long double value) {return TIME(__mul_timespec(time.time, 1.0/value));} |
|
532 |
|
533 /* The following operation is not in the standard, |
|
534 * but will ease the implementation of the default function CONCAT_DATE_TOD |
|
535 */ |
|
536 DT operator+ (const DATE &date, const TOD &tod) {return DT(__add_timespec(date.time, tod.time));}; |
|
537 DT operator+ (const TOD &tod, const DATE &date) {return DT(__add_timespec(date.time, tod.time));}; |
|
538 |
|
539 #endif |
|
540 |
|
541 /* global variable that will be used to implement the timers TON, TOFF and TP */ |
|
542 extern TIME __CURRENT_TIME; |
|
543 |
|
544 |
|
545 |
|
546 //typedef STRING; |
|
547 //typedef WSTRING; |
|
548 |
|
549 |
|
550 |
|
551 typedef union __IL_DEFVAR_T { |
|
552 BOOL BOOLvar; |
|
553 |
|
554 SINT SINTvar; |
|
555 INT INTvar; |
|
556 DINT DINTvar; |
|
557 LINT LINTvar; |
|
558 |
|
559 USINT USINTvar; |
|
560 UINT UINTvar; |
|
561 UDINT UDINTvar; |
|
562 ULINT ULINTvar; |
|
563 |
|
564 BYTE BYTEvar; |
|
565 WORD WORDvar; |
|
566 DWORD DWORDvar; |
|
567 LWORD LWORDvar; |
|
568 |
|
569 REAL REALvar; |
|
570 LREAL LREALvar; |
|
571 |
|
572 /* NOTE: since the TIME, DATE, ... classes all have constructors, |
|
573 * C++ does not allow them to be used as members of a union. |
|
574 * The workaround is to use a base data type (in this case __timebase_t) that |
|
575 * contains all the internal data these classes require, and then add an operator |
|
576 * member function to each class that allows it to be converted to that same base data type, |
|
577 * acompanied by a constructor using that data type. |
|
578 */ |
|
579 |
|
580 TIME TIMEvar; |
|
581 TOD TODvar; |
|
582 DT DTvar; |
|
583 DATE DATEvar; |
|
584 |
|
585 /* |
|
586 __timebase_t TIMEvar; |
|
587 __timebase_t TODvar; |
|
588 __timebase_t DTvar; |
|
589 __timebase_t DATEvar; |
|
590 */ |
|
591 } __IL_DEFVAR_T; |
|
592 /*TODO TODO TODO TODO TODO TODO TODO TODO TODO |
|
593 * How do we add support for the possibility of storing |
|
594 * data values of derived data types into the default register, |
|
595 * to be later used for calling functions, stroing in another |
|
596 * variable, etc...? |
|
597 * |
|
598 * For example: |
|
599 * TYPE |
|
600 * point_t : STRUCT |
|
601 * x : INT; |
|
602 * y : INT; |
|
603 * END_STRUCT; |
|
604 * END_TYPE |
|
605 * |
|
606 * VAR p1, p2, p3 : point_t; |
|
607 * |
|
608 * LD p1 |
|
609 * ST p2 |
|
610 * |
|
611 * |
|
612 * We could do it with a pointer to void, that would contain not |
|
613 * the value itself, but rather the address in which the value |
|
614 * is currently stored. |
|
615 * For example, we could add a |
|
616 * void *generic_ptr |
|
617 * to this union, and then have the above LD and ST instructions |
|
618 * converted to: |
|
619 * __IL_DEFVAR.generic_ptr = (void *)(&p1); |
|
620 * p2 = *((point_t *)__IL_DEFVAR.generic_ptr); |
|
621 * |
|
622 * Unfortunately the above will only work as long as the p1 variable |
|
623 * does not get a chance to change its value before the default register |
|
624 * gets loaded with something esle (and therefore the value is no |
|
625 * longer needed). |
|
626 * Additionally, a scenario where the value of p1 may change before the |
|
627 * default register gets a new value is if p1 is used in a function block |
|
628 * call for an output parameter! |
|
629 * For example: |
|
630 * |
|
631 * LD p1 |
|
632 * CAL funcblock( |
|
633 * param1 => p1 |
|
634 * ) |
|
635 * ST p2 |
|
636 * |
|
637 * In the above scenario, p1 gets a new value when the function block |
|
638 * funcblock is called. When we get to copy the default register to |
|
639 * p2, we will no longer be copying the value that got stored in the default |
|
640 * register when we did 'LD p1', but rather the value returned by the |
|
641 * function block call!!! |
|
642 * |
|
643 * How the do we implement this??? |
|
644 * We will probably need to declare a default variable of the correct data |
|
645 * type whenever we get these values stored to the default register. |
|
646 * For example |
|
647 * LD p1 |
|
648 * ST p2 |
|
649 * |
|
650 * would be converted to: |
|
651 * union { |
|
652 * point_tvar point_t; |
|
653 * } __IL_DEFVAR_special ; |
|
654 * |
|
655 * __IL_DEFVAR_special.point_tvar = p1; |
|
656 * p2 = __IL_DEFVAR_special.point_tvar; |
|
657 * |
|
658 * The above requires that we iterate through the whole Instruction list |
|
659 * before we start the conversion, in order to first determine if we need |
|
660 * to declare that new variable for the default register. |
|
661 * |
|
662 * Since we have to do this, it would probaly be a better idea to simply |
|
663 * do away with the __IL_DEFVAR_T data type we declare here, and |
|
664 * declare the __IL_DEFVAR at the begining of each IL code segment |
|
665 * with all the data types that get used in that segment! |
|
666 */ |
|
667 |
|
668 |
|
669 /* Names start with double underscore so as not to clash with |
|
670 * names in ST or IL source code! Names including a double underscore are |
|
671 * ilegal under IL and ST! |
|
672 */ |
|
673 |
|
674 /* This is an abstract base class, that cannot be instantiated... */ |
|
675 template<typename value_type> class __ext_ref_c { |
|
676 public: |
|
677 virtual void operator= (value_type value) = 0; |
|
678 virtual operator value_type(void) = 0; |
|
679 }; |
|
680 |
|
681 |
|
682 |
|
683 |
|
684 |
|
685 |
|
686 /* Names start with double underscore so as not to clash with |
|
687 * names in ST or IL source code! Names including a double underscore are |
|
688 * ilegal under IL and ST! |
|
689 */ |
|
690 template<typename value_type> class __ext_element_c |
|
691 : public __ext_ref_c<value_type> { |
|
692 //{ |
|
693 |
|
694 private: |
|
695 value_type value; |
|
696 |
|
697 public: |
|
698 virtual void operator= (value_type value) { |
|
699 this->value = value; |
|
700 } |
|
701 |
|
702 virtual operator value_type(void) { |
|
703 return value; |
|
704 } |
|
705 |
|
706 __ext_element_c(void) {} |
|
707 |
|
708 __ext_element_c(value_type value) { |
|
709 this->value = value; |
|
710 } |
|
711 }; |
|
712 |
|
713 |
|
714 /* Names start with double underscore so as not to clash with |
|
715 * names in ST or IL source code! Names including a double underscore are |
|
716 * ilegal under IL and ST! |
|
717 */ |
|
718 template<typename value_type, int size = 8 * sizeof(value_type) /* in bits */> class __plc_pt_c |
|
719 : public __ext_ref_c<value_type> { |
|
720 |
|
721 private: |
|
722 plc_pt_t plc_pt; |
|
723 bool valid_plc_pt; |
|
724 |
|
725 private: |
|
726 void init_name(const char *pt_name) { |
|
727 /* assume error! */ |
|
728 valid_plc_pt = false; |
|
729 plc_pt = plc_pt_by_name(pt_name); |
|
730 if (plc_pt.valid == 0) { |
|
731 plc_pt = plc_pt_null(); |
|
732 return; |
|
733 } |
|
734 /* We can't have this check here, otherwise the boolean variables won't work correctly, |
|
735 * since MatPLC uses 1 bit for boolean variables, whereas g++ uses 8 bits. |
|
736 */ |
|
737 /* |
|
738 if (plc_pt_len(plc_pt) != size) { |
|
739 plc_pt = plc_pt_null(); |
|
740 return; |
|
741 } |
|
742 */ |
|
743 valid_plc_pt = true; |
|
744 } |
|
745 |
|
746 public: |
|
747 virtual void operator= (value_type value) { |
|
748 plc_set(plc_pt, *((u32 *)&value)); |
|
749 } |
|
750 |
|
751 virtual operator value_type(void) { |
|
752 u32 tmp_val = plc_get(plc_pt); |
|
753 return *((value_type *)&tmp_val); |
|
754 } |
|
755 |
|
756 __plc_pt_c(const char *pt_name) { |
|
757 init_name(pt_name); |
|
758 } |
|
759 |
|
760 __plc_pt_c(const char *pt_name, value_type init_value) { |
|
761 init_name(pt_name); |
|
762 *this = init_value; |
|
763 } |
|
764 |
|
765 bool valid(void) {return valid_plc_pt;} |
|
766 }; |
|
767 |
|
768 |
|
769 |
|
770 #define DEFAULT_MODULE_NAME "iec" |
|
771 |
|
772 |
|
773 |
|
774 #endif /* __PLCIEC_H */ |
|
775 |
|
776 |
|