mirror of
https://github.com/mudita/MuditaOS.git
synced 2026-01-16 01:48:42 -05:00
187 lines
5.7 KiB
C++
187 lines
5.7 KiB
C++
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
|
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
|
|
|
#include "BluetoothRunLoop.hpp"
|
|
#include "btstack_util.h"
|
|
#include <log/log.hpp>
|
|
#include <cassert>
|
|
|
|
namespace bluetooth
|
|
{
|
|
QueueHandle_t RunLoop::btstackRunLoopQueue;
|
|
TaskHandle_t RunLoop::btstackRunLoopTask;
|
|
QueueHandle_t RunLoop::triggerQueue;
|
|
TimerHandle_t RunLoop::btstackTimer = nullptr;
|
|
btstack_linked_list_t RunLoop::timers;
|
|
btstack_linked_list_t RunLoop::dataSources;
|
|
bool RunLoop::runLoopExitRequested;
|
|
|
|
bool RunLoop::removeTimer(btstack_timer_source_t *timerSource)
|
|
{
|
|
return btstack_linked_list_remove(&timers, reinterpret_cast<btstack_linked_item_t *>(timerSource));
|
|
}
|
|
|
|
void RunLoop::setTriggerQueue(QueueHandle_t queue)
|
|
{
|
|
assert(queue != nullptr);
|
|
triggerQueue = queue;
|
|
}
|
|
|
|
void RunLoop::deinit()
|
|
{
|
|
vQueueDelete(btstackRunLoopQueue);
|
|
xTimerDelete(btstackTimer, 0);
|
|
}
|
|
|
|
void RunLoop::init()
|
|
{
|
|
timers = nullptr;
|
|
btstackRunLoopQueue = xQueueCreate(runLoopQueueLength, runLoopQueueItemSize);
|
|
|
|
// Task to handle to optimize 'run on main thread'
|
|
btstackRunLoopTask = xTaskGetCurrentTaskHandle();
|
|
|
|
LOG_INFO("Run loop init, task %p, queue item size %zu", btstackRunLoopTask, sizeof(FunctionCallType));
|
|
}
|
|
|
|
void RunLoop::enableDataSourceCallbacks(btstack_data_source_t *dataSource, std::uint16_t callbackTypes)
|
|
{
|
|
dataSource->flags |= callbackTypes;
|
|
}
|
|
|
|
void RunLoop::disableDataSourceCallbacks(btstack_data_source_t *dataSource, std::uint16_t callbackTypes)
|
|
{
|
|
dataSource->flags &= ~callbackTypes;
|
|
}
|
|
|
|
void RunLoop::addDataSource(btstack_data_source_t *dataSource)
|
|
{
|
|
btstack_linked_list_add(&dataSources, reinterpret_cast<btstack_linked_item_t *>(dataSource));
|
|
}
|
|
|
|
auto RunLoop::removeDataSource(btstack_data_source_t *dataSource) -> bool
|
|
{
|
|
return btstack_linked_list_remove(&dataSources, reinterpret_cast<btstack_linked_item_t *>(dataSource));
|
|
}
|
|
|
|
void RunLoop::triggerExit()
|
|
{
|
|
runLoopExitRequested = true;
|
|
}
|
|
|
|
auto RunLoop::getTimeMs() -> TickType_t
|
|
{
|
|
return xTaskGetTickCount();
|
|
}
|
|
|
|
void RunLoop::trigger()
|
|
{
|
|
bool trigger = true;
|
|
if (triggerQueue != nullptr) {
|
|
xQueueSend(triggerQueue, &trigger, 0);
|
|
}
|
|
else {
|
|
LOG_FATAL("Trigger queue does not exist!");
|
|
}
|
|
}
|
|
|
|
void RunLoop::addTimer(btstack_timer_source_t *timerSource)
|
|
{
|
|
btstack_linked_item_t *it = nullptr;
|
|
for (it = reinterpret_cast<btstack_linked_item_t *>(&timers); it->next != nullptr; it = it->next) {
|
|
// Don't add timer that's already in there
|
|
auto next = reinterpret_cast<btstack_timer_source_t *>(it->next);
|
|
if (next == timerSource) {
|
|
LOG_ERROR("Timer 'btstack_run_loop_timer' already in list!");
|
|
return;
|
|
}
|
|
|
|
// Exit if new timeout before list timeout
|
|
const auto delta = btstack_time_delta(timerSource->timeout, next->timeout);
|
|
if (delta < 0) {
|
|
break;
|
|
}
|
|
}
|
|
timerSource->item.next = it->next;
|
|
it->next = reinterpret_cast<btstack_linked_item_t *>(timerSource);
|
|
trigger();
|
|
}
|
|
|
|
void RunLoop::setTimer(btstack_timer_source_t *timerSource, std::uint32_t timeoutMs)
|
|
{
|
|
timerSource->timeout = getTimeMs() + timeoutMs + 1;
|
|
trigger();
|
|
}
|
|
|
|
void RunLoop::triggerCallback([[maybe_unused]] TimerHandle_t xTimer)
|
|
{
|
|
trigger();
|
|
}
|
|
|
|
void RunLoop::start()
|
|
{
|
|
if (btstackTimer == nullptr) {
|
|
btstackTimer =
|
|
xTimerCreate("BTStackTimer", pdMS_TO_TICKS(defaultTimerPeriodMs), pdTRUE, nullptr, triggerCallback);
|
|
xTimerStart(btstackTimer, 0);
|
|
}
|
|
}
|
|
|
|
auto RunLoop::process() -> bool
|
|
{
|
|
// Process registered function calls on run loop thread
|
|
while (true) {
|
|
FunctionCallType message = {nullptr, nullptr};
|
|
const auto res = xQueueReceive(btstackRunLoopQueue, &message, 0);
|
|
if (res == pdFALSE) {
|
|
break;
|
|
}
|
|
if (message.fn != nullptr) {
|
|
message.fn(message.arg);
|
|
}
|
|
}
|
|
|
|
// Process timers and get next timeout
|
|
std::uint32_t timeoutMs = defaultTimerPeriodMs;
|
|
while (timers != nullptr) {
|
|
auto timerSource = reinterpret_cast<btstack_timer_source_t *>(timers);
|
|
const auto now = getTimeMs();
|
|
const auto deltaMs = btstack_time_delta(timerSource->timeout, now);
|
|
if (deltaMs > 0) {
|
|
timeoutMs = deltaMs;
|
|
break;
|
|
}
|
|
|
|
// Remove timer before processing it to allow handler to re-register with run loop
|
|
removeTimer(timerSource);
|
|
timerSource->process(timerSource);
|
|
}
|
|
|
|
// Exit triggered by btstack_run_loop_freertos_trigger_exit (from data source, timer, run on main thread)
|
|
if (runLoopExitRequested) {
|
|
return true;
|
|
}
|
|
|
|
xTimerChangePeriod(btstackTimer, pdMS_TO_TICKS(timeoutMs), 0);
|
|
return false;
|
|
}
|
|
|
|
auto RunLoop::getRunLoopInstance() -> btstack_run_loop *
|
|
{
|
|
runLoop = btstack_run_loop{
|
|
&init,
|
|
&addDataSource,
|
|
&removeDataSource,
|
|
&enableDataSourceCallbacks,
|
|
&disableDataSourceCallbacks,
|
|
&setTimer,
|
|
&addTimer,
|
|
&removeTimer,
|
|
&start,
|
|
nullptr,
|
|
&getTimeMs,
|
|
};
|
|
return &runLoop;
|
|
}
|
|
} // namespace bluetooth
|