178 } |
178 } |
179 |
179 |
180 /**********************************************/ |
180 /**********************************************/ |
181 /* Time conversion to/from timespec functions */ |
181 /* Time conversion to/from timespec functions */ |
182 /**********************************************/ |
182 /**********************************************/ |
183 |
183 /* NOTE: The following function was turned into a macro, so it could be used to initialize the initial value of TIME variables. |
|
184 * Since each macro parameter is evaluated several times, the macro may result in multiple function invocations if an expression |
|
185 * containing a function invocation is passed as a parameter. However, currently matiec only uses this conversion macro with |
|
186 * constant literals, so it is safe to change it into a macro. |
|
187 */ |
|
188 /* NOTE: I (Mario - msousa@fe.up.pt) believe that the following function contains a bug when handling negative times. |
|
189 * The equivalent macro has this bug fixed. |
|
190 * e.g.; |
|
191 * T#3.8s |
|
192 * using the function, will result in a timespec of 3.8s !!!: |
|
193 * tv_sec = 4 <----- 1 * 3.8 is rounded up when converting a double to an int! |
|
194 * tv_nsec = -200 000 000 <----- 1 * (3.8 - 4)*1e9 |
|
195 * |
|
196 * -T#3.8s |
|
197 * using the function, will result in a timespec of -11.8s !!!: |
|
198 * tv_sec = -4 <----- -1 * 3.8 is rounded down when converting a double to an int! |
|
199 * tv_nsec = -7 800 000 000 <----- -1 * (3.8 - -4)*1e9 |
|
200 */ |
|
201 /* NOTE: Due to the fact that the C compiler may round a tv_sec number away from zero, |
|
202 * the following macro may result in a timespec that is not normalized, i.e. with a tv_sec > 0, and a tv_nsec < 0 !!!! |
|
203 * This is due to the rounding that C compiler applies when converting a (long double) to a (long int). |
|
204 * To produce normalized timespec's we need to use floor(), but we cannot call any library functions since we want this macro to be |
|
205 * useable as a variable initializer. |
|
206 * VAR x : TIME = T#3.5h; END_VAR ---> IEC_TIME x = __time_to_timespec(1, 0, 0, 0, 3.5, 0); |
|
207 */ |
|
208 /* |
184 static inline IEC_TIMESPEC __time_to_timespec(int sign, double mseconds, double seconds, double minutes, double hours, double days) { |
209 static inline IEC_TIMESPEC __time_to_timespec(int sign, double mseconds, double seconds, double minutes, double hours, double days) { |
185 IEC_TIMESPEC ts; |
210 IEC_TIMESPEC ts; |
186 |
211 |
187 /* sign is 1 for positive values, -1 for negative time... */ |
212 // sign is 1 for positive values, -1 for negative time... |
188 long double total_sec = ((days*24 + hours)*60 + minutes)*60 + seconds + mseconds/1e3; |
213 long double total_sec = ((days*24 + hours)*60 + minutes)*60 + seconds + mseconds/1e3; |
189 if (sign >= 0) sign = 1; else sign = -1; |
214 if (sign >= 0) sign = 1; else sign = -1; |
190 ts.tv_sec = sign * (long int)total_sec; |
215 ts.tv_sec = sign * (long int)total_sec; |
191 ts.tv_nsec = sign * (long int)((total_sec - ts.tv_sec)*1e9); |
216 ts.tv_nsec = sign * (long int)((total_sec - ts.tv_sec)*1e9); |
192 |
217 |
193 return ts; |
218 return ts; |
194 } |
219 } |
195 |
220 */ |
196 |
221 /* NOTE: Unfortunately older versions of ANSI C (e.g. C99) do not allow explicit identification of elements in initializers |
|
222 * e.g. {tv_sec = 1, tv_nsec = 300} |
|
223 * They are therefore commented out. This however means that any change to the definition of IEC_TIMESPEC may require this |
|
224 * macro to be updated too! |
|
225 */ |
|
226 #define ld long double |
|
227 #define __time_to_timespec(sign,mseconds,seconds,minutes,hours,days) \ |
|
228 ((IEC_TIMESPEC){\ |
|
229 /*tv_sec =*/ ((long int) (((sign>=0)?1:-1)*((((ld)days*24 + (ld)hours)*60 + (ld)minutes)*60 + (ld)seconds + (ld)mseconds/1e3))), \ |
|
230 /*tv_nsec =*/ ((long int)(( \ |
|
231 ((long double)(((sign>=0)?1:-1)*((((ld)days*24 + (ld)hours)*60 + (ld)minutes)*60 + (ld)seconds + (ld)mseconds/1e3))) - \ |
|
232 ((long int) (((sign>=0)?1:-1)*((((ld)days*24 + (ld)hours)*60 + (ld)minutes)*60 + (ld)seconds + (ld)mseconds/1e3))) \ |
|
233 )*1e9))\ |
|
234 }) |
|
235 #undef ld |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 /* NOTE: The following function was turned into a macro, so it could be used to initialize the initial value of TOD (TIME_OF_DAY) variables */ |
|
241 /* NOTE: many (but not all) of the same comments made regarding __time_to_timespec() are also valid here, so go and read those comments too! |
|
242 /* |
197 static inline IEC_TIMESPEC __tod_to_timespec(double seconds, double minutes, double hours) { |
243 static inline IEC_TIMESPEC __tod_to_timespec(double seconds, double minutes, double hours) { |
198 IEC_TIMESPEC ts; |
244 IEC_TIMESPEC ts; |
199 |
245 |
200 long double total_sec = (hours*60 + minutes)*60 + seconds; |
246 long double total_sec = (hours*60 + minutes)*60 + seconds; |
201 ts.tv_sec = (long int)total_sec; |
247 ts.tv_sec = (long int)total_sec; |
202 ts.tv_nsec = (long int)((total_sec - ts.tv_sec)*1e9); |
248 ts.tv_nsec = (long int)((total_sec - ts.tv_sec)*1e9); |
203 |
249 |
204 return ts; |
250 return ts; |
205 } |
251 } |
|
252 */ |
|
253 #define ld long double |
|
254 #define __tod_to_timespec(seconds,minutes,hours) \ |
|
255 ((IEC_TIMESPEC){\ |
|
256 /*tv_sec =*/ ((long int) ((((ld)hours)*60 + (ld)minutes)*60 + (ld)seconds)), \ |
|
257 /*tv_nsec =*/ ((long int)(( \ |
|
258 ((long double)((((ld)hours)*60 + (ld)minutes)*60 + (ld)seconds)) - \ |
|
259 ((long int) ((((ld)hours)*60 + (ld)minutes)*60 + (ld)seconds)) \ |
|
260 )*1e9))\ |
|
261 }) |
|
262 #undef ld |
|
263 |
206 |
264 |
207 #define EPOCH_YEAR 1970 |
265 #define EPOCH_YEAR 1970 |
208 #define SECONDS_PER_MINUTE 60 |
266 #define SECONDS_PER_MINUTE 60 |
209 #define SECONDS_PER_HOUR (60 * SECONDS_PER_MINUTE) |
267 #define SECONDS_PER_HOUR (60 * SECONDS_PER_MINUTE) |
210 #define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR) |
268 #define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR) |