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

The control plane: one protobuf message type, correlated by UID. More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_c6link.h"
#include "ra8_c6link_internal.h"
#include "ra8_secure.h"
Include dependency graph for ra8_c6link_rpc.c:

Go to the source code of this file.

Enumerations

enum  c6link_esp_status_t : int32_t {
  k_c6link_esp_err_no_mem = 0x101 ,
  k_c6link_esp_err_invalid_arg = 0x102 ,
  k_c6link_esp_err_invalid_state = 0x103 ,
  k_c6link_esp_err_invalid_size = 0x104 ,
  k_c6link_esp_err_not_found = 0x105 ,
  k_c6link_esp_err_not_supported = 0x106 ,
  k_c6link_esp_err_timeout = 0x107 ,
  k_c6link_esp_err_invalid_response = 0x108 ,
  k_c6link_esp_err_invalid_crc = 0x109 ,
  k_c6link_esp_err_not_allowed = 0x10D
}
 Stable ESP-IDF general error values carried on the wire. More...

Functions

static ra8_err_t internal_c6link_rpc_stage (ra8_c6link_t *link, Rpc *req)
 Stage a packed request in the link's transmit transaction.
static ra8_err_t internal_c6link_remote_error (int32_t response)
 Translate one nonzero ESP-IDF wire status into the RA8 error domain.
ra8_err_t priv_c6link_resp (ra8_c6link_t *link, uint32_t rpc_id, int32_t resp)
 Map a co-processor result code onto an ra8 error, recording it.
ra8_err_t priv_c6link_rpc_call (ra8_c6link_t *link, Rpc *req, uint32_t resp_id, ra8_c6link_take_fn_t take, void *take_ctx)
 Issue one request and pump until its answer arrives.
static void internal_c6link_rpc_ev_connected (ra8_c6link_event_t *ev, const WifiEventStaConnected *body)
 Turn a decoded station-connected event into a first-party record.
static void internal_c6link_rpc_ev_disconnected (ra8_c6link_event_t *ev, const WifiEventStaDisconnected *body)
 Turn a decoded station-disconnected event into a first-party record.
static void internal_c6link_rpc_event (ra8_c6link_t *link, const Rpc *msg)
 Decode one announcement and hand it to the link's callback.
static bool internal_c6link_rpc_answer (ra8_c6link_t *link, const Rpc *msg)
 Offer a decoded message to the outstanding wait.
bool priv_c6link_rpc_consume (ra8_c6link_t *link, const uint8_t *payload, uint16_t len)
 Decode one control-plane payload and act on it.

Detailed Description

The control plane: one protobuf message type, correlated by UID.

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

Everything the co-processor is asked and everything it volunteers is one generated Rpc message. Its msg_type says request, response or event; its msg_id says which; its uid correlates an answer with the question; and its payload is a oneof whose case number is the msg_id. Adding a request to this library is therefore naming two enumerators and one generated body type – which is the whole reason a narrow, RA8-native API costs so little here.

The message is packed and unpacked by the vendored generated codec, never by hand. Hand-encoding would prove only that this file and the co-processor agree, which is a far weaker claim than the codec and the co-processor agreeing – and the codec is the same one the co-processor's own host driver uses.

One outstanding request at a time
The link holds a single wait slot. That is not a simplification to be lifted later: this facade exists to be driven by a network stack that issues control operations from one thread and expects them to complete, and a pipeline of concurrent RPCs would need a queue, a timeout per entry and an ordering policy that nothing in this tree wants. Requests that arrive while one is outstanding are refused with k_ra8_err_busy rather than silently serialised.
Since
0.1.0

Definition in file ra8_c6link_rpc.c.

Enumeration Type Documentation

◆ c6link_esp_status_t

enum c6link_esp_status_t : int32_t

Stable ESP-IDF general error values carried on the wire.

Enumerator
k_c6link_esp_err_no_mem 

Remote allocation failed.

