xref: /btstack/platform/qt/btstack_run_loop_qt.cpp (revision 1b464e99afd70ddaf6b75be1ba7cc563a5f5dfd8)
1*1b464e99SMatthias Ringwald /*
2*1b464e99SMatthias Ringwald  * Copyright (C) 2019 BlueKitchen GmbH
3*1b464e99SMatthias Ringwald  *
4*1b464e99SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*1b464e99SMatthias Ringwald  * modification, are permitted provided that the following conditions
6*1b464e99SMatthias Ringwald  * are met:
7*1b464e99SMatthias Ringwald  *
8*1b464e99SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*1b464e99SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*1b464e99SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*1b464e99SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*1b464e99SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*1b464e99SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*1b464e99SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*1b464e99SMatthias Ringwald  *    from this software without specific prior written permission.
16*1b464e99SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*1b464e99SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*1b464e99SMatthias Ringwald  *    monetary gain.
19*1b464e99SMatthias Ringwald  *
20*1b464e99SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*1b464e99SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*1b464e99SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*1b464e99SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*1b464e99SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*1b464e99SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*1b464e99SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*1b464e99SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*1b464e99SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*1b464e99SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*1b464e99SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*1b464e99SMatthias Ringwald  * SUCH DAMAGE.
32*1b464e99SMatthias Ringwald  *
33*1b464e99SMatthias Ringwald  * Please inquire about commercial licensing options at
34*1b464e99SMatthias Ringwald  * [email protected]
35*1b464e99SMatthias Ringwald  *
36*1b464e99SMatthias Ringwald  */
37*1b464e99SMatthias Ringwald 
38*1b464e99SMatthias Ringwald #define BTSTACK_FILE__ "btstack_run_loop_qt.c"
39*1b464e99SMatthias Ringwald 
40*1b464e99SMatthias Ringwald /*
41*1b464e99SMatthias Ringwald  *  btstack_run_loop_qt.c
42*1b464e99SMatthias Ringwald  */
43*1b464e99SMatthias Ringwald 
44*1b464e99SMatthias Ringwald // enable POSIX functions (needed for -std=c99)
45*1b464e99SMatthias Ringwald #define _POSIX_C_SOURCE 200809
46*1b464e99SMatthias Ringwald 
47*1b464e99SMatthias Ringwald #include "btstack_run_loop_qt.h"
48*1b464e99SMatthias Ringwald 
49*1b464e99SMatthias Ringwald #include "btstack_run_loop.h"
50*1b464e99SMatthias Ringwald #include "btstack_run_loop_base.h"
51*1b464e99SMatthias Ringwald #include "btstack_util.h"
52*1b464e99SMatthias Ringwald #include "btstack_linked_list.h"
53*1b464e99SMatthias Ringwald #include "btstack_debug.h"
54*1b464e99SMatthias Ringwald 
55*1b464e99SMatthias Ringwald #include <stdio.h>
56*1b464e99SMatthias Ringwald #include <stdlib.h>
57*1b464e99SMatthias Ringwald #include <sys/select.h>
58*1b464e99SMatthias Ringwald #include <sys/time.h>
59*1b464e99SMatthias Ringwald #include <time.h>
60*1b464e99SMatthias Ringwald #include <unistd.h>
61*1b464e99SMatthias Ringwald 
62*1b464e99SMatthias Ringwald static void btstack_run_loop_qt_dump_timer(void);
63*1b464e99SMatthias Ringwald 
64*1b464e99SMatthias Ringwald // start time. tv_usec/tv_nsec = 0
65*1b464e99SMatthias Ringwald #ifdef _POSIX_MONOTONIC_CLOCK
66*1b464e99SMatthias Ringwald // use monotonic clock if available
67*1b464e99SMatthias Ringwald static struct timespec init_ts;
68*1b464e99SMatthias Ringwald #else
69*1b464e99SMatthias Ringwald // fallback to gettimeofday
70*1b464e99SMatthias Ringwald static struct timeval init_tv;
71*1b464e99SMatthias Ringwald #endif
72*1b464e99SMatthias Ringwald 
73*1b464e99SMatthias Ringwald static BTstackRunLoopQt * btstack_run_loop_object;
74*1b464e99SMatthias Ringwald 
75*1b464e99SMatthias Ringwald #ifdef _POSIX_MONOTONIC_CLOCK
76*1b464e99SMatthias Ringwald /**
77*1b464e99SMatthias Ringwald  * @brief Returns the timespec which represents the time(stop - start). It might be negative
78*1b464e99SMatthias Ringwald  */
79*1b464e99SMatthias Ringwald static void timespec_diff(struct timespec *start, struct timespec *stop, struct timespec *result){
80*1b464e99SMatthias Ringwald     result->tv_sec = stop->tv_sec - start->tv_sec;
81*1b464e99SMatthias Ringwald     if ((stop->tv_nsec - start->tv_nsec) < 0) {
82*1b464e99SMatthias Ringwald         result->tv_sec = stop->tv_sec - start->tv_sec - 1;
83*1b464e99SMatthias Ringwald         result->tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000;
84*1b464e99SMatthias Ringwald     } else {
85*1b464e99SMatthias Ringwald         result->tv_sec = stop->tv_sec - start->tv_sec;
86*1b464e99SMatthias Ringwald         result->tv_nsec = stop->tv_nsec - start->tv_nsec;
87*1b464e99SMatthias Ringwald     }
88*1b464e99SMatthias Ringwald }
89*1b464e99SMatthias Ringwald 
90*1b464e99SMatthias Ringwald /**
91*1b464e99SMatthias Ringwald  * @brief Convert timespec to miliseconds, might overflow
92*1b464e99SMatthias Ringwald  */
93*1b464e99SMatthias Ringwald static uint64_t timespec_to_milliseconds(struct timespec *a){
94*1b464e99SMatthias Ringwald     uint64_t ret = 0;
95*1b464e99SMatthias Ringwald     uint64_t sec_val = (uint64_t)(a->tv_sec);
96*1b464e99SMatthias Ringwald     uint64_t nsec_val = (uint64_t)(a->tv_nsec);
97*1b464e99SMatthias Ringwald     ret = (sec_val*1000) + (nsec_val/1000000);
98*1b464e99SMatthias Ringwald     return ret;
99*1b464e99SMatthias Ringwald }
100*1b464e99SMatthias Ringwald 
101*1b464e99SMatthias Ringwald /**
102*1b464e99SMatthias Ringwald  * @brief Returns the milisecond value of (stop - start). Might overflow
103*1b464e99SMatthias Ringwald  */
104*1b464e99SMatthias Ringwald static uint64_t timespec_diff_milis(struct timespec* start, struct timespec* stop){
105*1b464e99SMatthias Ringwald     struct timespec diff_ts;
106*1b464e99SMatthias Ringwald     timespec_diff(start, stop, &diff_ts);
107*1b464e99SMatthias Ringwald     return timespec_to_milliseconds(&diff_ts);
108*1b464e99SMatthias Ringwald }
109*1b464e99SMatthias Ringwald #endif
110*1b464e99SMatthias Ringwald 
111*1b464e99SMatthias Ringwald /**
112*1b464e99SMatthias Ringwald  * @brief Queries the current time in ms since start
113*1b464e99SMatthias Ringwald  */
114*1b464e99SMatthias Ringwald static uint32_t btstack_run_loop_qt_get_time_ms(void){
115*1b464e99SMatthias Ringwald     uint32_t time_ms;
116*1b464e99SMatthias Ringwald #ifdef _POSIX_MONOTONIC_CLOCK
117*1b464e99SMatthias Ringwald     struct timespec now_ts;
118*1b464e99SMatthias Ringwald     clock_gettime(CLOCK_MONOTONIC, &now_ts);
119*1b464e99SMatthias Ringwald     time_ms = (uint32_t) timespec_diff_milis(&init_ts, &now_ts);
120*1b464e99SMatthias Ringwald #else
121*1b464e99SMatthias Ringwald     struct timeval tv;
122*1b464e99SMatthias Ringwald     gettimeofday(&tv, NULL);
123*1b464e99SMatthias Ringwald     time_ms = (uint32_t) ((tv.tv_sec  - init_tv.tv_sec) * 1000) + (tv.tv_usec / 1000);
124*1b464e99SMatthias Ringwald #endif
125*1b464e99SMatthias Ringwald     return time_ms;
126*1b464e99SMatthias Ringwald }
127*1b464e99SMatthias Ringwald 
128*1b464e99SMatthias Ringwald /**
129*1b464e99SMatthias Ringwald  * Execute run_loop
130*1b464e99SMatthias Ringwald  */
131*1b464e99SMatthias Ringwald static void btstack_run_loop_qt_execute(void) {
132*1b464e99SMatthias Ringwald }
133*1b464e99SMatthias Ringwald 
134*1b464e99SMatthias Ringwald // set timer
135*1b464e99SMatthias Ringwald static void btstack_run_loop_qt_set_timer(btstack_timer_source_t *a, uint32_t timeout_in_ms){
136*1b464e99SMatthias Ringwald     uint32_t time_ms = btstack_run_loop_qt_get_time_ms();
137*1b464e99SMatthias Ringwald     a->timeout = time_ms + timeout_in_ms;
138*1b464e99SMatthias Ringwald     log_debug("btstack_run_loop_qt_set_timer to %u ms (now %u, timeout %u)", a->timeout, time_ms, timeout_in_ms);
139*1b464e99SMatthias Ringwald }
140*1b464e99SMatthias Ringwald 
141*1b464e99SMatthias Ringwald /**
142*1b464e99SMatthias Ringwald  * Add timer to run_loop (keep list sorted)
143*1b464e99SMatthias Ringwald  */
144*1b464e99SMatthias Ringwald static void btstack_run_loop_qt_add_timer(btstack_timer_source_t *ts){
145*1b464e99SMatthias Ringwald     uint32_t now = btstack_run_loop_qt_get_time_ms();
146*1b464e99SMatthias Ringwald     int32_t next_timeout_before = btstack_run_loop_base_get_time_until_timeout(now);
147*1b464e99SMatthias Ringwald     btstack_run_loop_base_add_timer(ts);
148*1b464e99SMatthias Ringwald     int32_t next_timeout_after = btstack_run_loop_base_get_time_until_timeout(now);
149*1b464e99SMatthias Ringwald     if (next_timeout_after >= 0 && (next_timeout_after != next_timeout_before)){
150*1b464e99SMatthias Ringwald         QTimer::singleShot((uint32_t)next_timeout_after, btstack_run_loop_object, SLOT(processTimers()));
151*1b464e99SMatthias Ringwald     }
152*1b464e99SMatthias Ringwald }
153*1b464e99SMatthias Ringwald 
154*1b464e99SMatthias Ringwald // BTstackRunLoopQt class implementation
155*1b464e99SMatthias Ringwald void BTstackRunLoopQt::processTimers(){
156*1b464e99SMatthias Ringwald     uint32_t now = btstack_run_loop_qt_get_time_ms();
157*1b464e99SMatthias Ringwald     int32_t next_timeout_before = btstack_run_loop_base_get_time_until_timeout(now);
158*1b464e99SMatthias Ringwald     btstack_run_loop_base_process_timers(btstack_run_loop_qt_get_time_ms());
159*1b464e99SMatthias Ringwald     int32_t next_timeout_after = btstack_run_loop_base_get_time_until_timeout(now);
160*1b464e99SMatthias Ringwald     if (next_timeout_after >= 0 && (next_timeout_after != next_timeout_before)){
161*1b464e99SMatthias Ringwald         QTimer::singleShot((uint32_t)next_timeout_after, this, SLOT(processTimers()));
162*1b464e99SMatthias Ringwald     }
163*1b464e99SMatthias Ringwald }
164*1b464e99SMatthias Ringwald 
165*1b464e99SMatthias Ringwald static void btstack_run_loop_qt_init(void){
166*1b464e99SMatthias Ringwald 
167*1b464e99SMatthias Ringwald     btstack_run_loop_base_init();
168*1b464e99SMatthias Ringwald 
169*1b464e99SMatthias Ringwald     btstack_run_loop_object = new BTstackRunLoopQt();
170*1b464e99SMatthias Ringwald 
171*1b464e99SMatthias Ringwald #ifdef _POSIX_MONOTONIC_CLOCK
172*1b464e99SMatthias Ringwald     clock_gettime(CLOCK_MONOTONIC, &init_ts);
173*1b464e99SMatthias Ringwald     init_ts.tv_nsec = 0;
174*1b464e99SMatthias Ringwald #else
175*1b464e99SMatthias Ringwald     // just assume that we started at tv_usec == 0
176*1b464e99SMatthias Ringwald     gettimeofday(&init_tv, NULL);
177*1b464e99SMatthias Ringwald     init_tv.tv_usec = 0;
178*1b464e99SMatthias Ringwald #endif
179*1b464e99SMatthias Ringwald }
180*1b464e99SMatthias Ringwald 
181*1b464e99SMatthias Ringwald static void btstack_run_loop_qt_dump_timer(void){
182*1b464e99SMatthias Ringwald     btstack_linked_item_t *it;
183*1b464e99SMatthias Ringwald     int i = 0;
184*1b464e99SMatthias Ringwald     for (it = (btstack_linked_item_t *) btstack_run_loop_base_timers; it ; it = it->next){
185*1b464e99SMatthias Ringwald         btstack_timer_source_t *ts = (btstack_timer_source_t*) it;
186*1b464e99SMatthias Ringwald         log_info("timer %u (%p): timeout %u\n", i, ts, ts->timeout);
187*1b464e99SMatthias Ringwald     }
188*1b464e99SMatthias Ringwald }
189*1b464e99SMatthias Ringwald 
190*1b464e99SMatthias Ringwald static const btstack_run_loop_t btstack_run_loop_qt = {
191*1b464e99SMatthias Ringwald     &btstack_run_loop_qt_init,
192*1b464e99SMatthias Ringwald     &btstack_run_loop_base_add_data_source,
193*1b464e99SMatthias Ringwald     &btstack_run_loop_base_remove_data_source,
194*1b464e99SMatthias Ringwald     &btstack_run_loop_base_enable_data_source_callbacks,
195*1b464e99SMatthias Ringwald     &btstack_run_loop_base_disable_data_source_callbacks,
196*1b464e99SMatthias Ringwald     &btstack_run_loop_qt_set_timer,
197*1b464e99SMatthias Ringwald     &btstack_run_loop_qt_add_timer,
198*1b464e99SMatthias Ringwald     &btstack_run_loop_base_remove_timer,
199*1b464e99SMatthias Ringwald     &btstack_run_loop_qt_execute,
200*1b464e99SMatthias Ringwald     &btstack_run_loop_qt_dump_timer,
201*1b464e99SMatthias Ringwald     &btstack_run_loop_qt_get_time_ms,
202*1b464e99SMatthias Ringwald };
203*1b464e99SMatthias Ringwald 
204*1b464e99SMatthias Ringwald /**
205*1b464e99SMatthias Ringwald  * Provide btstack_run_loop_posix instance
206*1b464e99SMatthias Ringwald  */
207*1b464e99SMatthias Ringwald const btstack_run_loop_t * btstack_run_loop_qt_get_instance(void){
208*1b464e99SMatthias Ringwald     return &btstack_run_loop_qt;
209*1b464e99SMatthias Ringwald }
210*1b464e99SMatthias Ringwald 
211