ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_esp_hosted_rtos_internal.h File Reference

Module-private contract of the esp-hosted RTOS abstraction slice. More...

#include <stddef.h>
#include <stdint.h>
#include "esp_hosted_os_abstraction.h"
#include "ra8_attributes.h"
#include "ra8_err.h"
Include dependency graph for ra8_esp_hosted_rtos_internal.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

ra8_err_t priv_ra8_esp_hosted_rtos_init (void)
 Bring the RTOS substrate up: byte pools and empty object tables.
ra8_err_t priv_ra8_esp_hosted_rtos_deinit (void)
 Tear the RTOS substrate down, deleting every outstanding object.
bool priv_ra8_esp_hosted_rtos_is_ready (void)
 Report whether the RTOS substrate is currently initialised.
void priv_ra8_esp_hosted_rtos_pool_stats (uint32_t *out_available, uint32_t *out_fragments)
 Read live transport-pool occupancy.
ra8_err_t priv_ra8_esp_hosted_rtos_bind (hosted_osi_funcs_t *out)
 Populate the thread, sleep, timer and clock slots of the vtable.
ra8_err_t priv_ra8_esp_hosted_rtos_bind_pool (hosted_osi_funcs_t *out)
 Populate the memory and queue slots of the vtable.
ra8_err_t priv_ra8_esp_hosted_rtos_bind_sync (hosted_osi_funcs_t *out)
 Populate the mutex and semaphore slots of the vtable.
ra8_err_t priv_ra8_esp_hosted_rtos_sync_init (void)
 Clear the mutex and semaphore tables and mark them usable.
ra8_err_t priv_ra8_esp_hosted_rtos_sync_deinit (void)
 Delete every outstanding mutex and semaphore.
uint32_t priv_ra8_esp_hosted_rtos_slot_take (bool *used, uint32_t count)
 Claim the first free row of an occupancy bitmap.
uint32_t priv_ra8_esp_hosted_rtos_slot_index (const void *handle, const void *base, size_t stride, uint32_t count, const bool *used)
 Resolve an opaque handle to its row index in a fixed table.
ra8_err_t priv_ra8_esp_hosted_rtos_pool_init (void)
 Create the two byte pools over their static backing arrays.
ra8_err_t priv_ra8_esp_hosted_rtos_pool_deinit (void)
 Destroy every queue and both byte pools.
uint32_t priv_ra8_esp_hosted_rtos_ms_to_ticks (int timeout_ms)
 Convert an esp-hosted millisecond timeout to a ThreadX wait option.
uint32_t priv_ra8_esp_hosted_rtos_queue_words (uint32_t item_bytes)
 Round an esp-hosted queue element size up to whole ThreadX words.
uint32_t priv_ra8_esp_hosted_rtos_us_spin_iters (uint32_t cpu_hz, uint32_t usec)
 Size the busy-wait loop that stands in for a microsecond delay.
void * priv_ra8_esp_hosted_rtos_alloc (size_t size, size_t align)
 Allocate an aligned block from the transport byte pool.
ra8_err_t priv_ra8_esp_hosted_rtos_release (void *ptr)
 Release a block obtained from priv_ra8_esp_hosted_rtos_alloc.
ra8_err_t priv_ra8_esp_hosted_rtos_block_size (const void *ptr, size_t *out_size)
 Read back the payload size recorded for an allocated block.

Detailed Description

Module-private contract of the esp-hosted RTOS abstraction slice.

Tag
[Ring 4 / PORT] {World: NS}

The vendored esp-hosted core reaches ThreadX only through the 72-entry hosted_osi_funcs_t vtable. This header declares the port-private symbols that build the RTOS part of that vtable and the fixed-storage substrate underneath it: the byte pools, the object tables, and the three pieces of arithmetic (millisecond-to-tick, queue word rounding, microsecond spin sizing) that carry real decisions and therefore have to be reachable from tests/ on their own terms.

Nothing here is public API. Production code outside port/esp-hosted/src/ must go through ra8_esp_hosted_port_init and then through g_h.funcs.

Allocation policy
This board has no heap: _sbrk is a strong symbol that reports a fatal error. Every object the vendored core asks the vtable to "allocate" is carved from a fixed TX_BYTE_POOL over a static array, or taken from a fixed object table with an in-use bitmap. Exhaustion returns a failure; it never grows anything. That is what keeps the port inside NASA Power of 10 Rule 3.
File split
The implementation is three translation units because one would be several times the project's thousand-line file cap. The split follows the object kinds, which is also how the fixed tables divide:
  • ra8_esp_hosted_rtos_pool.c – the byte pools, the allocator and the queues, whose storage comes out of one of those pools;
  • ra8_esp_hosted_rtos_sync.c – the mutex and semaphore tables;
  • ra8_esp_hosted_rtos.c – threads, sleeps, timers, the extended clock, and the lifecycle that brings the other two up. Each unit binds only its own vtable rows, so a row can never be assigned from a unit that cannot see the function behind it.
No mempool locks
H_USE_MEMPOOL is deliberately left undefined, so the four _h_*_lock_mempool members are absent from hosted_osi_funcs_t and nothing here binds them. port_esp_hosted_host_config.h records why: the vendored header guards them with #ifdef, not #if, so defining the macro to zero would switch them on and make the struct layout depend on include order.
Since
0.1.0

