ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_usb_paud.c
Go to the documentation of this file.
1
28
29#include "ra8_usb_paud.h"
30
31#include <stdint.h>
32
33#include "ra8_attributes.h"
34#include "ra8_check.h"
35#include "ra8_err.h"
36#include "ra8_log.h"
37#include "ra8_usb.h"
38
39static const char* s_tag = "USBPAUD";
40
41/* =============================================================================
42 * Internal constants
43 * =============================================================================
44 */
45
61
75
86
87/* =============================================================================
88 * Internal state
89 * =============================================================================
90 */
91
107
109
110/* =============================================================================
111 * Internal helpers
112 * =============================================================================
113 */
114
136
151{
152 const uint16_t mp = internal_iso_max_packet(speed);
153
154 /* Both calls receive the init-validated speed and compile-time pipe tuples
155 * that satisfy every `ra8_usb_configure_endpoint` argument guard. */
156 (void)ra8_usb_configure_endpoint(speed,
161 mp);
162 (void)ra8_usb_configure_endpoint(speed,
167 mp);
168}
169
184{
185 s_state.speed = speed;
186 s_state.iso_max_packet = internal_iso_max_packet(speed);
187 s_state.desc = nullptr;
188 s_state.desc_len = 0U;
189 s_state.format.sample_rate_hz = (uint32_t)k_ra8_paud_default_rate_hz;
190 s_state.format.channels = (uint8_t)k_ra8_paud_default_channels;
191 s_state.format.bytes_per_sample = (uint8_t)k_ra8_paud_default_bps;
192 s_state.volume_q8_8 = (int16_t)k_ra8_paud_default_volume;
193 s_state.setup_cb = nullptr;
194 s_state.setup_ctx = nullptr;
195}
196
212static bool internal_is_known_class_request(uint8_t b_request)
213{
214 return (b_request == k_ra8_paud_req_set_cur) || (b_request == k_ra8_paud_req_get_cur) ||
215 (b_request == k_ra8_paud_req_set_min) || (b_request == k_ra8_paud_req_get_min) ||
216 (b_request == k_ra8_paud_req_set_max) || (b_request == k_ra8_paud_req_get_max) ||
217 (b_request == k_ra8_paud_req_set_res) || (b_request == k_ra8_paud_req_get_res) ||
218 (b_request == k_ra8_paud_req_get_stat);
219}
220
236static bool internal_is_class_envelope(uint8_t bm)
237{
240}
241
242/* =============================================================================
243 * Lifecycle
244 * =============================================================================
245 */
246
248{
249 if ((speed != k_ra8_usb_speed_fs) && (speed != k_ra8_usb_speed_hs)) {
251 }
252 const ra8_err_t usb_err = ra8_usb_device_init(speed);
253 if (usb_err != k_ra8_ok) {
254 ra8_log_error_val(s_tag, "ra8_usb_device_init failed", (uint32_t)usb_err);
256 }
258
260 s_state.initialized = true;
261 ra8_log_info_val(s_tag, "device-Audio ready", (uint32_t)speed);
262 return k_ra8_ok;
263}
264
266{
267 if (!s_state.initialized) {
269 }
270 (void)ra8_usb_device_attach(s_state.speed, false);
271 const ra8_err_t err = ra8_usb_device_deinit(s_state.speed);
272 s_state.initialized = false;
273 s_state.desc = nullptr;
274 s_state.setup_cb = nullptr;
275 s_state.setup_ctx = nullptr;
276 return err;
277}
278
279/* =============================================================================
280 * Descriptor handoff
281 * =============================================================================
282 */
283
284ra8_err_t ra8_usb_paud_set_descriptors(const uint8_t* desc, uint16_t desc_len)
285{
286 if (!s_state.initialized) {
288 }
289 RA8_CHECK_NULL_PTR(desc, s_tag, "set_descriptors: desc");
290 if (desc_len == 0U) {
292 }
293 s_state.desc = desc;
294 s_state.desc_len = desc_len;
295 return k_ra8_ok;
296}
297
298/* =============================================================================
299 * Audio data transport
300 * =============================================================================
301 */
302
303ra8_err_t ra8_usb_paud_send_frame(const uint8_t* frame, uint16_t len)
304{
305 if (!s_state.initialized) {
307 }
308 if ((frame == nullptr) && (len != 0U)) {
309 return k_ra8_err_null_ptr;
310 }
311 if ((len == 0U) || (len > s_state.iso_max_packet)) {
313 }
314 return ra8_usb_queue_in(s_state.speed, k_ra8_paud_pipe_iso_in, frame, len);
315}
316
317ra8_err_t ra8_usb_paud_recv_frame(uint8_t* buf, uint16_t max_len, uint16_t* got_len)
318{
319 RA8_CHECK_NULL_PTR(buf, s_tag, "recv_frame: buf");
320 RA8_CHECK_NULL_PTR(got_len, s_tag, "recv_frame: got_len");
321 if (!s_state.initialized) {
323 }
324 if (max_len == 0U) {
326 }
327 uint16_t inout_len = max_len;
328 const ra8_err_t err =
329 ra8_usb_queue_out(s_state.speed, k_ra8_paud_pipe_iso_out, buf, &inout_len, true);
330 if (err == k_ra8_ok) {
331 *got_len = inout_len;
332 } else {
333 *got_len = 0U;
334 }
335 return err;
336}
337
338/* =============================================================================
339 * Format / volume helpers
340 * =============================================================================
341 */
342
344{
345 if (!s_state.initialized) {
347 }
348 if (format.sample_rate_hz == 0U) {
350 }
351 if ((format.channels < (uint8_t)k_ra8_paud_min_channels) ||
352 (format.channels > (uint8_t)k_ra8_paud_max_channels)) {
354 }
355 if ((format.bytes_per_sample < (uint8_t)k_ra8_paud_min_bps) ||
356 (format.bytes_per_sample > (uint8_t)k_ra8_paud_max_bps)) {
358 }
359 s_state.format = format;
360 return k_ra8_ok;
361}
362
364{
365 RA8_CHECK_NULL_PTR(out_format, s_tag, "get_format: out_format");
366 if (!s_state.initialized) {
368 }
369 *out_format = s_state.format;
370 return k_ra8_ok;
371}
372
374{
375 if (!s_state.initialized) {
377 }
378 s_state.volume_q8_8 = volume_q8_8;
379 return k_ra8_ok;
380}
381
383{
384 RA8_CHECK_NULL_PTR(out_volume, s_tag, "get_volume: out_volume");
385 if (!s_state.initialized) {
387 }
388 *out_volume = s_state.volume_q8_8;
389 return k_ra8_ok;
390}
391
392/* =============================================================================
393 * Setup-handler attach
394 * =============================================================================
395 */
396
398{
399 if (!s_state.initialized) {
401 }
402 s_state.setup_cb = setup_fn;
403 s_state.setup_ctx = ctx;
404 return k_ra8_ok;
405}
406
407/* =============================================================================
408 * Class SETUP dispatch
409 * =============================================================================
410 */
411
413{
414 RA8_CHECK_NULL_PTR(setup, s_tag, "handle_setup: setup");
415 if (!s_state.initialized) {
417 }
420 }
423 }
424 if (s_state.setup_cb != nullptr) {
425 const ra8_err_t cb_err = s_state.setup_cb(s_state.setup_ctx, setup);
426 if (cb_err != k_ra8_ok) {
427 return ra8_usb_control_response(s_state.speed, false);
428 }
429 }
430 return ra8_usb_control_response(s_state.speed, true);
431}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#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_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
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
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_info_val(tag, message, value)
RA8 log info val.
Definition ra8_log.h:366
#define ra8_log_error_val(tag, message, value)
RA8 log error val.
Definition ra8_log.h:337
static uint32_t s_state
Native USB controller driver public API (device + host modes).
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_iso
Isochronous 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_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.
ra8_usb_paud_default_t
Spec defaults the class layer seeds at init.
@ k_ra8_paud_default_volume
0 dB volume default.
@ k_ra8_paud_default_bps
16-bit default.
@ k_ra8_paud_default_rate_hz
48 kHz default rate.
@ k_ra8_paud_default_channels
Stereo default.
ra8_err_t ra8_usb_paud_recv_frame(uint8_t *buf, uint16_t max_len, uint16_t *got_len)
Drain a playback audio frame from the iso-OUT endpoint.
ra8_err_t ra8_usb_paud_attach_setup_handler(ra8_usb_paud_setup_fn_t setup_fn, void *ctx)
Register the application's audio class-setup handler.
ra8_err_t ra8_usb_paud_set_volume(int16_t volume_q8_8)
Apply a SET_CUR(volume) shadow update on the feature unit.
ra8_err_t ra8_usb_paud_set_descriptors(const uint8_t *desc, uint16_t desc_len)
Install the caller-supplied audio descriptor blob.
static bool internal_is_class_envelope(uint8_t bm)
Recognise an audio class request envelope.
ra8_usb_paud_limit_t
Format-shadow validation limits.
@ k_ra8_paud_max_channels
Stereo cap.
@ k_ra8_paud_max_bps
32-bit max sub-frame.
@ k_ra8_paud_min_channels
Mono min.
@ k_ra8_paud_min_bps
8-bit min sub-frame.
ra8_err_t ra8_usb_paud_set_format(ra8_usb_paud_format_t format)
Apply a SET_CUR(sampling-frequency) shadow update.
static uint16_t internal_iso_max_packet(ra8_usb_speed_t speed)
Pick the iso-max-packet ceiling matching the negotiated speed.
static void internal_reset_shadow(ra8_usb_speed_t speed)
Reset shadow state to spec defaults.
ra8_err_t ra8_usb_paud_get_format(ra8_usb_paud_format_t *out_format)
Read the current iso stream format.
static bool internal_is_known_class_request(uint8_t b_request)
Recognise an audio class request code we forward.
ra8_err_t ra8_usb_paud_close(void)
Tear down the device-Audio function and release the controller.
ra8_err_t ra8_usb_paud_send_frame(const uint8_t *frame, uint16_t len)
Push a captured audio frame on the iso-IN endpoint.
ra8_err_t ra8_usb_paud_handle_setup(const ra8_usb_setup_t *setup)
Process a class-specific SETUP packet on EP0.
ra8_err_t ra8_usb_paud_get_volume(int16_t *out_volume)
Read the current feature-unit volume.
ra8_usb_paud_setup_field_t
Constants used to recognise audio class-specific SETUPs.
@ k_ra8_paud_bm_class_iface_out
Class | Iface | Out.
@ k_ra8_paud_bm_class_ep_in
Class | EP | In.
@ k_ra8_paud_bm_class_ep_out
Class | EP | Out.
@ k_ra8_paud_bm_class_iface_in
Class | Iface | In.
ra8_err_t ra8_usb_paud_init(ra8_usb_speed_t speed)
Bring up the device-Audio function on a chosen USB controller.
Native USB device-side Audio (UAC) class layer.
@ k_ra8_paud_ep_iso_in_addr
EP1 IN address.
@ k_ra8_paud_ep_iso_out_addr
EP2 OUT address.
@ k_ra8_paud_req_get_cur
GET_CUR.
@ k_ra8_paud_req_get_stat
GET_STAT.
@ k_ra8_paud_req_get_max
GET_MAX.
@ k_ra8_paud_req_set_res
SET_RES.
@ k_ra8_paud_req_set_cur
SET_CUR.
@ k_ra8_paud_req_set_max
SET_MAX.
@ k_ra8_paud_req_get_res
GET_RES.
@ k_ra8_paud_req_get_min
GET_MIN.
@ k_ra8_paud_req_set_min
SET_MIN.
@ k_ra8_paud_iso_max_packet_fs_default
48 kHz stereo 16-bit.
@ k_ra8_paud_iso_max_packet_hs
HS iso ceiling.
ra8_err_t(* ra8_usb_paud_setup_fn_t)(void *ctx, const ra8_usb_setup_t *setup)
Caller-supplied audio class-setup handler signature.
@ k_ra8_paud_pipe_iso_out
PIPE2 -> EP2 OUT (playback).
@ k_ra8_paud_pipe_iso_in
PIPE1 -> EP1 IN (capture).
Current iso stream format negotiated with the host.
uint8_t bytes_per_sample
16-bit -> 2, 24-bit -> 3, etc.
uint32_t sample_rate_hz
Current SET_CUR sample rate.
uint8_t channels
1 = mono, 2 = stereo.
Singleton shadow state for the device-Audio function.
bool initialized
True after init.
uint16_t desc_len
Descriptor blob byte len.
const uint8_t * desc
Cached descriptor blob.
ra8_usb_paud_format_t format
Current iso format shadow.
int16_t volume_q8_8
Current volume in Q8.8 dB.
ra8_usb_paud_setup_fn_t setup_cb
Application class handler.
void * setup_ctx
Class handler context.
ra8_usb_speed_t speed
Underlying controller.
uint16_t iso_max_packet
Pipe max-packet size.
Decoded 8-byte USB SETUP packet.
uint8_t b_request
bRequest code.
uint8_t bm_request_type
Request direction / type / recipient.