btstack/platform/zephyr/btstack_run_loop_zephyr.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;
}