Definition in file ra8_esp_hosted_rtos_internal.h.

Function Documentation

◆ priv_ra8_esp_hosted_rtos_alloc()

void * priv_ra8_esp_hosted_rtos_alloc ( size_t size,
size_t align )
nodiscard

Allocate an aligned block from the transport byte pool.

The single allocation primitive underneath _h_malloc, _h_calloc, _h_realloc and _h_malloc_align. ThreadX byte pools neither record a block's size nor honour an alignment request, and tx_byte_release demands the exact pointer tx_byte_allocate returned – so the port over-allocates and lays each block out as:

* base ---> [ padding 0..align-1 ][ 16-byte header ][ payload (size bytes) ]
*                                 ^                 ^
*                                 |                 +-- returned to caller
*                                 +-- header sits immediately below it
* 

The header holds the base pointer (so the release can hand ThreadX exactly what it gave out), the payload size (so _h_realloc can copy the right number of bytes) and a sentinel (so a foreign pointer is rejected rather than followed). It is written and read with memcpy because its address inherits only the requested alignment, which may be weaker than the pointer's own.

Worst-case overhead is 16 + align - 1 bytes: 16 bytes for a plain _h_malloc (which asks for no extra alignment) and 79 bytes for a 64-byte-aligned transport buffer.

Parameters
[in]sizePayload bytes required. Must be non-zero.
[in]alignRequired payload alignment in bytes; must be a power of two no greater than k_ra8_esp_hosted_align_max. Pass 1 for "no particular alignment".
Returns
Pointer to the aligned payload, or null on failure.
Return values
nullptrThe substrate is down, an argument was out of contract, or the pool could not satisfy the request.
non-nullA block of at least size bytes aligned to align.
Precondition
The substrate is initialised.
align is a power of two.
Postcondition
On success the returned address is a multiple of align.
On failure the pool is left exactly as it was.
Note
Thread-safe; ThreadX serialises the pool internally.
Warning
The block must be released with priv_ra8_esp_hosted_rtos_release, not with tx_byte_release, or the padding leaks.
Example:
void* p = priv_ra8_esp_hosted_rtos_alloc(1600U, 64U);
void * priv_ra8_esp_hosted_rtos_alloc(size_t size, size_t align)
Allocate an aligned block from the transport byte pool.
See also
priv_ra8_esp_hosted_rtos_release
Since
0.1.0
NASA Power of 10 Compliance:
  • Rule 3: draws from a fixed init-time pool; never grows.
  • Rule 5: three preconditions and two postconditions are checked.

Definition at line 305 of file ra8_esp_hosted_rtos_pool.c.

References ra8_esp_hosted_alloc_hdr_t::base, k_ra8_esp_hosted_align_max, k_ra8_esp_hosted_alloc_max, k_ra8_esp_hosted_hdr_bytes, k_ra8_esp_hosted_hdr_magic, ra8_esp_hosted_alloc_hdr_t::magic, memcpy(), s_pool, ra8_esp_hosted_alloc_hdr_t::size, and TX_SUCCESS.

Referenced by internal_h_calloc(), internal_h_malloc(), internal_h_malloc_align(), and internal_h_realloc().

◆ priv_ra8_esp_hosted_rtos_bind()

ra8_err_t priv_ra8_esp_hosted_rtos_bind ( hosted_osi_funcs_t * out)

Populate the thread, sleep, timer and clock slots of the vtable.

Writes the ten rows this translation unit implements. It does not call the sibling binders: each unit binds only the rows whose implementations it can see, so a row can never be assigned from a unit that cannot name the function behind it. priv_ra8_esp_hosted_osi_bind_all calls all three. Every slot outside this group – memory, queue, mutex, semaphore, GPIO, bus, logging, transport – is left exactly as the caller had it.

Parameters
[out]outVtable to populate. Must be non-null.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe ten thread, sleep, timer and clock slots are set.
k_ra8_err_null_ptrout was null.
Precondition
out points at storage that outlives the vendored core.
priv_ra8_esp_hosted_rtos_init has run, or the slots will report failures.
Postcondition
Every slot in this group is non-null.
No slot outside this group is written.
Note
Not thread-safe; call once during bring-up.
Warning
Binding without initialising first produces a vtable whose allocators fail every call rather than one that faults.
Example:
hosted_osi_funcs_t g_hosted_osi_funcs
The OS-abstraction vtable the vendored core calls through.
ra8_err_t priv_ra8_esp_hosted_rtos_bind(hosted_osi_funcs_t *out)
Populate the thread, sleep, timer and clock slots of the vtable.
See also
priv_ra8_esp_hosted_rtos_bind_pool
priv_ra8_esp_hosted_rtos_bind_sync
Since
0.1.0

Definition at line 814 of file ra8_esp_hosted_rtos.c.

References internal_h_blocking_delay(), internal_h_get_time_ms(), internal_h_msleep(), internal_h_sleep(), internal_h_thread_cancel(), internal_h_thread_create(), internal_h_thread_yield(), internal_h_timer_start(), internal_h_timer_stop(), internal_h_usleep(), k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by priv_ra8_esp_hosted_osi_bind_all().

◆ priv_ra8_esp_hosted_rtos_bind_pool()

ra8_err_t priv_ra8_esp_hosted_rtos_bind_pool ( hosted_osi_funcs_t * out)

