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

The ESP_SERIAL_IF RPC channel: request, response, verdict. More...

#include <stddef.h>
#include <stdint.h>
#include "c6_fwver.h"
#include "esp_hosted_host_fw_ver.h"
#include "esp_hosted_interface.h"
#include "esp_hosted_os_abstraction.h"
#include "esp_hosted_rpc.pb-c.h"
#include "esp_hosted_transport.h"
#include "protobuf-c/protobuf-c.h"
#include "transport_drv.h"
Include dependency graph for c6_fwver_rpc.c:

Go to the source code of this file.

Data Structures

struct  c6_fwver_rsp
 Every field this application read out of the RPC response. More...

Typedefs

typedef struct c6_fwver_rsp c6_fwver_rsp_t

Enumerations

enum  c6_fwver_tlv_t : uint16_t {
  k_c6_fwver_tlv_t_epname = 0x01U ,
  k_c6_fwver_tlv_t_data = 0x02U ,
  k_c6_fwver_tlv_type = 0U ,
  k_c6_fwver_tlv_len_lo = 1U ,
  k_c6_fwver_tlv_len_hi = 2U ,
  k_c6_fwver_tlv_value = 3U ,
  k_c6_fwver_tlv_ep_len = (uint16_t)(sizeof(RPC_EP_NAME_RSP) - 1U) ,
  k_c6_fwver_tlv_overhead ,
  k_c6_fwver_tlv_shift = 8U ,
  k_c6_fwver_tlv_mask = 0xFFU
}
 The serial endpoint's TLV envelope, tag by tag. More...

Functions

static void * c6_fwver_rpc_pool_alloc (void *allocator_data, size_t size)
 Allocate through the esp-hosted port's fixed byte pool.
static void c6_fwver_rpc_pool_free (void *allocator_data, void *pointer)
 Return a block to the esp-hosted port's fixed byte pool.
static uint16_t c6_fwver_tlv_head (uint8_t *out, uint16_t at, uint8_t type, uint16_t len)
 Write one TLV tag header at a cursor.
ra8_err_t c6_fwver_rpc_request (uint8_t *out, uint16_t cap, uint16_t *out_len)
 Build the TLV-wrapped RPC firmware-version request.
static const uint8_t * c6_fwver_tlv_body (const uint8_t *payload, uint16_t len, uint16_t *proto_len)
 Strip the TLV envelope off a received serial payload.
static void c6_fwver_rpc_take_target (const ProtobufCBinaryData *target)
 Copy the response's target string into the record, bounded.
static bool c6_fwver_rpc_take (const Rpc *msg)
 Record a decoded message if it is the awaited response.
bool c6_fwver_rpc_consume (uint8_t if_type, uint8_t if_num, const uint8_t *payload, uint16_t len)
 Decode an ESP_SERIAL_IF frame as the awaited RPC response.
static void c6_fwver_rpc_print_response (void)
 Print the decoded response, field by field.
static void c6_fwver_rpc_print_crosscheck (void)
 Report the boot event's version reading beside the RPC's.
static void c6_fwver_rpc_print_expectation (void)
 Print what this host expects, before it says what it got.
bool c6_fwver_rpc_report (void)
 Print the recorded response and decide the run's verdict.
bool c6_fwver_dispatch (uint8_t if_type, uint8_t if_num, const uint8_t *payload, uint16_t len)
 Route a received frame to the module that understands it.

Variables

static c6_fwver_rsp_t s_c6_fwver_rsp
 The one response this application is waiting for.
static ProtobufCAllocator s_c6_fwver_allocator
 The allocator the generated protobuf decoder is handed.

Detailed Description

The ESP_SERIAL_IF RPC channel: request, response, verdict.

Tag
[Ring 6 / APP] {World: S}

The esp-hosted control plane is protobuf over a two-tag TLV envelope over ESP_SERIAL_IF. All three layers are exercised here:

  • protobuf through the vendored generated codec (common/proto/esp_hosted_rpc.pb-c.c) and the vendored protobuf-c runtime, both of which this tree already compiles. The message is not hand-encoded: hand-encoding it would prove only that this file and the co-processor agree, which is a much weaker claim than the generated codec and the co-processor agreeing.
  • TLV in first-party code here, mirroring compose_tlv() and parse_tlv() in the vendored serial_if.c. That file is not compiled in this tree because its send path expands HOSTED_CALLOC, whose failure arm is a goto that NASA Power of 10 Rule 1 forbids (see the reasoning in cmake/esp_hosted.cmake). The envelope itself is six bytes of framing, restated here rather than dragged in with a rule violation attached.
  • the payload header and the transaction, which belong to src/c6_fwver_link.c.

