mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-26 02:37:41 +00:00
226 lines
7.8 KiB
C
226 lines
7.8 KiB
C
/*
|
|
* Copyright (c) 2016 Nordic Semiconductor ASA
|
|
* Copyright (c) 2015-2016 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
//#include <errno.h>
|
|
//#include <stddef.h>
|
|
//#include <stdio.h>
|
|
//#include <string.h>
|
|
|
|
// Zephyr
|
|
#include <zephyr/kernel.h>
|
|
|
|
// BTstack
|
|
#include "btstack_debug.h"
|
|
#include "btstack_run_loop_zephyr.h"
|
|
|
|
#define SIGNAL_POLL (0xCA11)
|
|
#define SIGNAL_EXEC (0xE8EC)
|
|
|
|
#define NUM_EVENTS 10
|
|
|
|
static struct k_poll_event events[NUM_EVENTS];
|
|
static btstack_data_source_t *data_sources[NUM_EVENTS];
|
|
|
|
bool btstack_run_loop_zephyr_exit_requested = false;
|
|
bool btstack_run_loop_zephyr_data_sources_modified = false;
|
|
|
|
/**
|
|
* Add data_source to run_loop
|
|
*/
|
|
static void btstack_run_loop_zephyr_add_data_source(btstack_data_source_t *ds){
|
|
btstack_run_loop_zephyr_data_sources_modified = true;
|
|
btstack_run_loop_base_add_data_source(ds);
|
|
}
|
|
|
|
/**
|
|
* Remove data_source from run loop
|
|
*/
|
|
static bool btstack_run_loop_zephyr_remove_data_source(btstack_data_source_t *ds){
|
|
btstack_run_loop_zephyr_data_sources_modified = true;
|
|
return btstack_run_loop_base_remove_data_source(ds);
|
|
}
|
|
|
|
// TODO: handle 32 bit ms time overrun
|
|
static uint32_t btstack_run_loop_zephyr_get_time_ms(void){
|
|
return k_uptime_get_32();
|
|
}
|
|
|
|
static void btstack_run_loop_zephyr_set_timer(btstack_timer_source_t *ts, uint32_t timeout_in_ms){
|
|
ts->timeout = k_uptime_get_32() + 1 + timeout_in_ms;
|
|
}
|
|
|
|
static struct k_poll_signal signal;
|
|
static fat_variable_t signal_variable = { .variable = &signal, .id = K_POLL_TYPE_SIGNAL };
|
|
static btstack_data_source_t signal_data_source;
|
|
|
|
static void btstack_run_loop_zephyr_signal( int value ) {
|
|
k_poll_signal_raise(&signal, value);
|
|
}
|
|
|
|
static K_MUTEX_DEFINE(btstack_run_loop_zephyr_callbacks_mutex);
|
|
|
|
static void btstack_run_loop_zephyr_signal_handler(
|
|
btstack_data_source_t * ds,
|
|
btstack_data_source_callback_type_t callback_type ) {
|
|
int signaled, result;
|
|
k_poll_signal_check(&signal, &signaled, &result);
|
|
k_poll_signal_reset(&signal);
|
|
if( !signaled ) {
|
|
return;
|
|
}
|
|
log_debug("%s( %x )", __func__, result );
|
|
switch( result ) {
|
|
case SIGNAL_POLL:
|
|
btstack_run_loop_base_poll_data_sources();
|
|
break;
|
|
case SIGNAL_EXEC:
|
|
for (;;){
|
|
k_mutex_lock(&btstack_run_loop_zephyr_callbacks_mutex, K_FOREVER);
|
|
btstack_context_callback_registration_t * callback_registration = (btstack_context_callback_registration_t *) btstack_linked_list_pop(&btstack_run_loop_base_callbacks);
|
|
k_mutex_unlock(&btstack_run_loop_zephyr_callbacks_mutex);
|
|
if (callback_registration == NULL){
|
|
break;
|
|
}
|
|
(*callback_registration->callback)(callback_registration->context);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef ENABLE_LOG_DEBUG
|
|
#define STR(x) #x
|
|
static const char *event_state_to_text[] = {
|
|
[K_POLL_STATE_SEM_AVAILABLE] = STR(K_POLL_STATE_SEM_AVAILABLE),
|
|
[K_POLL_STATE_FIFO_DATA_AVAILABLE] = STR(K_POLL_STATE_FIFO_DATA_AVAILABLE),
|
|
[K_POLL_STATE_MSGQ_DATA_AVAILABLE] = STR(K_POLL_STATE_MSGQ_DATA_AVAILABLE),
|
|
[K_POLL_STATE_PIPE_DATA_AVAILABLE] = STR(K_POLL_STATE_PIPE_DATA_AVAILABLE),
|
|
[K_POLL_STATE_SIGNALED] = STR(K_POLL_STATE_SIGNALED),
|
|
};
|
|
|
|
static const char *event_type_to_text[] = {
|
|
[K_POLL_TYPE_SEM_AVAILABLE] = STR(K_POLL_TYPE_SEM_AVAILABLE),
|
|
[K_POLL_TYPE_FIFO_DATA_AVAILABLE] = STR(K_POLL_TYPE_FIFO_DATA_AVAILABLE),
|
|
[K_POLL_TYPE_MSGQ_DATA_AVAILABLE] = STR(K_POLL_TYPE_MSGQ_DATA_AVAILABLE),
|
|
[K_POLL_TYPE_PIPE_DATA_AVAILABLE] = STR(K_POLL_TYPE_PIPE_DATA_AVAILABLE),
|
|
[K_POLL_TYPE_SIGNAL] = STR(K_POLL_TYPE_SIGNAL),
|
|
};
|
|
#endif
|
|
|
|
/**
|
|
* Execute run_loop
|
|
*/
|
|
static void btstack_run_loop_zephyr_execute(void) {
|
|
btstack_linked_list_iterator_t it;
|
|
btstack_run_loop_zephyr_exit_requested = false;
|
|
|
|
k_poll_signal_init( &signal );
|
|
|
|
btstack_data_source_t *ds = &signal_data_source;
|
|
btstack_run_loop_set_data_source_handle(ds, &signal_variable);
|
|
btstack_run_loop_set_data_source_handler(ds, &btstack_run_loop_zephyr_signal_handler);
|
|
btstack_run_loop_add_data_source(ds);
|
|
btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
|
|
|
|
const uint32_t state_mask =
|
|
K_POLL_STATE_SEM_AVAILABLE |
|
|
K_POLL_STATE_FIFO_DATA_AVAILABLE |
|
|
K_POLL_STATE_MSGQ_DATA_AVAILABLE |
|
|
K_POLL_STATE_PIPE_DATA_AVAILABLE |
|
|
K_POLL_STATE_SIGNALED;
|
|
|
|
for (;btstack_run_loop_zephyr_exit_requested!=true;) {
|
|
// process timers
|
|
uint32_t now = k_uptime_get_32();
|
|
btstack_run_loop_base_process_timers(now);
|
|
|
|
btstack_linked_list_iterator_init(&it, &btstack_run_loop_base_data_sources);
|
|
int nbr_events = 0;
|
|
while( btstack_linked_list_iterator_has_next(&it) && (nbr_events<NUM_EVENTS) ) {
|
|
btstack_data_source_t *ds = (btstack_data_source_t*) btstack_linked_list_iterator_next(&it);
|
|
fat_variable_t *fat = (fat_variable_t*)ds->source.handle;
|
|
int current_event = nbr_events++;
|
|
log_debug("arm [%d] %s", current_event, event_type_to_text[fat->id]);
|
|
k_poll_event_init( &events[current_event],
|
|
fat->id,
|
|
K_POLL_MODE_NOTIFY_ONLY,
|
|
fat->variable);
|
|
data_sources[current_event] = ds;
|
|
}
|
|
// get time until next timer expires
|
|
int32_t timeout_ms = btstack_run_loop_base_get_time_until_timeout(now);
|
|
k_timeout_t timeout = K_MSEC(timeout_ms);
|
|
if (timeout_ms < 0){
|
|
timeout = K_FOREVER;
|
|
}
|
|
int rc = k_poll(events, nbr_events, timeout);
|
|
if( btstack_run_loop_zephyr_exit_requested ) {
|
|
return;
|
|
}
|
|
// handle timeouts on -EAGAIN
|
|
if( rc != 0 ) {
|
|
continue;
|
|
}
|
|
for( int i=0; i<nbr_events; ++i ) {
|
|
uint32_t state = events[i].state;
|
|
if((state & state_mask) > 0) {
|
|
log_debug("trigger [%d] %s", i, event_state_to_text[state]);
|
|
btstack_data_source_t *ds = data_sources[i];
|
|
ds->process(ds, DATA_SOURCE_CALLBACK_READ);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void btstack_run_loop_zephyr_execute_on_main_thread(btstack_context_callback_registration_t * callback_registration){
|
|
// protect list with mutex
|
|
k_mutex_lock(&btstack_run_loop_zephyr_callbacks_mutex, K_FOREVER);
|
|
btstack_run_loop_base_add_callback(callback_registration);
|
|
k_mutex_unlock(&btstack_run_loop_zephyr_callbacks_mutex);
|
|
// trigger run loop
|
|
btstack_run_loop_zephyr_signal( SIGNAL_EXEC );
|
|
}
|
|
|
|
static void btstack_run_loop_zephyr_btstack_run_loop_init(void){
|
|
btstack_run_loop_base_init();
|
|
}
|
|
|
|
static void btstack_run_loop_zephyr_poll_data_sources_from_irq(void) {
|
|
btstack_run_loop_zephyr_signal( SIGNAL_POLL );
|
|
}
|
|
|
|
static void btstack_run_loop_zephyr_trigger_exit(void) {
|
|
btstack_run_loop_zephyr_exit_requested = true;
|
|
btstack_run_loop_zephyr_signal( SIGNAL_POLL );
|
|
}
|
|
|
|
static const btstack_run_loop_t btstack_run_loop_zephyr = {
|
|
&btstack_run_loop_zephyr_btstack_run_loop_init,
|
|
&btstack_run_loop_zephyr_add_data_source,
|
|
&btstack_run_loop_zephyr_remove_data_source,
|
|
&btstack_run_loop_base_enable_data_source_callbacks,
|
|
&btstack_run_loop_base_disable_data_source_callbacks,
|
|
&btstack_run_loop_zephyr_set_timer,
|
|
&btstack_run_loop_base_add_timer,
|
|
&btstack_run_loop_base_remove_timer,
|
|
&btstack_run_loop_zephyr_execute,
|
|
&btstack_run_loop_base_dump_timer,
|
|
&btstack_run_loop_zephyr_get_time_ms,
|
|
&btstack_run_loop_zephyr_poll_data_sources_from_irq,
|
|
&btstack_run_loop_zephyr_execute_on_main_thread,
|
|
&btstack_run_loop_zephyr_trigger_exit,
|
|
};
|
|
/**
|
|
* @brief Provide btstack_run_loop_zephyr instance for use with btstack_run_loop_init
|
|
*/
|
|
const btstack_run_loop_t * btstack_run_loop_zephyr_get_instance(void){
|
|
return &btstack_run_loop_zephyr;
|
|
}
|
|
|