Populate the memory and queue slots of the vtable.

The binder of the pool translation unit, which owns the byte pools the allocators and queue rings draw from. Called by priv_ra8_esp_hosted_osi_bind_all alongside the other two binders.

Parameters
[out]outVtable to populate. Must be non-null.
Returns
ra8_err_t Error code.
Return values
k_ra8_okEvery memory and queue slot is populated.
k_ra8_err_null_ptrout was null.
Precondition
out points at storage that outlives the vendored core.
priv_ra8_esp_hosted_rtos_init has run, or the slots will report failures.
Postcondition
The eight memory slots and six queue slots are non-null.
No other slot is written.
Note
Not thread-safe; call once during bring-up.
Example:
ra8_err_t priv_ra8_esp_hosted_rtos_bind_pool(hosted_osi_funcs_t *out)
Populate the memory and queue slots of the vtable.
See also
priv_ra8_esp_hosted_rtos_bind
Since
0.1.0

Definition at line 845 of file ra8_esp_hosted_rtos_pool.c.

References internal_h_calloc(), internal_h_create_queue(), internal_h_dequeue_item(), internal_h_destroy_queue(), internal_h_free(), internal_h_free_align(), internal_h_malloc(), internal_h_malloc_align(), internal_h_memcpy(), internal_h_memset(), internal_h_queue_item(), internal_h_queue_msg_waiting(), internal_h_realloc(), internal_h_reset_queue(), k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by priv_ra8_esp_hosted_osi_bind_all().

◆ priv_ra8_esp_hosted_rtos_bind_sync()

ra8_err_t priv_ra8_esp_hosted_rtos_bind_sync ( hosted_osi_funcs_t * out)

Populate the mutex and semaphore slots of the vtable.

The binder of the synchronisation translation unit, which owns the mutex and semaphore tables. Called by priv_ra8_esp_hosted_osi_bind_all alongside the other two binders. There are no mempool-lock rows to fill; see the file-level note on H_USE_MEMPOOL.

Parameters
[out]outVtable to populate. Must be non-null.
Returns
ra8_err_t Error code.
Return values
k_ra8_okEvery mutex and semaphore slot is populated.
k_ra8_err_null_ptrout was null.
Precondition
out points at storage that outlives the vendored core.
priv_ra8_esp_hosted_rtos_init has run, or the slots will report failures.
Postcondition
The four mutex slots and five semaphore slots are non-null.
No other slot is written.
Note
Not thread-safe; call once during bring-up.
Example:
ra8_err_t priv_ra8_esp_hosted_rtos_bind_sync(hosted_osi_funcs_t *out)
Populate the mutex and semaphore slots of the vtable.
See also
priv_ra8_esp_hosted_rtos_bind
Since
0.1.0

Definition at line 452 of file ra8_esp_hosted_rtos_sync.c.

References internal_h_create_mutex(), internal_h_create_semaphore(), internal_h_destroy_mutex(), internal_h_destroy_semaphore(), internal_h_get_semaphore(), internal_h_lock_mutex(), internal_h_post_semaphore(), internal_h_post_semaphore_from_isr(), internal_h_unlock_mutex(), k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by priv_ra8_esp_hosted_osi_bind_all().

◆ priv_ra8_esp_hosted_rtos_block_size()

ra8_err_t priv_ra8_esp_hosted_rtos_block_size ( const void * ptr,
size_t * out_size )

Read back the payload size recorded for an allocated block.

Exists because _h_realloc has to copy min(old, new) bytes and ThreadX byte pools do not record a block's size. The value comes from the header priv_ra8_esp_hosted_rtos_alloc wrote, so it is the size the caller asked for, not the rounded pool footprint.

Parameters
[in]ptrPayload pointer previously returned by the allocator.
[out]out_sizeReceives the recorded payload size in bytes.
Returns
ra8_err_t Error code.
Return values
k_ra8_okout_size holds the recorded size.
k_ra8_err_null_ptrptr or out_size was null.
k_ra8_err_invalid_argThe header sentinel did not match.
Precondition
ptr came from priv_ra8_esp_hosted_rtos_alloc.
out_size is writable.
Postcondition
On success *out_size is the size originally requested.
No pool state is modified.
Note
Thread-safe; reads immutable header bytes.
Example:
size_t n = 0U;
ra8_err_t priv_ra8_esp_hosted_rtos_block_size(const void *ptr, size_t *out_size)
Read back the payload size recorded for an allocated block.
See also
priv_ra8_esp_hosted_rtos_alloc
Since
0.1.0

Definition at line 360 of file ra8_esp_hosted_rtos_pool.c.

References k_ra8_err_invalid_arg, k_ra8_esp_hosted_hdr_bytes, k_ra8_esp_hosted_hdr_magic, k_ra8_ok, ra8_esp_hosted_alloc_hdr_t::magic, memcpy(), RA8_CHECK_NULL_PTR, s_tag, and ra8_esp_hosted_alloc_hdr_t::size.

Referenced by internal_h_realloc().

◆ priv_ra8_esp_hosted_rtos_deinit()

ra8_err_t priv_ra8_esp_hosted_rtos_deinit ( void )
nodiscard

Tear the RTOS substrate down, deleting every outstanding object.

Walks each object table and deletes whatever is still in use – timers are deactivated then deleted, threads terminated then deleted, queues, mutexes and semaphores deleted – then deletes both byte pools and clears the module state. Objects the vendored core still holds handles to are deleted regardless, so the core must be stopped first.

