Imported Upstream version 0.9.1
[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 #ifndef WITH_ARDUINO
26 #include <pthread.h>
27 #include <unistd.h>
28 #include <memory.h>
29 #include <stdlib.h>
30 #endif
31
32 #include <string.h>
33 #include <stdio.h>
34
35 #include "timer.h"
36
37 #define SECOND (1)
38
39 #define TIMEOUTS 10
40
41 #define TIMEOUT_USED   1
42 #define TIMEOUT_UNUSED  2
43
44 #ifndef WITH_ARDUINO
45 pthread_t thread_id = 0; // 0: initial thread id (meaningless)
46 #endif
47
48 struct timelist_t
49 {
50     int timeout_state;
51     time_t timeout_seconds;
52     time_t timeout_time;
53     void (*cb)();
54 } timeout_list[TIMEOUTS];
55
56 /*
57  * Return the number of seconds between before and after, (after - before).
58  * This must be async-signal safe, so it cannot use difftime().
59  */
60 time_t timespec_diff(const time_t after, const time_t before)
61 {
62     return after - before;
63 }
64
65 /*
66  * Add positive seconds to a timespec, nothing if seconds is negative.
67  */
68 void timespec_add(time_t * to, const time_t seconds)
69 {
70     if (to && seconds > 0)
71     {
72         (*to) += seconds;
73     }
74 }
75
76 #ifndef WITH_ARDUINO
77
78 long int getSeconds(struct tm* tp)
79 {
80     long int nInterval = 0;
81
82     nInterval = (tp->tm_hour * SECS_PER_HOUR);
83     nInterval += (tp->tm_min * SECS_PER_MIN);
84     nInterval += (tp->tm_sec * SECOND);
85
86     printf("%ld", nInterval);
87
88     return nInterval;
89 }
90
91 long int getRelativeSecondsOfDayofweek(int ia, int ib)
92 {
93     if( ia > ib )
94         return (((long int)(7 - (ib - ia))) * SECS_PER_DAY);
95
96     return (((long int)((ib - ia))) * SECS_PER_DAY);
97 }
98
99 long int getRelativeIntervalOfWeek(struct tm* tp)
100 {
101     time_t current_time;
102     struct tm* current, *midnight;
103     time_t delayed_time = 0;
104
105     time(&current_time);
106     current = localtime(&current_time);
107     midnight = (struct tm* )malloc(sizeof(struct tm));
108     memcpy(midnight, current, sizeof(struct tm));
109
110     midnight->tm_hour = 0;
111     midnight->tm_min = 0;
112     midnight->tm_sec = 0;
113
114     // Seconds.
115     // Seconds from midnight.
116     delayed_time = current_time - mktime(midnight);
117     delayed_time = getRelativeSecondsOfDayofweek(current->tm_wday, tp->tm_wday) - delayed_time;
118     delayed_time = delayed_time + getSeconds(tp);
119
120     return delayed_time;
121 }
122
123 long int getSecondsFromAbsTime(struct tm* tp)
124 {
125    time_t current_time;
126    time_t delayed_time = 0;
127
128    time(&current_time);
129    localtime(&current_time);
130
131    delayed_time = mktime(tp) - current_time;
132
133    return delayed_time;
134 }
135
136 time_t registerTimer(const time_t seconds, int *id, void *cb)
137 {
138     time_t now, then;
139     time_t next;
140     int i, idx;
141
142     if (0 == thread_id)
143     {
144         initThread();
145     }
146
147     if (seconds <= 0)
148         return -1 ;
149
150     // get the current time
151     time(&now);
152
153     for (idx = 0; idx < TIMEOUTS; ++idx)
154         if (!((timeout_list[idx].timeout_state & TIMEOUT_USED) & TIMEOUT_USED))
155             break;
156
157     if (TIMEOUTS == idx) // reach to end of timer list
158         return -1;
159
160     // idx th timeout will be used.
161     // Reset and set state of the timer
162     timeout_list[idx].timeout_state = 0;
163     timeout_list[idx].timeout_state |= TIMEOUT_USED;
164
165     // calculate when the timeout should fire
166     then = now;
167     timespec_add(&then, seconds);
168
169     timeout_list[idx].timeout_time = then;
170     timeout_list[idx].timeout_seconds = seconds;
171
172     // printf( "\nbefore timeout_list[idx].cb = %X\n", timeout_list[idx].cb);
173     timeout_list[idx].cb = cb;
174     // printf( " after timeout_list[idx].cb = %X\n", timeout_list[idx].cb);
175
176     // How long till the next timeout?
177     next = seconds;
178     for (i = 0; i < TIMEOUTS; i++)
179     {
180         if ((timeout_list[i].timeout_state & (TIMEOUT_USED | TIMEOUT_UNUSED)) == TIMEOUT_USED)
181         {
182             const time_t secs = timespec_diff(timeout_list[i].timeout_time, now);
183
184             if (secs >= 0 && secs < next)
185                 next = secs;
186         }
187     }
188
189     *id = idx;
190     /* Return the timeout number. */
191     return timeout_list[idx].timeout_time;
192 }
193
194 void unregisterTimer(int idx)
195 {
196     if( 0 <= idx && idx <= TIMEOUTS)
197         timeout_list[idx].timeout_state = TIMEOUT_UNUSED;
198 }
199
200 void checkTimeout()
201 {
202     time_t now;
203     int i;
204
205     time(&now);
206
207     /* Check all timeouts that are used and armed, but not passed yet. */
208     for (i = 0; i < TIMEOUTS; i++)
209     {
210         if ((timeout_list[i].timeout_state & (TIMEOUT_USED | TIMEOUT_UNUSED)) == TIMEOUT_USED)
211         {
212             const time_t seconds = timespec_diff(timeout_list[i].timeout_time, now);
213
214             if (seconds <= 0)
215             {
216                 /* timeout [i] fires! */
217                 timeout_list[i].timeout_state = TIMEOUT_UNUSED;
218                 if (timeout_list[i].cb)
219                 {
220                     timeout_list[i].cb();
221                 }
222             }
223         }
224     }
225 }
226
227 void *loop(void *threadid)
228 {
229     while (1)
230     {
231         sleep(SECOND);
232         checkTimeout();
233     }
234
235     return NULL ;
236 }
237
238 int initThread()
239 {
240     int res;
241     long t = 0;
242
243     res = pthread_create(&thread_id, NULL, loop, (void *) t);
244
245     if (res)
246     {
247         printf("ERROR; return code from pthread_create() is %d\n", res);
248         return -1;
249     }
250
251     return 0;
252 }
253 #else   // WITH_ARDUINO
254 time_t timeToSecondsFromNow(tmElements_t *t_then)
255 {
256     time_t t, then;
257
258     t = now();
259     then = makeTime((*t_then));
260
261     return (time_t) (then - t);
262 }
263
264 time_t registerTimer(const time_t seconds, int *id,  void (*cb)())
265 {
266     time_t t, then;
267     time_t next;
268     int i, idx;
269
270     if (seconds <= 0)
271     return -1;
272
273     // get the current time
274     t = now();
275
276     for (idx = 0; idx < TIMEOUTS; ++idx)
277     if (!((timeout_list[idx].timeout_state & TIMEOUT_USED) & TIMEOUT_USED))
278     break;
279
280     if (TIMEOUTS == idx)// reach to end of timer list
281     return -1;
282
283     // idx th timeout will be used.
284     // Reset and set state of the timer
285     timeout_list[idx].timeout_state = 0;
286     timeout_list[idx].timeout_state |= TIMEOUT_USED;
287
288     // calculate when the timeout should fire
289     then = t;
290     timespec_add(&then, seconds);
291
292     timeout_list[idx].timeout_time = then;
293     timeout_list[idx].timeout_seconds = seconds;
294
295     // printf( "\nbefore timeout_list[idx].cb = %X\n", timeout_list[idx].cb);
296     timeout_list[idx].cb = cb;
297     // printf( " after timeout_list[idx].cb = %X\n", timeout_list[idx].cb);
298
299     // How long till the next timeout?
300     next = seconds;
301     for (i = 0; i < TIMEOUTS; i++)
302     {
303         if ((timeout_list[i].timeout_state & (TIMEOUT_USED | TIMEOUT_UNUSED))
304                 == TIMEOUT_USED)
305         {
306             const time_t secs = timespec_diff(timeout_list[i].timeout_time,
307                     t);
308
309             if (secs >= 0 && secs < next)
310             next = secs;
311         }
312     }
313
314     *id = idx;
315     /* Return the timeout number. */
316     return timeout_list[idx].timeout_time;
317 }
318
319 void unregisterTimer(int idx)
320 {
321     if( 0 <= idx && idx <= TIMEOUTS)
322         timeout_list[idx].timeout_state = TIMEOUT_UNUSED;
323 }
324
325 void checkTimeout()
326 {
327     time_t t;
328     int i;
329
330     t = now();
331
332     /* Check all timeouts that are used and armed, but not passed yet. */
333     for (i = 0; i < TIMEOUTS; i++)
334     {
335         if ((timeout_list[i].timeout_state & (TIMEOUT_USED | TIMEOUT_UNUSED))
336                 == TIMEOUT_USED)
337         {
338             const time_t seconds = timespec_diff(timeout_list[i].timeout_time,
339                     t);
340
341             if (seconds <= 0)
342             {
343                 /* timeout [i] fires! */
344                 timeout_list[i].timeout_state = TIMEOUT_UNUSED;
345                 if (timeout_list[i].cb)
346                 {
347                     timeout_list[i].cb();
348                 }
349             }
350         }
351     }
352 }
353
354 #endif