The request is RPC_ID__Req_GetCoprocessorFwVersion. It was chosen because its answer is checkable: the vendored host driver states its own version in esp_hosted_host_fw_ver.h, and the co-processor image was built from the same pinned upstream commit, so the two must agree exactly. The verdict is therefore the host/co-processor version lock – the hazard #316 exists to police – rather than "some bytes came back".

Allocation
rpc__unpack() needs an allocator. This image has no heap, so it is given one backed by the esp-hosted port's fixed ThreadX byte pool: the same storage the vendored transport allocates its buffers from, carved once at init, which is what keeps the whole path inside NASA Power of 10 Rule 3. Every unpacked message is freed on every path.
Since
0.1.0

Definition in file c6_fwver_rpc.c.

Typedef Documentation

◆ c6_fwver_rsp_t

typedef struct c6_fwver_rsp c6_fwver_rsp_t

Enumeration Type Documentation

◆ c6_fwver_tlv_t

enum c6_fwver_tlv_t : uint16_t

The serial endpoint's TLV envelope, tag by tag.

Two tags, each a one-byte type followed by a little-endian 16-bit length: the endpoint name, then the protobuf payload. The endpoint-name length is taken from the vendored RPC_EP_NAME_RSP string rather than written down, because upstream requires both endpoint names to have the same length and the parser checks that.

Invariant
k_c6_fwver_tlv_ep_len equals strlen(RPC_EP_NAME_RSP).
k_c6_fwver_tlv_overhead is the exact envelope cost, so a capacity check against it is neither loose nor tight.
Example:
@ k_c6_fwver_tlv_type
Offset of a tag's type byte.
@ k_c6_fwver_tlv_t_epname
Tag introducing the endpoint name.
See also
c6_fwver_rpc_request
Since
0.1.0
Enumerator
k_c6_fwver_tlv_t_epname 

Tag introducing the endpoint name.

k_c6_fwver_tlv_t_data 

Tag introducing the protobuf payload.

k_c6_fwver_tlv_type 

Offset of a tag's type byte.

k_c6_fwver_tlv_len_lo 

Offset of a tag's length, low byte.

k_c6_fwver_tlv_len_hi 

Offset of a tag's length, high byte.

k_c6_fwver_tlv_value 

Offset of a tag's value.

k_c6_fwver_tlv_ep_len 

Endpoint-name length; both endpoint names share it.

k_c6_fwver_tlv_overhead 

Bytes the envelope costs on top of the protobuf payload.

k_c6_fwver_tlv_shift 

Shift between the two length bytes.

k_c6_fwver_tlv_mask 

Byte mask for the low length byte.

Definition at line 77 of file c6_fwver_rpc.c.

Function Documentation

◆ c6_fwver_dispatch()

bool c6_fwver_dispatch ( uint8_t if_type,
uint8_t if_num,
const uint8_t * payload,
uint16_t len )

Route a received frame to the module that understands it.

Parameters
[in]if_typeInterface type from the received header.
[in]if_numInterface number from the received header.
[in]payloadFrame payload; null is ignored.
[in]lenPayload length in bytes.
Returns
true when the pump should stop.
Return values
trueThe RPC layer accepted the awaited response.
falseEverything else, including announcements.
Precondition
The console is up.
len bytes are readable at payload.
Postcondition
Exactly one module was offered the frame.
No application state is modified beyond that module's own.
Note
Matches c6_fwver_sink_t; it is the sink every pump is given.
See also
c6_fwver_link_pump
Since
0.1.0

Definition at line 539 of file c6_fwver_rpc.c.

References c6_fwver_priv_consume(), c6_fwver_put_u32(), c6_fwver_puts(), and c6_fwver_rpc_consume().

Referenced by c6_fwver_phase_caps(), and c6_fwver_phase_request().

◆ c6_fwver_rpc_consume()

bool c6_fwver_rpc_consume ( uint8_t if_type,
uint8_t if_num,
const uint8_t * payload,
uint16_t len )

Decode an ESP_SERIAL_IF frame as the awaited RPC response.

Unwraps the TLV envelope, unpacks the Rpc message with the vendored codec, and – only when it is the response to this application's request – records every field for the verdict.