Returns
ra8_err_t Error code.
Return values
k_ra8_okEverything was released.
k_ra8_err_not_initializedThe substrate was not up.
k_ra8_err_rtos_errorThreadX refused to delete an object or a pool.
Precondition
The vendored transport has been stopped.
No interrupt handler is currently posting to a port semaphore.
Postcondition
Every object table is empty.
The substrate reports not ready and both pools are gone.
Note
Not thread-safe; call from the same context as the init.
Warning
Tearing down while a thread is blocked on a port object leaves that thread waiting on a deleted control block.
Example:
ra8_err_t priv_ra8_esp_hosted_rtos_deinit(void)
Tear the RTOS substrate down, deleting every outstanding object.
See also
priv_ra8_esp_hosted_rtos_init
Since
0.1.0
NASA Power of 10 Compliance:
  • Rule 2: every table walk is bounded by its compile-time table size.
  • Rule 5: two preconditions and two postconditions are checked.

Definition at line 787 of file ra8_esp_hosted_rtos.c.

References internal_h_thread_cancel(), internal_h_timer_stop(), k_ra8_err_not_initialized, k_ra8_err_rtos_error, k_ra8_esp_hosted_max_threads, k_ra8_esp_hosted_max_timers, k_ra8_ok, memset(), priv_ra8_esp_hosted_rtos_pool_deinit(), priv_ra8_esp_hosted_rtos_sync_deinit(), ra8_log_error, RET_OK, s_rtos, and s_tag.

Referenced by internal_unwind().

◆ priv_ra8_esp_hosted_rtos_init()

ra8_err_t priv_ra8_esp_hosted_rtos_init ( void )
nodiscard

Bring the RTOS substrate up: byte pools and empty object tables.

Creates the two TX_BYTE_POOL instances – the transport buffer pool sized by k_ra8_esp_hosted_pool_bytes and the queue-storage pool sized by k_ra8_esp_hosted_queue_pool_bytes – over static arrays, clears every object table and caches the CPU rate used to size the sub-millisecond spin in _h_usleep. This is the only allocation the RTOS slice ever performs and it happens exactly here, during initialisation.

A second call is an error, not a no-op: a silent success would hand the caller pools whose contents the first caller still owns, and would hide a double bring-up that is always a bug in the calling sequence.

Returns
ra8_err_t Error code.
Return values
k_ra8_okThe substrate is ready; the vtable may be bound.
k_ra8_err_invalid_stateThe substrate was already initialised.
k_ra8_err_rtos_errorThreadX refused to create a byte pool.
Precondition
The ThreadX kernel is running, or this runs from tx_application_define.
No vendored esp-hosted entry point has been called yet.
Postcondition
On success the substrate reports ready and every object table is empty.
On failure no pool is left half-created and the substrate reports not ready.
Note
Not thread-safe; call once from a single-threaded bring-up path.
Warning
The CPU-rate query is best-effort; a failure leaves the documented fallback rate in place and only affects _h_usleep accuracy.
Example:
if (priv_ra8_esp_hosted_rtos_init() != k_ra8_ok) { report(); }
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_t priv_ra8_esp_hosted_rtos_init(void)
Bring the RTOS substrate up: byte pools and empty object tables.
See also
priv_ra8_esp_hosted_rtos_deinit
priv_ra8_esp_hosted_rtos_bind
Since
0.1.0
NASA Power of 10 Compliance:
  • Rule 3: the only allocation is this init-time pool carve.
  • Rule 5: two preconditions and two postconditions are checked.

Definition at line 767 of file ra8_esp_hosted_rtos.c.

References k_ra8_clock_id_cpuclk0, k_ra8_err_invalid_state, k_ra8_esp_hosted_default_cpu_hz, k_ra8_ok, memset(), priv_ra8_esp_hosted_rtos_pool_init(), priv_ra8_esp_hosted_rtos_sync_init(), ra8_cgc_get_clock_hz(), ra8_log_error, ra8_log_warn, RA8_RETURN_ON_ERROR, s_rtos, s_tag, and tx_time_get.

Referenced by internal_bring_up().

◆ priv_ra8_esp_hosted_rtos_is_ready()

bool priv_ra8_esp_hosted_rtos_is_ready ( void )
nodiscard

Report whether the RTOS substrate is currently initialised.

Reads the single module-state flag so callers can decide whether a teardown is needed without provoking an error return, and so host tests can assert the state machine without reaching into the module.

Returns
Whether the substrate is up.
Return values
truepriv_ra8_esp_hosted_rtos_init completed and no teardown has run.
falseThe substrate has never been up, failed, or was torn down.
Precondition
None; safe to call at any time, including before any init.
The caller tolerates a value a concurrent teardown may stale.
Postcondition
No module state is modified.
The value reflects the flag at the moment of the read.
Note
Safe from interrupt context; a single aligned load.
Example:
bool priv_ra8_esp_hosted_rtos_is_ready(void)
Report whether the RTOS substrate is currently initialised.
See also
priv_ra8_esp_hosted_rtos_init
Since
0.1.0

Definition at line 762 of file ra8_esp_hosted_rtos.c.

References s_rtos.

◆ priv_ra8_esp_hosted_rtos_ms_to_ticks()