k_c6link_esp_err_invalid_arg 

Remote argument validation failed.

k_c6link_esp_err_invalid_state 

Remote service state rejected the call.

k_c6link_esp_err_invalid_size 

Remote extent validation failed.

k_c6link_esp_err_not_found 

Remote object was absent.

k_c6link_esp_err_not_supported 

Remote image lacks the operation.

k_c6link_esp_err_timeout 

Remote operation timed out.

k_c6link_esp_err_invalid_response 

Remote protocol validation failed.

k_c6link_esp_err_invalid_crc 

Remote checksum validation failed.

k_c6link_esp_err_not_allowed 

Remote policy denied the operation.

Definition at line 46 of file ra8_c6link_rpc.c.

Function Documentation

◆ internal_c6link_remote_error()

ra8_err_t internal_c6link_remote_error ( int32_t response)
static

Translate one nonzero ESP-IDF wire status into the RA8 error domain.

Preserves actionable general-purpose failures while mapping unknown, component-specific, and generic ESP failures to a protocol error.

Parameters
[in]responseNonzero esp_err_t value received from the C6.
Returns
Closest stable RA8 error with no retained state.
Return values
k_ra8_err_no_memThe C6 exhausted memory.
k_ra8_err_invalid_argThe C6 rejected an argument.
k_ra8_err_invalid_stateThe C6 rejected its current state.
k_ra8_err_invalid_sizeThe C6 rejected an extent.
k_ra8_err_not_foundThe requested remote object was absent.
k_ra8_err_not_supportedThe remote image lacks the operation.
k_ra8_err_timeoutThe remote operation timed out.
k_ra8_err_checksum_mismatchThe remote checksum did not verify.
k_ra8_err_access_deniedRemote policy denied the operation.
k_ra8_err_protocol_errorThe status was generic or unknown.
Precondition
response is nonzero and came from a decoded RPC response.
ESP-IDF general error values retain their published wire numbers.
Postcondition
No link or caller state is modified.
The returned value is always a non-success RA8 error.
Note
Component-specific ESP errors remain available in the raw fault slot.
Since
0.1.0

Definition at line 126 of file ra8_c6link_rpc.c.

References k_c6link_esp_err_invalid_arg, k_c6link_esp_err_invalid_crc, k_c6link_esp_err_invalid_response, k_c6link_esp_err_invalid_size, k_c6link_esp_err_invalid_state, k_c6link_esp_err_no_mem, k_c6link_esp_err_not_allowed, k_c6link_esp_err_not_found, k_c6link_esp_err_not_supported, k_c6link_esp_err_timeout, k_ra8_err_access_denied, k_ra8_err_checksum_mismatch, k_ra8_err_invalid_arg, k_ra8_err_invalid_size, k_ra8_err_invalid_state, k_ra8_err_no_mem, k_ra8_err_not_found, k_ra8_err_not_supported, k_ra8_err_protocol_error, k_ra8_err_timeout, and RA8_INTERNAL.

Referenced by priv_c6link_resp().

◆ internal_c6link_rpc_answer()

bool internal_c6link_rpc_answer ( ra8_c6link_t * link,
const Rpc * msg )
static

Offer a decoded message to the outstanding wait.

The correlation step. An answer is only an answer to the outstanding request when the wait is armed, the UID is the one that was sent, and the message id is the one that request is answered by.

Parameters
[in,out]linkOpen handle; must be non-null.
[in]msgDecoded message; must be non-null.
Returns
true when the wait was satisfied by msg.
Return values
trueThe answer matched the outstanding request and was extracted.
falseNo request is outstanding, or msg is not its answer.
Precondition
msg is still owned by the decoder.
link is open.
Postcondition
The wait is satisfied at most once.
The extractor ran exactly once when it matched.
Note
All three conditions must hold: a UID that matches but an id that does not is a different question's answer arriving late.
Since
0.1.0
MC/DC:
armed && uid == wait.uid && msg_id == wait.resp_id is a three-condition decision; tests/wireless/src/test_ra8_c6link.c drives the N+1 vectors.

