-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathegi_timer.c
859 lines (704 loc) · 21.6 KB
/
egi_timer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
/*----------------------------------------------------------------
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
NOTE:
1. A pthread_join() failure may block followed sleep functons such
as egi_sleep() and tm_delay() permanently!???
2. Tick alarm signal may conflic with other app thread!
(--- Type of: time_t, suseconds_t ---)
time_t =-> long (BUT maybe double)
suseconds_t =-> long
linux/types.h:69:typedef __kernel_time_t time_t;
uapi/asm-generic/posix_types.h:88:typedef __kernel_long_t __kernel_time_t;
linux/types.h:24:typedef __kernel_suseconds_t suseconds_t;
uapi/linux/time.h:17: __kernel_suseconds_t tv_usec;
uapi/asm-generic/posix_types.h:40:typedef __kernel_long_t __kernel_suseconds_t;
uapi/asm-generic/posix_types.h:14:typedef long __kernel_long_t;
(--- Struct of time var. ---)
time_t =-> long (BUT maybe double)
struct timespec {
time_t tv_sec; seconds
long tv_nsec; nanoseconds
};
struct timeval {
time_t tv_sec; seconds
suseconds_t tv_usec; microseconds
};
struct tm {
int tm_sec; Seconds (0-60)
int tm_min; Minutes (0-59)
int tm_hour; Hours (0-23)
int tm_mday; Day of the month (1-31)
int tm_mon; Month (0-11)
int tm_year; Year - 1900
int tm_wday; Day of the week (0-6, Sunday = 0)
int tm_yday; Day in the year (0-365, 1 Jan = 0)
int tm_isdst; Daylight saving time
};
3. Conversion for 'struct time_t' AND 'struct tm':
struct tm *localtime(const time_t *timep);
time_t mktime(struct tm *tm);
4. double difftime(time_t time1, time_t time0);
Journal:
2021-05-03:
1. Add egi_clock_restart().
2021-07-10:
1. egi_clock_restart(): Force status to be RUNNING before
calling egi_clock_stop(). So an IDLE clock can also restart.
2021-07-13:
1. egi_clock_readCostUsec(), egi_clock_peekCostUsec(): Modified to be long long type.
2022-01-04:
1. Add tm_wait_till().
2022-04-25:
1. Add tm_daysInFeb().
TODO:
--- Critical ---
1. For 32bit system: time_t overflow for 2038 YEAR problem.
2. To apply POSIX timer APIs:
timer_create(), timer_settime(), timer_gettimer(), timer_getoverrun(), timer_delete()
Midas Zhou
-----------------------------------------------------------------*/
#include <signal.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h> /* usleep */
#include <stdbool.h>
#include <errno.h>
#include "egi_timer.h"
#include "egi_symbol.h"
#include "egi_fbgeom.h"
#include "egi_debug.h"
#include "dict.h"
#define EGI_ENABLE_TICK 0 /* Tick alarm signal may conflic with .curl? inet/unet? ... */
struct itimerval tm_val, tm_oval;
char tm_strbuf[50]={0};
const char *str_weekday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
//const char *str_weekday[]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
const char *str_month[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Sub"};
/* Days in a month, call tm_daysInFeb(year) to get days in Feb.
Month 1 2 3 4 5 6 7 8 9 10 11 12 */
const int tm_MonthDays[]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/* encoding uft8 */
const char *stru8_weekday[]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
const char *stru8_month[]={"一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"};
/* global tick */
static struct itimerval tm_tick_val; //tm_tick_oval;
static long long unsigned int tm_tick_count=0;
// struct timespec ts;
// clock_gettime(CLOCK_MONOTONIC, &ts);
/*-------------------------------
Return days in the February.
@year: Year. Example 2022
--------------------------------*/
int tm_daysInFeb(unsigned int year)
{
if( year%4 ==0 ) { /* Leap year */
if( year%100 ==0 ) {
if( year%400 ==0 )
return 29;
else
return 28;
}
else
return 29;
}
else /* Non leap year */
return 28;
}
/*--------------------------------------------------------
The function will wait until the preset time comes.
Note:
1. It checks time difference every second!
2. ONLY (strSet OR tm_set) and (strDely OR tm_delay)
to be effective.
@strSet: Preset time string in format "Y-m-d H:M:S"
If NULL, use tm_set instead.
If has NO 'Y-m-d' part, then take it as TODAY.
@tm_set: Preset time in time_t.
If =0, set to be tm_now!
@strDelay: Delay time(from the preset time) in string format "hs:ms:ss"
1. 'hs','ms' and 'ss' are NOT limited to clock time!
2. If NULL, use tm_delay instead.
@tm_delay Delay time in time_t.
Return:
0 OK
<0 Fails
--------------------------------------------------------*/
int tm_wait_till( const char *strSet, time_t tm_set,
const char *strDelay, time_t tm_delay )
{
time_t tm_now; /* time NOW, seconds from the Epoch. */
struct tm tm;
/* 1. Check tm_set */
if(strSet==NULL && tm_set==0)
tm_set=time(NULL);
/* 2. Read preset time */
if(strSet) {
memset(&tm, 0, sizeof(struct tm));
tm_set=time(NULL);
gmtime_r(&tm_set, &tm); /* Set as NOW, in case strSet has NO 'Y-m-d' part. */
if( strstr("-", strSet)==NULL ) {
if( strptime(strSet, "%H:%M:%S", &tm)==NULL )
return -1;
} else {
if( strptime(strSet, "%Y-%m-%d %H:%M:%S", &tm)==NULL )
return -1;
}
tm_set=mktime(&tm);
}
/* ELSE: use input tm_set */
/* 3. Read preset delay */
if(strDelay) {
long h=0, m=0, s=0;
sscanf(strDelay,"%ld:%ld:%ld", &h,&m,&s);
printf("h=%ld, m=%ld, s=%ld\n", h,m, s);
tm_delay = 3600*h +60*m +s;
}
/* ELSE: use input tm_dealy */
/* 4. Get final preset time */
tm_set += tm_delay;
printf("tm_set: %ld\n", (long)tm_set);
/* 5. Waiting */
do {
sleep(1);
tm_now=time(NULL);
} while( tm_now < tm_set );
return 0;
}
/*-------------------------------------
Get time stamp in ms
--------------------------------------*/
long long unsigned int tm_get_tmstampms(void)
{
struct timeval tmval;
gettimeofday(&tmval, NULL);
return ( ((long long unsigned int)tmval.tv_sec)*1000+tmval.tv_usec/1000);
}
/* SUBSTITUE: size_t strftime(char *s, size_t max, const char *format, const struct tm *tm) */
/*---------------------------------------------
Get local time string in form of:
H:M:S (in 24hours)
The caller must ensure enough space for tmbuf.
---------------------------------------------*/
void tm_get_strtime(char *tmbuf)
{
time_t tm_t; /* time in seconds */
struct tm *tm_s; /* time in struct */
time(&tm_t);
tm_s=localtime(&tm_t);
/* tm_s->tm_year start from 1900
tm_s->tm_mon start from 0
*/
sprintf(tmbuf,"%02d:%02d:%02d",tm_s->tm_hour,tm_s->tm_min,tm_s->tm_sec);
}
/*---------------------------------------------
Get local time string in form of:
Year-Month-Day_H:M:S.ms appenstr (in 24hours)
The caller must ensure enough space for tmbuf.
---------------------------------------------*/
void tm_get_strtime2(char *tmbuf, const char *appen)
{
time_t tm_t; /* time in seconds */
//struct tm *tm_s; /* time in struct */
struct tm tm_s;
struct timeb tp;
time(&tm_t);
//tm_s=localtime(&tm_t);
if(localtime_r(&tm_t, &tm_s)==NULL) {
tmbuf[0]=0;
return;
}
ftime(&tp);
/* tm_s->tm_year start from 1900
tm_s->tm_mon start from 0
*/
sprintf(tmbuf,"%d-%d-%d_%02d:%02d:%02d.%d%s",
tm_s.tm_year+1900,tm_s.tm_mon+1,tm_s.tm_mday,
tm_s.tm_hour,tm_s.tm_min,tm_s.tm_sec, tp.millitm, appen);
//tm_s->tm_year+1900,tm_s->tm_mon+1,tm_s->tm_mday,
//tm_s->tm_hour,tm_s->tm_min,tm_s->tm_sec, tp.millitm, appen);
}
/*---------------------------------------------
Get local time in string, in form of:
Year_Mon_Day Weekday
The caller must ensure enough space for tmdaybuf.
---------------------------------------------*/
void tm_get_strday(char *daybuf)
{
time_t tm_t; /* time in seconds */
struct tm *tm_s; /* time in struct tm */
time(&tm_t);
tm_s=localtime(&tm_t);
sprintf(daybuf,"%d-%d-%d %s", tm_s->tm_year+1900,tm_s->tm_mon+1,tm_s->tm_mday, \
str_weekday[tm_s->tm_wday] );
}
/*---------------------------------------------
Get local time in string, in form of:
Year_Mon_Day H:M:S
The caller must ensure enough space for dtbuf.
---------------------------------------------*/
void tm_get_strdaytime(char *dtbuf)
{
time_t tm_t; /* time in seconds */
struct tm *tm_s; /* time in struct tm */
time(&tm_t);
tm_s=localtime(&tm_t);
sprintf(dtbuf,"%d-%d-%d %02d:%02d:%02d",
tm_s->tm_year+1900,tm_s->tm_mon+1,tm_s->tm_mday,
tm_s->tm_hour,tm_s->tm_min,tm_s->tm_sec);
}
/*-----------------------------------
Get local time in uft-8 string:
x月x日
The caller must enusre enough space for
udaybuf.
------------------------------------*/
void tm_get_ustrday(char *udaybuf)
{
time_t tm_t; /* time in seconds */
struct tm *tm_s; /* time in struct tm */
time(&tm_t);
tm_s=localtime(&tm_t);
sprintf(udaybuf,"%d月%d日", tm_s->tm_mon+1,tm_s->tm_mday);
}
/*------------------------------
Timer routine
-------------------------------*/
void tm_sigroutine(int signo)
{
if(signo == SIGALRM)
{
/* ------- routine action every tick -------- */
#if 0 // put heavy action here is not a good idea ?????? !!!!!!
/* get time and display */
tm_get_strtime(tm_strbuf);
wirteFB_str20x15(&gv_fb_dev, 0, (30<<11|45<<5|10), tm_strbuf, 60, 320-38);
tm_get_strday(tm_strbuf);
symbol_string_writeFB(&gv_fb_dev, &sympg_testfont,0xffff,45,2,tm_strbuf);
//symbol_string_writeFB(&gv_fb_dev, &sympg_testfont,0xffff,32,90,tm_strbuf);
#endif
}
/* restore tm_sigroutine */
signal(SIGALRM, tm_sigroutine);
}
/*---------------------------------
set timer for SIGALRM
us: time interval in us.
----------------------------------*/
void tm_settimer(int us)
{
/* time left before next expiration */
tm_val.it_value.tv_sec=0;
tm_val.it_value.tv_usec=us;
/* time interval for periodic timer */
tm_val.it_interval.tv_sec=0;
tm_val.it_interval.tv_usec=us;
setitimer(ITIMER_REAL,&tm_val,NULL); /* NULL get rid of old time value */
}
/*-------------------------------------
set timer for SIGALRM of global tick
us: global tick time interval in us.
--------------------------------------*/
static void tm_tick_settimer(int us)
{
/* time left before next expiration */
tm_tick_val.it_value.tv_sec=0;
tm_tick_val.it_value.tv_usec=us;
/* time interval for periodic timer */
tm_tick_val.it_interval.tv_sec=0;
tm_tick_val.it_interval.tv_usec=us;
/* use real time */
setitimer(ITIMER_REAL,&tm_tick_val,NULL); /* NULL get rid of old time value */
}
/* -------------------------------------
global tick timer routine
--------------------------------------*/
static void tm_tick_sigroutine(int signo)
{
#if EGI_ENABLE_TICK
if(signo == SIGALRM) {
tm_tick_count+=1;
}
/* restore tm_sigroutine */
signal(SIGALRM, tm_tick_sigroutine);
#endif
}
/*-------------------------------
start egi_system tick
-------------------------------*/
void tm_start_egitick(void)
{
#if EGI_ENABLE_TICK
tm_tick_settimer(TM_TICK_INTERVAL);
signal(SIGALRM, tm_tick_sigroutine);
#endif
}
/*-----------------------------
return tm_tick_count
------------------------------*/
long long unsigned int tm_get_tickcount(void)
{
return tm_tick_count;
}
/*----- WARNING!!!! A lovely BUG :> -------
delay ms, at lease TM_TICK_INTERVAL/2000 ms
if ms<0, return.
-----------------------------------------*/
void tm_delayms(unsigned long ms)
{
if(ms==0) return;
#if EGI_ENABLE_TICK
unsigned int nticks;
long long unsigned int tm_now;
if(ms < TM_TICK_INTERVAL/1000)
nticks=TM_TICK_INTERVAL/1000;
else
nticks=ms*1000/TM_TICK_INTERVAL;
tm_now=tm_tick_count;
while(tm_tick_count-tm_now < nticks)
{
usleep(500); //usleep(1000) ?usleep disrupted by the timer signal? */
}
#else
egi_sleep(1,0,ms);
#endif
}
/*------------------ OBSOLETE -----------------------------
return:
TRUE: in every preset time interval gap(us), or time
interval exceeds gap(us).
FALSE: otherwise
gap: set period between pules
t: number of tm_pulse timer to be used.
return:
true pulse hits
false wait pulse or fails to call pulse
----------------------------------------------------------*/
static struct timeval tm_pulse_tmnew[10]={0};
static struct timeval tm_pulse_tmold[10]={0};
bool tm_pulseus(long long unsigned int gap, unsigned int t) /* gap(us) */
{
//struct timeval tmnew,tmold;
if(t>=10) {
printf("tm_pulseus(): timer number out of range!\n");
return false;
}
/* first init tmold */
if(tm_pulse_tmold[t].tv_sec==0 && tm_pulse_tmold[t].tv_usec==0)
gettimeofday(&tm_pulse_tmold[t],NULL);
/* get current time value */
gettimeofday(&tm_pulse_tmnew[t],NULL);
/* compare timers */
if(tm_pulse_tmnew[t].tv_sec*1000000+tm_pulse_tmnew[t].tv_usec >=
tm_pulse_tmold[t].tv_sec*1000000+tm_pulse_tmold[t].tv_usec + gap)
{
/* reset tmold */
tm_pulse_tmold[t].tv_sec=0;
tm_pulse_tmold[t].tv_usec=0;
tm_pulse_tmnew[t]=tm_pulse_tmold[t];
return true;
}
else
return false;
}
/*---------------------------------------------------------
return time difference in us, as an unsigned value.
t_start: start time
t_end: end time
-----------------------------------------------------------*/
unsigned long tm_diffus(struct timeval t_start, struct timeval t_end)
{
long ds=t_end.tv_sec-t_start.tv_sec;
long dus=t_end.tv_usec-t_start.tv_usec;
long td=ds*1000000+dus;
return ( td>0 ? td : -td );
}
/*------------------------------------------------------------------
return time difference in ms, as a signed value.
tm_start: start time
tm_end: end time
------------------------------------------------------------------*/
inline int tm_signed_diffms(struct timeval tm_start, struct timeval tm_end)
{
int time_cost;
time_cost=(tm_end.tv_sec-tm_start.tv_sec)*1000 \
+(tm_end.tv_usec-tm_start.tv_usec)/1000;
return time_cost;
}
/*------------------------------------------------------------
Use select to sleep
@s: seconds
@ms: millisecond, 0 - 999
NOTE:
1. In thread, it's OK. NO effect with egi timer????
2. In Main(), it'll fail, conflict with egi timer???
--------------------------------------------------------------*/
//static unsigned char gv_tm_fd[128]={0};
void egi_sleep(unsigned char fd, unsigned int s, unsigned int ms)
{
#if EGI_ENABLE_TICK
tm_delayms(s*1000+ms);
#else
int err;
struct timeval tmval;
tmval.tv_sec=s;
tmval.tv_usec=1000*ms;
do{
err=select(fd+1,NULL,NULL,NULL,&tmval); /* wait until timeout */
if(err<0)egi_dperr("select error!");
}while( err < 0 && errno==EINTR ); /* Ingore any signal */
#endif
}
/*---------------------------------------------
Start a clock, record tm_start.
Note:
1. tm_cost will be cleared if prevous status
is ECLOCK_STATUS_STOP.
TODO: To compare with
int clock_gettime(clockid_t clk_id, struct timespec *tp);
XXX Check clock resolution first
clock_getres(CLOCK_REALTIME, &tp) --> Clock resolution: 0.1 second!!!
Return:
0 OK
<0 Fails
---------------------------------------------*/
int egi_clock_start(EGI_CLOCK *eclock)
{
int ret=0;
/* Check status */
if(eclock==NULL)
return -1;
switch(eclock->status)
{
case ECLOCK_STATUS_RUNNING:
printf("%s: ECLOCK is running already!\n",__func__);
ret=-2;
break;
case ECLOCK_STATUS_PAUSE:
//printf("%s: ECLOCK is paused, start to activate and continue...\n",__func__);
/* Record tm_start and set status */
if( gettimeofday(&eclock->tm_start,NULL)<0 )
return -3;
/* Reset status */
eclock->status=ECLOCK_STATUS_RUNNING;
break;
case ECLOCK_STATUS_IDLE:
case ECLOCK_STATUS_STOP:
/* Reset tm_cost */
#if 0
eclock->tm_cost.tv_sec=0;
eclock->tm_cost.tv_usec=0;
#else
timerclear(&eclock->tm_cost);
#endif
/* Record tm_start and set status */
if( gettimeofday(&eclock->tm_start,NULL)<0 ) {
egi_dperr("gettimeofday");
ret=-3;
break;
}
/* Reset status */
eclock->status=ECLOCK_STATUS_RUNNING;
break;
default:
printf("%s: ECLOCK status unrecognizable!\n",__func__);
ret=-4;
break;
}
return ret;
}
/*-----------------------------------------------
Stop a clock, record tm_end and update tm_cost.
Return:
0 OK
<0 Fails
------------------------------------------------*/
int egi_clock_stop(EGI_CLOCK *eclock)
{
int ret=0;
/* Check status */
if(eclock==NULL)
return -1;
switch(eclock->status)
{
case ECLOCK_STATUS_IDLE:
printf("%s: ECLOCK status is IDLE!\n",__func__);
ret=-2;
break;
case ECLOCK_STATUS_RUNNING:
/* Record tm_end and set status */
if( gettimeofday(&eclock->tm_end,NULL)<0 ) {
egi_dperr("gettimeofday");
return -3;
}
/* Update tm_cost */
timersub(&eclock->tm_end, &eclock->tm_start, &eclock->tm_cost);
/* Reset status */
eclock->status=ECLOCK_STATUS_STOP;
break;
case ECLOCK_STATUS_PAUSE:
printf("%s: Stop a paused ECLOCK!\n",__func__);
/* Reset status */
eclock->status=ECLOCK_STATUS_STOP;
break;
case ECLOCK_STATUS_STOP:
printf("%s: ECLOCK already paused/stoped!\n",__func__);
break;
default:
printf("%s: ECLOCK status unrecognizable!\n",__func__);
ret=-3;
break;
}
return ret;
}
/*--------------------------------------
Restart a clock.
If current eclock status is IDLE, force
to be RUNNING to make egi_clock_stop()
succeed.
Return:
0 OK
<0 Fails
--------------------------------------*/
int egi_clock_restart(EGI_CLOCK *eclock)
{
int ret=0;
/* Force status to be RUNNING. */
eclock->status=ECLOCK_STATUS_RUNNING;
ret=egi_clock_stop(eclock);
if(ret)
return ret;
/* NOW status is ECLOCK_STATUS_STOP */
ret=egi_clock_start(eclock);
return ret;
}
/*-----------------------------------------------
Pause a clock, recoder tm_end and update tm_cost.
Pausing time will NOT be counted into tm_cost.
Return:
0 OK
<0 Fails
------------------------------------------------*/
int egi_clock_pause(EGI_CLOCK *eclock)
{
int ret=0;
// suseconds_t dus;
/* Check status */
if(eclock==NULL)
return -1;
switch(eclock->status)
{
case ECLOCK_STATUS_IDLE:
printf("%s: ECLOCK status is IDLE!\n",__func__);
ret=-2;
break;
case ECLOCK_STATUS_RUNNING:
/* Record tm_end and set status */
if( gettimeofday(&eclock->tm_end,NULL)<0 ) {
ret=-3;
break;
}
#if 0
/* Update tm_cost */
dus=eclock->tm_end.tv_usec - eclock->tm_start.tv_usec;
if(dus>=0) {
eclock->tm_cost.tv_usec += dus;
if( eclock->tm_cost.tv_usec > 999999 ) {
eclock->tm_cost.tv_sec += eclock->tm_cost.tv_usec/1000000;
eclock->tm_cost.tv_usec = eclock->tm_cost.tv_usec%1000000;
}
eclock->tm_cost.tv_sec += eclock->tm_end.tv_sec - eclock->tm_start.tv_sec;
}
else { /* dus<0 */
eclock->tm_cost.tv_usec += 1000000+dus;
eclock->tm_cost.tv_sec += eclock->tm_end.tv_sec - eclock->tm_start.tv_sec-1;
}
#else
struct timeval tm_tmp;
timersub(&eclock->tm_end, &eclock->tm_start, &tm_tmp);
timeradd(&eclock->tm_cost, &tm_tmp, &eclock->tm_cost);
#endif
/* Reset status */
eclock->status=ECLOCK_STATUS_PAUSE;
break;
case ECLOCK_STATUS_PAUSE:
printf("%s: ECLOCK already paused!\n",__func__);
break;
case ECLOCK_STATUS_STOP:
printf("%s: ECLOCK already stopped!\n",__func__);
ret=-4;
break;
default:
printf("%s: ECLOCK status unrecognizable!\n",__func__);
ret=-5;
break;
}
return ret;
}
/*--------------------------------------------------------
Read tm_end - tm_start, in us.(microsecond)
!!! --- WARNING --- !!!
A big value of tm_cost will make tus_cost overflow!
Use this function only when you are sure that tm_cost in eclock
is fairly small!
# define INT32_MIN (-2147483647-1)
# define INT64_MIN (-9223372036854775807LL-1)
# define INT32_MAX (2147483647)
# define INT64_MAX (9223372036854775807LL)
Note:
1. TEST Widora_NEO:
Under light CPU load condition, average Max. error is 100us.
Test usleep() will occasionally interrupted by sys schedule.
Return:
>=0 OK, time length in us.
<0 Fails
---------------------------------------------------------*/
long long egi_clock_readCostUsec(EGI_CLOCK *eclock)
{
long long tus_cost;
/* Check status */
if(eclock==NULL) return -1;
if( !(eclock->status&(ECLOCK_STATUS_STOP|ECLOCK_STATUS_PAUSE)) ) {
printf("%s: ECLOCK status error, you must stop/pause the clock first!\n",__func__);
return -2;
}
tus_cost=eclock->tm_cost.tv_sec*1000000LL+eclock->tm_cost.tv_usec;
return tus_cost;
}
/*--------------------------------------------------------
Read tm_now - tm_start, in us.(microsecond)
!!! --- WARNING --- !!!
A big value of tm_cost will make tus_cost overflow!
Use this function only when you are sure that tm_cost in eclock
is fairly small!
2147483647/3600000000 ~= 0.6 hour
# define INT32_MIN (-2147483647-1)
# define INT64_MIN (-9223372036854775807LL-1)
# define INT32_MAX (2147483647)
# define INT64_MAX (9223372036854775807LL)
Return:
>=0 OK, time cost in us.
<0 Fails
---------------------------------------------------------*/
long long egi_clock_peekCostUsec(EGI_CLOCK *eclock)
{
struct timeval tm_now;
struct timeval tm_cost;
/* Check status */
if(eclock==NULL)
return -1;
if( !(eclock->status & (ECLOCK_STATUS_RUNNING)) ) {
printf("%s: ECLOCK status error, you can ONLY peek a RUNNING eclock!\n",__func__);
return -2;
}
/* Timersub */
if( gettimeofday(&tm_now, NULL)<0 ) {
egi_dperr("gettimeofday");
return -3;
}
timersub(&tm_now, &eclock->tm_start, &tm_cost);
return 1000000LL*tm_cost.tv_sec+tm_cost.tv_usec;
}