uint32_t priv_ra8_esp_hosted_rtos_ms_to_ticks ( int timeout_ms)
nodiscard

Convert an esp-hosted millisecond timeout to a ThreadX wait option.

The vendored core expresses every timeout in milliseconds through an int parameter, and ThreadX takes a tick count. Two values are special: zero means "do not block" and HOSTED_BLOCK_MAX (all ones) means "block until satisfied". HOSTED_BLOCK_MAX reaches the vtable as -1 after its conversion to int, so the rule this function implements is "any negative value blocks forever" – deliberately wider than "exactly -1", so a sign-extension bug elsewhere can never turn an intended block into a zero-tick busy loop. The kernel runs at 1 kHz (TX_TIMER_TICKS_PER_SECOND is 1000), so the positive case is the identity; it is still spelled out here rather than inlined at 30 call sites so that changing the tick rate is a one-line change and so the mapping is directly testable.

Parameters
[in]timeout_msTimeout in milliseconds: 0 = do not block, negative = block forever, positive = that many milliseconds.
Returns
ThreadX wait option in ticks.
Return values
0timeout_ms was zero: TX_NO_WAIT.
0xFFFFFFFFtimeout_ms was negative: TX_WAIT_FOREVER.
1..0x7FFFFFFFThe millisecond count, unchanged.
Precondition
The kernel tick is 1 kHz.
The caller passes the value the vendored core supplied, unmodified.
Postcondition
No state is modified.
The result is never TX_WAIT_FOREVER for a non-negative input.
Note
Pure function; safe from any context including interrupts.
Warning
Do not pre-clamp the argument at the call site; the negative case is load-bearing.
MC/DC:
Three-way decision with no compound condition: timeout_ms < 0 is tested first, then timeout_ms == 0. Independence is trivial because each decision has a single condition; the vectors that cover every outcome are -1 (and (int)HOSTED_BLOCK_MAX), 0, and any positive value.
Example:
uint32_t priv_ra8_esp_hosted_rtos_ms_to_ticks(int timeout_ms)
Convert an esp-hosted millisecond timeout to a ThreadX wait option.
unsigned long ULONG
ThreadX-compatible unsigned long (host stub).
See also
priv_ra8_esp_hosted_rtos_queue_words
Since
0.1.0

Definition at line 364 of file ra8_esp_hosted_rtos.c.

References k_ra8_esp_hosted_ms_per_tick, and TX_WAIT_FOREVER.

Referenced by internal_h_dequeue_item(), internal_h_get_semaphore(), internal_h_lock_mutex(), internal_h_queue_item(), and internal_h_timer_start().

◆ priv_ra8_esp_hosted_rtos_pool_deinit()

ra8_err_t priv_ra8_esp_hosted_rtos_pool_deinit ( void )
nodiscard

Destroy every queue and both byte pools.

The pool half of priv_ra8_esp_hosted_rtos_deinit: deletes any queue still in use, releases its storage, then deletes both pools and clears the pool state so a later allocation fails cleanly rather than touching a dead control block.

Returns
ra8_err_t Error code.
Return values
k_ra8_okBoth pools and every queue were released.
k_ra8_err_not_initializedThe pools were not created.
k_ra8_err_rtos_errorThreadX refused a delete.
Precondition
No thread is blocked on a port queue.
The vendored core has stopped allocating.
Postcondition
The queue table is empty.
Neither pool satisfies a later allocation.
Note
Not thread-safe; call from the same context as the init.
Example:
ra8_err_t priv_ra8_esp_hosted_rtos_pool_deinit(void)
Destroy every queue and both byte pools.
See also
priv_ra8_esp_hosted_rtos_pool_init
Since
0.1.0

Definition at line 255 of file ra8_esp_hosted_rtos_pool.c.

References k_ra8_err_not_initialized, k_ra8_err_rtos_error, k_ra8_esp_hosted_max_queues, k_ra8_ok, memset(), ra8_log_error, s_pool, s_tag, and TX_SUCCESS.

Referenced by priv_ra8_esp_hosted_rtos_deinit().

◆ priv_ra8_esp_hosted_rtos_pool_init()

ra8_err_t priv_ra8_esp_hosted_rtos_pool_init ( void )
nodiscard

Create the two byte pools over their static backing arrays.

The pool half of priv_ra8_esp_hosted_rtos_init. Separated so the memory translation unit owns both the arrays and the control blocks, and so a test can bring the allocator up without the thread and timer tables.

Returns
ra8_err_t Error code.
Return values
k_ra8_okBoth pools are ready.
k_ra8_err_invalid_stateThe pools were already created.
k_ra8_err_rtos_errorThreadX refused one of the pools.
Precondition
The ThreadX kernel is running.
No block from a previous incarnation of the pools is still held.
Postcondition
On success both pools report their full size available.
On failure neither pool is left half-created.
Note
Not thread-safe; call once during bring-up.
Example:
ra8_err_t priv_ra8_esp_hosted_rtos_pool_init(void)
Create the two byte pools over their static backing arrays.
See also
priv_ra8_esp_hosted_rtos_pool_deinit
Since
0.1.0

Definition at line 228 of file ra8_esp_hosted_rtos_pool.c.

