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

Public entry point of the RA8D2 + ThreadX port of esp-hosted. More...

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

Go to the source code of this file.

Data Structures

struct  ra8_esp_hosted_port_cfg
 Everything the port needs that is not fixed by the board. More...

Typedefs

typedef struct ra8_esp_hosted_port_cfg ra8_esp_hosted_port_cfg_t
typedef void(* ra8_esp_hosted_event_cb_t) (void *ctx, const char *base, int32_t event_id, const void *data, size_t data_len)
 Application handler for an event the vendored core posts.

Enumerations

enum  ra8_esp_hosted_limits_t : uint32_t {
  k_ra8_esp_hosted_max_queues = 8U ,
  k_ra8_esp_hosted_max_semaphores = 8U ,
  k_ra8_esp_hosted_max_mutexes = 4U ,
  k_ra8_esp_hosted_max_threads = 4U ,
  k_ra8_esp_hosted_max_timers = 4U ,
  k_ra8_esp_hosted_queue_pool_bytes = 8192U ,
  k_ra8_esp_hosted_pool_bytes = 65536U
}
 Fixed budgets the port allocates out of static storage. More...

Functions

ra8_err_t ra8_esp_hosted_port_set_event_cb (ra8_esp_hosted_event_cb_t cb, void *ctx)
 Register the handler the port calls when the core posts an event.
ra8_err_t ra8_esp_hosted_port_init (const ra8_esp_hosted_port_cfg_t *cfg)
 Bring the esp-hosted port up and publish the OS-abstraction vtable.
ra8_err_t ra8_esp_hosted_port_deinit (void)
 Tear the port down, releasing every pin, interrupt and pool.
bool ra8_esp_hosted_port_is_ready (void)
 Report whether the port is currently initialised.
bool ra8_esp_hosted_port_rx_pending (void)
 Report whether the co-processor has queued receive data.
void ra8_esp_hosted_mem_dump (const char *label)
 Report transport pool occupancy at a named point.
void ra8_esp_hosted_alloc_failed (const char *func, size_t bytes)
 Record that an allocation through the vtable could not be served.

Detailed Description

Public entry point of the RA8D2 + ThreadX port of esp-hosted.

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

The vendored esp-hosted host driver reaches the hardware through exactly two seams: the ten port_esp_hosted_host_*.h headers, and the 72-entry hosted_osi_funcs_t vtable it finds behind the global g_h. This header is the first-party side of that arrangement – it brings the port up, and it declares the handful of port entry points the port headers expand macros onto.

Bring-up order
ra8_esp_hosted_port_init must run before any vendored esp-hosted call, and after the clock, MSTP and ThreadX kernel are up. It:
  1. validates the configuration and the pin map;
  2. carves the transport byte pool out of a static array;
  3. routes the SCI Simple-SPI pins and opens the bus at the requested mode and bit rate;
  4. takes the chip select as a GPIO output, idle high;
  5. configures HANDSHAKE and DATA_READY as inputs, attaching each to either an ICU channel or the software edge detector according to ra8_esp_hosted_pin_irq_num;
  6. publishes g_h so the vendored core can be started.
Runtime status – proven on silicon 2026-07-28
This port runs on the bench. ra8_esp_hosted_port_init returns k_ra8_ok, the pin map and interrupt routing resolve to the nets the board layer names, and _h_do_bus_transfer clocks 1600-byte full-duplex transactions at 5 MHz – five times the rate the original probe qualified – with zero bad checksums and zero handshake timeouts. examples/ek_ra8d2/hw_validated/c6/c6_hosted_init established the transaction, and c6_fw_version then completed a full esp-hosted RPC round-trip through this vtable and checked the co-processor's answer. just hil::c6 re-runs all of it.

The physical map came from c6_spi_probe, which scope-qualified every J26 hole on 2026-07-27 at SPI mode 3 / 1 MHz; that probe drives the SCI directly and reaches none of this code, which is why the port needed its own proof.

Since
0.1.0

Definition in file ra8_esp_hosted_port.h.

Typedef Documentation

◆ ra8_esp_hosted_event_cb_t

typedef void(* ra8_esp_hosted_event_cb_t) (void *ctx, const char *base, int32_t event_id, const void *data, size_t data_len)

Application handler for an event the vendored core posts.

ESP-IDF hosts deliver esp-hosted events through the IDF event loop. There is no such loop here, and adding a thread and a queue to re-create one would cost more than it buys: the port instead calls this handler synchronously, on the thread that posted, so the application sees exactly one delivery path.

Parameters
[in]ctxThe opaque context registered alongside the handler.
[in]baseEvent namespace as a NUL-terminated string; never null.
[in]event_idIdentifier within that namespace.
[in]dataPayload, or null when data_len is zero. Owned by the caller and invalid once the handler returns.
[in]data_lenPayload length in bytes.
Returns
Nothing.
Note
Runs on the posting thread – often the SPI receive dispatcher – so it must not block and must not call back into the transport.
Since
0.1.0