Parameters
[in]if_typeInterface type from the received header.
[in]if_numInterface number from the received header.
[in]payloadFrame payload; null is ignored.
[in]lenPayload length in bytes.
Returns
true when the awaited response has been recorded and the pump should stop.
Return values
trueThe response to this request arrived and was decoded.
falseThe frame was something else, or could not be decoded.
Precondition
The console is up.
len bytes are readable at payload.
Postcondition
On true the recorded response is complete and c6_fwver_rpc_report can judge it.
No frame is decoded twice: the first accepted response wins.
Note
Matches c6_fwver_sink_t so the pump can call it directly.
See also
c6_fwver_rpc_report
Since
0.1.0

Definition at line 369 of file c6_fwver_rpc.c.

References c6_fwver_put_u32(), c6_fwver_puts(), c6_fwver_rpc_take(), c6_fwver_tlv_body(), s_c6_fwver_allocator, and s_c6_fwver_rsp.

Referenced by c6_fwver_dispatch().

◆ c6_fwver_rpc_pool_alloc()

void * c6_fwver_rpc_pool_alloc ( void * allocator_data,
size_t size )
static

Allocate through the esp-hosted port's fixed byte pool.

Parameters
[in]allocator_dataUnused; the pool is a module singleton.
[in]sizeBytes requested.
Returns
Pointer to the block, or null when the pool cannot serve it.
Return values
NULLThe fixed pool is exhausted.
Precondition
The esp-hosted port is up, so the pool exists.
The caller frees through c6_fwver_rpc_pool_free.
Postcondition
No pool bookkeeping is bypassed.
A failure returns null rather than growing the address space.
Note
This is the whole reason a protobuf decoder is legal in a heapless image: the storage is a carve made once during initialisation.
Since
0.1.0

Definition at line 149 of file c6_fwver_rpc.c.

References g_h.

◆ c6_fwver_rpc_pool_free()

void c6_fwver_rpc_pool_free ( void * allocator_data,
void * pointer )
static

Return a block to the esp-hosted port's fixed byte pool.

Parameters
[in]allocator_dataUnused; the pool is a module singleton.
[in]pointerBlock to release; null is ignored.
Returns
Nothing.
Precondition
pointer came from c6_fwver_rpc_pool_alloc, or is null.
No other context holds a reference to the block.
Postcondition
The block is available to the pool again.
A null pointer is a no-op rather than a fault.
Note
Paired with c6_fwver_rpc_pool_alloc through the one ProtobufCAllocator this file installs.
Since
0.1.0

Definition at line 168 of file c6_fwver_rpc.c.

References g_h.

◆ c6_fwver_rpc_print_crosscheck()

void c6_fwver_rpc_print_crosscheck ( void )
static

Report the boot event's version reading beside the RPC's.

Returns
Nothing.
Precondition
The console is up.
A pump has run, so the event either arrived or provably did not.
Postcondition
Exactly one line was emitted.
No application state is modified.
Note
This is a cross-check, never a gate: the co-processor queues the INIT event once per boot, so a rerun without power-cycling the C6 legitimately has nothing to compare.
Since
0.1.0

Definition at line 450 of file c6_fwver_rpc.c.

References c6_fwver_priv_init_version(), c6_fwver_put_u32(), c6_fwver_puts(), and s_c6_fwver_rsp.

Referenced by c6_fwver_rpc_report().

◆ c6_fwver_rpc_print_expectation()

void c6_fwver_rpc_print_expectation ( void )
static

Print what this host expects, before it says what it got.

Returns
Nothing.
Precondition
The console is up.
The expectations are compile-time constants, so this cannot disagree with the comparison c6_fwver_rpc_report then performs.
Postcondition
Exactly one line was emitted.
No application state is modified.
Note
Printed unconditionally, including on the no-response path: a run that fails is exactly the run whose reader most wants to know what was being asked for.
Since
0.1.0

Definition at line 484 of file c6_fwver_rpc.c.

References c6_fwver_put_hex(), c6_fwver_put_u32(), c6_fwver_puts(), k_c6_fwver_hex_byte, and k_c6_fwver_rpc_uid.

Referenced by c6_fwver_rpc_report().

◆ c6_fwver_rpc_print_response()

void c6_fwver_rpc_print_response ( void )
static

Print the decoded response, field by field.

Returns
Nothing.
Precondition
s_c6_fwver_rsp holds a decoded response.
The console is up.
Postcondition
One line naming every decoded field was emitted.
No application state is modified.
Note
Split out of c6_fwver_rpc_report so the verdict logic there stays readable and inside the NASA Rule 4 length budget.
Since
0.1.0

Definition at line 419 of file c6_fwver_rpc.c.

