--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/stage4/generate_cc/plciec.h Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,688 @@
+/*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * This code is made available on the understanding that it will not be
+ * used in safety-critical situations without a full and competent review.
+ */
+
+/*
+ * An IEC 61131-3 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+
+/*
+ * Code to be included into the code generated by the 4th stage.
+ *
+ * This is part of the 4th stage that generates
+ * a c++ source program equivalent to the IL and ST
+ * code.
+ */
+
+
+#ifndef __PLCIEC_H
+#define __PLCIEC_H
+
+//#include <stdio.h>
+#include "plc.h"
+#include <math.h>
+#include <time.h>
+
+
+
+/* function that generates an IEC runtime error */
+void IEC_error(void) {
+ /* TODO... */
+ fprintf(stderr, "IEC 61131-3 runtime error.\n");
+ exit(1);
+}
+
+
+
+typedef bool BOOL;
+#define TRUE true
+#define FALSE false
+
+typedef i8 SINT;
+typedef i16 INT;
+typedef i32 DINT;
+typedef i64 LINT;
+
+typedef u8 USINT;
+typedef u16 UINT;
+typedef u32 UDINT;
+typedef u64 ULINT;
+
+typedef u8 BYTE;
+typedef u16 WORD;
+typedef u32 DWORD;
+typedef u64 LWORD;
+
+typedef f32 REAL;
+typedef f64 LREAL;
+
+
+
+
+
+
+/*********************************************/
+/* TIME AND DATE data trypes */
+/*********************************************/
+
+/* NOTE: All the time and date data types use a struct timespec
+ * internally to store the time and date. This is so as to ease all the
+ * operations (add, subtract, multiply and division) the standard defines
+ * on these same data types.
+ * However, in order to ease the implementation of the comparison operators
+ * (==, =>, <=, <, >, <>), the two elements in the timespec structure
+ * must be handled in such a way as to guarantee the following:
+ * - The stored time is always the result of the operation tv_sec + tv_nsec*1e-9
+ * - tv_sec and tv_nsec will always have the same sign
+ * (i.e. either both positive or both negative)
+ * - tv_nsec always holds a value in the range ]-1, +1[ seconds.
+ * (note that -1 and +1 are excluded form the range)
+ */
+
+
+/* NOTE: According to the C++ standard, the result of the % and / operations is implementation dependent
+ * when the at least one of the operands is negative! However, whatever the result of the operations, we are
+ * guaranteed that (a/b)*b + (a%b) is always equal to a.
+ * This means that, even knowing that both tv_sec and tv_sec always have the same sign (we make it so this is true),
+ * we must still re-normailze the result for both the addition and subtraction operations!
+ */
+
+static inline void __normalizesign_timespec (struct timespec *ts) {
+ if ((ts->tv_sec > 0) && (ts->tv_nsec < 0)) {
+ ts->tv_sec--;
+ ts->tv_nsec += 1000000000;
+ }
+ if ((ts->tv_sec < 0) && (ts->tv_nsec > 0)) {
+ ts->tv_sec++;
+ ts->tv_nsec -= 1000000000;
+ }
+}
+
+
+static inline struct timespec __add_timespec (const struct timespec &t1, const struct timespec &t2) {
+ /* NOTE the following sum works correctly because a long can hold a litle more than 2 seconds expressed in nano seconds! */
+ long nsec;
+ nsec = t1.tv_nsec + t2.tv_nsec;
+ struct timespec ts;
+ ts.tv_sec = t1.tv_sec + t2.tv_sec + (nsec / 1000000000);
+ ts.tv_nsec = nsec % 1000000000;
+
+ __normalizesign_timespec(&ts);
+
+return ts;
+}
+
+
+static inline struct timespec __sub_timespec (const struct timespec &t1, const struct timespec &t2) {
+ /* NOTE the following subtraction works correctly because a long can hold a litle more than 2 seconds expressed in nano seconds! */
+ long nsec = t1.tv_nsec - t2.tv_nsec;
+ struct timespec ts;
+ ts.tv_sec = t1.tv_sec - t2.tv_sec + nsec / 1000000000;
+ ts.tv_nsec = nsec % 1000000000;
+
+ __normalizesign_timespec(&ts);
+
+ return ts;
+}
+
+
+static inline struct timespec __mul_timespec (const struct timespec &t1, const long double value) {
+#if 0
+ /* A simple implementation that risks reducing the precision of the TIME value */
+ long double sec_d1 = t1.tv_nsec / (long double)1e9 * value;
+ long double sec_d2 = t1.tv_sec * value;
+ long int sec = (long int)truncl(sec_d1 + sec_d2);
+ struct timespec ts;
+ ts.tv_sec = sec;
+ ts.tv_nsec = (long int)((sec_d1 + sec_d2 - sec)*1e9);
+ return ts;
+#else
+ /* A more robust implementation that reduces the loss of precision of the TIME value */
+ /* NOTE: The following assumes that the value stored in tv_nsec is never larger than 1 sec
+ * and is also based on the fact that tv_nsec can safely store slighlty more thanb 2 sec.
+ */
+ long double sec_d1 = t1.tv_nsec / (long double)1e9 * value;
+ long double sec_d2 = t1.tv_sec * value;
+ long int sec1 = (long int)sec_d1;
+ long int sec2 = (long int)sec_d2;
+ struct timespec ts;
+ ts.tv_sec = sec1 + sec2;
+ ts.tv_nsec = (long int)(((sec_d1 - sec1) + (sec_d2 - sec2))*1e9);
+ /* re-normalize the value of tv_nsec */
+ /* i.e. guarantee that it falls in the range ]-1, +1[ seconds. */
+ if (ts.tv_nsec >= 1000000000) {ts.tv_nsec -= 1000000000; ts.tv_sec += 1;}
+ if (ts.tv_nsec <= -1000000000) {ts.tv_nsec += 1000000000; ts.tv_sec -= 1;}
+ /* We don't need to re-normalize the sign, since we are guaranteed that tv_sec and tv_nsec
+ * will still both have the same sign after being multiplied by the same value.
+ */
+ return ts;
+#endif
+}
+
+/* Helper Macro for the comparison operators... */
+#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)
+
+
+
+/* Some necessary forward declarations... */
+class TIME;
+class TOD;
+class DT;
+class DATE;
+
+typedef struct timespec __timebase_t;
+
+
+
+class TIME{
+ private:
+ /* private variable that contains the value of time. */
+ /* NOTE: The stored value is _always_ (time.tv_sec + time.tv_nsec),
+ no matter whether tv_sec is positive or negative, or tv_nsec is positive or negative.
+ */
+ __timebase_t time;
+
+ public:
+ /* conversion to __timebase_t */
+ operator __timebase_t(void) {return time;}
+
+ /* constructors... */
+ TIME (void) {time.tv_sec = 0; time.tv_nsec = 0;}
+ TIME (__timebase_t time) {this->time = time;}
+ TIME (const TIME &time) {this->time = time.time;} /* copy constructor */
+ TIME(int sign, double mseconds, double seconds=0, double minutes=0, double hours=0, double days=0) {
+ /* sign is 1 for positive values, -1 for negative time... */
+ long double total_sec = ((days*24 + hours)*60 + minutes)*60 + seconds + mseconds/1e3;
+ if (sign >= 0) sign = 1; else sign = -1;
+ time.tv_sec = sign * (long int)total_sec;
+ time.tv_nsec = sign * (long int)((total_sec - time.tv_sec)*1e9);
+ }
+
+ /* used in plciec.cc to set the value of the __CURRENT_TIME variable without having to call a
+ * TIME((__timebase_t time) constructor followed by the copy constructor.
+ */
+ void operator= (__timebase_t time) {this->time = time;}
+
+ /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */
+ TIME operator+ (const TIME &time) {return TIME(__add_timespec(this->time, time.time));}
+ TIME operator- (const TIME &time) {return TIME(__sub_timespec(this->time, time.time));}
+
+ friend TOD operator+ (const TIME &time, const TOD &tod);
+ friend TOD operator+ (const TOD &tod, const TIME &time);
+ friend TOD operator- (const TOD &tod, const TIME &time);
+
+ friend DT operator+ (const TIME &time, const DT &dt);
+ friend DT operator+ (const DT &dt, const TIME &time);
+ friend DT operator- (const DT &dt, const TIME &time);
+
+ friend TIME operator* (const TIME &time, const long double value);
+ friend TIME operator* (const long double value, const TIME &time);
+ friend TIME operator/ (const TIME &time, const long double value);
+
+ /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */
+ BOOL operator> (const TIME &time) {return __compare_timespec(>, this->time, time.time);}
+ BOOL operator>= (const TIME &time) {return __compare_timespec(>=, this->time, time.time);}
+ BOOL operator< (const TIME &time) {return __compare_timespec(<, this->time, time.time);}
+ BOOL operator<= (const TIME &time) {return __compare_timespec(<=, this->time, time.time);}
+ BOOL operator== (const TIME &time) {return __compare_timespec(==, this->time, time.time);}
+ BOOL operator!= (const TIME &time) {return !__compare_timespec(==, this->time, time.time);}
+};
+
+
+
+/* Time of Day */
+class TOD {
+ private:
+ __timebase_t time;
+
+ public:
+ /* conversion to __timebase_t */
+ operator __timebase_t(void) {return time;}
+
+ /* constructors... */
+ TOD (void) {time.tv_sec = 0; time.tv_nsec = 0;}
+ TOD (__timebase_t time) {this->time = time;}
+ TOD (const TOD &tod) {this->time = tod.time;} /* copy constructor */
+ TOD (double seconds, double minutes=0, double hours=0) {
+ long double total_sec = (hours*60 + minutes)*60 + seconds;
+ time.tv_sec = (long int)total_sec;
+ time.tv_nsec = (long int)((total_sec - time.tv_sec)*1e9);
+ }
+
+ /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */
+ TIME operator- (const TOD &tod) {return TIME(__sub_timespec(this->time, tod.time));}
+
+ friend TOD operator+ (const TIME &time, const TOD &tod);
+ friend TOD operator+ (const TOD &tod, const TIME &time);
+ friend TOD operator- (const TOD &tod, const TIME &time);
+
+ /* The following operation is not in the standard,
+ * but will ease the implementation of the default function CONCAT_DATE_TOD
+ */
+ friend DT operator+ (const DATE &date, const TOD &tod);
+ friend DT operator+ (const TOD &tod, const DATE &date);
+
+ /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */
+ BOOL operator> (const TOD &tod) {return __compare_timespec(>, this->time, tod.time);}
+ BOOL operator>= (const TOD &tod) {return __compare_timespec(>=, this->time, tod.time);}
+ BOOL operator< (const TOD &tod) {return __compare_timespec(<, this->time, tod.time);}
+ BOOL operator<= (const TOD &tod) {return __compare_timespec(<=, this->time, tod.time);}
+ BOOL operator== (const TOD &tod) {return __compare_timespec(==, this->time, tod.time);}
+ BOOL operator!= (const TOD &tod) {return !__compare_timespec(==, this->time, tod.time);}
+};
+
+
+
+//typedef DATE;
+class DATE {
+ private:
+ __timebase_t time;
+
+ public:
+ /* conversion to __timebase_t */
+ operator __timebase_t(void) {return time;}
+
+ /* constructors... */
+ DATE (void) {time.tv_sec = 0; time.tv_nsec = 0;}
+ DATE (__timebase_t time) {this->time = time;}
+ DATE (const DATE &date) {this->time = date.time;} /* copy constructor */
+ DATE (int day, int month, int year) {
+ struct tm broken_down_time;
+
+ broken_down_time.tm_sec = 0;
+ broken_down_time.tm_min = 0;
+ broken_down_time.tm_hour = 0;
+ broken_down_time.tm_mday = day; /* day of month, from 1 to 31 */
+ broken_down_time.tm_mon = month - 1; /* month since January, in the range 0 to 11 */
+ broken_down_time.tm_year = year - 1900; /* number of years since 1900 */
+
+ time_t epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */
+
+ if ((time_t)(-1) == epoch_seconds)
+ IEC_error();
+
+ time.tv_sec = epoch_seconds;
+ time.tv_nsec = 0;
+ }
+
+ /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */
+ TIME operator- (const DATE &date) {return TIME(__sub_timespec(this->time, date.time));}
+ /* The following operation is not in the standard,
+ * but will ease the implementation of the default function CONCAT_DATE_TOD
+ */
+ friend DT operator+ (const DATE &date, const TOD &tod);
+ friend DT operator+ (const TOD &tod, const DATE &date);
+
+ /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */
+ BOOL operator> (const DATE &date) {return __compare_timespec(>, this->time, date.time);}
+ BOOL operator>= (const DATE &date) {return __compare_timespec(>=, this->time, date.time);}
+ BOOL operator< (const DATE &date) {return __compare_timespec(<, this->time, date.time);}
+ BOOL operator<= (const DATE &date) {return __compare_timespec(<=, this->time, date.time);}
+ BOOL operator== (const DATE &date) {return __compare_timespec(==, this->time, date.time);}
+ BOOL operator!= (const DATE &date) {return !__compare_timespec(==, this->time, date.time);}
+};
+
+
+
+
+
+class DT {
+ private:
+ __timebase_t time;
+
+ public:
+ /* conversion to __timebase_t */
+ operator __timebase_t(void) {return time;}
+
+ /* constructors... */
+ DT (void) {time.tv_sec = 0; time.tv_nsec = 0;}
+ DT (__timebase_t time) {this->time = time;}
+ DT (const DT &dt) {this->time = dt.time;} /* copy constructor */
+ DT (double seconds, double minutes, double hours, int day, int month, int year) {
+ long double total_sec = (hours*60 + minutes)*60 + seconds;
+ time.tv_sec = (long int)total_sec;
+ time.tv_nsec = (long int)((total_sec - time.tv_sec)*1e9);
+
+ struct tm broken_down_time;
+ broken_down_time.tm_sec = 0;
+ broken_down_time.tm_min = 0;
+ broken_down_time.tm_hour = 0;
+ broken_down_time.tm_mday = day; /* day of month, from 1 to 31 */
+ broken_down_time.tm_mon = month - 1; /* month since January, in the range 0 to 11 */
+ broken_down_time.tm_year = year - 1900; /* number of years since 1900 */
+
+ time_t epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */
+ if ((time_t)(-1) == epoch_seconds)
+ IEC_error();
+
+ time.tv_sec += epoch_seconds;
+ if (time.tv_sec < epoch_seconds)
+ /* since the TOD is always positive, if the above happens then we had an overflow */
+ IEC_error();
+ }
+
+ /* Helpers to conversion operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */
+ DATE __to_DATE(void) {
+#if 0
+ /* slow version */
+ struct tm broken_down_time;
+ time_t seconds = time.tv_sec;
+ if (NULL == gmtime_r(seconds, &broken_down_time)) /* get the UTC (GMT) broken down time */
+ IEC_error();
+ return DATE(broken_down_time.tm_mday, broken_down_time.tm_mon, broken_down_time.tm_year);
+#else
+ /* Faster version, based on the fact that the date will always be a multiple of 60*60*24 seconds,
+ * and that the value of tv_nsec falls in the range ]-1, +1[
+ */
+ /* The above is true since the Unix function mktime() seems to ignore all leap seconds! */
+ struct timespec date_time = {time.tv_sec - (time.tv_sec % (24*60*60)), 0};
+ return DATE(date_time);
+#endif
+ }
+
+ TOD __to_TOD(void) {
+#if 0
+ /* slow version */
+ struct tm broken_down_time;
+ time_t seconds = time.tv_sec;
+ if (NULL == gmtime_r(seconds, &broken_down_time)) /* get the UTC (GMT) broken down time */
+ IEC_error();
+ return TOD(broken_down_time.tm_sec, broken_down_time.tm_min, broken_down_time.tm_hour);
+#else
+ /* Faster version, based on the fact that the date will always be a multiple of 60*60*24 seconds
+ * and that the value of tv_nsec falls in the range ]-1, +1[
+ */
+ /* The above is true since the Unix function mktime() seems to ignore all leap seconds! */
+ struct timespec time_time = {time.tv_sec % (24*60*60), time.tv_nsec};
+ return TOD(time_time);
+#endif
+ }
+
+ /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */
+ TIME operator- (const DT &dt) {return TIME(__sub_timespec(this->time, dt.time));}
+
+ friend DT operator+ (const TIME &time, const DT &dt);
+ friend DT operator+ (const DT &dt, const TIME &time);
+ friend DT operator- (const DT &dt, const TIME &time);
+
+ /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */
+ BOOL operator> (const DT &dt) {return __compare_timespec(>, this->time, dt.time);}
+ BOOL operator>= (const DT &dt) {return __compare_timespec(>=, this->time, dt.time);}
+ BOOL operator< (const DT &dt) {return __compare_timespec(<, this->time, dt.time);}
+ BOOL operator<= (const DT &dt) {return __compare_timespec(<=, this->time, dt.time);}
+ BOOL operator== (const DT &dt) {return __compare_timespec(==, this->time, dt.time);}
+ BOOL operator!= (const DT &dt) {return !__compare_timespec(==, this->time, dt.time);}
+};
+
+
+/* The operations on time and data types... */
+TOD operator+ (const TIME &time, const TOD &tod) {return TOD(__add_timespec(tod.time, time.time));};
+TOD operator+ (const TOD &tod, const TIME &time) {return TOD(__add_timespec(tod.time, time.time));};
+TOD operator- (const TOD &tod, const TIME &time) {return TOD(__sub_timespec(tod.time, time.time));};
+
+DT operator+ (const TIME &time, const DT &dt) {return DT(__add_timespec(dt.time, time.time));};
+DT operator+ (const DT &dt, const TIME &time) {return DT(__add_timespec(dt.time, time.time));};
+DT operator- (const DT &dt, const TIME &time) {return DT(__sub_timespec(dt.time, time.time));};
+
+TIME operator* (const TIME &time, const long double value) {return TIME(__mul_timespec(time.time, value));}
+TIME operator* (const long double value, const TIME &time) {return TIME(__mul_timespec(time.time, value));}
+TIME operator/ (const TIME &time, const long double value) {return TIME(__mul_timespec(time.time, 1.0/value));}
+
+/* The following operation is not in the standard,
+ * but will ease the implementation of the default function CONCAT_DATE_TOD
+ */
+DT operator+ (const DATE &date, const TOD &tod) {return DT(__add_timespec(date.time, tod.time));};
+DT operator+ (const TOD &tod, const DATE &date) {return DT(__add_timespec(date.time, tod.time));};
+
+
+/* global variable that will be used to implement the timers TON, TOFF and TP */
+extern TIME __CURRENT_TIME;
+
+
+
+//typedef STRING;
+//typedef WSTRING;
+
+
+
+typedef union __IL_DEFVAR_T {
+ BOOL BOOLvar;
+
+ SINT SINTvar;
+ INT INTvar;
+ DINT DINTvar;
+ LINT LINTvar;
+
+ USINT USINTvar;
+ UINT UINTvar;
+ UDINT UDINTvar;
+ ULINT ULINTvar;
+
+ BYTE BYTEvar;
+ WORD WORDvar;
+ DWORD DWORDvar;
+ LWORD LWORDvar;
+
+ REAL REALvar;
+ LREAL LREALvar;
+
+ /* NOTE: since the TIME, DATE, ... classes all have constructors,
+ * C++ does not allow them to be used as members of a union.
+ * The workaround is to use a base data type (in this case __timebase_t) that
+ * contains all the internal data these classes require, and then add an operator
+ * member function to each class that allows it to be converted to that same base data type,
+ * acompanied by a constructor using that data type.
+ */
+ /*
+ TIME TIMEvar;
+ TOD TODvar;
+ DT DTvar;
+ DATE DATEvar;
+ */
+ __timebase_t TIMEvar;
+ __timebase_t TODvar;
+ __timebase_t DTvar;
+ __timebase_t DATEvar;
+} __IL_DEFVAR_T;
+ /*TODO TODO TODO TODO TODO TODO TODO TODO TODO
+ * How do we add support for the possibility of storing
+ * data values of derived data types into the default register,
+ * to be later used for calling functions, stroing in another
+ * variable, etc...?
+ *
+ * For example:
+ * TYPE
+ * point_t : STRUCT
+ * x : INT;
+ * y : INT;
+ * END_STRUCT;
+ * END_TYPE
+ *
+ * VAR p1, p2, p3 : point_t;
+ *
+ * LD p1
+ * ST p2
+ *
+ *
+ * We could do it with a pointer to void, that would contain not
+ * the value itself, but rather the address in which the value
+ * is currently stored.
+ * For example, we could add a
+ * void *generic_ptr
+ * to this union, and then have the above LD and ST instructions
+ * converted to:
+ * __IL_DEFVAR.generic_ptr = (void *)(&p1);
+ * p2 = *((point_t *)__IL_DEFVAR.generic_ptr);
+ *
+ * Unfortunately the above will only work as long as the p1 variable
+ * does not get a chance to change its value before the default register
+ * gets loaded with something esle (and therefore the value is no
+ * longer needed).
+ * Additionally, a scenario where the value of p1 may change before the
+ * default register gets a new value is if p1 is used in a function block
+ * call for an output parameter!
+ * For example:
+ *
+ * LD p1
+ * CAL funcblock(
+ * param1 => p1
+ * )
+ * ST p2
+ *
+ * In the above scenario, p1 gets a new value when the function block
+ * funcblock is called. When we get to copy the default register to
+ * p2, we will no longer be copying the value that got stored in the default
+ * register when we did 'LD p1', but rather the value returned by the
+ * function block call!!!
+ *
+ * How the do we implement this???
+ * We will probably need to declare a default variable of the correct data
+ * type whenever we get these values stored to the default register.
+ * For example
+ * LD p1
+ * ST p2
+ *
+ * would be converted to:
+ * union {
+ * point_tvar point_t;
+ * } __IL_DEFVAR_special ;
+ *
+ * __IL_DEFVAR_special.point_tvar = p1;
+ * p2 = __IL_DEFVAR_special.point_tvar;
+ *
+ * The above requires that we iterate through the whole Instruction list
+ * before we start the conversion, in order to first determine if we need
+ * to declare that new variable for the default register.
+ *
+ * Since we have to do this, it would probaly be a better idea to simply
+ * do away with the __IL_DEFVAR_T data type we declare here, and
+ * declare the __IL_DEFVAR at the begining of each IL code segment
+ * with all the data types that get used in that segment!
+ */
+
+
+/* Names start with double underscore so as not to clash with
+ * names in ST or IL source code! Names including a double underscore are
+ * ilegal under IL and ST!
+ */
+
+/* This is an abstract base class, that cannot be instantiated... */
+template<typename value_type> class __ext_ref_c {
+ public:
+ virtual void operator= (value_type value) = 0;
+ virtual operator value_type(void) = 0;
+};
+
+
+
+
+
+
+/* Names start with double underscore so as not to clash with
+ * names in ST or IL source code! Names including a double underscore are
+ * ilegal under IL and ST!
+ */
+template<typename value_type> class __ext_element_c
+ : public __ext_ref_c<value_type> {
+//{
+
+ private:
+ value_type value;
+
+ public:
+ virtual void operator= (value_type value) {
+ this->value = value;
+ }
+
+ virtual operator value_type(void) {
+ return value;
+ }
+
+ __ext_element_c(void) {}
+
+ __ext_element_c(value_type value) {
+ this->value = value;
+ }
+};
+
+
+/* Names start with double underscore so as not to clash with
+ * names in ST or IL source code! Names including a double underscore are
+ * ilegal under IL and ST!
+ */
+template<typename value_type, int size = 8 * sizeof(value_type) /* in bits */> class __plc_pt_c
+ : public __ext_ref_c<value_type> {
+
+ private:
+ plc_pt_t plc_pt;
+ bool valid_plc_pt;
+
+ private:
+ void init_name(const char *pt_name) {
+ /* assume error! */
+ valid_plc_pt = false;
+ plc_pt = plc_pt_by_name(pt_name);
+ if (plc_pt.valid == 0) {
+ plc_pt = plc_pt_null();
+ return;
+ }
+ /* We can't have this check here, otherwise the boolean variables won't work correctly,
+ * since MatPLC uses 1 bit for boolean variables, whereas g++ uses 8 bits.
+ */
+ /*
+ if (plc_pt_len(plc_pt) != size) {
+ plc_pt = plc_pt_null();
+ return;
+ }
+ */
+ valid_plc_pt = true;
+ }
+
+ public:
+ virtual void operator= (value_type value) {
+ plc_set(plc_pt, *((u32 *)&value));
+ }
+
+ virtual operator value_type(void) {
+ u32 tmp_val = plc_get(plc_pt);
+ return *((value_type *)&tmp_val);
+ }
+
+ __plc_pt_c(const char *pt_name) {
+ init_name(pt_name);
+ }
+
+ __plc_pt_c(const char *pt_name, value_type init_value) {
+ init_name(pt_name);
+ *this = init_value;
+ }
+
+ bool valid(void) {return valid_plc_pt;}
+};
+
+
+
+#define DEFAULT_MODULE_NAME "iec"
+
+
+
+#endif /* __PLCIEC_H */
+
+