Definition at line 167 of file ra8_esp_hosted_port.h.

◆ ra8_esp_hosted_port_cfg_t

Enumeration Type Documentation

◆ ra8_esp_hosted_limits_t

enum ra8_esp_hosted_limits_t : uint32_t

Fixed budgets the port allocates out of static storage.

NASA Power of 10 Rule 3 forbids dynamic allocation after initialisation, and this board has no heap at all – _sbrk is a strong symbol that reports a fatal error. Every object the vendored core asks the vtable to "allocate" therefore comes out of a fixed pool sized by these bounds, and an over-request fails cleanly rather than growing the address space.

Invariant
The queue, semaphore, mutex and thread counts each cover the worst case the SPI transport reaches: three priority queues in each direction, three semaphores, one bus mutex, one mempool lock and two transport threads, with headroom for the serial and Bluetooth channels layered above.
k_ra8_esp_hosted_pool_bytes is a multiple of HOSTED_MEM_ALIGNMENT_64.
Example:
static_assert(k_ra8_esp_hosted_max_queues >= 6, "two directions x 3 priorities");
@ k_ra8_esp_hosted_max_queues
Message queues the port can hand out before refusing.
See also
ra8_esp_hosted_port_init
Since
0.1.0
Enumerator
k_ra8_esp_hosted_max_queues 

Message queues the port can hand out before refusing.

k_ra8_esp_hosted_max_semaphores 

Counting semaphores the port can hand out before refusing.

k_ra8_esp_hosted_max_mutexes 

Mutexes the port can hand out, covering the bus lock and the mempool lock with headroom for the RPC layer.

k_ra8_esp_hosted_max_threads 

Threads the port can start: the SPI transaction pump, the receive dispatcher, and headroom for the RPC worker.

k_ra8_esp_hosted_max_timers 

Software timers the port can arm concurrently.

k_ra8_esp_hosted_queue_pool_bytes 

Bytes reserved for queue message storage, shared across all queues; one esp-hosted buffer handle is 28 bytes on this ABI and the transport wants twenty per queue.

k_ra8_esp_hosted_pool_bytes 

Bytes reserved for the transport buffer pool: enough for the receive ring, a transmit frame, and the mempool bookkeeping, all at 1600 bytes per block.

Definition at line 84 of file ra8_esp_hosted_port.h.

Function Documentation

◆ ra8_esp_hosted_alloc_failed()

void ra8_esp_hosted_alloc_failed ( const char * func,
size_t bytes )

Record that an allocation through the vtable could not be served.

Backs the failure arm of the HOSTED_CALLOC macro. On a fixed-pool port an allocation failure is a budgeting fact rather than a transient one, so the report names the requesting function and the size it wanted – which together are enough to resize k_ra8_esp_hosted_pool_bytes without guesswork.

Parameters
[in]funcName of the requesting function, normally __func__. A null pointer is replaced with a fixed placeholder.
[in]bytesSize that could not be served, in bytes.
Returns
Nothing.
Precondition
Logging has been initialised, or the line is dropped.
The caller has already decided to abandon the operation.
Postcondition
No pool state is modified.
Exactly one log line is emitted per call.
Note
Safe from any thread; it only formats and logs.
Example:
HOSTED_CALLOC(uint8_t, write_buf, buf_len, free_bufs2);
See also
ra8_esp_hosted_mem_dump
Since
0.1.0

Record that an allocation through the vtable could not be served.

Definition at line 275 of file ra8_esp_hosted_log.c.

References ESP_LOG_ERROR, ra8_esp_hosted_log_write(), and s_ra8_esp_hosted_log_tag.

◆ ra8_esp_hosted_mem_dump()

void ra8_esp_hosted_mem_dump ( const char * label)

Report transport pool occupancy at a named point.

Backs the MEM_DUMP macro the vendored core sprinkles through its allocation paths. Reads the live ThreadX byte-pool statistics – bytes available and fragment count – and emits them at info level under the port's log tag. Those are real numbers on this port because the pool is a fixed carve, so a shrinking largest-fragment is exactly how a fragmentation problem announces itself.

Parameters
[in]labelShort call-site name, used verbatim in the log line. A null pointer is replaced with a fixed placeholder rather than dereferenced.
Returns
Nothing.
Precondition
The port is initialised, or the call reports the pool as absent.
Logging has been initialised, or the line is dropped.
Postcondition
No pool state is modified.
Exactly one log line is emitted per call.
Note
Not for per-packet paths; it logs unconditionally at info level.
Example:
MEM_DUMP("spi_mempool_create");
#define MEM_DUMP(s)
Report heap occupancy at a named point.
See also
ra8_esp_hosted_port_init
Since
0.1.0

