ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_c6link.c
Go to the documentation of this file.
1
28
29#include "ra8_c6link.h"
30
31#include <stddef.h>
32#include <stdint.h>
33
34#include "ra8_attributes.h"
35#include "ra8_c6link_internal.h"
36
37RA8_PRIV uint8_t priv_c6link_copy_str(char* dst, uint8_t cap, const ProtobufCBinaryData* src)
38{
39 if ((dst == nullptr) || (cap == 0U)) {
40 return 0U;
41 }
42 dst[0] = '\0';
43 if ((src == nullptr) || (src->data == nullptr)) {
44 return 0U;
45 }
46
47 const size_t room = (size_t)cap - 1U;
48 const size_t take = (src->len < room) ? src->len : room;
49 for (size_t i = 0U; i < take; i++) {
50 dst[i] = (char)src->data[i];
51 }
52 dst[take] = '\0';
53 return (uint8_t)take;
54}
55
56RA8_PRIV bool priv_c6link_copy_mac(ra8_c6link_mac_t* dst, const ProtobufCBinaryData* src)
57{
58 if (dst == nullptr) {
59 return false;
60 }
61 *dst = (ra8_c6link_mac_t){};
62 if ((src == nullptr) || (src->data == nullptr) || (src->len != (size_t)k_ra8_c6link_mac_bytes)) {
63 return false;
64 }
65 for (uint8_t i = 0U; i < (uint8_t)k_ra8_c6link_mac_bytes; i++) {
66 dst->octet[i] = src->data[i];
67 }
68 return true;
69}
70
72{
73 if ((link == nullptr) || (ev == nullptr)) {
74 return;
75 }
76 if (ev->kind == k_ra8_c6link_event_boot) {
77 link->boot_seen = true;
78 }
79 if (link->stats != nullptr) {
80 link->stats->events++;
81 }
82 if (link->event_cb != nullptr) {
83 link->event_cb(link->cb_ctx, ev);
84 }
85}
86
88{
89 if ((link == nullptr) || (view == nullptr)) {
90 return false;
91 }
92 const uint8_t* payload = &link->rx[view->offset];
93
94 if (view->if_type == (uint8_t)ESP_SERIAL_IF) {
95 return priv_c6link_rpc_consume(link, payload, view->len);
96 }
97 if ((view->if_type == (uint8_t)ESP_STA_IF) || (view->if_type == (uint8_t)ESP_AP_IF)) {
98 if (link->stats != nullptr) {
99 link->stats->eth_in++;
100 }
101 if (link->rx_cb != nullptr) {
102 link->rx_cb(link->cb_ctx, payload, view->len);
103 }
104 return false;
105 }
106 /* `ESP_PRIV_IF` lands here. Upstream reads peripheral-side capabilities from it, but
107 this co-processor build transmits its only privileged frame with a
108 checksum computed as if `if_num` were zero (#529), so a conformant host
109 never sees a valid one and nothing in this library depends on it. */
110 if (link->stats != nullptr) {
111 link->stats->unrouted++;
112 }
113 return false;
114}
115
135{
136 if ((cfg->transport.transfer == nullptr) || (cfg->transport.handshake_active == nullptr) ||
137 (cfg->transport.delay_ms == nullptr) || (cfg->arena == nullptr)) {
138 return k_ra8_err_null_ptr;
139 }
140 if (cfg->arena_bytes < (uint32_t)k_ra8_c6link_arena_min) {
142 }
143 return k_ra8_ok;
144}
145
147{
148 if ((link == nullptr) || (cfg == nullptr)) {
149 return k_ra8_err_null_ptr;
150 }
151 if (link->open) {
153 }
154 const ra8_err_t bad = internal_c6link_check_cfg(cfg);
155 if (bad != k_ra8_ok) {
156 return bad;
157 }
158
159 link->transport = cfg->transport;
160 link->event_cb = cfg->event_cb;
161 link->rx_cb = cfg->rx_cb;
162 link->cb_ctx = cfg->cb_ctx;
163 link->arena = cfg->arena;
164 link->arena_bytes = cfg->arena_bytes;
165 link->arena_used = 0U;
166 link->arena_last = 0U;
167 link->next_uid = 0U;
168 link->wait = (ra8_c6link_wait_t){};
169 link->fault = (ra8_c6link_fault_t){};
170 link->stats = nullptr;
171 link->tx_len = 0U;
172 link->tx_if = 0U;
173 link->boot_seen = false;
174 link->open = true;
175 return k_ra8_ok;
176}
177
179{
180 if (link == nullptr) {
181 return k_ra8_err_null_ptr;
182 }
183 if (!link->open) {
185 }
187 link->event_cb = nullptr;
188 link->rx_cb = nullptr;
189 link->cb_ctx = nullptr;
190 link->arena = nullptr;
191 link->stats = nullptr;
192 link->tx_len = 0U;
193 link->wait = (ra8_c6link_wait_t){};
194 link->open = false;
195 return k_ra8_ok;
196}
197
199{
200 return (link != nullptr) && link->open;
201}
202
204{
205 if ((link == nullptr) || (out == nullptr)) {
206 return k_ra8_err_null_ptr;
207 }
208 *out = link->fault;
209 return k_ra8_ok;
210}
211
212ra8_err_t ra8_c6link_poll(ra8_c6link_t* link, uint16_t max_transactions, ra8_c6link_stats_t* stats)
213{
214 if (link == nullptr) {
215 return k_ra8_err_null_ptr;
216 }
217 if (!link->open) {
219 }
220 if (max_transactions == 0U) {
222 }
223
224 ra8_c6link_stats_t local = {};
225 const ra8_err_t err = priv_c6link_pump(link, max_transactions, &local);
226 if (stats != nullptr) {
227 *stats = local;
228 }
229 return err;
230}
231
233ra8_c6link_await_ready(ra8_c6link_t* link, uint16_t max_transactions, ra8_c6link_fw_version_t* out)
234{
235 if ((link == nullptr) || (out == nullptr)) {
236 return k_ra8_err_null_ptr;
237 }
238 if (!link->open) {
240 }
241 if (max_transactions == 0U) {
243 }
244 if (link->tx_len != 0U) {
245 return k_ra8_err_busy;
246 }
247
248 /* Announce this host first. A co-processor that has just booted services no
249 RPC until the host has introduced itself, and one that is already up
250 ignores a restatement of capabilities that have not changed -- so sending
251 it unconditionally is both necessary and harmless. */
252 const uint8_t caps =
254 if (caps == 0U) {
256 }
257 link->tx_len = (uint16_t)caps;
258 link->tx_if = (uint8_t)ESP_PRIV_IF;
259
260 ra8_c6link_stats_t local = {};
261 const ra8_err_t announced = priv_c6link_pump(link, max_transactions, &local);
262 link->tx_len = 0U;
263 if (announced != k_ra8_ok) {
264 return announced;
265 }
266
267 /* Readiness is the answer to a question, not the arrival of an event. See the
268 header: `Event_ESPInit` fires once when the CO-PROCESSOR boots, which is
269 not when this host boots, so waiting for it works exactly once. */
270 return ra8_c6link_fw_version(link, out);
271}
272
291RA8_INTERNAL static ra8_err_t internal_c6link_take_fw(void* ctx, const void* msg_v)
292{
294 const Rpc* msg = (const Rpc*)msg_v;
296
297 const RpcRespGetCoprocessorFwVersion* body = msg->resp_get_coprocessor_fwversion;
298 if (body == nullptr) {
300 }
301 out->major = body->major1;
302 out->minor = body->minor1;
303 out->patch = body->patch1;
304 out->chip_id = body->chip_id;
305 out->target_len =
306 priv_c6link_copy_str(out->target, (uint8_t)sizeof out->target, &body->idf_target);
307 return priv_c6link_resp(take->link, (uint32_t)RPC_ID__Req_GetCoprocessorFwVersion, body->resp);
308}
309
311{
312 if ((link == nullptr) || (out == nullptr)) {
313 return k_ra8_err_null_ptr;
314 }
315 if (!link->open) {
317 }
318 *out = (ra8_c6link_fw_version_t){};
319
320 RpcReqGetCoprocessorFwVersion body;
321 rpc__req__get_coprocessor_fw_version__init(&body);
322
323 Rpc req;
324 rpc__init(&req);
325 req.msg_type = RPC_TYPE__Req;
326 req.msg_id = RPC_ID__Req_GetCoprocessorFwVersion;
327 req.payload_case = RPC__PAYLOAD_REQ_GET_COPROCESSOR_FWVERSION;
328 req.req_get_coprocessor_fwversion = &body;
329
330 ra8_c6link_take_ctx_t take = {.link = link, .out = out};
331 return priv_c6link_rpc_call(link,
332 &req,
333 (uint32_t)RPC_ID__Resp_GetCoprocessorFwVersion,
335 &take);
336}
337
338ra8_err_t ra8_c6link_eth_send(ra8_c6link_t* link, const uint8_t* frame, uint16_t len)
339{
340 if ((link == nullptr) || (frame == nullptr)) {
341 return k_ra8_err_null_ptr;
342 }
343 if (!link->open) {
345 }
346 if ((len == 0U) || (len > (uint16_t)k_ra8_c6link_max_payload)) {
348 }
349 if (link->tx_len != 0U) {
350 return k_ra8_err_busy;
351 }
352
353 for (uint16_t i = 0U; i < len; i++) {
354 link->tx[(uint16_t)k_ra8_c6link_header_bytes + i] = frame[i];
355 }
356 link->tx_len = len;
357 link->tx_if = (uint8_t)ESP_STA_IF;
358
359 ra8_c6link_stats_t local = {};
360 const ra8_err_t pumped = priv_c6link_pump(link, (uint16_t)k_ra8_c6link_hs_giveup, &local);
361 if (pumped != k_ra8_ok) {
362 link->tx_len = 0U;
363 return pumped;
364 }
365 if (link->tx_len != 0U) {
366 link->tx_len = 0U;
368 }
369 return k_ra8_ok;
370}
Annotation-attribute framework macros for ra8-firmware.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_busy
Resource busy – blocking operation cannot proceed.
Definition ra8_err.h:195
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ 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_protocol_error
Protocol-level error (e.g.
Definition ra8_err.h:429
@ 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