Definition at line 348 of file ra8_c6link_rpc.c.

References ra8_c6link_wait::armed, RA8_INTERNAL, ra8_c6link_wait::resp_id, ra8_c6link_wait::result, ra8_c6link_wait::satisfied, ra8_c6link_wait::take, ra8_c6link_wait::take_ctx, ra8_c6link_wait::uid, and ra8_c6link::wait.

Referenced by priv_c6link_rpc_consume().

◆ internal_c6link_rpc_ev_connected()

void internal_c6link_rpc_ev_connected ( ra8_c6link_event_t * ev,
const WifiEventStaConnected * body )
static

Turn a decoded station-connected event into a first-party record.

The association's own account of which AP it reached, which is not necessarily the one that was asked for when the request left the channel and BSSID open.

Parameters
[out]evRecord to fill; must be non-null and already cleared.
[in]bodyDecoded event body; null leaves ev with its kind only.
Returns
Nothing.
Precondition
ev has been zero-initialised by the caller.
body belongs to a message still owned by the decoder.
Postcondition
ev names the AP the station reached.
Every string in ev is NUL-terminated.
Note
Split out so the event switch stays inside NASA Rule 4.
Since
0.1.0

Definition at line 237 of file ra8_c6link_rpc.c.

References ra8_c6link_event::bssid, ra8_c6link_event::channel, priv_c6link_copy_mac(), priv_c6link_copy_str(), RA8_INTERNAL, ra8_c6link_event::ssid, and ra8_c6link_event::ssid_len.

Referenced by internal_c6link_rpc_event().

◆ internal_c6link_rpc_ev_disconnected()

void internal_c6link_rpc_ev_disconnected ( ra8_c6link_event_t * ev,
const WifiEventStaDisconnected * body )
static

Turn a decoded station-disconnected event into a first-party record.

Carries the field an IP driver acts on: the 802.11 reason code, which is how a vanished AP is told from a rejected passphrase.

Parameters
[out]evRecord to fill; must be non-null and already cleared.
[in]bodyDecoded event body; null leaves ev with its kind only.
Returns
Nothing.
Precondition
ev has been zero-initialised by the caller.
body belongs to a message still owned by the decoder.
Postcondition
ev carries the 802.11 reason code the AP or the radio supplied.
Every string in ev is NUL-terminated.
Note
The reason code is the actionable field: an IP driver distinguishes "AP went away" from "credentials rejected" by it alone.
Since
0.1.0

Definition at line 263 of file ra8_c6link_rpc.c.

References ra8_c6link_event::bssid, priv_c6link_copy_mac(), priv_c6link_copy_str(), RA8_INTERNAL, ra8_c6link_event::reason, ra8_c6link_event::rssi, ra8_c6link_event::ssid, and ra8_c6link_event::ssid_len.

Referenced by internal_c6link_rpc_event().

◆ internal_c6link_rpc_event()

void internal_c6link_rpc_event ( ra8_c6link_t * link,
const Rpc * msg )
static

Decode one announcement and hand it to the link's callback.

One switch over the four announcements this facade models. Everything else the protocol defines returns before a record is built.

Parameters
[in,out]linkOpen handle; must be non-null.
[in]msgDecoded message whose msg_type is Event; must be non-null.
Returns
Nothing.
Precondition
msg is still owned by the decoder and its arena is live.
link is open.
Postcondition
Announcements this library models were delivered exactly once.
Announcements it does not model changed no link state.
Note
Events outside the four modelled kinds are ignored rather than half-decoded into a record no caller can interpret.
Since
0.1.0

Definition at line 291 of file ra8_c6link_rpc.c.

