|
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 class TIME; |
|
186 class TOD; |
|
187 class DT; |
|
188 class DATE; |
|
189 |
|
190 typedef struct timespec __timebase_t; |
|
191 |
|
192 |
|
193 |
|
194 class TIME{ |
|
195 private: |
|
196 /* private variable that contains the value of time. */ |
|
197 /* NOTE: The stored value is _always_ (time.tv_sec + time.tv_nsec), |
|
198 no matter whether tv_sec is positive or negative, or tv_nsec is positive or negative. |
|
199 */ |
|
200 __timebase_t time; |
|
201 |
|
202 public: |
|
203 /* conversion to __timebase_t */ |
|
204 operator __timebase_t(void) {return time;} |
|
205 |
|
206 /* constructors... */ |
|
207 TIME (void) {time.tv_sec = 0; time.tv_nsec = 0;} |
|
208 TIME (__timebase_t time) {this->time = time;} |
|
209 TIME (const TIME &time) {this->time = time.time;} /* copy constructor */ |
|
210 TIME(int sign, double mseconds, double seconds=0, double minutes=0, double hours=0, double days=0) { |
|
211 /* sign is 1 for positive values, -1 for negative time... */ |
|
212 long double total_sec = ((days*24 + hours)*60 + minutes)*60 + seconds + mseconds/1e3; |
|
213 if (sign >= 0) sign = 1; else sign = -1; |
|
214 time.tv_sec = sign * (long int)total_sec; |
|
215 time.tv_nsec = sign * (long int)((total_sec - time.tv_sec)*1e9); |
|
216 } |
|
217 |
|
218 /* used in plciec.cc to set the value of the __CURRENT_TIME variable without having to call a |
|
219 * TIME((__timebase_t time) constructor followed by the copy constructor. |
|
220 */ |
|
221 void operator= (__timebase_t time) {this->time = time;} |
|
222 |
|
223 /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */ |
|
224 TIME operator+ (const TIME &time) {return TIME(__add_timespec(this->time, time.time));} |
|
225 TIME operator- (const TIME &time) {return TIME(__sub_timespec(this->time, time.time));} |
|
226 |
|
227 friend TOD operator+ (const TIME &time, const TOD &tod); |
|
228 friend TOD operator+ (const TOD &tod, const TIME &time); |
|
229 friend TOD operator- (const TOD &tod, const TIME &time); |
|
230 |
|
231 friend DT operator+ (const TIME &time, const DT &dt); |
|
232 friend DT operator+ (const DT &dt, const TIME &time); |
|
233 friend DT operator- (const DT &dt, const TIME &time); |
|
234 |
|
235 friend TIME operator* (const TIME &time, const long double value); |
|
236 friend TIME operator* (const long double value, const TIME &time); |
|
237 friend TIME operator/ (const TIME &time, const long double value); |
|
238 |
|
239 /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */ |
|
240 BOOL operator> (const TIME &time) {return __compare_timespec(>, this->time, time.time);} |
|
241 BOOL operator>= (const TIME &time) {return __compare_timespec(>=, this->time, time.time);} |
|
242 BOOL operator< (const TIME &time) {return __compare_timespec(<, this->time, time.time);} |
|
243 BOOL operator<= (const TIME &time) {return __compare_timespec(<=, this->time, time.time);} |
|
244 BOOL operator== (const TIME &time) {return __compare_timespec(==, this->time, time.time);} |
|
245 BOOL operator!= (const TIME &time) {return !__compare_timespec(==, this->time, time.time);} |
|
246 }; |
|
247 |
|
248 |
|
249 |
|
250 /* Time of Day */ |
|
251 class TOD { |
|
252 private: |
|
253 __timebase_t time; |
|
254 |
|
255 public: |
|
256 /* conversion to __timebase_t */ |
|
257 operator __timebase_t(void) {return time;} |
|
258 |
|
259 /* constructors... */ |
|
260 TOD (void) {time.tv_sec = 0; time.tv_nsec = 0;} |
|
261 TOD (__timebase_t time) {this->time = time;} |
|
262 TOD (const TOD &tod) {this->time = tod.time;} /* copy constructor */ |
|
263 TOD (double seconds, double minutes=0, double hours=0) { |
|
264 long double total_sec = (hours*60 + minutes)*60 + seconds; |
|
265 time.tv_sec = (long int)total_sec; |
|
266 time.tv_nsec = (long int)((total_sec - time.tv_sec)*1e9); |
|
267 } |
|
268 |
|
269 /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */ |
|
270 TIME operator- (const TOD &tod) {return TIME(__sub_timespec(this->time, tod.time));} |
|
271 |
|
272 friend TOD operator+ (const TIME &time, const TOD &tod); |
|
273 friend TOD operator+ (const TOD &tod, const TIME &time); |
|
274 friend TOD operator- (const TOD &tod, const TIME &time); |
|
275 |
|
276 /* The following operation is not in the standard, |
|
277 * but will ease the implementation of the default function CONCAT_DATE_TOD |
|
278 */ |
|
279 friend DT operator+ (const DATE &date, const TOD &tod); |
|
280 friend DT operator+ (const TOD &tod, const DATE &date); |
|
281 |
|
282 /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */ |
|
283 BOOL operator> (const TOD &tod) {return __compare_timespec(>, this->time, tod.time);} |
|
284 BOOL operator>= (const TOD &tod) {return __compare_timespec(>=, this->time, tod.time);} |
|
285 BOOL operator< (const TOD &tod) {return __compare_timespec(<, this->time, tod.time);} |
|
286 BOOL operator<= (const TOD &tod) {return __compare_timespec(<=, this->time, tod.time);} |
|
287 BOOL operator== (const TOD &tod) {return __compare_timespec(==, this->time, tod.time);} |
|
288 BOOL operator!= (const TOD &tod) {return !__compare_timespec(==, this->time, tod.time);} |
|
289 }; |
|
290 |
|
291 |
|
292 |
|
293 //typedef DATE; |
|
294 class DATE { |
|
295 private: |
|
296 __timebase_t time; |
|
297 |
|
298 public: |
|
299 /* conversion to __timebase_t */ |
|
300 operator __timebase_t(void) {return time;} |
|
301 |
|
302 /* constructors... */ |
|
303 DATE (void) {time.tv_sec = 0; time.tv_nsec = 0;} |
|
304 DATE (__timebase_t time) {this->time = time;} |
|
305 DATE (const DATE &date) {this->time = date.time;} /* copy constructor */ |
|
306 DATE (int day, int month, int year) { |
|
307 struct tm broken_down_time; |
|
308 |
|
309 broken_down_time.tm_sec = 0; |
|
310 broken_down_time.tm_min = 0; |
|
311 broken_down_time.tm_hour = 0; |
|
312 broken_down_time.tm_mday = day; /* day of month, from 1 to 31 */ |
|
313 broken_down_time.tm_mon = month - 1; /* month since January, in the range 0 to 11 */ |
|
314 broken_down_time.tm_year = year - 1900; /* number of years since 1900 */ |
|
315 |
|
316 time_t epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */ |
|
317 |
|
318 if ((time_t)(-1) == epoch_seconds) |
|
319 IEC_error(); |
|
320 |
|
321 time.tv_sec = epoch_seconds; |
|
322 time.tv_nsec = 0; |
|
323 } |
|
324 |
|
325 /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */ |
|
326 TIME operator- (const DATE &date) {return TIME(__sub_timespec(this->time, date.time));} |
|
327 /* The following operation is not in the standard, |
|
328 * but will ease the implementation of the default function CONCAT_DATE_TOD |
|
329 */ |
|
330 friend DT operator+ (const DATE &date, const TOD &tod); |
|
331 friend DT operator+ (const TOD &tod, const DATE &date); |
|
332 |
|
333 /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */ |
|
334 BOOL operator> (const DATE &date) {return __compare_timespec(>, this->time, date.time);} |
|
335 BOOL operator>= (const DATE &date) {return __compare_timespec(>=, this->time, date.time);} |
|
336 BOOL operator< (const DATE &date) {return __compare_timespec(<, this->time, date.time);} |
|
337 BOOL operator<= (const DATE &date) {return __compare_timespec(<=, this->time, date.time);} |
|
338 BOOL operator== (const DATE &date) {return __compare_timespec(==, this->time, date.time);} |
|
339 BOOL operator!= (const DATE &date) {return !__compare_timespec(==, this->time, date.time);} |
|
340 }; |
|
341 |
|
342 |
|
343 |
|
344 |
|
345 |
|
346 class DT { |
|
347 private: |
|
348 __timebase_t time; |
|
349 |
|
350 public: |
|
351 /* conversion to __timebase_t */ |
|
352 operator __timebase_t(void) {return time;} |
|
353 |
|
354 /* constructors... */ |
|
355 DT (void) {time.tv_sec = 0; time.tv_nsec = 0;} |
|
356 DT (__timebase_t time) {this->time = time;} |
|
357 DT (const DT &dt) {this->time = dt.time;} /* copy constructor */ |
|
358 DT (double seconds, double minutes, double hours, int day, int month, int year) { |
|
359 long double total_sec = (hours*60 + minutes)*60 + seconds; |
|
360 time.tv_sec = (long int)total_sec; |
|
361 time.tv_nsec = (long int)((total_sec - time.tv_sec)*1e9); |
|
362 |
|
363 struct tm broken_down_time; |
|
364 broken_down_time.tm_sec = 0; |
|
365 broken_down_time.tm_min = 0; |
|
366 broken_down_time.tm_hour = 0; |
|
367 broken_down_time.tm_mday = day; /* day of month, from 1 to 31 */ |
|
368 broken_down_time.tm_mon = month - 1; /* month since January, in the range 0 to 11 */ |
|
369 broken_down_time.tm_year = year - 1900; /* number of years since 1900 */ |
|
370 |
|
371 time_t epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */ |
|
372 if ((time_t)(-1) == epoch_seconds) |
|
373 IEC_error(); |
|
374 |
|
375 time.tv_sec += epoch_seconds; |
|
376 if (time.tv_sec < epoch_seconds) |
|
377 /* since the TOD is always positive, if the above happens then we had an overflow */ |
|
378 IEC_error(); |
|
379 } |
|
380 |
|
381 /* Helpers to conversion operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */ |
|
382 DATE __to_DATE(void) { |
|
383 #if 0 |
|
384 /* slow version */ |
|
385 struct tm broken_down_time; |
|
386 time_t seconds = time.tv_sec; |
|
387 if (NULL == gmtime_r(seconds, &broken_down_time)) /* get the UTC (GMT) broken down time */ |
|
388 IEC_error(); |
|
389 return DATE(broken_down_time.tm_mday, broken_down_time.tm_mon, broken_down_time.tm_year); |
|
390 #else |
|
391 /* Faster version, based on the fact that the date will always be a multiple of 60*60*24 seconds, |
|
392 * and that the value of tv_nsec falls in the range ]-1, +1[ |
|
393 */ |
|
394 /* The above is true since the Unix function mktime() seems to ignore all leap seconds! */ |
|
395 struct timespec date_time = {time.tv_sec - (time.tv_sec % (24*60*60)), 0}; |
|
396 return DATE(date_time); |
|
397 #endif |
|
398 } |
|
399 |
|
400 TOD __to_TOD(void) { |
|
401 #if 0 |
|
402 /* slow version */ |
|
403 struct tm broken_down_time; |
|
404 time_t seconds = time.tv_sec; |
|
405 if (NULL == gmtime_r(seconds, &broken_down_time)) /* get the UTC (GMT) broken down time */ |
|
406 IEC_error(); |
|
407 return TOD(broken_down_time.tm_sec, broken_down_time.tm_min, broken_down_time.tm_hour); |
|
408 #else |
|
409 /* Faster version, based on the fact that the date will always be a multiple of 60*60*24 seconds |
|
410 * and that the value of tv_nsec falls in the range ]-1, +1[ |
|
411 */ |
|
412 /* The above is true since the Unix function mktime() seems to ignore all leap seconds! */ |
|
413 struct timespec time_time = {time.tv_sec % (24*60*60), time.tv_nsec}; |
|
414 return TOD(time_time); |
|
415 #endif |
|
416 } |
|
417 |
|
418 /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */ |
|
419 TIME operator- (const DT &dt) {return TIME(__sub_timespec(this->time, dt.time));} |
|
420 |
|
421 friend DT operator+ (const TIME &time, const DT &dt); |
|
422 friend DT operator+ (const DT &dt, const TIME &time); |
|
423 friend DT operator- (const DT &dt, const TIME &time); |
|
424 |
|
425 /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */ |
|
426 BOOL operator> (const DT &dt) {return __compare_timespec(>, this->time, dt.time);} |
|
427 BOOL operator>= (const DT &dt) {return __compare_timespec(>=, this->time, dt.time);} |
|
428 BOOL operator< (const DT &dt) {return __compare_timespec(<, this->time, dt.time);} |
|
429 BOOL operator<= (const DT &dt) {return __compare_timespec(<=, this->time, dt.time);} |
|
430 BOOL operator== (const DT &dt) {return __compare_timespec(==, this->time, dt.time);} |
|
431 BOOL operator!= (const DT &dt) {return !__compare_timespec(==, this->time, dt.time);} |
|
432 }; |
|
433 |
|
434 |
|
435 /* The operations on time and data types... */ |
|
436 TOD operator+ (const TIME &time, const TOD &tod) {return TOD(__add_timespec(tod.time, time.time));}; |
|
437 TOD operator+ (const TOD &tod, const TIME &time) {return TOD(__add_timespec(tod.time, time.time));}; |
|
438 TOD operator- (const TOD &tod, const TIME &time) {return TOD(__sub_timespec(tod.time, time.time));}; |
|
439 |
|
440 DT operator+ (const TIME &time, const DT &dt) {return DT(__add_timespec(dt.time, time.time));}; |
|
441 DT operator+ (const DT &dt, const TIME &time) {return DT(__add_timespec(dt.time, time.time));}; |
|
442 DT operator- (const DT &dt, const TIME &time) {return DT(__sub_timespec(dt.time, time.time));}; |
|
443 |
|
444 TIME operator* (const TIME &time, const long double value) {return TIME(__mul_timespec(time.time, value));} |
|
445 TIME operator* (const long double value, const TIME &time) {return TIME(__mul_timespec(time.time, value));} |
|
446 TIME operator/ (const TIME &time, const long double value) {return TIME(__mul_timespec(time.time, 1.0/value));} |
|
447 |
|
448 /* The following operation is not in the standard, |
|
449 * but will ease the implementation of the default function CONCAT_DATE_TOD |
|
450 */ |
|
451 DT operator+ (const DATE &date, const TOD &tod) {return DT(__add_timespec(date.time, tod.time));}; |
|
452 DT operator+ (const TOD &tod, const DATE &date) {return DT(__add_timespec(date.time, tod.time));}; |
|
453 |
|
454 |
|
455 /* global variable that will be used to implement the timers TON, TOFF and TP */ |
|
456 extern TIME __CURRENT_TIME; |
|
457 |
|
458 |
|
459 |
|
460 //typedef STRING; |
|
461 //typedef WSTRING; |
|
462 |
|
463 |
|
464 |
|
465 typedef union __IL_DEFVAR_T { |
|
466 BOOL BOOLvar; |
|
467 |
|
468 SINT SINTvar; |
|
469 INT INTvar; |
|
470 DINT DINTvar; |
|
471 LINT LINTvar; |
|
472 |
|
473 USINT USINTvar; |
|
474 UINT UINTvar; |
|
475 UDINT UDINTvar; |
|
476 ULINT ULINTvar; |
|
477 |
|
478 BYTE BYTEvar; |
|
479 WORD WORDvar; |
|
480 DWORD DWORDvar; |
|
481 LWORD LWORDvar; |
|
482 |
|
483 REAL REALvar; |
|
484 LREAL LREALvar; |
|
485 |
|
486 /* NOTE: since the TIME, DATE, ... classes all have constructors, |
|
487 * C++ does not allow them to be used as members of a union. |
|
488 * The workaround is to use a base data type (in this case __timebase_t) that |
|
489 * contains all the internal data these classes require, and then add an operator |
|
490 * member function to each class that allows it to be converted to that same base data type, |
|
491 * acompanied by a constructor using that data type. |
|
492 */ |
|
493 /* |
|
494 TIME TIMEvar; |
|
495 TOD TODvar; |
|
496 DT DTvar; |
|
497 DATE DATEvar; |
|
498 */ |
|
499 __timebase_t TIMEvar; |
|
500 __timebase_t TODvar; |
|
501 __timebase_t DTvar; |
|
502 __timebase_t DATEvar; |
|
503 } __IL_DEFVAR_T; |
|
504 /*TODO TODO TODO TODO TODO TODO TODO TODO TODO |
|
505 * How do we add support for the possibility of storing |
|
506 * data values of derived data types into the default register, |
|
507 * to be later used for calling functions, stroing in another |
|
508 * variable, etc...? |
|
509 * |
|
510 * For example: |
|
511 * TYPE |
|
512 * point_t : STRUCT |
|
513 * x : INT; |
|
514 * y : INT; |
|
515 * END_STRUCT; |
|
516 * END_TYPE |
|
517 * |
|
518 * VAR p1, p2, p3 : point_t; |
|
519 * |
|
520 * LD p1 |
|
521 * ST p2 |
|
522 * |
|
523 * |
|
524 * We could do it with a pointer to void, that would contain not |
|
525 * the value itself, but rather the address in which the value |
|
526 * is currently stored. |
|
527 * For example, we could add a |
|
528 * void *generic_ptr |
|
529 * to this union, and then have the above LD and ST instructions |
|
530 * converted to: |
|
531 * __IL_DEFVAR.generic_ptr = (void *)(&p1); |
|
532 * p2 = *((point_t *)__IL_DEFVAR.generic_ptr); |
|
533 * |
|
534 * Unfortunately the above will only work as long as the p1 variable |
|
535 * does not get a chance to change its value before the default register |
|
536 * gets loaded with something esle (and therefore the value is no |
|
537 * longer needed). |
|
538 * Additionally, a scenario where the value of p1 may change before the |
|
539 * default register gets a new value is if p1 is used in a function block |
|
540 * call for an output parameter! |
|
541 * For example: |
|
542 * |
|
543 * LD p1 |
|
544 * CAL funcblock( |
|
545 * param1 => p1 |
|
546 * ) |
|
547 * ST p2 |
|
548 * |
|
549 * In the above scenario, p1 gets a new value when the function block |
|
550 * funcblock is called. When we get to copy the default register to |
|
551 * p2, we will no longer be copying the value that got stored in the default |
|
552 * register when we did 'LD p1', but rather the value returned by the |
|
553 * function block call!!! |
|
554 * |
|
555 * How the do we implement this??? |
|
556 * We will probably need to declare a default variable of the correct data |
|
557 * type whenever we get these values stored to the default register. |
|
558 * For example |
|
559 * LD p1 |
|
560 * ST p2 |
|
561 * |
|
562 * would be converted to: |
|
563 * union { |
|
564 * point_tvar point_t; |
|
565 * } __IL_DEFVAR_special ; |
|
566 * |
|
567 * __IL_DEFVAR_special.point_tvar = p1; |
|
568 * p2 = __IL_DEFVAR_special.point_tvar; |
|
569 * |
|
570 * The above requires that we iterate through the whole Instruction list |
|
571 * before we start the conversion, in order to first determine if we need |
|
572 * to declare that new variable for the default register. |
|
573 * |
|
574 * Since we have to do this, it would probaly be a better idea to simply |
|
575 * do away with the __IL_DEFVAR_T data type we declare here, and |
|
576 * declare the __IL_DEFVAR at the begining of each IL code segment |
|
577 * with all the data types that get used in that segment! |
|
578 */ |
|
579 |
|
580 |
|
581 /* Names start with double underscore so as not to clash with |
|
582 * names in ST or IL source code! Names including a double underscore are |
|
583 * ilegal under IL and ST! |
|
584 */ |
|
585 |
|
586 /* This is an abstract base class, that cannot be instantiated... */ |
|
587 template<typename value_type> class __ext_ref_c { |
|
588 public: |
|
589 virtual void operator= (value_type value) = 0; |
|
590 virtual operator value_type(void) = 0; |
|
591 }; |
|
592 |
|
593 |
|
594 |
|
595 |
|
596 |
|
597 |
|
598 /* Names start with double underscore so as not to clash with |
|
599 * names in ST or IL source code! Names including a double underscore are |
|
600 * ilegal under IL and ST! |
|
601 */ |
|
602 template<typename value_type> class __ext_element_c |
|
603 : public __ext_ref_c<value_type> { |
|
604 //{ |
|
605 |
|
606 private: |
|
607 value_type value; |
|
608 |
|
609 public: |
|
610 virtual void operator= (value_type value) { |
|
611 this->value = value; |
|
612 } |
|
613 |
|
614 virtual operator value_type(void) { |
|
615 return value; |
|
616 } |
|
617 |
|
618 __ext_element_c(void) {} |
|
619 |
|
620 __ext_element_c(value_type value) { |
|
621 this->value = value; |
|
622 } |
|
623 }; |
|
624 |
|
625 |
|
626 /* Names start with double underscore so as not to clash with |
|
627 * names in ST or IL source code! Names including a double underscore are |
|
628 * ilegal under IL and ST! |
|
629 */ |
|
630 template<typename value_type, int size = 8 * sizeof(value_type) /* in bits */> class __plc_pt_c |
|
631 : public __ext_ref_c<value_type> { |
|
632 |
|
633 private: |
|
634 plc_pt_t plc_pt; |
|
635 bool valid_plc_pt; |
|
636 |
|
637 private: |
|
638 void init_name(const char *pt_name) { |
|
639 /* assume error! */ |
|
640 valid_plc_pt = false; |
|
641 plc_pt = plc_pt_by_name(pt_name); |
|
642 if (plc_pt.valid == 0) { |
|
643 plc_pt = plc_pt_null(); |
|
644 return; |
|
645 } |
|
646 /* We can't have this check here, otherwise the boolean variables won't work correctly, |
|
647 * since MatPLC uses 1 bit for boolean variables, whereas g++ uses 8 bits. |
|
648 */ |
|
649 /* |
|
650 if (plc_pt_len(plc_pt) != size) { |
|
651 plc_pt = plc_pt_null(); |
|
652 return; |
|
653 } |
|
654 */ |
|
655 valid_plc_pt = true; |
|
656 } |
|
657 |
|
658 public: |
|
659 virtual void operator= (value_type value) { |
|
660 plc_set(plc_pt, *((u32 *)&value)); |
|
661 } |
|
662 |
|
663 virtual operator value_type(void) { |
|
664 u32 tmp_val = plc_get(plc_pt); |
|
665 return *((value_type *)&tmp_val); |
|
666 } |
|
667 |
|
668 __plc_pt_c(const char *pt_name) { |
|
669 init_name(pt_name); |
|
670 } |
|
671 |
|
672 __plc_pt_c(const char *pt_name, value_type init_value) { |
|
673 init_name(pt_name); |
|
674 *this = init_value; |
|
675 } |
|
676 |
|
677 bool valid(void) {return valid_plc_pt;} |
|
678 }; |
|
679 |
|
680 |
|
681 |
|
682 #define DEFAULT_MODULE_NAME "iec" |
|
683 |
|
684 |
|
685 |
|
686 #endif /* __PLCIEC_H */ |
|
687 |
|
688 |