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

The esp-hosted transaction pump: frame in, frame out, counted. More...

#include <stdint.h>
#include "c6_fwver.h"
#include "esp_hosted_header.h"
#include "esp_hosted_interface.h"
#include "esp_hosted_os_abstraction.h"
#include "esp_hosted_transport.h"
#include "port_esp_hosted_host_config.h"
#include "port_esp_hosted_host_os.h"
#include "ra8_esp_hosted_port.h"
#include "transport_drv.h"
Include dependency graph for c6_fwver_link.c:

Go to the source code of this file.

Enumerations

enum  c6_fwver_proto_t : uint16_t {
  k_c6_fwver_hdr_bytes = (uint16_t)sizeof(struct esp_payload_header) ,
  k_c6_fwver_max_payload = (uint16_t)MAX_PAYLOAD_SIZE ,
  k_c6_fwver_nibble_mask = 0x0FU ,
  k_c6_fwver_ifnum_shift = 4U
}
 Protocol constants the pump judges a received frame against. More...

Functions

static void c6_fwver_tx_clear (void)
 Zero the whole transmit frame.
static void c6_fwver_tx_filler (void)
 Stamp the transmit frame as the host's idle filler.
static void c6_fwver_tx_frame (uint8_t if_type, uint8_t if_num, const uint8_t *payload, uint16_t len)
 Wrap a payload in a payload header, checksum included.
static bool c6_fwver_wait_handshake (void)
 Wait, bounded, for the co-processor to arm HANDSHAKE.
static uint16_t c6_fwver_rx_checksum (uint16_t span)
 Recompute the received frame's checksum over header plus payload.
static void c6_fwver_print_reject (const char *why, uint16_t calc)
 Print every header field of a frame the pump is about to drop.
static bool c6_fwver_ifnum_defect (uint16_t calc, uint16_t stated)
 Decide whether a checksum failure is the known if_num defect.
static bool c6_fwver_rx_dispatch (c6_fwver_sink_t sink, c6_fwver_pump_stats_t *stats)
 Classify the received frame and deliver it if it is real.
static ra8_err_t c6_fwver_pump_check (const uint8_t *payload, uint16_t payload_len, uint16_t max_transfers, const c6_fwver_pump_stats_t *stats)
 Reject a pump request whose arguments cannot be honoured.
ra8_err_t c6_fwver_link_pump (uint8_t if_type, uint8_t if_num, const uint8_t *payload, uint16_t payload_len, uint16_t max_transfers, c6_fwver_sink_t sink, c6_fwver_pump_stats_t *stats)
 Clock full-duplex transactions until the sink is satisfied.

Variables

static c6_fwver_frame_t s_c6_fwver_tx
 Transmit buffer for the frame the pump is currently clocking.
static c6_fwver_frame_t s_c6_fwver_rx
 Receive buffer the co-processor's frame lands in.

Detailed Description

The esp-hosted transaction pump: frame in, frame out, counted.

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

This is the application's own reduction of the vendored spi_transaction_task down to what a bring-up needs. The vendored task cannot be used here: it lives in transport_drv.c, which is written against ESP-IDF's Wi-Fi API and is deliberately not compiled into this tree (see cmake/esp_hosted.cmake). What it does on the wire, though, is small and fully specified, and this file does exactly that and nothing more:

  1. wait for HANDSHAKE to go active – the co-processor's "I am armed for the next transaction" signal;
  2. transmit either the caller's one payload, wrapped in a payload header with the checksum get_next_tx_buffer() computes, or an ESP_MAX_IF filler frame, which is what the reference host sends when it has nothing queued;
  3. clock 1600 bytes full duplex through _h_do_bus_transfer;
  4. classify what came back, exactly as process_spi_rx_buf() does: zero length is filler, an offset that is not the header size or a length past MAX_PAYLOAD_SIZE is malformed, and everything else is checksum-verified before it is believed.

Filler frames are counted rather than delivered. Their header is genuinely not a header – the co-processor stamps if_type = ESP_MAX_IF, if_num = 0x0F and leaves offset at zero – which is why c6_hosted_init first read one as "offset is not the payload-header size". Judging a filler frame by the rules for a data frame is a false negative, and this file does not repeat it.

