1 /*
2 * Copyright (C) 2022 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * 4. Any redistribution, use, or modification is done solely for
17 * personal benefit and not for any commercial purpose or for
18 * monetary gain.
19 *
20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Please inquire about commercial licensing options at
34 * [email protected]
35 *
36 */
37
38 /*
39 * btstack_run_loop_chibios.c
40 *
41 * Run loop on dedicated thread on FreeRTOS
42 * The run loop is triggered from other task/ISRs either via Event Groups
43 * or Task Notifications if HAVE_FREERTOS_TASK_NOTIFICATIONS is defined
44 */
45
46 #define BTSTACK_FILE__ "btstack_run_loop_chibios.c"
47
48 #include <stddef.h> // NULL
49
50 #include "btstack_run_loop_chibios.h"
51
52 #include "btstack_linked_list.h"
53 #include "btstack_debug.h"
54 #include "btstack_util.h"
55 #include "hal_time_ms.h"
56
57 #include "ch.h"
58
59
60 // main event
61 #define EVT_TRIGGER EVENT_MASK(0)
62
63 // checks, assert that these are enabled
64 // CH_CFG_USE_EVENTS
65 // CH_CFG_USE_EVENTS_TIMEOUT
66
67 static thread_t * btstack_thread;
68 static mutex_t btstack_run_loop_callbacks_mutex;
69
70 // the run loop
71 static bool run_loop_exit_requested;
72
btstack_run_loop_chibios_get_time_ms(void)73 static uint32_t btstack_run_loop_chibios_get_time_ms(void){
74 return (uint32_t) chTimeI2MS(chVTGetSystemTime());
75 }
76
77 // set timer
btstack_run_loop_chibios_set_timer(btstack_timer_source_t * ts,uint32_t timeout_in_ms)78 static void btstack_run_loop_chibios_set_timer(btstack_timer_source_t *ts, uint32_t timeout_in_ms){
79 ts->timeout = btstack_run_loop_chibios_get_time_ms() + timeout_in_ms + 1;
80 }
81
btstack_run_loop_chibios_trigger_from_thread(void)82 static void btstack_run_loop_chibios_trigger_from_thread(void){
83 chEvtSignal(btstack_thread, EVT_TRIGGER);
84 }
85
btstack_run_loop_chibios_poll_data_sources_from_irq(void)86 static void btstack_run_loop_chibios_poll_data_sources_from_irq(void){
87 chSysLockFromISR();
88 chEvtSignalI(btstack_thread, EVT_TRIGGER);
89 chSysUnlockFromISR();
90 }
91
btstack_run_loop_chibios_trigger_exit_internal(void)92 static void btstack_run_loop_chibios_trigger_exit_internal(void){
93 run_loop_exit_requested = true;
94 }
95
96 /**
97 * Execute run_loop
98 */
btstack_run_loop_chibios_execute(void)99 static void btstack_run_loop_chibios_execute(void) {
100 log_debug("RL: execute");
101
102 run_loop_exit_requested = false;
103
104 while (true) {
105
106 // process data sources
107 btstack_run_loop_base_poll_data_sources();
108
109 // execute callbacks - protect list with mutex
110 while (1){
111 chMtxLock(&btstack_run_loop_callbacks_mutex);
112 btstack_context_callback_registration_t * callback_registration = (btstack_context_callback_registration_t *) btstack_linked_list_pop(&btstack_run_loop_base_callbacks);
113 chMtxUnlock(&btstack_run_loop_callbacks_mutex);
114 if (callback_registration == NULL){
115 break;
116 }
117 (*callback_registration->callback)(callback_registration->context);
118 }
119
120 // process timers
121 uint32_t now = btstack_run_loop_chibios_get_time_ms();
122 btstack_run_loop_base_process_timers(now);
123
124 // exit triggered by btstack_run_loop_trigger_exit (main thread or other thread)
125 if (run_loop_exit_requested) break;
126
127 // wait for timeout or event notification
128 int32_t timeout_next_timer_ms = btstack_run_loop_base_get_time_until_timeout(now);
129
130 if (timeout_next_timer_ms > 0){
131 chEvtWaitOneTimeout(EVT_TRIGGER, chTimeMS2I(timeout_next_timer_ms));
132 } else {
133 chEvtWaitOne(EVT_TRIGGER);
134 }
135 }
136 }
137
btstack_run_loop_chibios_execute_on_main_thread(btstack_context_callback_registration_t * callback_registration)138 static void btstack_run_loop_chibios_execute_on_main_thread(btstack_context_callback_registration_t * callback_registration){
139 // protect list with mutex
140 chMtxLock(&btstack_run_loop_callbacks_mutex);
141 btstack_run_loop_base_add_callback(callback_registration);
142 chMtxUnlock(&btstack_run_loop_callbacks_mutex);
143 btstack_run_loop_chibios_trigger_from_thread();
144 }
145
btstack_run_loop_chibios_init(void)146 static void btstack_run_loop_chibios_init(void){
147 btstack_run_loop_base_init();
148 chMtxObjectInit(&btstack_run_loop_callbacks_mutex);
149 btstack_thread = chThdGetSelfX();
150 }
151
152 /**
153 * @brief Provide btstack_run_loop_posix instance for use with btstack_run_loop_init
154 */
155
156 static const btstack_run_loop_t btstack_run_loop_chibios = {
157 &btstack_run_loop_chibios_init,
158 &btstack_run_loop_base_add_data_source,
159 &btstack_run_loop_base_remove_data_source,
160 &btstack_run_loop_base_enable_data_source_callbacks,
161 &btstack_run_loop_base_disable_data_source_callbacks,
162 &btstack_run_loop_chibios_set_timer,
163 &btstack_run_loop_base_add_timer,
164 &btstack_run_loop_base_remove_timer,
165 &btstack_run_loop_chibios_execute,
166 &btstack_run_loop_base_dump_timer,
167 &btstack_run_loop_chibios_get_time_ms,
168 &btstack_run_loop_chibios_poll_data_sources_from_irq,
169 &btstack_run_loop_chibios_execute_on_main_thread,
170 &btstack_run_loop_chibios_trigger_exit_internal,
171 };
172
btstack_run_loop_chibios_get_instance(void)173 const btstack_run_loop_t * btstack_run_loop_chibios_get_instance(void){
174 return &btstack_run_loop_chibios;
175 }
176