References k_ra8_err_invalid_state, k_ra8_err_rtos_error, k_ra8_ok, memset(), ra8_log_error, s_pool, s_queue_mem, s_tag, s_transport_mem, s_tx_name_esph_buf, s_tx_name_esph_q, and TX_SUCCESS.

Referenced by priv_ra8_esp_hosted_rtos_init().

◆ priv_ra8_esp_hosted_rtos_pool_stats()

void priv_ra8_esp_hosted_rtos_pool_stats ( uint32_t * out_available,
uint32_t * out_fragments )

Read live transport-pool occupancy.

Calls tx_byte_pool_info_get on the transport buffer pool and hands back the two numbers a fragmentation problem actually shows up in: bytes still available, and the fragment count. These are real ThreadX numbers, not a port-side tally, which is the whole reason the port keeps a real byte pool rather than a bump allocator. Backs ra8_esp_hosted_mem_dump.

Parameters
[out]out_availableReceives bytes still allocatable. May be null.
[out]out_fragmentsReceives the pool's fragment count. May be null.
Precondition
The substrate is initialised, or both outputs are set to zero.
At least one output pointer is non-null for the call to be useful.
Postcondition
No pool state is modified.
Every non-null output has been written.
Note
Safe from any thread; ThreadX guards the pool internally.
Example:
uint32_t avail = 0U;
uint32_t frags = 0U;
void priv_ra8_esp_hosted_rtos_pool_stats(uint32_t *out_available, uint32_t *out_fragments)
Read live transport-pool occupancy.
See also
priv_ra8_esp_hosted_rtos_init
Since
0.1.0

Definition at line 284 of file ra8_esp_hosted_rtos_pool.c.

References s_pool.

Referenced by ra8_esp_hosted_mem_dump().

◆ priv_ra8_esp_hosted_rtos_queue_words()

uint32_t priv_ra8_esp_hosted_rtos_queue_words ( uint32_t item_bytes)
nodiscard

Round an esp-hosted queue element size up to whole ThreadX words.

tx_queue_create takes its message size in 32-bit words, capped at TX_16_ULONG. The core asks for byte sizes that are not necessarily a whole number of words – sizeof(interface_buffer_handle_t) is 28 bytes on this ABI, which is seven words exactly, but nothing in the vtable contract guarantees that. The rounding is upward, so an element always fits; the cost is at most three unused bytes per message, which is why rounding is preferable to rejecting an odd size.

A request that would need more than sixteen words is rejected rather than truncated: ThreadX would refuse the create anyway, and a truncating port would silently corrupt every message.

Parameters
[in]item_bytesElement size in bytes as the core supplied it.
Returns
Message size in 32-bit words, or zero when unusable.
Return values
0item_bytes was zero, or exceeded sixteen words.
1..16The rounded-up word count.
Precondition
item_bytes is the size the core will actually copy.
The caller treats zero as "refuse to create the queue".
Postcondition
No state is modified.
The result multiplied by four is at least item_bytes.
Note
Pure function; safe from any context.
Warning
A zero return must not be passed to tx_queue_create.
MC/DC:
Decision (item_bytes == 0U) || (words > k_ra8_esp_hosted_queue_words_max) (2 conditions). Vector 1: 28 bytes -> false/false. Vector 2: 0 bytes -> true/(short-circuit). Vector 3: 68 bytes -> false/true. Vectors 1+2 prove the emptiness condition's independent influence; 1+3 prove the same for the word cap. N+1 = 3 vectors for N=2: minimal MC/DC.
Example:
const uint32_t words = priv_ra8_esp_hosted_rtos_queue_words((uint32_t)qitem_size);
uint32_t priv_ra8_esp_hosted_rtos_queue_words(uint32_t item_bytes)
Round an esp-hosted queue element size up to whole ThreadX words.
See also
priv_ra8_esp_hosted_rtos_ms_to_ticks
Since
0.1.0

Definition at line 375 of file ra8_esp_hosted_rtos_pool.c.

References k_ra8_esp_hosted_queue_word_bytes, and k_ra8_esp_hosted_queue_words_max.

Referenced by internal_h_create_queue().

◆ priv_ra8_esp_hosted_rtos_release()

ra8_err_t priv_ra8_esp_hosted_rtos_release ( void * ptr)

Release a block obtained from priv_ra8_esp_hosted_rtos_alloc.

Reads the header immediately below ptr, checks its sentinel, and hands ThreadX the original base pointer. Because every allocation carries the same header, an aligned block and a plain one are released identically – which is why _h_free and _h_free_align can be, and are, the same operation.

Parameters
[in]ptrPayload pointer previously returned by the allocator. A null pointer is accepted and reported as invalid rather than dereferenced.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe block was returned to the pool.
k_ra8_err_null_ptrptr was null.
k_ra8_err_invalid_argThe header sentinel did not match.
k_ra8_err_rtos_errorThreadX refused the release.
Precondition
ptr came from priv_ra8_esp_hosted_rtos_alloc.
The block has not already been released.
Postcondition
On success the pool reports the block's bytes as available again.
On failure no pool state changes.
Note
Thread-safe; ThreadX serialises the pool internally.
Warning
Releasing a foreign pointer is detected by the sentinel, but a double release of a reallocated address is not.
Example:
ra8_err_t priv_ra8_esp_hosted_rtos_release(void *ptr)
Release a block obtained from priv_ra8_esp_hosted_rtos_alloc.
See also
priv_ra8_esp_hosted_rtos_alloc
Since
0.1.0