References internal_c6link_rpc_ev_connected(), internal_c6link_rpc_ev_disconnected(), k_ra8_c6link_event_boot, k_ra8_c6link_event_sta_connected, k_ra8_c6link_event_sta_disconnected, k_ra8_c6link_event_wifi, ra8_c6link_event::kind, priv_c6link_emit(), RA8_INTERNAL, ra8_c6link_event::reset_reason, and ra8_c6link_event::wifi_event_id.

Referenced by priv_c6link_rpc_consume().

◆ internal_c6link_rpc_stage()

ra8_err_t internal_c6link_rpc_stage ( ra8_c6link_t * link,
Rpc * req )
static

Stage a packed request in the link's transmit transaction.

Packs directly into the transmit transaction behind its envelope, so the message is never copied twice: the encoder writes where the transport will read from.

Parameters
[in,out]linkOpen handle; must be non-null.
[in]reqRequest to pack; must be non-null with its UID already set.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe request is staged and tx_len describes it.
k_ra8_err_invalid_sizeThe envelope plus message exceeds one frame.
k_ra8_err_validation_failedThe codec packed a different number of bytes than it predicted.
Precondition
The transmit transaction is free, which the busy check guarantees.
req is fully populated.
Postcondition
On success the payload sits behind the payload header, ready to seal.
On failure tx_len is zero.
Note
Packs directly into the transaction, so nothing is copied twice.
Since
0.1.0

Definition at line 78 of file ra8_c6link_rpc.c.

References k_ra8_c6link_header_bytes, k_ra8_c6link_max_payload, k_ra8_err_invalid_size, k_ra8_err_validation_failed, k_ra8_ok, priv_c6link_tlv_open(), RA8_INTERNAL, ra8_c6link::tx, ra8_c6link::tx_if, and ra8_c6link::tx_len.

Referenced by priv_c6link_rpc_call().

◆ priv_c6link_resp()

ra8_err_t priv_c6link_resp ( ra8_c6link_t * link,
uint32_t rpc_id,
int32_t resp )
nodiscard

Map a co-processor result code onto an ra8 error, recording it.

Every Resp_* message carries an int32_t resp that is an esp_err_t on the far side. This preserves the general-purpose error's meaning in the RA8 domain while recording both the original value and request id in the fault slot. Unknown and component-specific values remain protocol errors, but the retained raw status still tells bring-up exactly what the C6 reported.

Parameters
[in,out]linkOpen handle; must be non-null.
[in]rpc_idRPC_ID__Req_* the answer belongs to.
[in]respThe co-processor's result code.
Returns
ra8_err_t Error code.
Return values
k_ra8_okresp was zero and the fault slot was cleared.
k_ra8_err_*A mapped general error, or protocol error for an unknown status; the fault slot names rpc_id and the exact raw resp.
Precondition
link is open.
resp came from a decoded answer, not from a default.
Postcondition
The fault slot reflects exactly this call.
No other link state is modified.
Note
Not thread-safe.
Example:
return priv_c6link_resp(link, RPC_ID__Req_WifiStart, body->resp);
See also
ra8_c6link_last_fault
Since
0.1.0

Definition at line 153 of file ra8_c6link_rpc.c.

References ra8_c6link::fault, internal_c6link_remote_error(), k_ra8_err_null_ptr, k_ra8_ok, RA8_PRIV, ra8_c6link_fault::resp, and ra8_c6link_fault::rpc_id.

Referenced by internal_c6link_take_ap(), internal_c6link_take_fw(), internal_c6link_take_mac(), internal_mdl_take_response(), and priv_c6link_take_resp().

◆ priv_c6link_rpc_call()

ra8_err_t priv_c6link_rpc_call ( ra8_c6link_t * link,
Rpc * req,
uint32_t resp_id,
ra8_c6link_take_fn_t take,
void * take_ctx )
nodiscard

Issue one request and pump until its answer arrives.

Assigns a fresh UID, packs req into the transmit transaction behind its TLV envelope, arms the link's wait slot, and pumps. Announcements and Ethernet frames that arrive meanwhile are dispatched normally; the pump stops as soon as the answer is extracted.

