ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
nimble_npl_threadx.c
Go to the documentation of this file.
1
34
35#include "nimble_npl_threadx.h"
36
37#include <stdint.h>
38#include <string.h>
39
41#include "ra8_attributes.h"
42#include "tx_api.h"
43
44/* =============================================================================
45 * NPL public API forward decls (matches upstream nimble/nimble_npl.h)
46 * =============================================================================
47 */
48
49/* =============================================================================
50 * Generic helpers
51 * =============================================================================
52 */
53
63
87
88/* =============================================================================
89 * Mutex
90 * =============================================================================
91 */
92
93/* Initialise an NPL mutex -- see implementation for details. */
94ble_npl_error_t ble_npl_mutex_init(struct ble_npl_mutex* mu)
95{
96 if (mu == nullptr) {
97 return BLE_NPL_INVALID_PARAM;
98 }
100 static CHAR s_name[] = {'n', 'p', 'l', '_', 'm', 'u', '\0'};
101 const UINT st = tx_mutex_create(&mu->handle, s_name, TX_NO_INHERIT);
102 return (st == TX_SUCCESS) ? BLE_NPL_OK : BLE_NPL_ERROR;
103}
104
105/* Pend on an NPL mutex with timeout -- see implementation for details. */
106ble_npl_error_t ble_npl_mutex_pend(struct ble_npl_mutex* mu, ble_npl_time_t timeout)
107{
108 if (mu == nullptr) {
109 return BLE_NPL_INVALID_PARAM;
110 }
111 const UINT st = tx_mutex_get(&mu->handle, internal_tmo_to_tx(timeout));
112 if (st == TX_SUCCESS) {
113 return BLE_NPL_OK;
114 }
115 return (st == TX_NOT_AVAILABLE) ? BLE_NPL_TIMEOUT : BLE_NPL_ERROR;
116}
117
118/* Release an NPL mutex -- see implementation for details. */
119ble_npl_error_t ble_npl_mutex_release(struct ble_npl_mutex* mu)
120{
121 if (mu == nullptr) {
122 return BLE_NPL_INVALID_PARAM;
123 }
124 const UINT st = tx_mutex_put(&mu->handle);
125 return (st == TX_SUCCESS) ? BLE_NPL_OK : BLE_NPL_ERROR;
126}
127
128/* =============================================================================
129 * Semaphore
130 * =============================================================================
131 */
132
133/* Initialise an NPL counting semaphore -- see implementation for details. */
134ble_npl_error_t ble_npl_sem_init(struct ble_npl_sem* sem, uint16_t tokens)
135{
136 if (sem == nullptr) {
137 return BLE_NPL_INVALID_PARAM;
138 }
140 static CHAR s_name[] = {'n', 'p', 'l', '_', 's', 'e', 'm', '\0'};
141 const UINT st = tx_semaphore_create(&sem->handle, s_name, (ULONG)tokens);
142 return (st == TX_SUCCESS) ? BLE_NPL_OK : BLE_NPL_ERROR;
143}
144
145/* Pend on an NPL semaphore -- see implementation for details. */
146ble_npl_error_t ble_npl_sem_pend(struct ble_npl_sem* sem, ble_npl_time_t timeout)
147{
148 if (sem == nullptr) {
149 return BLE_NPL_INVALID_PARAM;
150 }
151 const UINT st = tx_semaphore_get(&sem->handle, internal_tmo_to_tx(timeout));
152 if (st == TX_SUCCESS) {
153 return BLE_NPL_OK;
154 }
155 return (st == TX_NO_INSTANCE) ? BLE_NPL_TIMEOUT : BLE_NPL_ERROR;
156}
157
158/* Release a token back into an NPL semaphore -- see implementation for details. */
159ble_npl_error_t ble_npl_sem_release(struct ble_npl_sem* sem)
160{
161 if (sem == nullptr) {
162 return BLE_NPL_INVALID_PARAM;
163 }
164 const UINT st = tx_semaphore_put(&sem->handle);
165 return (st == TX_SUCCESS) ? BLE_NPL_OK : BLE_NPL_ERROR;
166}
167
168/* Read the current token count of an NPL semaphore -- see implementation for details. */
170{
171 if (sem == nullptr) {
172 return 0U;
173 }
174 ULONG current = 0U;
175 (void)tx_semaphore_info_get(&sem->handle, nullptr, &current, nullptr, nullptr, nullptr);
176 return (uint16_t)current;
177}
178
179/* =============================================================================
180 * Event + event queue
181 * =============================================================================
182 */
183
184/* Initialise an NPL event -- see implementation for details. */
185void ble_npl_event_init(struct ble_npl_event* ev, ble_npl_event_fn* fn, void* arg)
186{
187 if (ev == nullptr) {
188 return;
189 }
190 (void)memset(ev, 0, sizeof(*ev));
191 ev->fn = fn;
192 ev->arg = arg;
193}
194
195/* Initialise an NPL event queue -- see implementation for details. */
197{
198 if (evq == nullptr) {
199 return;
200 }
201 (void)memset(evq, 0, sizeof(*evq));
203 static CHAR s_name[] = {'n', 'p', 'l', '_', 'e', 'v', 'q', '\0'};
204 (void)tx_queue_create(&evq->q, s_name, TX_1_ULONG, evq->storage, (ULONG)sizeof(evq->storage));
205}
206
221{
222 if (evq == nullptr) {
223 return nullptr;
224 }
225 ULONG slot = 0U;
226 if (tx_queue_receive(&evq->q, &slot, internal_tmo_to_tx(tmo)) != TX_SUCCESS) {
227 return nullptr;
228 }
229 struct ble_npl_event* ev = (struct ble_npl_event*)(uintptr_t)slot;
230 if (ev != nullptr) {
231 ev->queued = 0U;
232 }
233 return ev;
234}
235
236/* Post an event into an NPL event queue (idempotent) -- see implementation for details. */
238{
239 if (evq == nullptr || ev == nullptr) {
240 return;
241 }
242 if (ev->queued != 0U) {
243 return;
244 }
245 ev->queued = 1U;
246 ULONG slot = (ULONG)(uintptr_t)ev;
247 (void)tx_queue_send(&evq->q, &slot, TX_NO_WAIT);
248}
249
250/* Best-effort removal of an event from a queue -- see implementation for details. */
252{
253 (void)evq;
254 if (ev == nullptr) {
255 return;
256 }
257 ev->queued = 0U;
258}
259
260/* Run an NPL event by invoking its callback -- see implementation for details. */
262{
263 if (ev == nullptr || ev->fn == nullptr) {
264 return;
265 }
266 ev->fn(ev);
267}
268
269/* Test whether an event is currently queued -- see implementation for details. */
271{
272 return (ev != nullptr) && (ev->queued != 0U);
273}
274
287{
288 return (ev == nullptr) ? nullptr : ev->arg;
289}
290
291/* Replace the user-arg pointer attached to an event -- see implementation for details. */
293{
294 if (ev != nullptr) {
295 ev->arg = arg;
296 }
297}
298
299/* True when the event queue is empty -- see implementation for details. */
301{
302 if (evq == nullptr) {
303 return true;
304 }
305 ULONG enqueued = 0U;
306 if (tx_queue_info_get(&evq->q, nullptr, &enqueued, nullptr, nullptr, nullptr, nullptr) !=
307 TX_SUCCESS) {
308 return true;
309 }
310 return enqueued == 0U;
311}
312
313/* =============================================================================
314 * Callout (one-shot timer that posts an event)
315 * =============================================================================
316 */
317
334{
335 struct ble_npl_callout* co = (struct ble_npl_callout*)(uintptr_t)arg;
336 if (co == nullptr) {
337 return;
338 }
339 ble_npl_eventq_put(co->evq, &co->ev);
340}
341
342/* Initialise an NPL callout (does not start it) -- see implementation for details. */
344 struct ble_npl_eventq* evq,
345 ble_npl_event_fn* ev_cb,
346 void* ev_arg)
347{
348 if (co == nullptr) {
349 return;
350 }
351 (void)memset(co, 0, sizeof(*co));
352 co->evq = evq;
353 co->ev.fn = ev_cb;
354 co->ev.arg = ev_arg;
356 static CHAR s_name[] = {'n', 'p', 'l', '_', 'c', 'o', '\0'};
357 (void)tx_timer_create(&co->handle,
358 s_name,
360 (ULONG)(uintptr_t)co,
361 1U, /* initial-ticks (placeholder, reset on arm) */
362 0U, /* reschedule-ticks (one-shot) */
363 TX_NO_ACTIVATE);
364}
365
366/* Arm the callout to fire ``ticks`` from now -- see implementation for details. */
367ble_npl_error_t ble_npl_callout_reset(struct ble_npl_callout* co, ble_npl_time_t ticks)
368{
369 if (co == nullptr) {
370 return BLE_NPL_INVALID_PARAM;
371 }
372 if (ticks == 0U) {
373 ticks = 1U;
374 }
375 (void)tx_timer_deactivate(&co->handle);
376 (void)tx_timer_change(&co->handle, (ULONG)ticks, 0U);
377 const UINT st = tx_timer_activate(&co->handle);
378 return (st == TX_SUCCESS) ? BLE_NPL_OK : BLE_NPL_ERROR;
379}
380
381/* Stop the callout if it is armed -- see implementation for details. */
383{
384 if (co == nullptr) {
385 return;
386 }
387 (void)tx_timer_deactivate(&co->handle);
388}
389
390/* Test whether the callout is armed -- see implementation for details. */
392{
393 if (co == nullptr) {
394 return false;
395 }
396 UINT active = 0U;
397 if (tx_timer_info_get(&co->handle, nullptr, &active, nullptr, nullptr, nullptr) != TX_SUCCESS) {
398 return false;
399 }
400 return active != 0U;
401}
402
403/* Replace the callout's event arg pointer -- see implementation for details. */
404void ble_npl_callout_set_arg(struct ble_npl_callout* co, void* arg)
405{
406 if (co != nullptr) {
407 co->ev.arg = arg;
408 }
409}
410
411/* =============================================================================
412 * Time
413 * =============================================================================
414 */
415
416/* Read the kernel tick counter -- see implementation for details. */
421
422/* Convert ms to NPL ticks (lossless when tick == 1 ms) -- see implementation for details. */
423ble_npl_error_t ble_npl_time_ms_to_ticks(uint32_t ms, ble_npl_time_t* out_ticks)
424{
425 if (out_ticks == nullptr) {
426 return BLE_NPL_INVALID_PARAM;
427 }
428 /* Project tick rate is 1000 Hz -> 1 tick == 1 ms. */
429 *out_ticks = (ble_npl_time_t)ms;
430 return BLE_NPL_OK;
431}
432
433/* Convert NPL ticks to ms -- see implementation for details. */
434ble_npl_error_t ble_npl_time_ticks_to_ms(ble_npl_time_t ticks, uint32_t* out_ms)
435{
436 if (out_ms == nullptr) {
437 return BLE_NPL_INVALID_PARAM;
438 }
439 *out_ms = (uint32_t)ticks;
440 return BLE_NPL_OK;
441}
442
443/* Sleep for the given number of NPL ticks -- see implementation for details. */
445{
446 (void)tx_thread_sleep((ULONG)ticks);
447}
448
449/* =============================================================================
450 * Critical section
451 * =============================================================================
452 */
453
454/* Enter a critical section by disabling interrupts -- see implementation for details. */
456{
457 return (uint32_t)tx_interrupt_control(TX_INT_DISABLE);
458}
459
460/* Exit a critical section, restoring the previous int mask -- see implementation for details. */
461void ble_npl_hw_exit_critical(uint32_t ctx)
462{
463 (void)tx_interrupt_control((UINT)ctx);
464}
465
485{
486 return false;
487}
488
489/* =============================================================================
490 * NimBLE port + transport stubs
491 * =============================================================================
492 *
493 * These provide minimal definitions so the example app and the
494 * companion `ble_hci_ra8_ble.c` link without pulling the heavyweight
495 * upstream NimBLE host TUs into this curated build. When the host
496 * stack is later wired in (Phase 1.4 / 1.5), these stubs are
497 * superseded by the upstream symbols.
498 */
499
507
509static uint8_t s_dflt_eventq_ready = 0U;
510
511/* Bring the default eventq up -- see implementation for details. */
513{
514 if (s_dflt_eventq_ready == 0U) {
517 }
518}
519
531{
532 return &s_dflt_eventq;
533}
534
551{
552 while (1) {
553 struct ble_npl_event* ev =
555 if (ev != nullptr) {
557 }
558 }
559}
560
561/* =============================================================================
562 * NimBLE transport allocator stubs
563 * =============================================================================
564 *
565 * These are deliberately minimal: the curated build does not pull in
566 * the upstream nimble/transport object library yet, but
567 * `ble_hci_ra8_ble.c` references ``ble_transport_alloc_evt`` /
568 * ``ble_transport_alloc_acl_from_ll`` / ``ble_transport_to_hs_evt``
569 * / ``ble_transport_to_hs_acl`` / ``ble_transport_free`` /
570 * ``os_mbuf_*``. We provide weak no-op definitions so the demo app
571 * links; once the host stack lands these are replaced by the real
572 * symbols at link time (the linker prefers strong over weak).
573 */
574
575[[gnu::weak]] void* ble_transport_alloc_evt(int discardable)
576{
577 (void)discardable;
578 return nullptr;
579}
580
581[[gnu::weak]] struct os_mbuf* ble_transport_alloc_acl_from_ll(void)
582{
583 return nullptr;
584}
585
586[[gnu::weak]] void ble_transport_free(void* buf)
587{
588 (void)buf;
589}
590
591[[gnu::weak]] int ble_transport_to_hs_evt(void* buf)
592{
593 (void)buf;
594 return 0;
595}
596
597[[gnu::weak]] int ble_transport_to_hs_acl(struct os_mbuf* om)
598{
599 (void)om;
600 return 0;
601}
602
603[[gnu::weak]] int os_mbuf_append(struct os_mbuf* om, const void* data, uint16_t len)
604{
605 (void)om;
606 (void)data;
607 (void)len;
608 return 0;
609}
610
611[[gnu::weak]] int os_mbuf_free_chain(struct os_mbuf* om)
612{
613 (void)om;
614 return 0;
615}
616
617[[gnu::weak]] uint16_t os_mbuf_len(const struct os_mbuf* om)
618{
619 (void)om;
620 return 0U;
621}
622
623[[gnu::weak]] int os_mbuf_copydata(const struct os_mbuf* om, int off, int len, void* dst)
624{
625 (void)om;
626 (void)off;
627 (void)len;
628 (void)dst;
629 return 0;
630}
631
632[[gnu::weak]] int ble_transport_to_ll_cmd(void* buf)
633{
635}
636
637[[gnu::weak]] int ble_transport_to_ll_acl(struct os_mbuf* om)
638{
640}
#define nullptr
uint32_t ble_npl_time_t
Tick-count type used by the NPL.
void ble_npl_event_set_arg(struct ble_npl_event *ev, void *arg)
struct ble_npl_eventq * nimble_port_get_dflt_eventq(void)
Return the address of the default eventq.
ble_npl_time_t ble_npl_time_get(void)
void ble_npl_eventq_remove(struct ble_npl_eventq *evq, struct ble_npl_event *ev)
static struct ble_npl_eventq s_dflt_eventq
Default eventq used by the host stack.
bool ble_npl_hw_is_in_critical(void)
Test whether the calling context is inside a critical section.
struct ble_npl_event * ble_npl_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo)
Wait for an event from an NPL event queue.
static ULONG internal_tmo_to_tx(ble_npl_time_t tmo)
Translate an NPL timeout into a ThreadX wait code.
ble_npl_error_t ble_npl_time_ms_to_ticks(uint32_t ms, ble_npl_time_t *out_ticks)
void ble_npl_callout_set_arg(struct ble_npl_callout *co, void *arg)
int ble_transport_to_hs_acl(struct os_mbuf *om)
Push an ACL packet up to the host stack.
void nimble_port_run(void)
Run the NimBLE host event loop forever.
void * ble_npl_event_get_arg(struct ble_npl_event *ev)
Read the user-arg pointer attached to an event.
void nimble_port_init(void)
Bring the NimBLE host port up.
void ble_npl_callout_stop(struct ble_npl_callout *co)
void ble_npl_hw_exit_critical(uint32_t ctx)
static uint8_t s_dflt_eventq_ready
Initialized flag for the default eventq.
int os_mbuf_free_chain(struct os_mbuf *om)
Free every mbuf in a chain.
void ble_npl_event_init(struct ble_npl_event *ev, ble_npl_event_fn *fn, void *arg)
void ble_transport_free(void *buf)
Release a buffer obtained from ble_transport_alloc_evt().
ble_npl_error_t ble_npl_mutex_pend(struct ble_npl_mutex *mu, ble_npl_time_t timeout)
uint16_t os_mbuf_len(const struct os_mbuf *om)
Total payload length of an mbuf chain.
void ble_npl_callout_init(struct ble_npl_callout *co, struct ble_npl_eventq *evq, ble_npl_event_fn *ev_cb, void *ev_arg)
int ble_transport_to_ll_cmd(void *buf)
Host-to-controller HCI command entry point.
bool ble_npl_event_is_queued(struct ble_npl_event *ev)
int ble_transport_to_ll_acl(struct os_mbuf *om)
Host-to-controller ACL entry point.
int os_mbuf_copydata(const struct os_mbuf *om, int off, int len, void *dst)
Copy a byte range out of an mbuf chain.
void ble_npl_eventq_put(struct ble_npl_eventq *evq, struct ble_npl_event *ev)
ble_npl_error_t ble_npl_sem_init(struct ble_npl_sem *sem, uint16_t tokens)
void ble_npl_eventq_init(struct ble_npl_eventq *evq)
uint32_t ble_npl_hw_enter_critical(void)
void ble_npl_time_delay(ble_npl_time_t ticks)
ble_npl_error_t ble_npl_sem_pend(struct ble_npl_sem *sem, ble_npl_time_t timeout)
ble_npl_error_t ble_npl_time_ticks_to_ms(ble_npl_time_t ticks, uint32_t *out_ms)
int os_mbuf_append(struct os_mbuf *om, const void *data, uint16_t len)
Append bytes to an mbuf chain (upstream os_mbuf.h).
static void internal_callout_trampoline(ULONG arg)
Post a callout event from the ThreadX timer trampoline.
int ble_transport_to_hs_evt(void *buf)
Push an HCI event up to the host stack.
void * ble_transport_alloc_evt(int discardable)
Allocate an HCI event buffer (upstream ble_transport.h).
struct os_mbuf * ble_transport_alloc_acl_from_ll(void)
Allocate an ACL mbuf for the LL-to-host direction.
bool ble_npl_callout_is_active(struct ble_npl_callout *co)
void ble_npl_event_run(struct ble_npl_event *ev)
uint16_t ble_npl_sem_get_count(struct ble_npl_sem *sem)
ble_npl_error_t ble_npl_sem_release(struct ble_npl_sem *sem)
bool ble_npl_eventq_is_empty(struct ble_npl_eventq *evq)
ble_npl_error_t ble_npl_mutex_init(struct ble_npl_mutex *mu)
ble_npl_error_t ble_npl_mutex_release(struct ble_npl_mutex *mu)
ble_npl_threadx_const_t
Local sizing/timeout constants.
@ k_ble_npl_tx_wait_forever
TX_WAIT_FOREVER literal.
@ k_ble_npl_tx_no_wait
TX_NO_WAIT literal.
@ k_ble_npl_ms_per_sec
Helper: ms / second.
ble_npl_error_t ble_npl_callout_reset(struct ble_npl_callout *co, ble_npl_time_t ticks)
NimBLE Native Porting Layer mapping onto Eclipse ThreadX.
@ k_ble_npl_threadx_wait_forever
Wait forever – maps onto TX_WAIT_FOREVER.
Weak link stubs standing in for the NimBLE transport core.
int ble_transport_to_ll_cmd_impl(void *buf)
Controller-side handler for an HCI command from the host.
int ble_transport_to_ll_acl_impl(struct os_mbuf *om)
Controller-side handler for an ACL packet from the host.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
#define TX_NO_INHERIT
unsigned int UINT
ThreadX-compatible unsigned int (host stub).
#define TX_SUCCESS
#define tx_time_get
#define tx_thread_sleep
#define tx_mutex_create
#define tx_mutex_put
char CHAR
ThreadX-compatible CHAR (host stub).
unsigned long ULONG
ThreadX-compatible unsigned long (host stub).
#define tx_mutex_get
One-shot timer that posts an event into a queue when it fires.
struct ble_npl_event ev
Event posted on each firing.
TX_TIMER handle
Backing ThreadX one-shot timer.
struct ble_npl_eventq * evq
Queue to post the event into.
NimBLE event opaque – pairs a callback with an argument.
ble_npl_event_fn * fn
Callback invoked by ble_npl_event_run.
uint8_t queued
1 while sitting in an evq, 0 otherwise.
void * arg
Opaque user argument passed to fn().
Event queue mapped onto TX_QUEUE.
TX_QUEUE q
Backing ThreadX queue.
uint8_t storage[64]
Backing storage (16 entries * 4 bytes).
Mutex mapped onto TX_MUTEX.
TX_MUTEX handle
Backing ThreadX mutex.
Counting semaphore mapped onto TX_SEMAPHORE.
TX_SEMAPHORE handle
Backing ThreadX counting semaphore.