Definition at line 343 of file ra8_esp_hosted_rtos_pool.c.

References ra8_esp_hosted_alloc_hdr_t::base, k_ra8_err_invalid_arg, k_ra8_err_rtos_error, k_ra8_esp_hosted_hdr_bytes, k_ra8_esp_hosted_hdr_magic, k_ra8_ok, ra8_esp_hosted_alloc_hdr_t::magic, memcpy(), RA8_CHECK_NULL_PTR, ra8_log_error, s_tag, and TX_SUCCESS.

Referenced by internal_h_free(), internal_h_free_align(), and internal_h_realloc().

◆ priv_ra8_esp_hosted_rtos_slot_index()

uint32_t priv_ra8_esp_hosted_rtos_slot_index ( const void * handle,
const void * base,
size_t stride,
uint32_t count,
const bool * used )
nodiscard

Resolve an opaque handle to its row index in a fixed table.

Every handle the port hands the vendored core is the address of a table row. Rather than trusting that address, this scans the table for pointer identity and checks the occupancy flag, so a foreign pointer or a handle retained past its destroy is rejected instead of followed. The tables hold at most eight rows, so the scan is cheaper than any bookkeeping that would replace it.

Parameters
[in]handleOpaque handle the core is holding.
[in]baseAddress of the table's first row.
[in]strideBytes between consecutive rows.
[in]countNumber of rows in the table.
[in]usedOccupancy flags for the same table.
Returns
Row index, or count when the handle is not live.
Return values
countThe handle is null, foreign, or names a freed row.
0..count-1The live row index.
Precondition
base and used describe the same table.
stride is sizeof one row.
Postcondition
No state is modified.
A returned index always has its occupancy flag set.
Note
Thread-safe for reads; the tables are mutated only during bring-up and teardown.
Warning
Passing a stride that is not the real row size makes every lookup miss rather than fault.
MC/DC:
Decision (handle == nullptr) || (base == nullptr) || (used == nullptr) (3 conditions) plus (row == handle) && used[i] (2 conditions). Four vectors cover the first – all non-null, then each argument null in turn – and three cover the second: a matching live row, a non-matching row, and a matching row whose flag is clear.
Example:
h, s_rows, sizeof(s_rows[0]), k_max, s_used);
static ra8_esp_hosted_gpio_edge_row_t s_rows[k_ra8_esp_hosted_gpio_row_max]
Every pin currently under software edge detection.
uint32_t priv_ra8_esp_hosted_rtos_slot_index(const void *handle, const void *base, size_t stride, uint32_t count, const bool *used)
Resolve an opaque handle to its row index in a fixed table.
See also
priv_ra8_esp_hosted_rtos_slot_take
Since
0.1.0

Definition at line 230 of file ra8_esp_hosted_rtos.c.

Referenced by internal_h_destroy_mutex(), internal_h_destroy_semaphore(), internal_h_get_semaphore(), internal_h_lock_mutex(), internal_h_post_semaphore(), internal_h_post_semaphore_from_isr(), internal_h_thread_cancel(), internal_h_timer_stop(), and internal_h_unlock_mutex().

◆ priv_ra8_esp_hosted_rtos_slot_take()

uint32_t priv_ra8_esp_hosted_rtos_slot_take ( bool * used,
uint32_t count )
nodiscard

Claim the first free row of an occupancy bitmap.

The one place a table row is taken, shared by every object kind so none of them can grow its table by accident. Returning count rather than a sentinel index keeps the caller's bound check and the failure check the same comparison.

Parameters
[in,out]usedOccupancy flags; must cover count entries.
[in]countNumber of rows in the table.
Returns
Index of the claimed row, or count when the table is full.
Return values
countEvery row was occupied, or used was null.
0..count-1The claimed row, now marked in use.
Precondition
used covers count entries.
The caller releases the row on any later failure.
Postcondition
Exactly one flag changes from false to true on success.
No flag changes when the table is full.
Note
Not thread-safe against a concurrent claim; creates happen during single-threaded bring-up.
Warning
A claimed row is in use even if the caller then fails to create the ThreadX object; release it explicitly on that path.
MC/DC:
Two single-condition decisions, used == nullptr and !used[i]; no compound condition, so a null table, a table with a free row, and a full table cover every outcome.
Example:
const uint32_t idx = priv_ra8_esp_hosted_rtos_slot_take(s_used, k_max);
uint32_t priv_ra8_esp_hosted_rtos_slot_take(bool *used, uint32_t count)
Claim the first free row of an occupancy bitmap.
See also
priv_ra8_esp_hosted_rtos_slot_index
Since
0.1.0

Definition at line 216 of file ra8_esp_hosted_rtos.c.

Referenced by internal_h_create_mutex(), internal_h_create_semaphore(), internal_h_thread_create(), and internal_h_timer_start().

◆ priv_ra8_esp_hosted_rtos_sync_deinit()

ra8_err_t priv_ra8_esp_hosted_rtos_sync_deinit ( void )
nodiscard

Delete every outstanding mutex and semaphore.

The synchronisation half of priv_ra8_esp_hosted_rtos_deinit: walks both tables and deletes whatever is still in use, then clears the state so a later create fails cleanly rather than touching a dead control block.