Since
0.1.0

Definition in file c6_fwver_link.c.

Enumeration Type Documentation

◆ c6_fwver_proto_t

enum c6_fwver_proto_t : uint16_t

Protocol constants the pump judges a received frame against.

Each is derived from a vendored header, so an upstream change to the payload header or the transport buffer moves this file with it instead of leaving a stale literal behind.

Invariant
k_c6_fwver_hdr_bytes is the offset a well-formed data frame carries.
k_c6_fwver_max_payload bounds the length such a frame may advertise; anything larger cannot fit the transaction.
Example:
if (rx.header.offset != (uint16_t)k_c6_fwver_hdr_bytes) { reject(); }
See also
esp_payload_header
Since
0.1.0
Enumerator
k_c6_fwver_hdr_bytes 

Payload-header size; twelve bytes on this ABI.

k_c6_fwver_max_payload 

Largest payload a valid data frame may advertise.

k_c6_fwver_nibble_mask 

Mask applied before a write to a four-bit header field.

if_type and if_num share one byte, and an unmasked assignment is a narrowing conversion the project's -Wconversion rejects.

k_c6_fwver_ifnum_shift 

Bit position of if_num within the header's first byte.

Used to reconstruct how much a non-zero if_num contributes to the frame checksum, which is what identifies the co-processor defect below.

Definition at line 70 of file c6_fwver_link.c.

Function Documentation

◆ c6_fwver_ifnum_defect()

bool c6_fwver_ifnum_defect ( uint16_t calc,
uint16_t stated )
static

Decide whether a checksum failure is the known if_num defect.

The ESP32-C6 running esp-hosted-mcu 2.12.11 transmits its bootup ESP_PRIV_IF INIT event with a non-zero if_num in the header's first byte, but computes the frame checksum with that nibble still zero. The shortfall is therefore exactly if_num << 4, and a host that tests for that can say so by name instead of reporting an unexplained mismatch.

This DIAGNOSES; it does not excuse. The frame is still dropped, because the bytes on the wire do not match the integrity check that accompanies them and a host that decoded them anyway would be trusting an unverified header.

Parameters
[in]calcChecksum recomputed over the frame as received.
[in]statedChecksum the co-processor put in the header.
Returns
true when the shortfall is exactly the if_num contribution.
Return values
trueThe mismatch is fully explained by the defect above.
falseThe mismatch is something else, and stays unexplained.
Precondition
The transfer has completed and s_c6_fwver_rx is stable.
calc and stated genuinely disagree.
Postcondition
No module state is modified.
No frame is accepted as a result of this call.
Note
The arithmetic is deliberately 16-bit and wrapping, matching the accumulator in the vendored compute_checksum().
Since
0.1.0

Definition at line 295 of file c6_fwver_link.c.

References k_c6_fwver_ifnum_shift, and s_c6_fwver_rx.

Referenced by c6_fwver_rx_dispatch().

◆ c6_fwver_link_pump()

ra8_err_t c6_fwver_link_pump ( uint8_t if_type,
uint8_t if_num,
const uint8_t * payload,
uint16_t payload_len,
uint16_t max_transfers,
c6_fwver_sink_t sink,
c6_fwver_pump_stats_t * stats )
nodiscard

Clock full-duplex transactions until the sink is satisfied.

The pump is this application's stand-in for the vendored spi_transaction_task, reduced to what a bring-up needs: it transmits at most one payload, then keeps clocking filler frames so the co-processor has transactions to answer in. Each iteration waits for HANDSHAKE, builds either the pending payload frame or an ESP_MAX_IF filler, clocks _h_do_bus_transfer, and classifies what came back. Frames that are well-formed and carry a payload go to sink; filler and malformed frames are counted and dropped.

