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