Returns
ra8_err_t Error code.
Return values
k_ra8_okEvery object was released.
k_ra8_err_not_initializedThe tables were not initialised.
k_ra8_err_rtos_errorThreadX refused a delete.
Precondition
No thread is blocked on a port mutex or semaphore.
The vendored core has stopped using its handles.
Postcondition
Every occupancy flag is clear.
A later take through a stale handle reports RET_INVALID.
Note
Not thread-safe; call from the same context as the init.
Example:
ra8_err_t priv_ra8_esp_hosted_rtos_sync_deinit(void)
Delete every outstanding mutex and semaphore.
See also
priv_ra8_esp_hosted_rtos_sync_init
Since
0.1.0

Definition at line 431 of file ra8_esp_hosted_rtos_sync.c.

References internal_h_destroy_mutex(), internal_h_destroy_semaphore(), k_ra8_err_not_initialized, k_ra8_err_rtos_error, k_ra8_esp_hosted_max_mutexes, k_ra8_esp_hosted_max_semaphores, k_ra8_ok, memset(), ra8_log_error, RET_OK, s_sync, and s_tag.

Referenced by priv_ra8_esp_hosted_rtos_deinit().

◆ priv_ra8_esp_hosted_rtos_sync_init()

ra8_err_t priv_ra8_esp_hosted_rtos_sync_init ( void )
nodiscard

Clear the mutex and semaphore tables and mark them usable.

The synchronisation half of priv_ra8_esp_hosted_rtos_init. Separated so the unit that owns the tables also owns their lifecycle, and so a test can bring the locks up without the allocator.

Returns
ra8_err_t Error code.
Return values
k_ra8_okBoth tables are empty and usable.
k_ra8_err_invalid_stateThe tables were already initialised.
Precondition
The ThreadX kernel is running.
No handle from a previous incarnation of the tables is still held.
Postcondition
Every occupancy flag is clear.
A create call will now succeed.
Note
Not thread-safe; call once during bring-up.
Example:
ra8_err_t priv_ra8_esp_hosted_rtos_sync_init(void)
Clear the mutex and semaphore tables and mark them usable.
See also
priv_ra8_esp_hosted_rtos_sync_deinit
Since
0.1.0

Definition at line 420 of file ra8_esp_hosted_rtos_sync.c.

References k_ra8_err_invalid_state, k_ra8_ok, memset(), ra8_log_error, s_sync, and s_tag.

Referenced by priv_ra8_esp_hosted_rtos_init().

◆ priv_ra8_esp_hosted_rtos_us_spin_iters()

uint32_t priv_ra8_esp_hosted_rtos_us_spin_iters ( uint32_t cpu_hz,
uint32_t usec )
nodiscard

Size the busy-wait loop that stands in for a microsecond delay.

There is no microsecond timer on this target: ra8_time.h offers a millisecond tick and a millisecond busy delay, and nothing finer. Rather than fake a microsecond sleep or round every sub-millisecond request to zero, _h_usleep spins, and this function decides for how long. The estimate is cpu_hz / 1e6 cycles per microsecond divided by k_ra8_esp_hosted_spin_cycles_per_iter, the measured cost of one iteration of the volatile-counter loop on the Cortex-M85.

The result is clamped to k_ra8_esp_hosted_spin_iters_max so the loop is statically bounded (NASA Power of 10 Rule 2) whatever the caller asks for. Accuracy is roughly a factor of two: cache state, the branch predictor and any interrupt taken mid-spin all move the real duration, and none of them is modelled. That is stated rather than hidden – a caller needing better than that needs a hardware timer, not a better guess.

Parameters
[in]cpu_hzCore clock in hertz; zero means "rate unknown".
[in]usecMicroseconds to spin for.
Returns
Loop iterations to execute.
Return values
0cpu_hz or usec was zero: do not spin at all.
1..k_ra8_esp_hosted_spin_iters_maxThe clamped iteration count.
Precondition
cpu_hz is the live core rate, or zero.
The caller runs the loop with a volatile counter so it is not deleted.
Postcondition
No state is modified.
The result never exceeds k_ra8_esp_hosted_spin_iters_max.
Note
Pure function; safe from any context.
Warning
The duration is an estimate, not a guarantee; do not use it for a protocol timing requirement.
MC/DC:
Decision (cpu_hz == 0U) || (usec == 0U) (2 conditions). Vector 1: cpu_hz=1e9, usec=10 -> false/false. Vector 2: cpu_hz=0, usec=10 -> true/(short-circuit). Vector 3: cpu_hz=1e9, usec=0 -> false/true. Vectors 1+2 prove the rate condition's independent influence; 1+3 prove the same for the duration. N+1 = 3 vectors for N=2: minimal MC/DC.
Example:
const uint32_t iters = priv_ra8_esp_hosted_rtos_us_spin_iters(cpu_hz, 250U);
uint32_t priv_ra8_esp_hosted_rtos_us_spin_iters(uint32_t cpu_hz, uint32_t usec)
Size the busy-wait loop that stands in for a microsecond delay.
See also
priv_ra8_esp_hosted_rtos_ms_to_ticks
Since
0.1.0

Definition at line 375 of file ra8_esp_hosted_rtos.c.

References k_ra8_esp_hosted_hz_per_mhz, k_ra8_esp_hosted_spin_cycles_per_iter, and k_ra8_esp_hosted_spin_iters_max.

Referenced by internal_spin_us().