Report transport pool occupancy at a named point.

Definition at line 260 of file ra8_esp_hosted_log.c.

References ESP_LOG_INFO, priv_ra8_esp_hosted_rtos_pool_stats(), ra8_esp_hosted_log_write(), and s_ra8_esp_hosted_log_tag.

Referenced by c6_fwver_worker_entry(), c6_hosted_worker_entry(), c6_wifi_worker_entry(), and internal_init_hook().

◆ ra8_esp_hosted_port_deinit()

ra8_err_t ra8_esp_hosted_port_deinit ( void )
nodiscard

Tear the port down, releasing every pin, interrupt and pool.

Reverses ra8_esp_hosted_port_init in the opposite order: detaches the side-band interrupts, stops the software edge detector, closes the SCI channel, releases the chip select and the two side-band pins, deletes the pools and marks the port not ready. Objects the vendored core still holds handles to are deleted, so the core must be torn down first.

Returns
ra8_err_t Error code.
Return values
k_ra8_okEverything was released.
k_ra8_err_not_initializedThe port was not up.
k_ra8_err_rtos_errorThreadX refused to delete an object, typically because a thread is still blocked on it.
Precondition
The vendored transport has been stopped.
No interrupt handler is currently executing against this port.
Postcondition
Every pin the port claimed is released.
The port reports not ready and g_h.funcs must not be used.
Note
Not thread-safe; call from the same context as the init.
Warning
Tearing down while the SPI transaction thread runs leaves it blocked on a deleted semaphore.
Example:
ra8_err_t ra8_esp_hosted_port_deinit(void)
Tear the port down, releasing every pin, interrupt and pool.
See also
ra8_esp_hosted_port_init
Since
0.1.0
NASA Power of 10 Compliance:
  • Rule 5: one precondition and two postconditions are checked.

Tear the port down, releasing every pin, interrupt and pool.

Definition at line 364 of file ra8_esp_hosted_port.c.

References internal_unwind(), k_ra8_err_not_initialized, and s_ra8_esp_hosted_port_ready.

◆ ra8_esp_hosted_port_init()

ra8_err_t ra8_esp_hosted_port_init ( const ra8_esp_hosted_port_cfg_t * cfg)
nodiscard

Bring the esp-hosted port up and publish the OS-abstraction vtable.

Performs the six bring-up steps listed in the file-level documentation. Every step is checked; the first failure unwinds the steps already taken – the SCI channel is closed, claimed pins are released and attached interrupts are detached – so a failed init leaves no pin stranded and a retry after fixing the cause can succeed.

The pool carve is the only allocation the port ever performs, and it happens exactly here, during initialisation, which is what keeps the whole port inside NASA Power of 10 Rule 3.

Parameters
[in]cfgClocking and pacing configuration. Must be non-null; pclk_hz and sck_hz must be non-zero, edge_poll_ms must be non-zero, and sci_channel must be below the SCI channel count.
Returns
ra8_err_t Error code.
Return values
k_ra8_okPort is up; g_h may be used.
k_ra8_err_null_ptrcfg was null.
k_ra8_err_invalid_argA configuration field was out of range.
k_ra8_err_invalid_stateThe port was already initialised.
k_ra8_err_gpio_conflictA link pin is owned by another module.
k_ra8_err_rtos_errorThreadX refused a pool, mutex or timer.
k_ra8_err_spi_errorThe SCI Simple-SPI channel would not open.
Precondition
The CGC is configured and pclk_hz reflects the live PCLKA rate.
The ThreadX kernel is running, or this is called from tx_application_define.
Postcondition
On success the port reports ready and g_h.funcs is populated.
On failure no pin is left claimed and no interrupt is left attached by this call.
Note
Not thread-safe; call once from a single-threaded bring-up path.
Warning
Calling any vendored esp-hosted entry point before this dereferences an unpopulated vtable.
Example:
ra8_esp_hosted_port_cfg_t cfg = { .pclk_hz = pclka, .sck_hz = 5000000U,
.edge_poll_ms = 2U, .sci_channel = 2U };
if (ra8_esp_hosted_port_init(&cfg) != k_ra8_ok) { report(); }
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
struct ra8_esp_hosted_port_cfg ra8_esp_hosted_port_cfg_t
ra8_err_t ra8_esp_hosted_port_init(const ra8_esp_hosted_port_cfg_t *cfg)
Bring the esp-hosted port up and publish the OS-abstraction vtable.
See also
ra8_esp_hosted_port_deinit
ra8_esp_hosted_port_is_ready
Since
0.1.0
NASA Power of 10 Compliance:
  • Rule 3: the only allocation is this init-time pool carve.
  • Rule 5: four preconditions and two postconditions are checked.