References c6_fwver_put_hex(), c6_fwver_put_i32(), c6_fwver_put_text(), c6_fwver_put_u32(), c6_fwver_puts(), k_c6_fwver_hex_byte, and s_c6_fwver_rsp.

Referenced by c6_fwver_rpc_report().

◆ c6_fwver_rpc_report()

bool c6_fwver_rpc_report ( void )

Print the recorded response and decide the run's verdict.

Prints every decoded field, then the version this host expects, and then exactly one PASS/FAIL line. The expectation is the vendored host driver's own version from esp_hosted_host_fw_ver.h, so the check is the host/co-processor version lock rather than a literal written twice.

Returns
true when the response arrived and every checked field matched.
Return values
trueThe co-processor answered with the expected version.
falseNo response arrived, or a field did not match.
Precondition
The console is up.
A pump has run, so a response either arrived or provably did not.
Postcondition
Exactly one verdict line was emitted.
No application state is modified.
Note
The verdict is printed here rather than returned only, so the console capture that CI greps and the value the code sees cannot disagree.
See also
c6_fwver_rpc_consume
Since
0.1.0

Definition at line 499 of file c6_fwver_rpc.c.

References c6_fwver_put_u32(), c6_fwver_puts(), c6_fwver_rpc_print_crosscheck(), c6_fwver_rpc_print_expectation(), c6_fwver_rpc_print_response(), k_c6_fwver_rpc_uid, and s_c6_fwver_rsp.

Referenced by c6_fwver_worker_entry().

◆ c6_fwver_rpc_request()

ra8_err_t c6_fwver_rpc_request ( uint8_t * out,
uint16_t cap,
uint16_t * out_len )
nodiscard

Build the TLV-wrapped RPC firmware-version request.

Packs an Rpc protobuf message carrying RPC_ID__Req_GetCoprocessorFwVersion with the vendored generated codec, then wraps it in the two-tag TLV envelope the co-processor's serial endpoint expects (endpoint name, then data), exactly as compose_tlv() does in the vendored serial_if.c.

Parameters
[out]outBuffer to fill; must be non-null.
[in]capBytes available at out.
[out]out_lenBytes written; must be non-null.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe request was built and out_len is its length.
k_ra8_err_null_ptrout or out_len was null.
k_ra8_err_invalid_sizecap cannot hold the envelope.
k_ra8_err_validation_failedThe generated codec packed a different number of bytes than it predicted.
Precondition
cap bytes are writable at out.
The caller transmits the result on ESP_SERIAL_IF, interface 0.
Postcondition
On success out_len is non-zero and at most cap.
On failure out_len is zero.
Note
Pure formatting; touches no hardware and is safe from any thread.
See also
c6_fwver_rpc_consume
Since
0.1.0

Definition at line 217 of file c6_fwver_rpc.c.

References c6_fwver_tlv_head(), k_c6_fwver_rpc_uid, k_c6_fwver_tlv_ep_len, k_c6_fwver_tlv_overhead, k_c6_fwver_tlv_t_data, k_c6_fwver_tlv_t_epname, k_ra8_err_invalid_size, k_ra8_err_null_ptr, k_ra8_err_validation_failed, and k_ra8_ok.

Referenced by c6_fwver_phase_request().

◆ c6_fwver_rpc_take()

bool c6_fwver_rpc_take ( const Rpc * msg)
static

Record a decoded message if it is the awaited response.

Parameters
[in]msgDecoded Rpc message; must be non-null.
Returns
true when the record was filled from msg.
Return values
trueThis is the response to this application's request.
falseIt is an event, a different response, or a different UID.
Precondition
msg came from rpc__unpack and is still owned by the caller.
s_c6_fwver_rsp has not already been filled.
Postcondition
On true every field of the record is set from msg.
msg itself is not modified or freed here.
Note
The UID check is what makes this a round trip rather than a coincidence: the co-processor echoes the request's UID back.
Since
0.1.0

Definition at line 350 of file c6_fwver_rpc.c.

References c6_fwver_rpc_take_target(), and s_c6_fwver_rsp.

Referenced by c6_fwver_rpc_consume().

◆ c6_fwver_rpc_take_target()

void c6_fwver_rpc_take_target ( const ProtobufCBinaryData * target)
static

Copy the response's target string into the record, bounded.

Parameters
[in]targetBinary field from the decoded message.
Returns
Nothing.
Precondition
s_c6_fwver_rsp is the live record.
target's data covers len bytes, or len is zero.
Postcondition
target_len is at most the record's capacity.
Every copied byte came from the decoded message.
Note
The loop is bounded by the record capacity (NASA Rule 2); a longer string is truncated rather than trusted.
Since
0.1.0

