08b9a6efb0364a71d7a8f934ad96e64abd5e9f19
[platform/upstream/iotivity.git] / extlibs / timer / timer.c
1 //******************************************************************
2 //
3 // Copyright 2014 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21
22
23 #define _BSD_SOURCE
24
25 #include "iotivity_config.h"
26 #ifdef HAVE_WINDOWS_H
27 #include <windows.h>
28 #endif
29 #ifdef HAVE_PTHREAD_H
30 #include <pthread.h>
31 #endif
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35 #ifdef HAVE_MEMORY_H
36 #include <memory.h>
37 #endif
38 #ifdef HAVE_STDLIB_H
39 #include <stdlib.h>
40 #endif
41 #ifdef HAVE_STRING_H
42 #include <string.h>
43 #endif
44
45 #include <stdio.h>
46
47 #include "timer.h"
48
49 #define SECOND (1)
50
51 #define TIMEOUTS 10
52
53 #define TIMEOUT_USED   1
54 #define TIMEOUT_UNUSED  2
55
56 #ifndef WITH_ARDUINO
57 pthread_t thread_id = 0; // 0: initial thread id (meaningless)
58 #endif
59
60 struct timelist_t
61 {
62     int timeout_state;
63     time_t timeout_seconds;
64     time_t timeout_time;
65     void (*cb)();
66 } timeout_list[TIMEOUTS];
67
68 /*
69  * Return the number of seconds between before and after, (after - before).
70  * This must be async-signal safe, so it cannot use difftime().
71  */
72 time_t timespec_diff(const time_t after, const time_t before)
73 {
74     return after - before;
75 }
76
77 /*
78  * Add positive seconds to a timespec, nothing if seconds is negative.
79  */
80 void timespec_add(time_t * to, const time_t seconds)
81 {
82     if (to && seconds > 0)
83     {
84         (*to) += seconds;
85     }
86 }
87
88 #ifndef WITH_ARDUINO
89
90 long int getSeconds(struct tm* tp)
91 {
92     long int nInterval = 0;
93
94     nInterval = (tp->tm_hour * SECS_PER_HOUR);
95     nInterval += (tp->tm_min * SECS_PER_MIN);
96     nInterval += (tp->tm_sec * SECOND);
97
98     printf("%ld", nInterval);
99
100     return nInterval;
101 }
102
103 long int getRelativeSecondsOfDayofweek(int ia, int ib)
104 {
105     if( ia > ib )
106         return (((long int)(7 - (ib - ia))) * SECS_PER_DAY);
107
108     return (((long int)((ib - ia))) * SECS_PER_DAY);
109 }
110
111 long int getRelativeIntervalOfWeek(struct tm* tp)
112 {
113     time_t current_time;
114     struct tm* current, *midnight;
115     time_t delayed_time = 0;
116
117     time(&current_time);
118     current = localtime(&current_time);
119
120     if(current == NULL)
121     {
122         printf("ERROR; Getting local time fails\n");
123         return 0;
124     }
125
126     midnight = (struct tm* )malloc(sizeof(struct tm));
127
128     if(midnight == NULL)
129     {
130         printf("ERROR; Memory allocation fails\n");
131         return 0;
132     }
133
134     memcpy(midnight, current, sizeof(struct tm));
135
136     midnight->tm_hour = 0;
137     midnight->tm_min = 0;
138     midnight->tm_sec = 0;
139
140     // Seconds.
141     // Seconds from midnight.
142     delayed_time = current_time - mktime(midnight);
143     delayed_time = getRelativeSecondsOfDayofweek(current->tm_wday, tp->tm_wday) - delayed_time;
144     delayed_time = delayed_time + getSeconds(tp);
145
146     free(midnight);
147
148     return delayed_time;
149 }
150
151 long int getSecondsFromAbsTime(struct tm* tp)
152 {
153    time_t current_time;
154    time_t delayed_time = 0;
155
156    time(&current_time);
157    localtime(&current_time);
158
159    delayed_time = mktime(tp) - current_time;
160
161    return delayed_time;
162 }
163
164 time_t registerTimer(const time_t seconds, int *id, void *cb)
165 {
166     time_t now, then;
167     time_t next;
168     int i, idx;
169
170     if (0 == thread_id)
171     {
172         initThread();
173     }
174
175     if (seconds <= 0)
176         return -1 ;
177
178     // get the current time
179     time(&now);
180
181     for (idx = 0; idx < TIMEOUTS; ++idx)
182         if (!((timeout_list[idx].timeout_state & TIMEOUT_USED) & TIMEOUT_USED))
183             break;
184
185     if (TIMEOUTS == idx) // reach to end of timer list
186         return -1;
187
188     // idx th timeout will be used.
189     // Reset and set state of the timer
190     timeout_list[idx].timeout_state = 0;
191     timeout_list[idx].timeout_state |= TIMEOUT_USED;
192
193     // calculate when the timeout should fire
194     then = now;
195     timespec_add(&then, seconds);
196
197     timeout_list[idx].timeout_time = then;
198     timeout_list[idx].timeout_seconds = seconds;
199
200     // printf( "\nbefore timeout_list[idx].cb = %X\n", timeout_list[idx].cb);
201     timeout_list[idx].cb = cb;
202     // printf( " after timeout_list[idx].cb = %X\n", timeout_list[idx].cb);
203
204     // How long till the next timeout?
205     next = seconds;
206     for (i = 0; i < TIMEOUTS; i++)
207     {
208         if ((timeout_list[i].timeout_state & (TIMEOUT_USED | TIMEOUT_UNUSED)) == TIMEOUT_USED)
209         {
210             const time_t secs = timespec_diff(timeout_list[i].timeout_time, now);
211
212             if (secs >= 0 && secs < next)
213                 next = secs;
214         }
215     }
216
217     *id = idx;
218     /* Return the timeout number. */
219     return timeout_list[idx].timeout_time;
220 }
221
222 void unregisterTimer(int idx)
223 {
224     if( 0 <= idx && idx < TIMEOUTS)
225         timeout_list[idx].timeout_state = TIMEOUT_UNUSED;
226 }
227
228 void checkTimeout()
229 {
230     time_t now;
231     int i;
232
233     time(&now);
234
235     /* Check all timeouts that are used and armed, but not passed yet. */
236     for (i = 0; i < TIMEOUTS; i++)
237     {
238         if ((timeout_list[i].timeout_state & (TIMEOUT_USED | TIMEOUT_UNUSED)) == TIMEOUT_USED)
239         {
240             const time_t seconds = timespec_diff(timeout_list[i].timeout_time, now);
241
242             if (seconds <= 0)
243             {
244                 /* timeout [i] fires! */
245                 timeout_list[i].timeout_state = TIMEOUT_UNUSED;
246                 if (timeout_list[i].cb)
247                 {
248                     timeout_list[i].cb();
249                 }
250             }
251         }
252     }
253 }
254
255 void *loop(void *threadid)
256 {
257     (void)threadid;
258     while (1)
259     {
260         sleep(SECOND);
261         checkTimeout();
262     }
263
264     return NULL ;
265 }
266
267 int initThread()
268 {
269     int res = pthread_create(&thread_id, NULL, loop, NULL);
270
271     if (res)
272     {
273         printf("ERROR; return code from pthread_create() is %d\n", res);
274         return -1;
275     }
276
277     return 0;
278 }
279 #else   // WITH_ARDUINO
280 time_t timeToSecondsFromNow(tmElements_t *t_then)
281 {
282     time_t t, then;
283
284     t = now();
285     then = makeTime((*t_then));
286
287     return (time_t) (then - t);
288 }
289
290 time_t registerTimer(const time_t seconds, int *id,  void (*cb)())
291 {
292     time_t t, then;
293     time_t next;
294     int i, idx;
295
296     if (seconds <= 0)
297     return -1;
298
299     // get the current time
300     t = now();
301
302     for (idx = 0; idx < TIMEOUTS; ++idx)
303     if (!((timeout_list[idx].timeout_state & TIMEOUT_USED) & TIMEOUT_USED))
304     break;
305
306     if (TIMEOUTS == idx)// reach to end of timer list
307     return -1;
308
309     // idx th timeout will be used.
310     // Reset and set state of the timer
311     timeout_list[idx].timeout_state = 0;
312     timeout_list[idx].timeout_state |= TIMEOUT_USED;
313
314     // calculate when the timeout should fire
315     then = t;
316     timespec_add(&then, seconds);
317
318     timeout_list[idx].timeout_time = then;
319     timeout_list[idx].timeout_seconds = seconds;
320
321     // printf( "\nbefore timeout_list[idx].cb = %X\n", timeout_list[idx].cb);
322     timeout_list[idx].cb = cb;
323     // printf( " after timeout_list[idx].cb = %X\n", timeout_list[idx].cb);
324
325     // How long till the next timeout?
326     next = seconds;
327     for (i = 0; i < TIMEOUTS; i++)
328     {
329         if ((timeout_list[i].timeout_state & (TIMEOUT_USED | TIMEOUT_UNUSED))
330                 == TIMEOUT_USED)
331         {
332             const time_t secs = timespec_diff(timeout_list[i].timeout_time,
333                     t);
334
335             if (secs >= 0 && secs < next)
336             next = secs;
337         }
338     }
339
340     *id = idx;
341     /* Return the timeout number. */
342     return timeout_list[idx].timeout_time;
343 }
344
345 void unregisterTimer(int idx)
346 {
347     if( 0 <= idx && idx < TIMEOUTS)
348         timeout_list[idx].timeout_state = TIMEOUT_UNUSED;
349 }
350
351 void checkTimeout()
352 {
353     time_t t;
354     int i;
355
356     t = now();
357
358     /* Check all timeouts that are used and armed, but not passed yet. */
359     for (i = 0; i < TIMEOUTS; i++)
360     {
361         if ((timeout_list[i].timeout_state & (TIMEOUT_USED | TIMEOUT_UNUSED))
362                 == TIMEOUT_USED)
363         {
364             const time_t seconds = timespec_diff(timeout_list[i].timeout_time,
365                     t);
366
367             if (seconds <= 0)
368             {
369                 /* timeout [i] fires! */
370                 timeout_list[i].timeout_state = TIMEOUT_UNUSED;
371                 if (timeout_list[i].cb)
372                 {
373                     timeout_list[i].cb();
374                 }
375             }
376         }
377     }
378 }
379
380 #endif