~aleteoryx/muditaos

ref: 25a5d90f4e12ee5d33f4202170f18b59e16a9564 muditaos/module-bluetooth/Bluetooth/glucode/BluetoothRunLoop.cpp -rw-r--r-- 6.0 KiB
25a5d90f — rrandomsky [CP-2156] Fixed no response when editing a contact to have the same number as another 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// Copyright (c) 2017-2023, 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 <cassert>
namespace bluetooth
{

    btstack_linked_list_t RunLoop::timers;
    btstack_linked_list_t RunLoop::data_sources;
    bool RunLoop::run_loop_exit_requested;

    QueueHandle_t RunLoop::btstack_run_loop_queue;
    TaskHandle_t RunLoop::btstack_run_loop_task;
    QueueHandle_t RunLoop::triggerQueue;
    TimerHandle_t RunLoop::testTimer = nullptr;

    auto RunLoop::removeTimer(btstack_timer_source_t *ts) -> bool
    {
        return btstack_linked_list_remove(&timers, reinterpret_cast<btstack_linked_item_t *>(ts));
    }
    void RunLoop::setTriggerQueue(QueueHandle_t queue)
    {
        assert(queue != nullptr);
        triggerQueue = queue;
    }
    void RunLoop::deinit()
    {
        vQueueDelete(btstack_run_loop_queue);
        xTimerDelete(testTimer, 0);
    }
    void RunLoop::init()
    {
        timers                 = nullptr;
        btstack_run_loop_queue = xQueueCreate(RUN_LOOP_QUEUE_LENGTH, RUN_LOOP_QUEUE_ITEM_SIZE);

        // task to handle to optimize 'run on main thread'
        btstack_run_loop_task = xTaskGetCurrentTaskHandle();

        LOG_INFO("Run loop init, task %p, queue item size %u",
                 btstack_run_loop_task,
                 static_cast<int>(sizeof(function_call_t)));
    }
    void RunLoop::enableDataSourceCallbacks(btstack_data_source_t *ds, uint16_t callback_types)
    {
        ds->flags |= callback_types;
    }

    void RunLoop::disableDataSourceCallbacks(btstack_data_source_t *ds, uint16_t callback_types)
    {
        ds->flags &= ~callback_types;
    }

    void RunLoop::addDataSource(btstack_data_source_t *ds)
    {
        btstack_linked_list_add(&data_sources, (btstack_linked_item_t *)ds);
    }

    auto RunLoop::removeDataSource(btstack_data_source_t *ds) -> bool
    {
        return btstack_linked_list_remove(&data_sources, (btstack_linked_item_t *)ds);
    }
    void RunLoop::triggerExit()
    {
        run_loop_exit_requested = 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::executeCodeOnMainThread(void (*fn)(void *arg), void *arg)
    {

        // directly call function if already on btstack task
        if (xTaskGetCurrentTaskHandle() == btstack_run_loop_task) {
            (*fn)(arg);
            return;
        }

        function_call_t message;
        message.fn     = fn;
        message.arg    = arg;
        BaseType_t res = xQueueSendToBack(btstack_run_loop_queue, &message, 0); // portMAX_DELAY);
        if (res != pdTRUE) {
            LOG_ERROR("Failed to post fn %p", fn);
        }
        trigger();
    }

    void RunLoop::addTimer(btstack_timer_source_t *ts)
    {
        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 == ts) {
                LOG_ERROR("Timer 'btstack_run_loop_timer' already in list!");
                return;
            }
            // exit if new timeout before list timeout
            int32_t delta = btstack_time_delta(ts->timeout, next->timeout);
            if (delta < 0) {
                break;
            }
        }
        ts->item.next = it->next;
        it->next      = reinterpret_cast<btstack_linked_item_t *>(ts);
        trigger();
    }
    void RunLoop::setTimer(btstack_timer_source_t *ts, uint32_t timeout_in_ms)
    {
        ts->timeout = getTimeMs() + timeout_in_ms + 1;
        trigger();
    }
    void RunLoop::triggerCallback(TimerHandle_t xTimer)
    {
        trigger();
    }
    void RunLoop::start()
    {
        if (testTimer == nullptr) {
            testTimer = xTimerCreate("TestTimer", pdMS_TO_TICKS(1000), pdTRUE, nullptr, triggerCallback);
            xTimerStart(testTimer, 0);
        }
    }
    auto RunLoop::process() -> bool
    {
        // process registered function calls on run loop thread
        while (true) {
            function_call_t message = {nullptr, nullptr};
            BaseType_t res          = xQueueReceive(btstack_run_loop_queue, &message, 0);
            if (res == pdFALSE) {
                break;
            }
            if (message.fn != nullptr) {
                message.fn(message.arg);
            }
        }

        // process timers and get next timeout
        uint32_t timeout_ms = 1000;
        while (timers != nullptr) {
            auto *ts         = reinterpret_cast<btstack_timer_source_t *>(timers);
            uint32_t now     = getTimeMs();
            int32_t delta_ms = btstack_time_delta(ts->timeout, now);
            if (delta_ms > 0) {
                timeout_ms = delta_ms;
                break;
            }
            // remove timer before processing it to allow handler to re-register with run loop
            removeTimer(ts);
            ts->process(ts);
        }

        // exit triggered by btstack_run_loop_freertos_trigger_exit (from data source, timer, run on main thread)
        if (run_loop_exit_requested) {
            return true;
        }

        xTimerChangePeriod(testTimer, pdMS_TO_TICKS(timeout_ms), 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