Parameters
[in,out]linkOpen handle; must be non-null.
[in,out]reqRequest to send; must be non-null and fully populated apart from its UID, which this call assigns.
[in]resp_idRPC_ID__Resp_* that answers req.
[in]takeExtractor for the answer's fields; must be non-null.
[in]take_ctxContext handed to take.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe answer arrived and take accepted it.
k_ra8_err_null_ptrAn argument was null.
k_ra8_err_not_initializedlink is not open.
k_ra8_err_busyA request is already outstanding.
k_ra8_err_invalid_sizeThe packed request does not fit a frame.
k_ra8_err_validation_failedThe codec packed a different number of bytes than it predicted.
k_ra8_err_timeoutNo answer arrived within the budget.
k_ra8_err_hw_timeoutThe co-processor never armed HANDSHAKE, so no transaction was clocked.
k_ra8_err_protocol_errortake rejected the answer.
k_ra8_err_spi_errorThe transport refused a transfer.
Precondition
The transport is up.
No other request is outstanding on link.
Postcondition
The wait slot is disarmed however the call ends.
On failure the link's last fault names req.
Note
Not thread-safe; it pumps.
Example:
(void)priv_c6link_rpc_call(link, &req, RPC_ID__Resp_WifiStart, take, &out);
See also
priv_c6link_rpc_consume
Since
0.1.0

Definition at line 168 of file ra8_c6link_rpc.c.

References ra8_c6link_wait::armed, ra8_c6link::fault, internal_c6link_rpc_stage(), k_ra8_c6link_rpc_transfers, k_ra8_err_busy, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_err_timeout, k_ra8_ok, ra8_c6link::next_uid, ra8_c6link::open, priv_c6link_pump(), RA8_PRIV, ra8_secure_memzero(), ra8_c6link_fault::resp, ra8_c6link_wait::result, ra8_c6link_fault::rpc_id, ra8_c6link_wait::satisfied, ra8_c6link::tx, ra8_c6link::tx_len, and ra8_c6link::wait.

Referenced by internal_c6link_sta_set_config(), internal_c6link_wifi_do_init(), internal_c6link_wifi_do_mode(), internal_mdl_call(), priv_c6link_bare_req(), ra8_c6link_fw_version(), ra8_c6link_wifi_ap_info(), and ra8_c6link_wifi_mac().

◆ priv_c6link_rpc_consume()

bool priv_c6link_rpc_consume ( ra8_c6link_t * link,
const uint8_t * payload,
uint16_t len )
nodiscard

Decode one control-plane payload and act on it.

Unwraps the envelope, decodes the message into the arena, then either satisfies the outstanding wait, delivers an announcement, or drops it. The arena is reset before returning however that goes.

Parameters
[in,out]linkOpen handle; must be non-null.
[in]payloadFrame payload; must be non-null.
[in]lenPayload length in bytes.
Returns
true when the outstanding wait was satisfied and the pump should stop.
Return values
trueThe awaited answer arrived and was extracted.
falseAnything else, including a delivered announcement.
Precondition
len bytes are readable at payload.
The link's arena is empty.
Postcondition
The arena is empty again.
At most one wait is satisfied per call.
Note
Not thread-safe; runs inside the pump.
Example:
if (priv_c6link_rpc_consume(link, &link->rx[view.offset], view.len)) { break; }
See also
priv_c6link_rpc_call
Since
0.1.0

Definition at line 359 of file ra8_c6link_rpc.c.

References internal_c6link_rpc_answer(), internal_c6link_rpc_event(), priv_c6link_arena_bind(), priv_c6link_arena_reset(), priv_c6link_tlv_body(), RA8_PRIV, ra8_c6link_stats::rpc_in, ra8_c6link::stats, and ra8_c6link_stats::undecodable.

Referenced by priv_c6link_dispatch().