Bring the esp-hosted port up and publish the OS-abstraction vtable.

Definition at line 331 of file ra8_esp_hosted_port.c.

References ESP_LOGE, ESP_LOGI, internal_bring_up(), internal_unwind(), k_ra8_err_invalid_state, k_ra8_ok, priv_ra8_esp_hosted_port_cfg_check(), priv_ra8_esp_hosted_port_pins_check(), s_esp_hosted_tag, s_ra8_esp_hosted_port_ready, ra8_esp_hosted_port_cfg::sci_channel, and ra8_esp_hosted_port_cfg::sck_hz.

Referenced by tx_application_define().

◆ ra8_esp_hosted_port_is_ready()

bool ra8_esp_hosted_port_is_ready ( void )
nodiscard

Report whether the port is currently initialised.

Reads the single module-state flag. Exists so an application 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
true when ra8_esp_hosted_port_init has completed successfully and no teardown has run since.
Return values
trueThe port is up.
falseThe port has never been up, failed to come up, or has been torn down.
Precondition
None; safe to call at any time, including before any init.
The caller tolerates a value that a concurrent teardown may stale.
Postcondition
No module state is modified.
The returned value reflects the flag at the moment of the read.
Note
Safe from interrupt context; a single aligned load.
Example:
bool ra8_esp_hosted_port_is_ready(void)
Report whether the port is currently initialised.
See also
ra8_esp_hosted_port_init
Since
0.1.0

Report whether the port is currently initialised.

Definition at line 374 of file ra8_esp_hosted_port.c.

References s_ra8_esp_hosted_port_ready.

Referenced by c6_fwver_pump_check(), c6_hosted_heartbeat(), internal_init_hook(), internal_ra8_esp_hosted_c6link_delay(), internal_ra8_esp_hosted_c6link_handshake(), internal_ra8_esp_hosted_c6link_transfer(), and ra8_esp_hosted_c6link_bind().

◆ ra8_esp_hosted_port_rx_pending()

bool ra8_esp_hosted_port_rx_pending ( void )
nodiscard

Report whether the co-processor has queued receive data.

Samples the held DATA_READY side-band signal through the bound esp-hosted GPIO seam. This is a non-blocking level check for poll schedulers; it does not clock SPI or consume the pending frame.

Returns
Whether one or more receive frames are pending.
Return values
trueDATA_READY is asserted on an initialized port.
falseThe port is not initialized or DATA_READY is inactive.
Precondition
The caller does not concurrently tear the port down.
DATA_READY retains the board-qualified active polarity.
Postcondition
No GPIO, SPI, or queue state is modified.
A true result remains advisory until the caller acquires its wire lock.
Note
Reentrant while the port remains initialized.
Since
0.1.0

Definition at line 379 of file ra8_esp_hosted_port.c.

References g_h, H_DR_VAL_ACTIVE, H_GPIO_DATA_READY_Pin, H_GPIO_DATA_READY_Port, and s_ra8_esp_hosted_port_ready.

Referenced by internal_rx_worker_entry().

◆ ra8_esp_hosted_port_set_event_cb()

ra8_err_t ra8_esp_hosted_port_set_event_cb ( ra8_esp_hosted_event_cb_t cb,
void * ctx )
nodiscard

Register the handler the port calls when the core posts an event.

Registering a null handler removes the current one, after which posted events are reported to the core as unconsumed rather than dropped quietly – the core can then decide whether the loss matters.

Parameters
[in]cbHandler to install, or null to remove the current one.
[in]ctxOpaque context handed back to the handler. Must be null when cb is null, since there would be nothing to hand it to.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe registration was stored.
k_ra8_err_invalid_argA context was supplied without a handler.
Precondition
The caller owns ctx and keeps it alive past any deregistration.
No event is being dispatched concurrently on another thread.
Postcondition
Subsequent posts reach cb, or are reported unconsumed when it is null.
No other port state is modified.
Note
Not thread-safe against a concurrent post; register during bring-up, before the transport is started.
Example:
(void)ra8_esp_hosted_port_set_event_cb(on_link_event, &app_state);
ra8_err_t ra8_esp_hosted_port_set_event_cb(ra8_esp_hosted_event_cb_t cb, void *ctx)
Register the handler the port calls when the core posts an event.
See also
ra8_esp_hosted_event_cb_t
Since
0.1.0

Register the handler the port calls when the core posts an event.

Definition at line 163 of file ra8_esp_hosted_osi.c.

References k_ra8_err_invalid_arg, k_ra8_ok, s_ra8_esp_hosted_event_cb, and s_ra8_esp_hosted_event_ctx.

Referenced by tx_application_define().