ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_usb_cdc.c
Go to the documentation of this file.
1
27
28#include "ra8_usb_cdc.h"
29
30#include <stdint.h>
31
32#include "ra8_attributes.h"
33#include "ra8_check.h"
34#include "ra8_err.h"
35#include "ra8_log.h"
36#include "ra8_usb.h"
38
39static const char* s_tag = "USBCDC";
40
53
71typedef enum : uint16_t {
74
79typedef enum : uint32_t {
82
94
108
120
122
123/* =============================================================================
124 * Internal helpers
125 * =============================================================================
126 */
127
147
164{
165 const uint16_t bulk_mp =
167
173 bulk_mp);
174 RA8_RETURN_ON_ERROR(err, /* GCOVR_EXCL_BR_LINE -- valid speed + static valid bulk-IN tuple */
175 s_tag,
176 "cdc: bulk-in cfg");
177
178 err = ra8_usb_configure_endpoint(speed,
183 bulk_mp);
184 RA8_RETURN_ON_ERROR(err, /* GCOVR_EXCL_BR_LINE -- valid speed + static valid bulk-OUT tuple */
185 s_tag,
186 "cdc: bulk-out cfg");
187
188 err = ra8_usb_configure_endpoint(speed,
194 return err;
195}
196
225static void internal_apply_line_coding(const uint8_t* data, uint16_t len)
226{
227 if ((data == nullptr) || (len < k_ra8_cdc_line_coding_len)) {
228 return;
229 }
230 uint32_t baud = (uint32_t)data[k_ra8_cdc_idx_baud_b0];
231 baud |= (uint32_t)((uint32_t)data[k_ra8_cdc_idx_baud_b1] << k_ra8_cdc_shift_byte1);
232 baud |= (uint32_t)((uint32_t)data[k_ra8_cdc_idx_baud_b2] << k_ra8_cdc_shift_byte2);
233 baud |= (uint32_t)((uint32_t)data[k_ra8_cdc_idx_baud_b3] << k_ra8_cdc_shift_byte3);
234 s_state.coding.dte_rate = baud;
235 s_state.coding.char_format = data[k_ra8_cdc_idx_char_format];
236 s_state.coding.parity_type = data[k_ra8_cdc_idx_parity_type];
237 s_state.coding.data_bits = data[k_ra8_cdc_idx_data_bits];
238}
239
241void ra8_usb_cdc_test_apply_line_coding(const uint8_t* data, uint16_t len)
242{
244}
245
246/* =============================================================================
247 * Lifecycle
248 * =============================================================================
249 */
250
252{
253 if ((speed != k_ra8_usb_speed_fs) && (speed != k_ra8_usb_speed_hs)) {
255 }
256 const ra8_err_t usb_err = ra8_usb_device_init(speed);
257 if (usb_err != k_ra8_ok) {
258 ra8_log_error_val(s_tag, "ra8_usb_device_init failed", (uint32_t)usb_err);
260 }
261
262 s_state.speed = speed;
263 s_state.dtr = false;
264 s_state.rts = false;
266
267 const ra8_err_t pipes_err = internal_configure_pipes(speed);
268 if (pipes_err != k_ra8_ok) {
269 (void)ra8_usb_device_deinit(speed);
270 return pipes_err;
271 }
272 s_state.initialized = true;
273 ra8_log_info(s_tag, "CDC ready");
274 return k_ra8_ok;
275}
276
278{
279 if (!s_state.initialized) {
281 }
282 (void)ra8_usb_device_attach(s_state.speed, false);
283 const ra8_err_t err = ra8_usb_device_deinit(s_state.speed);
284 s_state.initialized = false;
285 s_state.dtr = false;
286 s_state.rts = false;
287 return err;
288}
289
291{
292 if (!s_state.initialized) {
294 }
295 return ra8_usb_device_attach(s_state.speed, attached);
296}
297
298/* =============================================================================
299 * Bulk byte pipe
300 * =============================================================================
301 */
302
303ra8_err_t ra8_usb_cdc_send(const uint8_t* data, uint16_t len)
304{
305 if (!s_state.initialized) {
307 }
308 if ((data == nullptr) && (len != 0U)) {
310 }
311 return ra8_usb_queue_in(s_state.speed, k_ra8_cdc_pipe_bulk_in, data, len);
312}
313
314ra8_err_t ra8_usb_cdc_recv(uint8_t* out_buf, uint16_t* inout_len)
315{
316 RA8_CHECK_NULL_PTR(out_buf, s_tag, "cdc_recv: out_buf");
317 RA8_CHECK_NULL_PTR(inout_len, s_tag, "cdc_recv: inout_len");
318 if (!s_state.initialized) {
320 }
321 if (*inout_len == 0U) {
323 }
324 /* rearm = true: re-arm PID=BUF so the bulk-OUT pipe keeps ACKing
325 * host data between cdc_recv calls (the legacy queue_out behaviour). */
326 return ra8_usb_queue_out(s_state.speed, k_ra8_cdc_pipe_bulk_out, out_buf, inout_len, true);
327}
328
329/* =============================================================================
330 * SETUP request handler
331 * =============================================================================
332 */
333
375static ra8_err_t internal_pull_data_stage(uint8_t* buf, uint16_t cap, uint16_t* out_len)
376{
377 RA8_CHECK_NULL_PTR(buf, s_tag, "pull_data_stage: buf");
378 RA8_CHECK_NULL_PTR(out_len, s_tag, "pull_data_stage: out_len");
379 if (cap == 0U) {
381 }
382 *out_len = 0U;
383 const ra8_err_t armed = ra8_usb_dcp_out_arm(s_state.speed);
384 if (armed != k_ra8_ok) {
385 return armed;
386 }
388 for (uint16_t i = 0U; i < k_ra8_cdc_data_stage_polls; ++i) {
389 rc = ra8_usb_dcp_out_read(s_state.speed, buf, cap, out_len);
390 if (rc != k_ra8_err_no_data) {
391 return rc;
392 }
393 }
394 return rc;
395}
396
415{
416 switch (setup->b_request) {
418 uint8_t buf[k_ra8_cdc_line_coding_len + 1U] = {};
419 uint16_t plen = 0U;
420 const ra8_err_t pull = internal_pull_data_stage(buf, (uint16_t)sizeof(buf), &plen);
421 if (pull == k_ra8_ok) {
423 }
424 /* The status stage is ACKed either way: a host that abandoned the data
425 * stage still gets a well-formed control-write completion, and the cached
426 * coding simply keeps its previous value. */
427 return ra8_usb_control_response(s_state.speed, true);
428 }
430 return ra8_usb_control_response(s_state.speed, true);
431 }
433 const uint16_t mask = setup->w_value;
434 s_state.dtr = ((mask & k_ra8_cdc_line_state_dtr) != 0U);
435 s_state.rts = ((mask & k_ra8_cdc_line_state_rts) != 0U);
436 return ra8_usb_control_response(s_state.speed, true);
437 }
438 default: {
440 }
441 }
442}
443
445{
446 RA8_CHECK_NULL_PTR(setup, s_tag, "handle_setup: setup");
447 if (!s_state.initialized) {
449 }
453 }
454 return internal_dispatch_class_setup(setup);
455}
456
458{
459 RA8_CHECK_NULL_PTR(out, s_tag, "get_line_coding: out");
460 if (!s_state.initialized) {
462 }
463 *out = s_state.coding;
464 return k_ra8_ok;
465}
466
467ra8_err_t ra8_usb_cdc_get_line_state(bool* out_dtr, bool* out_rts)
468{
469 RA8_CHECK_NULL_PTR(out_dtr, s_tag, "get_line_state: out_dtr");
470 RA8_CHECK_NULL_PTR(out_rts, s_tag, "get_line_state: out_rts");
471 if (!s_state.initialized) {
473 }
474 *out_dtr = s_state.dtr;
475 *out_rts = s_state.rts;
476 return k_ra8_ok;
477}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_BOUNDED_LOOP(symbol)
NASA Power-of-10 Rule 2: every loop in a FUNCTION has a constant bound.
#define RA8_TEST_HELPER
Mark a symbol as externally-linked but only callable from tests.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_hw_init_failed
Hardware peripheral failed to initialise.
Definition ra8_err.h:290
@ k_ra8_err_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
Definition ra8_err.h:180
@ k_ra8_err_no_data
No application data available (e.g.
Definition ra8_err.h:202
@ 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_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_error_val(tag, message, value)
RA8 log error val.
Definition ra8_log.h:337
#define ra8_log_info(tag, message)
RA8 log info.
Definition ra8_log.h:364
static uint32_t s_state
Native USB controller driver public API (device + host modes).
ra8_err_t ra8_usb_cdc_recv(uint8_t *out_buf, uint16_t *inout_len)
Drain a chunk of bytes OUT (host -> device).
static ra8_err_t internal_pull_data_stage(uint8_t *buf, uint16_t cap, uint16_t *out_len)
Pull the SET_LINE_CODING data stage off EP0 (DCP) once it lands.
ra8_usb_cdc_default_baud_t
9600 baud assembled from the two low bytes above.
Definition ra8_usb_cdc.c:79
@ k_ra8_cdc_default_baud
RA8 cdc default baud.
Definition ra8_usb_cdc.c:80
ra8_err_t ra8_usb_cdc_get_line_state(bool *out_dtr, bool *out_rts)
Get the most recently received DTR / RTS bits.
static void internal_default_coding(ra8_usb_cdc_line_coding_t *coding)
Internal helper.
ra8_err_t ra8_usb_cdc_handle_setup(const ra8_usb_setup_t *setup)
Process a class-specific SETUP packet.
static void internal_apply_line_coding(const uint8_t *data, uint16_t len)
Apply a host SET_LINE_CODING payload to the cached CDC line coding.
ra8_err_t ra8_usb_cdc_init(ra8_usb_speed_t speed)
Bring up the CDC ACM function on a chosen USB controller.
ra8_err_t ra8_usb_cdc_deinit(void)
Tear down the CDC function and release the underlying controller.
static ra8_err_t internal_dispatch_class_setup(const ra8_usb_setup_t *setup)
Decode a CDC class-specific SETUP packet body.
ra8_usb_cdc_data_stage_t
Bound on the polled control-OUT data-stage drain.
Definition ra8_usb_cdc.c:71
@ k_ra8_cdc_data_stage_polls
Max ra8_usb_dcp_out_read attempts.
Definition ra8_usb_cdc.c:72
ra8_err_t ra8_usb_cdc_get_line_coding(ra8_usb_cdc_line_coding_t *out)
Get the most recently negotiated line coding.
void ra8_usb_cdc_test_apply_line_coding(const uint8_t *data, uint16_t len)
Drive the private SET_LINE_CODING decoder from host tests.
ra8_err_t ra8_usb_cdc_attach(bool attached)
Raise / drop the D+ pull-up to advertise the CDC function.
ra8_err_t ra8_usb_cdc_send(const uint8_t *data, uint16_t len)
Send a chunk of bytes IN (device -> host).
ra8_usb_cdc_byte_idx_t
Indices into the 7-byte SET_LINE_CODING payload.
Definition ra8_usb_cdc.c:99
@ k_ra8_cdc_idx_data_bits
RA8 cdc index data bits.
@ k_ra8_cdc_idx_baud_b3
RA8 cdc index baud b3.
@ k_ra8_cdc_idx_char_format
RA8 cdc index char format.
@ k_ra8_cdc_idx_parity_type
RA8 cdc index parity type.
@ k_ra8_cdc_idx_baud_b2
RA8 cdc index baud b2.
@ k_ra8_cdc_idx_baud_b1
RA8 cdc index baud b1.
@ k_ra8_cdc_idx_baud_b0
RA8 cdc index baud b0.
ra8_usb_cdc_byte_shift_t
Per-byte left-shift constants for the little-endian baud accumulator in internal_apply_line_coding.
Definition ra8_usb_cdc.c:88
@ k_ra8_cdc_shift_byte2
RA8 cdc shift byte2.
Definition ra8_usb_cdc.c:91
@ k_ra8_cdc_shift_byte3
RA8 cdc shift byte3.
Definition ra8_usb_cdc.c:92
@ k_ra8_cdc_shift_byte0
RA8 cdc shift byte0.
Definition ra8_usb_cdc.c:89
@ k_ra8_cdc_shift_byte1
RA8 cdc shift byte1.
Definition ra8_usb_cdc.c:90
ra8_usb_cdc_setup_field_t
Constants used to decode CDC class-specific SETUPs.
Definition ra8_usb_cdc.c:45
@ k_ra8_cdc_default_stop_bits
1 stop bit.
Definition ra8_usb_cdc.c:49
@ k_ra8_cdc_default_data_bits
8 data bits.
Definition ra8_usb_cdc.c:48
@ k_ra8_cdc_bm_class_recip_in
Class | Interface | In.
Definition ra8_usb_cdc.c:47
@ k_ra8_cdc_line_coding_len
7-byte payload length.
Definition ra8_usb_cdc.c:51
@ k_ra8_cdc_bm_class_recip_iface
Class | Interface | Out.
Definition ra8_usb_cdc.c:46
@ k_ra8_cdc_default_parity_none
No parity.
Definition ra8_usb_cdc.c:50
Native USB CDC ACM (Communications Device Class - AbstractControl Model) class layer.
@ k_ra8_cdc_line_state_rts
Request to send.
Definition ra8_usb_cdc.h:97
@ k_ra8_cdc_line_state_dtr
Data terminal ready.
Definition ra8_usb_cdc.h:96
@ k_ra8_cdc_ep_bulk_in_addr
EP1 IN address.
Definition ra8_usb_cdc.h:64
@ k_ra8_cdc_ep_bulk_out_addr
EP2 OUT address.
Definition ra8_usb_cdc.h:65
@ k_ra8_cdc_ep_intr_in_addr
EP3 IN address.
Definition ra8_usb_cdc.h:66
@ k_ra8_cdc_pipe_intr_in
PIPE6 -> EP3 IN (interrupt).
Definition ra8_usb_cdc.h:56
@ k_ra8_cdc_pipe_bulk_in
PIPE1 -> EP1 IN (bulk).
Definition ra8_usb_cdc.h:54
@ k_ra8_cdc_pipe_bulk_out
PIPE2 -> EP2 OUT (bulk).
Definition ra8_usb_cdc.h:55
@ k_ra8_cdc_bulk_max_packet_fs
Bulk size at full speed.
Definition ra8_usb_cdc.h:74
@ k_ra8_cdc_bulk_max_packet_hs
Bulk size at high speed.
Definition ra8_usb_cdc.h:75
@ k_ra8_cdc_intr_max_packet
Notification pipe size.
Definition ra8_usb_cdc.h:76
@ k_ra8_cdc_req_set_line_coding
7-byte payload.
Definition ra8_usb_cdc.h:86
@ k_ra8_cdc_req_get_line_coding
7-byte payload.
Definition ra8_usb_cdc.h:87
@ k_ra8_cdc_req_set_control_line_state
0-byte payload.
Definition ra8_usb_cdc.h:88
Test-access surface for the USB CDC line-coding decoder.
ra8_err_t ra8_usb_dcp_out_arm(ra8_usb_speed_t speed)
Arm the DCP (EP0) to receive a host-to-device control data stage.
ra8_err_t ra8_usb_queue_out(ra8_usb_speed_t speed, uint8_t pipe_num, uint8_t *out_buf, uint16_t *inout_len, bool rearm)
Drain an OUT transfer (host -> device) from pipe_num.
@ k_ra8_usb_ep_type_bulk
Bulk transfer.
@ k_ra8_usb_ep_type_intr
Interrupt transfer.
ra8_err_t ra8_usb_device_init(ra8_usb_speed_t speed)
Bring up a USB controller in device mode.
ra8_err_t ra8_usb_control_response(ra8_usb_speed_t speed, bool accept)
Issue a control-transfer status response on EP0.
ra8_err_t ra8_usb_device_deinit(ra8_usb_speed_t speed)
Tear down a USB controller and drop its MSTP reference.
ra8_err_t ra8_usb_configure_endpoint(ra8_usb_speed_t speed, uint8_t pipe_num, uint8_t ep_addr, ra8_usb_ep_dir_t dir, ra8_usb_ep_type_t type, uint16_t max_packet)
Configure a non-control PIPE for IN or OUT bulk / interrupt / iso transfers.
ra8_err_t ra8_usb_device_attach(ra8_usb_speed_t speed, bool attached)
Raise / drop the D+ pull-up to advertise the device to the host.
@ k_ra8_usb_ep_dir_in
Device -> host.
@ k_ra8_usb_ep_dir_out
Host -> device.
ra8_usb_speed_t
Selects which controller instance the call targets.
@ k_ra8_usb_speed_hs
High-Speed controller (USBHS @ 0x40351000).
@ k_ra8_usb_speed_fs
Full-Speed controller (USBFS @ 0x40250000).
ra8_err_t ra8_usb_dcp_out_read(ra8_usb_speed_t speed, uint8_t *buf, uint16_t cap, uint16_t *out_rx)
Drain an armed control-OUT data stage from the DCP (EP0).
ra8_err_t ra8_usb_queue_in(ra8_usb_speed_t speed, uint8_t pipe_num, const uint8_t *data, uint16_t len)
Queue an IN transfer (device -> host) on pipe_num.
static ra8_err_t internal_configure_pipes(void)
Configure the host-Audio iso pipes against the attached device's endpoints.
7-byte payload of SET_LINE_CODING / GET_LINE_CODING.
uint32_t dte_rate
Baud rate in bits/sec.
uint8_t data_bits
5 / 6 / 7 / 8 / 16.
uint8_t parity_type
0=none, 1=odd, 2=even, ...
uint8_t char_format
0=1 stop, 1=1.5 stop, 2=2 stop.
Singleton shadow state for the CDC function.
bool dtr
DTR shadow.
bool initialized
True after ra8_usb_cdc_init.
ra8_usb_speed_t speed
Underlying controller.
ra8_usb_cdc_line_coding_t coding
Most recent line coding.
bool rts
RTS shadow.
Decoded 8-byte USB SETUP packet.
uint8_t b_request
bRequest code.
uint8_t bm_request_type
Request direction / type / recipient.
uint16_t w_value
wValue.