Definition at line 322 of file c6_fwver_rpc.c.

References k_c6_fwver_text_max, and s_c6_fwver_rsp.

Referenced by c6_fwver_rpc_take().

◆ c6_fwver_tlv_body()

const uint8_t * c6_fwver_tlv_body ( const uint8_t * payload,
uint16_t len,
uint16_t * proto_len )
static

Strip the TLV envelope off a received serial payload.

Parameters
[in]payloadFrame payload; must be non-null.
[in]lenPayload length in bytes.
[out]proto_lenProtobuf length found; must be non-null.
Returns
Pointer to the protobuf bytes, or null when the envelope is not one this endpoint recognises.
Return values
NULLThe tags, the endpoint name or the lengths did not check out.
Precondition
len bytes are readable at payload.
proto_len is writable.
Postcondition
On success proto_len is non-zero and the returned range lies wholly inside payload.
On failure proto_len is zero.
Note
Both endpoint names are accepted, as parse_tlv() does upstream: a response arrives on RPCRsp and an unsolicited event on RPCEvt, and the two are the same length by construction.
Since
0.1.0

Definition at line 273 of file c6_fwver_rpc.c.

References k_c6_fwver_tlv_ep_len, k_c6_fwver_tlv_len_hi, k_c6_fwver_tlv_len_lo, k_c6_fwver_tlv_overhead, k_c6_fwver_tlv_shift, k_c6_fwver_tlv_t_data, k_c6_fwver_tlv_t_epname, k_c6_fwver_tlv_type, and k_c6_fwver_tlv_value.

Referenced by c6_fwver_rpc_consume().

◆ c6_fwver_tlv_head()

uint16_t c6_fwver_tlv_head ( uint8_t * out,
uint16_t at,
uint8_t type,
uint16_t len )
static

Write one TLV tag header at a cursor.

Parameters
[out]outBuffer being filled; must be non-null.
[in]atOffset to write at.
[in]typeTag type.
[in]lenValue length that follows.
Returns
The offset just past the three-byte tag header.
Precondition
At least k_c6_fwver_tlv_value bytes are writable at out + at.
The caller has already checked the buffer capacity.
Postcondition
Exactly three bytes were written, length little-endian.
The returned offset addresses the tag's value.
Note
Matches the byte order compose_tlv() writes in the vendored serial_if.c: low byte first.
Since
0.1.0

Definition at line 208 of file c6_fwver_rpc.c.

References k_c6_fwver_tlv_len_hi, k_c6_fwver_tlv_len_lo, k_c6_fwver_tlv_mask, k_c6_fwver_tlv_shift, k_c6_fwver_tlv_type, and k_c6_fwver_tlv_value.

Referenced by c6_fwver_rpc_request().

Variable Documentation

◆ s_c6_fwver_allocator

ProtobufCAllocator s_c6_fwver_allocator
static
Initial value:
= {
.allocator_data = nullptr,
}
static void * c6_fwver_rpc_pool_alloc(void *allocator_data, size_t size)
Allocate through the esp-hosted port's fixed byte pool.
static void c6_fwver_rpc_pool_free(void *allocator_data, void *pointer)
Return a block to the esp-hosted port's fixed byte pool.

The allocator the generated protobuf decoder is handed.

Points at the esp-hosted port's fixed pool, never at newlib's heap: _sbrk in this image is a strong symbol that reports a fatal error, so the default protobuf-c allocator would fault rather than fail.

Note
Read by the vendored codec; never modified after initialisation.
Warning
Passing null instead would select that default allocator, which is the fault above; the pointer is not optional.
Since
0.1.0

Definition at line 187 of file c6_fwver_rpc.c.

Referenced by c6_fwver_rpc_consume().

◆ s_c6_fwver_rsp

c6_fwver_rsp_t s_c6_fwver_rsp
static

The one response this application is waiting for.

File scope because the sink that fills it and the report that judges it are different calls on different stacks.

Note
Written only from the pump thread, inside c6_fwver_rpc_consume.
Warning
The first accepted response wins; a later one is ignored so the verdict cannot be rewritten by a stray frame.
Since
0.1.0

Definition at line 133 of file c6_fwver_rpc.c.

Referenced by c6_fwver_rpc_consume(), c6_fwver_rpc_print_crosscheck(), c6_fwver_rpc_print_response(), c6_fwver_rpc_report(), c6_fwver_rpc_take(), and c6_fwver_rpc_take_target().