ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
c6_fwver_link.c
Go to the documentation of this file.
1
40
41#include <stdint.h>
42
43#include "c6_fwver.h"
44#include "esp_hosted_header.h"
45#include "esp_hosted_interface.h"
46#include "esp_hosted_os_abstraction.h"
47#include "esp_hosted_transport.h"
50#include "ra8_esp_hosted_port.h"
51#include "transport_drv.h"
52
70typedef enum : uint16_t {
71 k_c6_fwver_hdr_bytes = (uint16_t)sizeof(struct esp_payload_header),
84
97
108
119static void c6_fwver_tx_clear(void)
120{
121 for (uint16_t i = 0U; i < (uint16_t)k_c6_fwver_frame_bytes; i++) {
122 s_c6_fwver_tx.bytes[i] = 0U;
123 }
124}
125
138static void c6_fwver_tx_filler(void)
139{
141 s_c6_fwver_tx.header.if_type = (uint8_t)((uint8_t)ESP_MAX_IF & (uint8_t)k_c6_fwver_nibble_mask);
142}
143
161static void c6_fwver_tx_frame(uint8_t if_type, uint8_t if_num, const uint8_t* payload, uint16_t len)
162{
164 s_c6_fwver_tx.header.if_type = (uint8_t)(if_type & (uint8_t)k_c6_fwver_nibble_mask);
165 s_c6_fwver_tx.header.if_num = (uint8_t)(if_num & (uint8_t)k_c6_fwver_nibble_mask);
166 s_c6_fwver_tx.header.len = len;
167 s_c6_fwver_tx.header.offset = (uint16_t)k_c6_fwver_hdr_bytes;
168 for (uint16_t i = 0U; i < len; i++) {
169 s_c6_fwver_tx.bytes[(uint16_t)k_c6_fwver_hdr_bytes + i] = payload[i];
170 }
171 s_c6_fwver_tx.header.checksum =
172 compute_checksum(s_c6_fwver_tx.bytes, (uint16_t)((uint16_t)k_c6_fwver_hdr_bytes + len));
173}
174
189static bool c6_fwver_wait_handshake(void)
190{
191 for (uint16_t waited = 0U; waited < (uint16_t)k_c6_fwver_hs_wait_ms;
192 waited = (uint16_t)(waited + (uint16_t)k_c6_fwver_hs_poll_ms)) {
193 const int32_t level =
194 (int32_t)g_h.funcs->_h_read_gpio(H_GPIO_HANDSHAKE_Port, (uint32_t)H_GPIO_HANDSHAKE_Pin);
195 if (level == (int32_t)H_HS_VAL_ACTIVE) {
196 return true;
197 }
198 (void)g_h.funcs->_h_msleep((unsigned int)k_c6_fwver_hs_poll_ms);
199 }
200 return false;
201}
202
216static uint16_t c6_fwver_rx_checksum(uint16_t span)
217{
218 const uint16_t saved = s_c6_fwver_rx.header.checksum;
219 s_c6_fwver_rx.header.checksum = 0U;
220 const uint16_t calc = compute_checksum(s_c6_fwver_rx.bytes, span);
221 s_c6_fwver_rx.header.checksum = saved;
222 return calc;
223}
224
239static void c6_fwver_print_reject(const char* why, uint16_t calc)
240{
241 c6_fwver_puts("c6_fwver: dropped ");
242 c6_fwver_puts(why);
243 c6_fwver_puts(" if_type=");
244 c6_fwver_put_u32((uint32_t)s_c6_fwver_rx.header.if_type);
245 c6_fwver_puts(" if_num=");
246 c6_fwver_put_u32((uint32_t)s_c6_fwver_rx.header.if_num);
247 c6_fwver_puts(" flags=0x");
248 c6_fwver_put_hex((uint32_t)s_c6_fwver_rx.header.flags, (uint8_t)k_c6_fwver_hex_byte);
249 c6_fwver_puts(" len=");
250 c6_fwver_put_u32((uint32_t)s_c6_fwver_rx.header.len);
251 c6_fwver_puts(" offset=");
252 c6_fwver_put_u32((uint32_t)s_c6_fwver_rx.header.offset);
253 c6_fwver_puts(" seq=");
254 c6_fwver_put_u32((uint32_t)s_c6_fwver_rx.header.seq_num);
255 c6_fwver_puts(" pkt_type=0x");
256 c6_fwver_put_hex((uint32_t)s_c6_fwver_rx.header.reserved3, (uint8_t)k_c6_fwver_hex_byte);
257 c6_fwver_puts(" csum=0x");
258 c6_fwver_put_hex((uint32_t)s_c6_fwver_rx.header.checksum, (uint8_t)k_c6_fwver_hex_word);
259 c6_fwver_puts(" calc=0x");
260 c6_fwver_put_hex((uint32_t)calc, (uint8_t)k_c6_fwver_hex_word);
261 c6_fwver_puts(" raw=");
262 for (uint16_t i = 0U; i < (uint16_t)k_c6_fwver_hdr_bytes; i++) {
263 c6_fwver_put_hex((uint32_t)s_c6_fwver_rx.bytes[i], (uint8_t)k_c6_fwver_hex_byte);
264 }
265 c6_fwver_puts("\r\n");
266}
267
295static bool c6_fwver_ifnum_defect(uint16_t calc, uint16_t stated)
296{
297 const uint16_t contribution =
298 (uint16_t)((uint16_t)s_c6_fwver_rx.header.if_num << (uint16_t)k_c6_fwver_ifnum_shift);
299 return (contribution != 0U) && ((uint16_t)(calc - stated) == contribution);
300}
301
318{
319 const uint16_t len = s_c6_fwver_rx.header.len;
320 const uint16_t offset = s_c6_fwver_rx.header.offset;
321
322 if (len == 0U) {
323 stats->idle++;
324 return false;
325 }
326 if ((offset != (uint16_t)k_c6_fwver_hdr_bytes) || (len > (uint16_t)k_c6_fwver_max_payload)) {
327 stats->malformed++;
328 c6_fwver_print_reject("malformed", 0U);
329 return false;
330 }
331 const uint16_t calc = c6_fwver_rx_checksum((uint16_t)(offset + len));
332 if (calc != s_c6_fwver_rx.header.checksum) {
333 stats->bad_checksum++;
334 c6_fwver_print_reject("bad-checksum", calc);
335 if (c6_fwver_ifnum_defect(calc, s_c6_fwver_rx.header.checksum)) {
336 stats->ifnum_defect++;
337 c6_fwver_puts("c6_fwver: ^ explained: the co-processor checksummed this frame with "
338 "if_num=0 and then transmitted a non-zero if_num. A conformant host "
339 "drops it -- upstream's own process_spi_rx_buf() would too.\r\n");
340 }
341 return false;
342 }
343
344 stats->frames++;
345 if (sink == nullptr) {
346 return false;
347 }
348 return sink(s_c6_fwver_rx.header.if_type,
349 s_c6_fwver_rx.header.if_num,
350 &s_c6_fwver_rx.bytes[offset],
351 len);
352}
353
375static ra8_err_t c6_fwver_pump_check(const uint8_t* payload,
376 uint16_t payload_len,
377 uint16_t max_transfers,
378 const c6_fwver_pump_stats_t* stats)
379{
380 if ((stats == nullptr) || ((payload_len != 0U) && (payload == nullptr))) {
381 return k_ra8_err_null_ptr;
382 }
383 if (max_transfers == 0U) {
385 }
386 if (payload_len > (uint16_t)k_c6_fwver_tx_max) {
388 }
391 }
392 return k_ra8_ok;
393}
394
396 uint8_t if_num,
397 const uint8_t* payload,
398 uint16_t payload_len,
399 uint16_t max_transfers,
400 c6_fwver_sink_t sink,
402{
403 const ra8_err_t bad = c6_fwver_pump_check(payload, payload_len, max_transfers, stats);
404 if (bad != k_ra8_ok) {
405 return bad;
406 }
407
408 *stats = (c6_fwver_pump_stats_t){};
409 bool tx_pending = (payload_len != 0U);
410 struct hosted_transport_context_t ctx = {};
411
412 uint16_t consecutive_timeouts = 0U;
413
414 for (uint16_t i = 0U; i < max_transfers; i++) {
416 stats->hs_timeouts++;
417 consecutive_timeouts++;
418 if (consecutive_timeouts >= (uint16_t)k_c6_fwver_hs_giveup) {
419 break;
420 }
421 continue;
422 }
423 consecutive_timeouts = 0U;
424 if (tx_pending) {
425 c6_fwver_tx_frame(if_type, if_num, payload, payload_len);
426 tx_pending = false;
427 } else {
429 }
430
431 ctx.tx_buf = s_c6_fwver_tx.bytes;
432 ctx.tx_buf_size = (uint32_t)k_c6_fwver_frame_bytes;
433 ctx.rx_buf = s_c6_fwver_rx.bytes;
434 if ((int32_t)g_h.funcs->_h_do_bus_transfer(&ctx) != (int32_t)RET_OK) {
435 stats->bus_error = true;
436 return k_ra8_err_spi_error;
437 }
438 stats->transfers++;
439
440 if (c6_fwver_rx_dispatch(sink, stats)) {
441 stats->sink_stopped = true;
442 return k_ra8_ok;
443 }
444 (void)g_h.funcs->_h_msleep((unsigned int)k_c6_fwver_gap_ms);
445 }
446
447 return (stats->transfers == 0U) ? k_ra8_err_hw_timeout : k_ra8_ok;
448}
Shared contract for the esp-hosted RPC round-trip application.
@ k_c6_fwver_dma_align
Transaction-buffer alignment, in bytes.
Definition c6_fwver.h:79
bool(* c6_fwver_sink_t)(uint8_t if_type, uint8_t if_num, const uint8_t *payload, uint16_t len)
Receiver for one well-formed frame the co-processor sent.
Definition c6_fwver.h:237
void c6_fwver_put_hex(uint32_t value, uint8_t digits)
Emit a value as a fixed-width lower-case hexadecimal field.
@ k_c6_fwver_gap_ms
Settling gap between consecutive transactions.
Definition c6_fwver.h:154
@ k_c6_fwver_hs_poll_ms
Sampling period while waiting for HANDSHAKE.
Definition c6_fwver.h:152
@ k_c6_fwver_hs_giveup
Consecutive HANDSHAKE timeouts after which the pump stops.
Definition c6_fwver.h:145
@ k_c6_fwver_frame_bytes
Bytes clocked in one full-duplex transaction.
Definition c6_fwver.h:139
@ k_c6_fwver_hs_wait_ms
Milliseconds to wait for HANDSHAKE before abandoning a transaction.
Definition c6_fwver.h:143
@ k_c6_fwver_tx_max
Bound on any payload this application transmits: the packed RPC request and its TLV envelope are two ...
Definition c6_fwver.h:156
union c6_fwver_frame c6_fwver_frame_t
struct c6_fwver_pump_stats c6_fwver_pump_stats_t
@ k_c6_fwver_hex_word
Hex digits printed for a 16-bit field.
Definition c6_fwver.h:112
@ k_c6_fwver_hex_byte
Hex digits printed for a byte-wide field.
Definition c6_fwver.h:111
void c6_fwver_put_u32(uint32_t value)
Emit an unsigned 32-bit value in decimal.
void c6_fwver_puts(const char *text)
Write a NUL-terminated string to the board console.
esp-hosted port header: transport selection, side-band pin map, link polarity.
#define H_GPIO_HANDSHAKE_Pin
Pin index of the HANDSHAKE input, or -1 when it is not wired.
#define H_GPIO_HANDSHAKE_Port
Opaque port handle of the HANDSHAKE input.
#define H_HS_VAL_ACTIVE
Level read back on HANDSHAKE when it is asserted.
esp-hosted port header: RTOS handle types, return codes and budgets.
#define MAX_PAYLOAD_SIZE
Largest payload one transport frame can carry, in bytes.
#define RET_OK
Operation completed.
@ k_ra8_err_spi_error
SPI transfer failed (bus fault, mode fault, overrun, ...).
Definition ra8_err.h:405
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_hw_timeout
Hardware timed out waiting for a flag or handshake.
Definition ra8_err.h:304
@ k_ra8_err_not_initialized
Module not initialized – _init() not yet called successfully.
Definition ra8_err.h:235
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
struct hosted_config_t g_h
The handle the vendored core dereferences to reach the vtable.
Public entry point of the RA8D2 + ThreadX port of esp-hosted.
bool ra8_esp_hosted_port_is_ready(void)
Report whether the port is currently initialised.
uint16_t malformed
Frames whose offset or length could not be believed.
Definition c6_fwver.h:214
uint16_t idle
Filler frames the co-processor returned (len zero).
Definition c6_fwver.h:212
bool bus_error
A bus transfer did not return RET_OK.
Definition c6_fwver.h:218
uint16_t transfers
Full-duplex transactions clocked.
Definition c6_fwver.h:210
bool sink_stopped
The sink asked the pump to stop early.
Definition c6_fwver.h:219
uint16_t bad_checksum
Frames whose recomputed checksum disagreed.
Definition c6_fwver.h:213
uint16_t frames
Well-formed payload frames handed to the sink.
Definition c6_fwver.h:211
uint16_t ifnum_defect
Bad-checksum frames explained by the co-processor's if_num accounting; see the app README.
Definition c6_fwver.h:216
uint16_t hs_timeouts
Transactions abandoned waiting for HANDSHAKE.
Definition c6_fwver.h:215