85 #endif |
85 #endif |
86 |
86 |
87 |
87 |
88 #define __lit(type,value,...) (type)value##__VA_ARGS__ |
88 #define __lit(type,value,...) (type)value##__VA_ARGS__ |
89 // Keep this macro expention step to let sfx(__VA_ARGS__) change into L or LL |
89 // Keep this macro expention step to let sfx(__VA_ARGS__) change into L or LL |
90 #define __literal(type,value,...) __lit(type,value,##__VA_ARGS__) |
90 #define __literal(type,value,...) __lit(type,value,__VA_ARGS__) |
91 |
91 |
92 #define __BOOL_LITERAL(value) __literal(BOOL,value) |
92 #define __BOOL_LITERAL(value) __literal(BOOL,value) |
93 #define __SINT_LITERAL(value) __literal(SINT,value) |
93 #define __SINT_LITERAL(value) __literal(SINT,value) |
94 #define __INT_LITERAL(value) __literal(INT,value) |
94 #define __INT_LITERAL(value) __literal(INT,value) |
95 #define __DINT_LITERAL(value) __literal(DINT,value,__32b_sufix) |
95 #define __DINT_LITERAL(value) __literal(DINT,value,__32b_sufix) |
225 ts.tv_nsec = (long int)((total_sec - ts.tv_sec)*1e9); |
225 ts.tv_nsec = (long int)((total_sec - ts.tv_sec)*1e9); |
226 |
226 |
227 return ts; |
227 return ts; |
228 } |
228 } |
229 |
229 |
|
230 #define EPOCH_YEAR 1970 |
|
231 #define SECONDS_PER_HOUR (60 * 60) |
|
232 #define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR) |
|
233 #define __isleap(year) \ |
|
234 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) |
|
235 static const unsigned short int __mon_yday[2][13] = |
|
236 { |
|
237 /* Normal years. */ |
|
238 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, |
|
239 /* Leap years. */ |
|
240 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} |
|
241 }; |
|
242 |
|
243 typedef struct { |
|
244 int tm_sec; /* Seconds. [0-60] (1 leap second) */ |
|
245 int tm_min; /* Minutes. [0-59] */ |
|
246 int tm_hour; /* Hours. [0-23] */ |
|
247 int tm_day; /* Day. [1-31] */ |
|
248 int tm_mon; /* Month. [0-11] */ |
|
249 int tm_year; /* Year */ |
|
250 } tm; |
|
251 |
|
252 static inline tm convert_seconds_to_date_and_time(long int seconds) { |
|
253 tm dt; |
|
254 long int days, rem; |
|
255 days = seconds / SECONDS_PER_DAY; |
|
256 rem = seconds % SECONDS_PER_DAY; |
|
257 if (rem < 0) { |
|
258 rem += SECONDS_PER_DAY; |
|
259 days--; |
|
260 } |
|
261 |
|
262 // time of day |
|
263 dt.tm_hour = rem / SECONDS_PER_HOUR; |
|
264 rem %= SECONDS_PER_HOUR; |
|
265 dt.tm_min = rem / 60; |
|
266 dt.tm_sec = rem % 60; |
|
267 |
|
268 // date |
|
269 dt.tm_year = EPOCH_YEAR; |
|
270 while (days >= (rem = __isleap(dt.tm_year) ? 366 : 365)) { |
|
271 dt.tm_year++; |
|
272 days -= rem; |
|
273 } |
|
274 while (days < 0) { |
|
275 dt.tm_year--; |
|
276 days += __isleap(dt.tm_year) ? 366 : 365; |
|
277 } |
|
278 dt.tm_mon = 1; |
|
279 while (days > __mon_yday[__isleap(dt.tm_year)][dt.tm_mon]) { |
|
280 dt.tm_mon += 1; |
|
281 } |
|
282 dt.tm_day = days - __mon_yday[__isleap(dt.tm_year)][dt.tm_mon - 1] + 1; |
|
283 |
|
284 return dt; |
|
285 } |
|
286 |
230 static inline IEC_TIMESPEC __date_to_timespec(int day, int month, int year) { |
287 static inline IEC_TIMESPEC __date_to_timespec(int day, int month, int year) { |
231 IEC_TIMESPEC ts; |
288 IEC_TIMESPEC ts; |
232 struct tm broken_down_time; |
289 int a4, b4, a100, b100, a400, b400; |
233 time_t epoch_seconds; |
290 int yday; |
234 |
291 int intervening_leap_days; |
235 broken_down_time.tm_sec = 0; |
292 |
236 broken_down_time.tm_min = 0; |
293 if (month < 1 || month > 12) |
237 broken_down_time.tm_hour = 0; |
294 __iec_error(); |
238 broken_down_time.tm_mday = day; /* day of month, from 1 to 31 */ |
295 |
239 broken_down_time.tm_mon = month - 1; /* month since January, in the range 0 to 11 */ |
296 yday = __mon_yday[__isleap(year)][month - 1] + day; |
240 broken_down_time.tm_year = year - 1900; /* number of years since 1900 */ |
297 |
241 |
298 if (yday > __mon_yday[__isleap(year)][month]) |
242 epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */ |
299 __iec_error(); |
243 |
300 |
244 if ((time_t)(-1) == epoch_seconds) |
301 a4 = (year >> 2) - ! (year & 3); |
245 __iec_error(); |
302 b4 = (EPOCH_YEAR >> 2) - ! (EPOCH_YEAR & 3); |
246 |
303 a100 = a4 / 25 - (a4 % 25 < 0); |
247 ts.tv_sec = epoch_seconds; |
304 b100 = b4 / 25 - (b4 % 25 < 0); |
|
305 a400 = a100 >> 2; |
|
306 b400 = b100 >> 2; |
|
307 intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); |
|
308 |
|
309 ts.tv_sec = ((year - EPOCH_YEAR) * 365 + intervening_leap_days + yday - 1) * 24 * 60 * 60; |
248 ts.tv_nsec = 0; |
310 ts.tv_nsec = 0; |
249 |
311 |
250 return ts; |
312 return ts; |
251 } |
313 } |
252 |
314 |
253 static inline IEC_TIMESPEC __dt_to_timespec(double seconds, double minutes, double hours, int day, int month, int year) { |
315 static inline IEC_TIMESPEC __dt_to_timespec(double seconds, double minutes, double hours, int day, int month, int year) { |
254 IEC_TIMESPEC ts; |
316 IEC_TIMESPEC ts_date = __date_to_timespec(day, month, year); |
255 struct tm broken_down_time; |
317 IEC_TIMESPEC ts = __tod_to_timespec(seconds, minutes, hours); |
256 time_t epoch_seconds; |
318 |
257 |
319 ts.tv_sec += ts_date.tv_sec; |
258 long double total_sec = (hours*60 + minutes)*60 + seconds; |
|
259 ts.tv_sec = (long int)total_sec; |
|
260 ts.tv_nsec = (long int)((total_sec - ts.tv_sec)*1e9); |
|
261 |
|
262 broken_down_time.tm_sec = 0; |
|
263 broken_down_time.tm_min = 0; |
|
264 broken_down_time.tm_hour = 0; |
|
265 broken_down_time.tm_mday = day; /* day of month, from 1 to 31 */ |
|
266 broken_down_time.tm_mon = month - 1; /* month since January, in the range 0 to 11 */ |
|
267 broken_down_time.tm_year = year - 1900; /* number of years since 1900 */ |
|
268 broken_down_time.tm_isdst = 0; /* disable daylight savings time */ |
|
269 |
|
270 epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */ |
|
271 if ((time_t)(-1) == epoch_seconds) |
|
272 __iec_error(); |
|
273 |
|
274 ts.tv_sec += epoch_seconds; |
|
275 if (ts.tv_sec < epoch_seconds) |
|
276 /* since the TOD is always positive, if the above happens then we had an overflow */ |
|
277 __iec_error(); |
|
278 |
320 |
279 return ts; |
321 return ts; |
280 } |
322 } |
281 |
323 |
282 /*******************/ |
324 /*******************/ |
527 if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; |
572 if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; |
528 return res; |
573 return res; |
529 } |
574 } |
530 static inline STRING __date_to_string(DATE IN){ |
575 static inline STRING __date_to_string(DATE IN){ |
531 STRING res; |
576 STRING res; |
532 struct tm* broken_down_time; |
577 tm broken_down_time; |
533 time_t seconds; |
|
534 /* D#1984-06-25 */ |
578 /* D#1984-06-25 */ |
|
579 broken_down_time = convert_seconds_to_date_and_time(IN.tv_sec); |
535 res = __INIT_STRING; |
580 res = __INIT_STRING; |
536 seconds = IN.tv_sec; |
581 res.len = snprintf((char*)&res.body, STR_MAX_LEN, "D#%d-%2.2d-%2.2d", |
537 if (NULL == (broken_down_time = localtime(&seconds))){ /* get the UTC (GMT) broken down time */ |
582 broken_down_time.tm_year, |
538 __iec_error(); |
583 broken_down_time.tm_mon, |
539 return (STRING){7,"D#ERROR"}; |
584 broken_down_time.tm_day); |
540 } |
|
541 res.len = snprintf((char*)&res.body, STR_MAX_LEN, "D#%d-%2.2d-%2.2d", broken_down_time->tm_year + 1900, broken_down_time->tm_mon + 1, broken_down_time->tm_mday); |
|
542 if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; |
585 if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; |
543 return res; |
586 return res; |
544 } |
587 } |
545 static inline STRING __tod_to_string(TOD IN){ |
588 static inline STRING __tod_to_string(TOD IN){ |
546 STRING res; |
589 STRING res; |
547 struct tm* broken_down_time; |
590 tm broken_down_time; |
548 time_t seconds; |
591 time_t seconds; |
549 /* TOD#15:36:55.36 */ |
592 /* TOD#15:36:55.36 */ |
|
593 seconds = IN.tv_sec; |
|
594 if (seconds >= SECONDS_PER_DAY){ |
|
595 __iec_error(); |
|
596 return (STRING){9,"TOD#ERROR"}; |
|
597 } |
|
598 broken_down_time = convert_seconds_to_date_and_time(seconds); |
550 res = __INIT_STRING; |
599 res = __INIT_STRING; |
551 seconds = IN.tv_sec; |
|
552 if (NULL == (broken_down_time = localtime(&seconds))){ /* get the UTC (GMT) broken down time */ |
|
553 __iec_error(); |
|
554 return (STRING){9,"TOD#ERROR"}; |
|
555 } |
|
556 if(IN.tv_nsec == 0){ |
600 if(IN.tv_nsec == 0){ |
557 res.len = snprintf((char*)&res.body, STR_MAX_LEN, "TOD#%2.2d:%2.2d:%d", broken_down_time->tm_hour, broken_down_time->tm_min, broken_down_time->tm_sec); |
601 res.len = snprintf((char*)&res.body, STR_MAX_LEN, "TOD#%2.2d:%2.2d:%2.2d", |
|
602 broken_down_time.tm_hour, |
|
603 broken_down_time.tm_min, |
|
604 broken_down_time.tm_sec); |
558 }else{ |
605 }else{ |
559 res.len = snprintf((char*)&res.body, STR_MAX_LEN, "TOD#%2.2d:%2.2d:%g", broken_down_time->tm_hour, broken_down_time->tm_min, (LREAL)broken_down_time->tm_sec + (LREAL)IN.tv_nsec / 1e9); |
606 res.len = snprintf((char*)&res.body, STR_MAX_LEN, "TOD#%2.2d:%2.2d:%09.6g", |
|
607 broken_down_time.tm_hour, |
|
608 broken_down_time.tm_min, |
|
609 (LREAL)broken_down_time.tm_sec + (LREAL)IN.tv_nsec / 1e9); |
560 } |
610 } |
561 if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; |
611 if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; |
562 return res; |
612 return res; |
563 } |
613 } |
564 static inline STRING __dt_to_string(DT IN){ |
614 static inline STRING __dt_to_string(DT IN){ |
565 STRING res; |
615 STRING res; |
566 struct tm* broken_down_time; |
616 tm broken_down_time; |
567 time_t seconds; |
|
568 /* DT#1984-06-25-15:36:55.36 */ |
617 /* DT#1984-06-25-15:36:55.36 */ |
569 seconds = IN.tv_sec; |
618 broken_down_time = convert_seconds_to_date_and_time(IN.tv_sec); |
570 if (NULL == (broken_down_time = localtime(&seconds))){ /* get the UTC (GMT) broken down time */ |
|
571 __iec_error(); |
|
572 return (STRING){8,"DT#ERROR"}; |
|
573 } |
|
574 if(IN.tv_nsec == 0){ |
619 if(IN.tv_nsec == 0){ |
575 res.len = snprintf((char*)&res.body, STR_MAX_LEN, "DT#%d-%2.2d-%2.2d-%2.2d:%2.2d:%d", |
620 res.len = snprintf((char*)&res.body, STR_MAX_LEN, "DT#%d-%2.2d-%2.2d-%2.2d:%2.2d:%2.2d", |
576 broken_down_time->tm_year + 1900, |
621 broken_down_time.tm_year, |
577 broken_down_time->tm_mon + 1, |
622 broken_down_time.tm_mon, |
578 broken_down_time->tm_mday, |
623 broken_down_time.tm_day, |
579 broken_down_time->tm_hour, |
624 broken_down_time.tm_hour, |
580 broken_down_time->tm_min, |
625 broken_down_time.tm_min, |
581 broken_down_time->tm_sec); |
626 broken_down_time.tm_sec); |
582 }else{ |
627 }else{ |
583 res.len = snprintf((char*)&res.body, STR_MAX_LEN, "DT#%d-%2.2d-%2.2d-%2.2d:%2.2d:%g", |
628 res.len = snprintf((char*)&res.body, STR_MAX_LEN, "DT#%d-%2.2d-%2.2d-%2.2d:%2.2d:%09.6g", |
584 broken_down_time->tm_year + 1900, |
629 broken_down_time.tm_year, |
585 broken_down_time->tm_mon + 1, |
630 broken_down_time.tm_mon, |
586 broken_down_time->tm_mday, |
631 broken_down_time.tm_day, |
587 broken_down_time->tm_hour, |
632 broken_down_time.tm_hour, |
588 broken_down_time->tm_min, |
633 broken_down_time.tm_min, |
589 (LREAL)broken_down_time->tm_sec + ((LREAL)IN.tv_nsec / 1e9)); |
634 (LREAL)broken_down_time.tm_sec + ((LREAL)IN.tv_nsec / 1e9)); |
590 } |
635 } |
591 if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; |
636 if(res.len > STR_MAX_LEN) res.len = STR_MAX_LEN; |
592 return res; |
637 return res; |
593 } |
638 } |
594 |
639 |
595 /**********************************************/ |
640 /**********************************************/ |
596 /* [ANY_DATE | TIME] _TO_ [ANY_DATE | TIME] */ |
641 /* [ANY_DATE | TIME] _TO_ [ANY_DATE | TIME] */ |
597 /**********************************************/ |
642 /**********************************************/ |
598 |
643 |
599 static inline TOD __date_and_time_to_time_of_day(DT IN) {return (TOD){IN.tv_sec % 86400, IN.tv_nsec};} |
644 static inline TOD __date_and_time_to_time_of_day(DT IN) {return (TOD){IN.tv_sec % (24*60*60), IN.tv_nsec};} |
600 static inline DATE __date_and_time_to_date(DT IN){return (DATE){IN.tv_sec - (IN.tv_sec % (24*60*60)), 0};} |
645 static inline DATE __date_and_time_to_date(DT IN){return (DATE){IN.tv_sec - (IN.tv_sec % (24*60*60)), 0};} |
601 |
646 |
602 /*****************/ |
647 /*****************/ |
603 /* FROM/TO BCD */ |
648 /* FROM/TO BCD */ |
604 /*****************/ |
649 /*****************/ |
821 |
866 |
822 |
867 |
823 /******** [ANY_DATE]_TO_[ANY_DATE | TIME] ************/ |
868 /******** [ANY_DATE]_TO_[ANY_DATE | TIME] ************/ |
824 /* Not supported: DT_TO_TIME */ |
869 /* Not supported: DT_TO_TIME */ |
825 __convert_type(DT, DATE, __date_and_time_to_date) |
870 __convert_type(DT, DATE, __date_and_time_to_date) |
|
871 static inline DATE DATE_AND_TIME_TO_DATE(EN_ENO_PARAMS, DT op){ |
|
872 return DT_TO_DATE(EN_ENO, op); |
|
873 } |
826 __convert_type(DT, DT, __move_DT) |
874 __convert_type(DT, DT, __move_DT) |
827 __convert_type(DT, TOD, __date_and_time_to_time_of_day) |
875 __convert_type(DT, TOD, __date_and_time_to_time_of_day) |
|
876 static inline DATE DATE_AND_TIME_TO_TIME_OF_DAY(EN_ENO_PARAMS, DT op){ |
|
877 return DT_TO_TOD(EN_ENO, op); |
|
878 } |
828 /* Not supported: DATE_TO_TIME */ |
879 /* Not supported: DATE_TO_TIME */ |
829 __convert_type(DATE, DATE, __move_DATE) |
880 __convert_type(DATE, DATE, __move_DATE) |
830 /* Not supported: DATE_TO_DT */ |
881 /* Not supported: DATE_TO_DT */ |
831 /* Not supported: DATE_TO_TOD */ |
882 /* Not supported: DATE_TO_TOD */ |
832 /* Not supported: TOD_TO_TIME */ |
883 /* Not supported: TOD_TO_TIME */ |
908 } |
959 } |
909 __ANY_REAL(__to_anyint_) |
960 __ANY_REAL(__to_anyint_) |
910 #undef __iec_ |
961 #undef __iec_ |
911 |
962 |
912 |
963 |
913 /******** _TO_BCD ************/ |
964 /******** _TO_BCD ************/ |
914 #define __iec_(to_TYPENAME,from_TYPENAME) \ |
965 #define __iec_(to_TYPENAME,from_TYPENAME) \ |
915 static inline to_TYPENAME from_TYPENAME##_TO_BCD_##to_TYPENAME(EN_ENO_PARAMS, from_TYPENAME op){\ |
966 static inline to_TYPENAME from_TYPENAME##_TO_BCD_##to_TYPENAME(EN_ENO_PARAMS, from_TYPENAME op){\ |
916 TEST_EN(to_TYPENAME)\ |
967 TEST_EN(to_TYPENAME)\ |
917 return (to_TYPENAME)__uint_to_bcd(op);\ |
968 return (to_TYPENAME)__uint_to_bcd(op);\ |
|
969 }\ |
|
970 static inline to_TYPENAME from_TYPENAME##_TO_BCD__##to_TYPENAME##__##from_TYPENAME(EN_ENO_PARAMS, from_TYPENAME op){\ |
|
971 return from_TYPENAME##_TO_BCD_##to_TYPENAME(EN_ENO, op);\ |
918 } |
972 } |
919 __ANY_UINT(__to_anynbit_) |
973 __ANY_UINT(__to_anynbit_) |
920 #undef __iec_ |
974 #undef __iec_ |
921 |
975 |
922 |
976 |
923 /******** BCD_TO_ ************/ |
977 /******** BCD_TO_ ************/ |
924 #define __iec_(to_TYPENAME,from_TYPENAME) \ |
978 #define __iec_(to_TYPENAME,from_TYPENAME) \ |
925 static inline to_TYPENAME from_TYPENAME##_BCD_TO_##to_TYPENAME(EN_ENO_PARAMS, from_TYPENAME op){\ |
979 static inline to_TYPENAME from_TYPENAME##_BCD_TO_##to_TYPENAME(EN_ENO_PARAMS, from_TYPENAME op){\ |
926 TEST_EN(to_TYPENAME)\ |
980 TEST_EN(to_TYPENAME)\ |
927 return (to_TYPENAME)__bcd_to_uint(op);\ |
981 return (to_TYPENAME)__bcd_to_uint(op);\ |
|
982 }\ |
|
983 static inline to_TYPENAME BCD_TO_##to_TYPENAME##__##to_TYPENAME##__##from_TYPENAME(EN_ENO_PARAMS, from_TYPENAME op){\ |
|
984 return from_TYPENAME##_BCD_TO_##to_TYPENAME(EN_ENO, op);\ |
928 } |
985 } |
929 __ANY_NBIT(__to_anyuint_) |
986 __ANY_NBIT(__to_anyuint_) |
930 #undef __iec_ |
987 #undef __iec_ |
931 |
988 |
932 |
989 |