stage4/generate_cc/plciec.h
changeset 40 873a5b60a7ea
parent 39 e08c65e27557
child 41 8998c8b24b60
equal deleted inserted replaced
39:e08c65e27557 40:873a5b60a7ea
     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