ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
c6_fwver_rpc.c
Go to the documentation of this file.
1
46
47#include <stddef.h>
48#include <stdint.h>
49
50#include "c6_fwver.h"
51#include "esp_hosted_host_fw_ver.h"
52#include "esp_hosted_interface.h"
53#include "esp_hosted_os_abstraction.h"
54#include "esp_hosted_rpc.pb-c.h"
55#include "esp_hosted_transport.h"
56#include "protobuf-c/protobuf-c.h"
57#include "transport_drv.h"
58
77typedef enum : uint16_t {
84 k_c6_fwver_tlv_ep_len = (uint16_t)(sizeof(RPC_EP_NAME_RSP) - 1U),
87 (uint16_t)((uint16_t)k_c6_fwver_tlv_value + (uint16_t)(sizeof(RPC_EP_NAME_RSP) - 1U) +
88 (uint16_t)k_c6_fwver_tlv_value),
93
111typedef struct c6_fwver_rsp {
112 uint32_t uid;
113 int32_t resp;
114 uint32_t major;
115 uint32_t minor;
116 uint32_t patch;
117 uint32_t chip_id;
119 uint8_t target_len;
120 bool seen;
122
134
149static void* c6_fwver_rpc_pool_alloc(void* allocator_data, size_t size)
150{
151 (void)allocator_data;
152 return g_h.funcs->_h_malloc(size);
153}
154
168static void c6_fwver_rpc_pool_free(void* allocator_data, void* pointer)
169{
170 (void)allocator_data;
171 if (pointer != nullptr) {
172 g_h.funcs->_h_free(pointer);
173 }
174}
175
187static ProtobufCAllocator s_c6_fwver_allocator = {
190 .allocator_data = nullptr,
191};
192
208static uint16_t c6_fwver_tlv_head(uint8_t* out, uint16_t at, uint8_t type, uint16_t len)
209{
210 out[at + (uint16_t)k_c6_fwver_tlv_type] = type;
211 out[at + (uint16_t)k_c6_fwver_tlv_len_lo] = (uint8_t)(len & (uint16_t)k_c6_fwver_tlv_mask);
212 out[at + (uint16_t)k_c6_fwver_tlv_len_hi] =
213 (uint8_t)((len >> (uint16_t)k_c6_fwver_tlv_shift) & (uint16_t)k_c6_fwver_tlv_mask);
214 return (uint16_t)(at + (uint16_t)k_c6_fwver_tlv_value);
215}
216
217ra8_err_t c6_fwver_rpc_request(uint8_t* out, uint16_t cap, uint16_t* out_len)
218{
219 if ((out == nullptr) || (out_len == nullptr)) {
220 return k_ra8_err_null_ptr;
221 }
222 *out_len = 0U;
223
224 RpcReqGetCoprocessorFwVersion body;
225 rpc__req__get_coprocessor_fw_version__init(&body);
226
227 Rpc req;
228 rpc__init(&req);
229 req.msg_type = RPC_TYPE__Req;
230 req.msg_id = RPC_ID__Req_GetCoprocessorFwVersion;
231 req.uid = (uint32_t)k_c6_fwver_rpc_uid;
232 req.payload_case = RPC__PAYLOAD_REQ_GET_COPROCESSOR_FWVERSION;
233 req.req_get_coprocessor_fwversion = &body;
234
235 const size_t proto_len = rpc__get_packed_size(&req);
236 if ((size_t)cap < (proto_len + (size_t)k_c6_fwver_tlv_overhead)) {
238 }
239
240 uint16_t at =
242 for (uint16_t i = 0U; i < (uint16_t)k_c6_fwver_tlv_ep_len; i++) {
243 out[at + i] = (uint8_t)RPC_EP_NAME_RSP[i];
244 }
245 at = (uint16_t)(at + (uint16_t)k_c6_fwver_tlv_ep_len);
246 at = c6_fwver_tlv_head(out, at, (uint8_t)k_c6_fwver_tlv_t_data, (uint16_t)proto_len);
247
248 if (rpc__pack(&req, &out[at]) != proto_len) {
250 }
251 *out_len = (uint16_t)(at + (uint16_t)proto_len);
252 return k_ra8_ok;
253}
254
273static const uint8_t* c6_fwver_tlv_body(const uint8_t* payload, uint16_t len, uint16_t* proto_len)
274{
275 *proto_len = 0U;
276 const uint16_t ep_len = (uint16_t)k_c6_fwver_tlv_ep_len;
277 const uint16_t data_tag = (uint16_t)((uint16_t)k_c6_fwver_tlv_value + ep_len);
278
279 if ((len < (uint16_t)k_c6_fwver_tlv_overhead) ||
280 (payload[k_c6_fwver_tlv_type] != (uint8_t)k_c6_fwver_tlv_t_epname) ||
281 (payload[data_tag] != (uint8_t)k_c6_fwver_tlv_t_data)) {
282 return nullptr;
283 }
284 const uint16_t seen_ep =
285 (uint16_t)((uint16_t)payload[k_c6_fwver_tlv_len_lo] |
286 ((uint16_t)payload[k_c6_fwver_tlv_len_hi] << (uint16_t)k_c6_fwver_tlv_shift));
287 if (seen_ep != ep_len) {
288 return nullptr;
289 }
290 bool named = true;
291 for (uint16_t i = 0U; i < ep_len; i++) {
292 const uint8_t got = payload[(uint16_t)k_c6_fwver_tlv_value + i];
293 if ((got != (uint8_t)RPC_EP_NAME_RSP[i]) && (got != (uint8_t)RPC_EP_NAME_EVT[i])) {
294 named = false;
295 }
296 }
297 if (!named) {
298 return nullptr;
299 }
300 const uint16_t body = (uint16_t)((uint16_t)payload[data_tag + (uint16_t)k_c6_fwver_tlv_len_lo] |
301 ((uint16_t)payload[data_tag + (uint16_t)k_c6_fwver_tlv_len_hi]
302 << (uint16_t)k_c6_fwver_tlv_shift));
303 if ((body == 0U) || ((uint32_t)body + (uint32_t)k_c6_fwver_tlv_overhead > (uint32_t)len)) {
304 return nullptr;
305 }
306 *proto_len = body;
307 return &payload[k_c6_fwver_tlv_overhead];
308}
309
322static void c6_fwver_rpc_take_target(const ProtobufCBinaryData* target)
323{
324 s_c6_fwver_rsp.target_len = 0U;
325 if ((target == nullptr) || (target->data == nullptr)) {
326 return;
327 }
328 const size_t take =
329 (target->len < (size_t)k_c6_fwver_text_max) ? target->len : (size_t)k_c6_fwver_text_max;
330 for (size_t i = 0U; i < take; i++) {
331 s_c6_fwver_rsp.target[i] = target->data[i];
332 }
333 s_c6_fwver_rsp.target_len = (uint8_t)take;
334}
335
350static bool c6_fwver_rpc_take(const Rpc* msg)
351{
352 if ((msg->msg_type != RPC_TYPE__Resp) || (msg->msg_id != RPC_ID__Resp_GetCoprocessorFwVersion) ||
353 (msg->payload_case != RPC__PAYLOAD_RESP_GET_COPROCESSOR_FWVERSION) ||
354 (msg->resp_get_coprocessor_fwversion == nullptr)) {
355 return false;
356 }
357 const RpcRespGetCoprocessorFwVersion* body = msg->resp_get_coprocessor_fwversion;
358 s_c6_fwver_rsp.uid = msg->uid;
359 s_c6_fwver_rsp.resp = body->resp;
360 s_c6_fwver_rsp.major = body->major1;
361 s_c6_fwver_rsp.minor = body->minor1;
362 s_c6_fwver_rsp.patch = body->patch1;
363 s_c6_fwver_rsp.chip_id = body->chip_id;
364 c6_fwver_rpc_take_target(&body->idf_target);
365 s_c6_fwver_rsp.seen = true;
366 return true;
367}
368
369bool c6_fwver_rpc_consume(uint8_t if_type, uint8_t if_num, const uint8_t* payload, uint16_t len)
370{
371 (void)if_num;
372 if ((if_type != (uint8_t)ESP_SERIAL_IF) || (payload == nullptr) || s_c6_fwver_rsp.seen) {
373 return false;
374 }
375
376 uint16_t proto_len = 0U;
377 const uint8_t* proto = c6_fwver_tlv_body(payload, len, &proto_len);
378 if (proto == nullptr) {
379 c6_fwver_puts("c6_fwver: serial frame is not an RPC envelope, len=");
380 c6_fwver_put_u32((uint32_t)len);
381 c6_fwver_puts("\r\n");
382 return false;
383 }
384
385 Rpc* msg = rpc__unpack(&s_c6_fwver_allocator, (size_t)proto_len, proto);
386 if (msg == nullptr) {
387 c6_fwver_puts("c6_fwver: protobuf decode refused ");
388 c6_fwver_put_u32((uint32_t)proto_len);
389 c6_fwver_puts(" bytes\r\n");
390 return false;
391 }
392
393 c6_fwver_puts("c6_fwver: rpc in type=");
394 c6_fwver_put_u32((uint32_t)msg->msg_type);
395 c6_fwver_puts(" id=");
396 c6_fwver_put_u32((uint32_t)msg->msg_id);
397 c6_fwver_puts(" uid=");
398 c6_fwver_put_u32(msg->uid);
399 c6_fwver_puts(" proto_bytes=");
400 c6_fwver_put_u32((uint32_t)proto_len);
401 c6_fwver_puts("\r\n");
402
403 const bool matched = c6_fwver_rpc_take(msg);
404 rpc__free_unpacked(msg, &s_c6_fwver_allocator);
405 return matched;
406}
407
420{
421 c6_fwver_puts("c6_fwver: rsp uid=");
423 c6_fwver_puts(" resp=");
425 c6_fwver_puts(" fw=");
427 c6_fwver_puts(".");
429 c6_fwver_puts(".");
431 c6_fwver_puts(" chip_id=0x");
433 c6_fwver_puts(" idf_target=");
434 c6_fwver_put_text(s_c6_fwver_rsp.target, (size_t)s_c6_fwver_rsp.target_len);
435 c6_fwver_puts("\r\n");
436}
437
451{
452 const uint32_t seen = c6_fwver_priv_init_version();
453 c6_fwver_puts("c6_fwver: crosscheck priv_init_event=");
454 if (seen == 0U) {
455 c6_fwver_puts("absent -- either the co-processor has not been power-cycled since its "
456 "last drain, or its INIT event was dropped (read ifnum_defect on the "
457 "caps pump line)\r\n");
458 return;
459 }
460 c6_fwver_put_u32(ESP_HOSTED_VERSION_MAJOR(seen));
461 c6_fwver_puts(".");
462 c6_fwver_put_u32(ESP_HOSTED_VERSION_MINOR(seen));
463 c6_fwver_puts(".");
464 c6_fwver_put_u32(ESP_HOSTED_VERSION_PATCH(seen));
465 const bool agrees = (ESP_HOSTED_VERSION_MAJOR(seen) == s_c6_fwver_rsp.major) &&
466 (ESP_HOSTED_VERSION_MINOR(seen) == s_c6_fwver_rsp.minor) &&
467 (ESP_HOSTED_VERSION_PATCH(seen) == s_c6_fwver_rsp.patch);
468 c6_fwver_puts(agrees ? " agrees with the RPC answer\r\n" : " DISAGREES with the RPC answer\r\n");
469}
470
485{
486 c6_fwver_puts("c6_fwver: expect uid=");
488 c6_fwver_puts(" resp=0 fw=");
489 c6_fwver_put_u32((uint32_t)ESP_HOSTED_VERSION_MAJOR_1);
490 c6_fwver_puts(".");
491 c6_fwver_put_u32((uint32_t)ESP_HOSTED_VERSION_MINOR_1);
492 c6_fwver_puts(".");
493 c6_fwver_put_u32((uint32_t)ESP_HOSTED_VERSION_PATCH_1);
494 c6_fwver_puts(" (the vendored host driver's own version) chip_id=0x");
495 c6_fwver_put_hex((uint32_t)ESP_PRIV_FIRMWARE_CHIP_ESP32C6, (uint8_t)k_c6_fwver_hex_byte);
496 c6_fwver_puts("\r\n");
497}
498
500{
502
503 if (!s_c6_fwver_rsp.seen) {
504 c6_fwver_puts("c6_fwver: FAIL no RPC response -- the co-processor never answered\r\n");
505 return false;
506 }
509
510 if (s_c6_fwver_rsp.uid != (uint32_t)k_c6_fwver_rpc_uid) {
511 c6_fwver_puts("c6_fwver: FAIL response UID does not match the request\r\n");
512 return false;
513 }
514 if (s_c6_fwver_rsp.resp != 0) {
515 c6_fwver_puts("c6_fwver: FAIL co-processor reported an error result\r\n");
516 return false;
517 }
518 if ((s_c6_fwver_rsp.major != (uint32_t)ESP_HOSTED_VERSION_MAJOR_1) ||
519 (s_c6_fwver_rsp.minor != (uint32_t)ESP_HOSTED_VERSION_MINOR_1) ||
520 (s_c6_fwver_rsp.patch != (uint32_t)ESP_HOSTED_VERSION_PATCH_1)) {
521 c6_fwver_puts("c6_fwver: FAIL co-processor firmware version is not the one this host "
522 "was built against\r\n");
523 return false;
524 }
525 if (s_c6_fwver_rsp.chip_id != (uint32_t)ESP_PRIV_FIRMWARE_CHIP_ESP32C6) {
526 c6_fwver_puts("c6_fwver: FAIL the answering co-processor is not an ESP32-C6\r\n");
527 return false;
528 }
529 c6_fwver_puts("c6_fwver: PASS esp-hosted RPC round-trip, co-processor firmware ");
531 c6_fwver_puts(".");
533 c6_fwver_puts(".");
535 c6_fwver_puts("\r\n");
536 return true;
537}
538
539bool c6_fwver_dispatch(uint8_t if_type, uint8_t if_num, const uint8_t* payload, uint16_t len)
540{
541 c6_fwver_puts("c6_fwver: frame if_type=");
542 c6_fwver_put_u32((uint32_t)if_type);
543 c6_fwver_puts(" if_num=");
544 c6_fwver_put_u32((uint32_t)if_num);
545 c6_fwver_puts(" len=");
546 c6_fwver_put_u32((uint32_t)len);
547 c6_fwver_puts("\r\n");
548
549 if (if_type == (uint8_t)ESP_PRIV_IF) {
550 return c6_fwver_priv_consume(if_type, if_num, payload, len);
551 }
552 if (if_type == (uint8_t)ESP_SERIAL_IF) {
553 return c6_fwver_rpc_consume(if_type, if_num, payload, len);
554 }
555 c6_fwver_puts("c6_fwver: frame on an interface this app does not use\r\n");
556 return false;
557}
Shared contract for the esp-hosted RPC round-trip application.
@ k_c6_fwver_rpc_uid
UID stamped on the request; the response must carry it back unchanged.
Definition c6_fwver.h:84
void c6_fwver_put_i32(int32_t value)
Emit a signed 32-bit value in decimal.
void c6_fwver_put_hex(uint32_t value, uint8_t digits)
Emit a value as a fixed-width lower-case hexadecimal field.
bool c6_fwver_priv_consume(uint8_t if_type, uint8_t if_num, const uint8_t *payload, uint16_t len)
Decode an ESP_PRIV_IF frame and report what it announced.
@ k_c6_fwver_hex_byte
Hex digits printed for a byte-wide field.
Definition c6_fwver.h:111
@ k_c6_fwver_text_max
Longest co-processor-supplied string echoed to the console; anything longer is truncated rather than ...
Definition c6_fwver.h:113
void c6_fwver_put_text(const uint8_t *text, size_t len)
Emit a length-counted byte range as printable text.
uint32_t c6_fwver_priv_init_version(void)
Report the version the boot INIT event announced, if one arrived.
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.
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.
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.
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_crosscheck(void)
Report the boot event's version reading beside the RPC's.
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.
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_print_expectation(void)
Print what this host expects, before it says what it got.
c6_fwver_tlv_t
The serial endpoint's TLV envelope, tag by tag.
@ k_c6_fwver_tlv_overhead
Bytes the envelope costs on top of 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_value
Offset of a tag's value.
@ k_c6_fwver_tlv_t_epname
Tag introducing the endpoint name.
@ k_c6_fwver_tlv_len_hi
Offset of a tag's length, high byte.
@ k_c6_fwver_tlv_shift
Shift between the two length bytes.
@ k_c6_fwver_tlv_mask
Byte mask for the low length byte.
@ k_c6_fwver_tlv_t_data
Tag introducing the protobuf payload.
@ k_c6_fwver_tlv_ep_len
Endpoint-name length; both endpoint names share it.
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.
static void c6_fwver_rpc_print_response(void)
Print the decoded response, field by field.
static ProtobufCAllocator s_c6_fwver_allocator
The allocator the generated protobuf decoder is handed.
static c6_fwver_rsp_t s_c6_fwver_rsp
The one response this application is waiting for.
struct c6_fwver_rsp c6_fwver_rsp_t
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 void c6_fwver_rpc_pool_free(void *allocator_data, void *pointer)
Return a block to the esp-hosted port's fixed byte pool.
bool c6_fwver_rpc_report(void)
Print the recorded response and decide the run's verdict.
@ k_ra8_err_validation_failed
Validation rule failed (caller-supplied invariant not satisfied).
Definition ra8_err.h:459
@ 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.
Every field this application read out of the RPC response.
uint32_t minor
Firmware minor version.
uint32_t major
Firmware major version.
uint8_t target_len
Bytes held in target.
uint8_t target[k_c6_fwver_text_max]
CONFIG_IDF_TARGET, truncated.
uint32_t patch
Firmware patch version.
bool seen
A matching response was decoded.
uint32_t uid
UID echoed back by the co-processor.
int32_t resp
Co-processor result code; 0 is ok.
uint32_t chip_id
CONFIG_IDF_FIRMWARE_CHIP_ID.