Parameters
[in]if_typeInterface type for the transmitted payload, from esp_hosted_if_type_t. Ignored when payload_len is zero.
[in]if_numInterface number for the transmitted payload, 0..15.
[in]payloadPayload to transmit once, or null to pump filler only.
[in]payload_lenLength of payload in bytes; must be zero when payload is null and at most k_c6_fwver_tx_max otherwise.
[in]max_transfersTransactions this call may clock; must be non-zero.
[in]sinkReceiver for well-formed frames, or null to count only.
[out]statsCounters describing the run; must be non-null.
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe pump ran; stats says what happened.
k_ra8_err_null_ptrstats was null, or payload_len was non-zero with a null payload.
k_ra8_err_invalid_argpayload_len exceeds k_c6_fwver_tx_max, or max_transfers was zero.
k_ra8_err_not_initializedThe esp-hosted port is not up, so the vtable behind g_h cannot be called.
k_ra8_err_hw_timeoutHANDSHAKE never went active, so not one transaction was clocked.
k_ra8_err_spi_errorA bus transfer did not return RET_OK.
Precondition
ra8_esp_hosted_port_init returned k_ra8_ok.
No other context is driving the SPI bus.
Postcondition
At most max_transfers transactions were clocked.
stats holds the counts for exactly this call.
Note
Not thread-safe; one pump at a time owns the bus.
Warning
The sink runs inside the pump, so it must not start a transaction.
Example:
(void)c6_fwver_link_pump((uint8_t)ESP_SERIAL_IF, 0U, req, req_len,
ra8_err_t c6_fwver_link_pump(uint8_t if_type, uint8_t if_num, const uint8_t *payload, uint16_t payload_len, uint16_t max_transfers, c6_fwver_sink_t sink, c6_fwver_pump_stats_t *stats)
Clock full-duplex transactions until the sink is satisfied.
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.
@ k_c6_fwver_max_transfers
Transactions one pump may clock before giving up.
Definition c6_fwver.h:141
struct c6_fwver_pump_stats c6_fwver_pump_stats_t
See also
c6_fwver_pump_stats
Since
0.1.0
NASA Power of 10 Compliance:
  • Rule 2: the transaction loop is bounded by max_transfers and the HANDSHAKE wait by k_c6_fwver_hs_wait_ms.
  • Rule 5: four preconditions and two postconditions are checked.

Definition at line 395 of file c6_fwver_link.c.

References c6_fwver_pump_stats::bus_error, c6_fwver_pump_check(), c6_fwver_rx_dispatch(), c6_fwver_tx_filler(), c6_fwver_tx_frame(), c6_fwver_wait_handshake(), g_h, c6_fwver_pump_stats::hs_timeouts, k_c6_fwver_frame_bytes, k_c6_fwver_gap_ms, k_c6_fwver_hs_giveup, k_ra8_err_hw_timeout, k_ra8_err_spi_error, k_ra8_ok, RET_OK, s_c6_fwver_rx, s_c6_fwver_tx, c6_fwver_pump_stats::sink_stopped, and c6_fwver_pump_stats::transfers.

Referenced by c6_fwver_phase_caps(), and c6_fwver_phase_request().

◆ c6_fwver_print_reject()

void c6_fwver_print_reject ( const char * why,
uint16_t calc )
static

Print every header field of a frame the pump is about to drop.

Parameters
[in]whyShort reason, printed verbatim; must be non-null.
[in]calcRecomputed checksum, or zero when it was not computed.
Returns
Nothing.
Precondition
The transfer has completed and s_c6_fwver_rx is stable.
The console is up.
Postcondition
One line naming every header field was emitted.
No module state is modified.
Note
A dropped frame is the most informative thing on a bring-up bench, and a counter alone cannot say which frame it was. The call sites are inside a bounded loop, so this cannot flood the console.
Since
0.1.0

Definition at line 239 of file c6_fwver_link.c.

References c6_fwver_put_hex(), c6_fwver_put_u32(), c6_fwver_puts(), k_c6_fwver_hdr_bytes, k_c6_fwver_hex_byte, k_c6_fwver_hex_word, and s_c6_fwver_rx.

Referenced by c6_fwver_rx_dispatch().

◆ c6_fwver_pump_check()

ra8_err_t c6_fwver_pump_check ( const uint8_t * payload,
uint16_t payload_len,
uint16_t max_transfers,
const c6_fwver_pump_stats_t * stats )
static

Reject a pump request whose arguments cannot be honoured.

Parameters
[in]payloadPayload the caller passed, possibly null.
[in]payload_lenLength the caller passed.
[in]max_transfersTransaction budget the caller passed.
[in]statsCounter block the caller passed, possibly null.
Returns
ra8_err_t Error code.
Return values
k_ra8_okEvery argument is usable.
k_ra8_err_null_ptrstats was null, or a length came with no buffer.
k_ra8_err_invalid_argmax_transfers was zero.
k_ra8_err_invalid_sizepayload_len exceeds k_c6_fwver_tx_max.
k_ra8_err_not_initializedThe esp-hosted port is not up.
Precondition
The caller has not yet touched the bus.
The port's readiness flag reflects a completed init.
Postcondition
No module state is modified.
Exactly one code is returned, naming the first failing check.
Note
Split out of c6_fwver_link_pump so that function stays inside the NASA Rule 4 length budget.
Since
0.1.0

Definition at line 375 of file c6_fwver_link.c.

References k_c6_fwver_tx_max, k_ra8_err_invalid_arg, k_ra8_err_invalid_size, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_ok, and ra8_esp_hosted_port_is_ready().

Referenced by c6_fwver_link_pump().

◆ c6_fwver_rx_checksum()

uint16_t c6_fwver_rx_checksum ( uint16_t span)
static

Recompute the received frame's checksum over header plus payload.

Parameters
[in]spanBytes the checksum is defined over.
Returns
The checksum computed with the checksum field taken as zero.
Precondition
The transfer has completed and s_c6_fwver_rx is stable.
span is at most k_c6_fwver_frame_bytes.
Postcondition
The checksum field holds exactly the value it held on entry.
No other buffer byte is modified.
Note
The field is zeroed in place rather than copied out, which is what the vendored process_spi_rx_buf() does; restoring it afterwards keeps the printed value honest.
Since
0.1.0

Definition at line 216 of file c6_fwver_link.c.

References s_c6_fwver_rx.

Referenced by c6_fwver_rx_dispatch().

◆ c6_fwver_rx_dispatch()

bool c6_fwver_rx_dispatch ( c6_fwver_sink_t sink,
c6_fwver_pump_stats_t * stats )
static

Classify the received frame and deliver it if it is real.

Parameters
[in]sinkReceiver for a well-formed data frame, or null.
[in,out]statsCounters to update; must be non-null.
Returns
true when the sink asked the pump to stop.
Return values
trueThe sink accepted the frame and wants no more transactions.
falseKeep pumping.
Precondition
The transfer has completed and s_c6_fwver_rx is stable.
stats is the caller's live counter block.
Postcondition
Exactly one counter in stats was incremented.
The sink saw the frame only if it verified.
Note
Ordering matches the vendored process_spi_rx_buf(): zero length first (filler), then the header sanity tests, then the checksum.
Since
0.1.0

Definition at line 317 of file c6_fwver_link.c.

References c6_fwver_pump_stats::bad_checksum, c6_fwver_ifnum_defect(), c6_fwver_print_reject(), c6_fwver_puts(), c6_fwver_rx_checksum(), c6_fwver_pump_stats::frames, c6_fwver_pump_stats::idle, c6_fwver_pump_stats::ifnum_defect, k_c6_fwver_hdr_bytes, k_c6_fwver_max_payload, c6_fwver_pump_stats::malformed, and s_c6_fwver_rx.

Referenced by c6_fwver_link_pump().

◆ c6_fwver_tx_clear()

void c6_fwver_tx_clear ( void )
static

Zero the whole transmit frame.

Returns
Nothing.
Precondition
s_c6_fwver_tx is k_c6_fwver_frame_bytes long.
No transfer is in flight.
Postcondition
Every byte of s_c6_fwver_tx is zero.
No other module state is modified.
Note
The loop is bounded by k_c6_fwver_frame_bytes (NASA Rule 2).
Since
0.1.0

Definition at line 119 of file c6_fwver_link.c.

References k_c6_fwver_frame_bytes, and s_c6_fwver_tx.

Referenced by c6_fwver_tx_filler(), and c6_fwver_tx_frame().

◆ c6_fwver_tx_filler()

void c6_fwver_tx_filler ( void )
static

Stamp the transmit frame as the host's idle filler.

Returns
Nothing.
Precondition
s_c6_fwver_tx has been cleared.
The co-processor expects a full transaction even with nothing to send.
Postcondition
Byte zero carries ESP_MAX_IF; every other byte is zero.
The frame is exactly what the reference host sends when idle.
Note
Mirrors the dummy-buffer branch of the vendored check_and_execute_spi_transaction(), which sets only if_type and leaves length, offset and checksum at zero.
Since
0.1.0

Definition at line 138 of file c6_fwver_link.c.

References c6_fwver_tx_clear(), k_c6_fwver_nibble_mask, and s_c6_fwver_tx.

Referenced by c6_fwver_link_pump().

◆ c6_fwver_tx_frame()

void c6_fwver_tx_frame ( uint8_t if_type,
uint8_t if_num,
const uint8_t * payload,
uint16_t len )
static

Wrap a payload in a payload header, checksum included.

Parameters
[in]if_typeInterface type for the frame.
[in]if_numInterface number for the frame.
[in]payloadPayload bytes; must be non-null.
[in]lenPayload length, at most k_c6_fwver_max_payload.
Returns
Nothing.
Precondition
len bytes are readable at payload.
len is at most k_c6_fwver_max_payload.
Postcondition
s_c6_fwver_tx holds a well-formed frame whose checksum covers the header plus the payload.
Every byte past the payload is zero.
Note
Field for field what get_next_tx_buffer() builds in the vendored spi_drv.c: length, offset, interface, flags, then a checksum over header plus payload with the checksum field taken as zero.
Since
0.1.0

Definition at line 161 of file c6_fwver_link.c.

References c6_fwver_tx_clear(), k_c6_fwver_hdr_bytes, k_c6_fwver_nibble_mask, and s_c6_fwver_tx.

Referenced by c6_fwver_link_pump().

◆ c6_fwver_wait_handshake()

bool c6_fwver_wait_handshake ( void )
static

Wait, bounded, for the co-processor to arm HANDSHAKE.

Returns
true when HANDSHAKE read active within the budget.
Return values
trueThe co-processor is ready for a transaction.
falsek_c6_fwver_hs_wait_ms elapsed with the line inactive.
Precondition
The port is up, so g_h.funcs is populated.
HANDSHAKE is configured as an input.
Postcondition
No module state is modified.
At most k_c6_fwver_hs_wait_ms elapsed.
Note
The loop is bounded by k_c6_fwver_hs_wait_ms (NASA Rule 2). The line is read through the vtable, not the GPIO HAL, so the pump sees exactly what the vendored driver would see.
Since
0.1.0

Definition at line 189 of file c6_fwver_link.c.

References g_h, H_GPIO_HANDSHAKE_Pin, H_GPIO_HANDSHAKE_Port, H_HS_VAL_ACTIVE, k_c6_fwver_hs_poll_ms, and k_c6_fwver_hs_wait_ms.

Referenced by c6_fwver_link_pump().

Variable Documentation

◆ s_c6_fwver_rx

c6_fwver_frame_t s_c6_fwver_rx
static

Receive buffer the co-processor's frame lands in.

Same type and alignment as s_c6_fwver_tx.

Note
Touched only by the worker thread inside c6_fwver_link_pump.
Warning
The checksum check zeroes the checksum field in place and restores it; do not read that field concurrently.
Since
0.1.0

Definition at line 107 of file c6_fwver_link.c.

Referenced by c6_fwver_ifnum_defect(), c6_fwver_link_pump(), c6_fwver_print_reject(), c6_fwver_rx_checksum(), and c6_fwver_rx_dispatch().

◆ s_c6_fwver_tx

c6_fwver_frame_t s_c6_fwver_tx
static

Transmit buffer for the frame the pump is currently clocking.

A c6_fwver_frame_t, so the payload header is reached through a union member rather than a cast. Aligned to k_c6_fwver_dma_align, the alignment the transport expects of a transaction buffer.

Note
Touched only by the worker thread inside c6_fwver_link_pump.
Warning
Do not resize independently of s_c6_fwver_rx; both ends clock exactly k_c6_fwver_frame_bytes.
Since
0.1.0

Definition at line 96 of file c6_fwver_link.c.

Referenced by c6_fwver_link_pump(), c6_fwver_tx_clear(), c6_fwver_tx_filler(), and c6_fwver_tx_frame().