ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_usb_paud.c File Reference

Native USB device-side Audio (UAC1) class layer implementation. More...

#include "ra8_usb_paud.h"
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_log.h"
#include "ra8_usb.h"
Include dependency graph for ra8_usb_paud.c:

Go to the source code of this file.

Data Structures

struct  ra8_usb_paud_state_t
 Singleton shadow state for the device-Audio function. More...

Enumerations

enum  ra8_usb_paud_setup_field_t : uint8_t {
  k_ra8_paud_bm_class_iface_in = 0xA1U ,
  k_ra8_paud_bm_class_iface_out = 0x21U ,
  k_ra8_paud_bm_class_ep_in = 0xA2U ,
  k_ra8_paud_bm_class_ep_out = 0x22U
}
 Constants used to recognise audio class-specific SETUPs. More...
enum  ra8_usb_paud_default_t : uint32_t {
  k_ra8_paud_default_rate_hz = 48000U ,
  k_ra8_paud_default_channels = 2U ,
  k_ra8_paud_default_bps = 2U ,
  k_ra8_paud_default_volume = 0U
}
 Spec defaults the class layer seeds at init. More...
enum  ra8_usb_paud_limit_t : uint8_t {
  k_ra8_paud_max_channels = 2U ,
  k_ra8_paud_max_bps = 4U ,
  k_ra8_paud_min_bps = 1U ,
  k_ra8_paud_min_channels = 1U
}
 Format-shadow validation limits. More...

Functions

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_configure_pipes (ra8_usb_speed_t speed)
 Configure the two iso pipes.
static void internal_reset_shadow (ra8_usb_speed_t speed)
 Reset shadow state to spec defaults.
static bool internal_is_known_class_request (uint8_t b_request)
 Recognise an audio class request code we forward.
static bool internal_is_class_envelope (uint8_t bm)
 Recognise an audio class request envelope.
ra8_err_t ra8_usb_paud_init (ra8_usb_speed_t speed)
 Bring up the device-Audio function on a chosen USB controller.
ra8_err_t ra8_usb_paud_close (void)
 Tear down the device-Audio function and release the controller.
ra8_err_t ra8_usb_paud_set_descriptors (const uint8_t *desc, uint16_t desc_len)
 Install the caller-supplied audio descriptor blob.
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_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_set_format (ra8_usb_paud_format_t format)
 Apply a SET_CUR(sampling-frequency) shadow update.
ra8_err_t ra8_usb_paud_get_format (ra8_usb_paud_format_t *out_format)
 Read the current iso stream format.
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_get_volume (int16_t *out_volume)
 Read the current feature-unit volume.
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_handle_setup (const ra8_usb_setup_t *setup)
 Process a class-specific SETUP packet on EP0.

Variables

static const char * s_tag = "USBPAUD"
static ra8_usb_paud_state_t s_state = {}

Detailed Description

Native USB device-side Audio (UAC1) class layer implementation.

Tag
[Ring 3 / HAL] {World: NS}

Glues the device-mode ra8_usb driver to a USB Audio Class 1.0 function so the EK-RA8D2 enumerates as a microphone (iso IN), a speaker (iso OUT), or both. This file is the native peripheral-Audio class layer; FSP's r_usb_paud_driver.c is reference material only, nothing is pulled in verbatim.

Mapping vs FSP:

Reference: USB Audio 1.0 sec 5.2.1 "Request Layout" and sec A.9 "Audio Class-Specific Request Codes".

Definition in file ra8_usb_paud.c.

Enumeration Type Documentation

◆ ra8_usb_paud_default_t

enum ra8_usb_paud_default_t : uint32_t

Spec defaults the class layer seeds at init.

48 kHz / stereo / 16-bit is the most common HID-class / UAC1 default for capture and playback gadgets.

Enumerator
k_ra8_paud_default_rate_hz 

48 kHz default rate.

k_ra8_paud_default_channels 

Stereo default.

k_ra8_paud_default_bps 

16-bit default.

k_ra8_paud_default_volume 

0 dB volume default.

Definition at line 69 of file ra8_usb_paud.c.

◆ ra8_usb_paud_limit_t

enum ra8_usb_paud_limit_t : uint8_t

Format-shadow validation limits.

Enumerator
k_ra8_paud_max_channels 

Stereo cap.

k_ra8_paud_max_bps 

32-bit max sub-frame.

k_ra8_paud_min_bps 

8-bit min sub-frame.

k_ra8_paud_min_channels 

Mono min.

Definition at line 80 of file ra8_usb_paud.c.

◆ ra8_usb_paud_setup_field_t

Constants used to recognise audio class-specific SETUPs.

Per USB Audio 1.0 sec 5.2 "Class-Specific Request" the standard envelopes are interface-recipient class (0x21 / 0xA1) for AC / AS interface controls and endpoint-recipient class (0x22 / 0xA2) for endpoint-controls (e.g. sampling-frequency).

Enumerator
k_ra8_paud_bm_class_iface_in 

Class | Iface | In.

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.

Definition at line 55 of file ra8_usb_paud.c.

Function Documentation

◆ internal_configure_pipes()

void internal_configure_pipes ( ra8_usb_speed_t speed)
static

Configure the two iso pipes.

See implementation.

Parameters
[in]speedSee implementation.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 150 of file ra8_usb_paud.c.

References internal_iso_max_packet(), k_ra8_paud_ep_iso_in_addr, k_ra8_paud_ep_iso_out_addr, k_ra8_paud_pipe_iso_in, k_ra8_paud_pipe_iso_out, k_ra8_usb_ep_dir_in, k_ra8_usb_ep_dir_out, k_ra8_usb_ep_type_iso, and ra8_usb_configure_endpoint().

◆ internal_is_class_envelope()

bool internal_is_class_envelope ( uint8_t bm)
static

Recognise an audio class request envelope.

See implementation.

Parameters
[in]bmSee implementation.
Returns
Result code.
Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 236 of file ra8_usb_paud.c.

References k_ra8_paud_bm_class_ep_in, k_ra8_paud_bm_class_ep_out, k_ra8_paud_bm_class_iface_in, and k_ra8_paud_bm_class_iface_out.

Referenced by ra8_usb_paud_handle_setup().

◆ internal_is_known_class_request()

bool internal_is_known_class_request ( uint8_t b_request)
static

Recognise an audio class request code we forward.

See implementation.

Parameters
[in]b_requestSee implementation.
Returns
Result code.
Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 212 of file ra8_usb_paud.c.

References k_ra8_paud_req_get_cur, k_ra8_paud_req_get_max, k_ra8_paud_req_get_min, k_ra8_paud_req_get_res, k_ra8_paud_req_get_stat, k_ra8_paud_req_set_cur, k_ra8_paud_req_set_max, k_ra8_paud_req_set_min, and k_ra8_paud_req_set_res.

Referenced by ra8_usb_paud_handle_setup().

◆ internal_iso_max_packet()

uint16_t internal_iso_max_packet ( ra8_usb_speed_t speed)
static

Pick the iso-max-packet ceiling matching the negotiated speed.

See implementation.

Parameters
[in]speedSee implementation.
Returns
The iso-endpoint maximum packet size in bytes for speed.
Return values
k_ra8_paud_iso_max_packet_hsspeed is k_ra8_usb_speed_hs.
k_ra8_paud_iso_max_packet_fs_defaultAny other speed.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 131 of file ra8_usb_paud.c.

References k_ra8_paud_iso_max_packet_fs_default, k_ra8_paud_iso_max_packet_hs, and k_ra8_usb_speed_hs.

Referenced by internal_configure_pipes(), and internal_reset_shadow().

◆ internal_reset_shadow()

void internal_reset_shadow ( ra8_usb_speed_t speed)
static

Reset shadow state to spec defaults.

See implementation.

Parameters
[in]speedSee implementation.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 183 of file ra8_usb_paud.c.

References internal_iso_max_packet(), k_ra8_paud_default_bps, k_ra8_paud_default_channels, k_ra8_paud_default_rate_hz, k_ra8_paud_default_volume, and s_state.

Referenced by ra8_usb_paud_init().

◆ ra8_usb_paud_attach_setup_handler()

ra8_err_t ra8_usb_paud_attach_setup_handler ( ra8_usb_paud_setup_fn_t setup_fn,
void * ctx )
nodiscard

Register the application's audio class-setup handler.

Pass NULL for setup_fn to detach. The class layer drains the SETUP envelope from the controller and forwards it if its bmRequestType indicates a class-recipient-interface or class-recipient-endpoint request and its bRequest is one of the audio class request codes (USB Audio 1.0 sec A.9).

Parameters
[in]setup_fnApplication's handler. NULL detaches.
[in]ctxContext pointer threaded back into setup_fn.
Returns
ra8_err_t error code.
Return values
k_ra8_okHandler installed.
k_ra8_err_invalid_stateDriver not initialized.
Precondition
ra8_usb_paud_init succeeded.
Postcondition
On the next class SETUP, setup_fn(ctx, &setup) fires.
Note
Not thread-safe.
Since
0.1.0

Definition at line 397 of file ra8_usb_paud.c.

References k_ra8_err_invalid_state, k_ra8_ok, and s_state.

◆ ra8_usb_paud_close()

ra8_err_t ra8_usb_paud_close ( void )
nodiscard

Tear down the device-Audio function and release the controller.

Returns
ra8_err_t error code.
Return values
k_ra8_okReleased.
k_ra8_err_invalid_stateDriver was never initialized.
Precondition
Single-threaded shutdown context.
Postcondition
ra8_usb_device_deinit ran; D+ pull-up dropped; subsequent device-Audio API calls return k_ra8_err_invalid_state.
Note
Not thread-safe.
Since
0.1.0

Definition at line 265 of file ra8_usb_paud.c.

References k_ra8_err_invalid_state, ra8_usb_device_attach(), ra8_usb_device_deinit(), and s_state.

◆ ra8_usb_paud_get_format()

ra8_err_t ra8_usb_paud_get_format ( ra8_usb_paud_format_t * out_format)
nodiscard

Read the current iso stream format.

Parameters
[out]out_formatReceives the current format.
Returns
ra8_err_t error code.
Return values
k_ra8_okValue copied.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrout_format was NULL.
Precondition
out_format non-NULL.
Postcondition
No internal state mutated.
Note
Not thread-safe.
Since
0.1.0

Definition at line 363 of file ra8_usb_paud.c.

References k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, s_state, and s_tag.

◆ ra8_usb_paud_get_volume()

ra8_err_t ra8_usb_paud_get_volume ( int16_t * out_volume)
nodiscard

Read the current feature-unit volume.

Parameters
[out]out_volumeReceives the current volume in Q8.8 dB.
Returns
ra8_err_t error code.
Return values
k_ra8_okValue copied.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrout_volume was NULL.
Precondition
out_volume non-NULL.
Postcondition
No internal state mutated.
Note
Not thread-safe.
Since
0.1.0

Definition at line 382 of file ra8_usb_paud.c.

References k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, s_state, and s_tag.

◆ ra8_usb_paud_handle_setup()

ra8_err_t ra8_usb_paud_handle_setup ( const ra8_usb_setup_t * setup)
nodiscard

Process a class-specific SETUP packet on EP0.

Switches on b_request and forwards the SETUP to the registered application handler if any. Standard (non-class) SETUPs are rejected with k_ra8_err_not_supported so the caller can fall back to its own standard-request handler.

Parameters
[in]setupThe SETUP packet returned by ra8_usb_read_setup_if_valid.
Returns
ra8_err_t error code.
Return values
k_ra8_okSETUP handled (status stage queued internally).
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrsetup was NULL.
k_ra8_err_not_supportedbRequest is not an audio class request this layer cares about.
Precondition
ra8_usb_paud_init succeeded.
Postcondition
Internal shadows may have been updated by the callback.
Note
Call from the CTRT ISR path of ra8_usb.
Since
0.1.0

Definition at line 412 of file ra8_usb_paud.c.

References ra8_usb_setup_t::b_request, ra8_usb_setup_t::bm_request_type, internal_is_class_envelope(), internal_is_known_class_request(), k_ra8_err_invalid_state, k_ra8_err_not_supported, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_usb_control_response(), s_state, and s_tag.

◆ ra8_usb_paud_init()

ra8_err_t ra8_usb_paud_init ( ra8_usb_speed_t speed)
nodiscard

Bring up the device-Audio function on a chosen USB controller.

Initialises the underlying ra8_usb driver in DEVICE mode for speed, configures PIPE1 (iso IN) and PIPE2 (iso OUT), seeds the format shadow to 48 kHz / stereo / 16-bit, and leaves the D+ pull-up dropped. The caller raises it via ra8_usb_device_attach once descriptors are set.

Parameters
[in]speedWhich USB controller (FS or HS).
Returns
ra8_err_t error code.
Return values
k_ra8_okDevice-Audio ready.
k_ra8_err_invalid_argspeed out of range.
k_ra8_err_hw_init_failedUnderlying ra8_usb_device_init failed.
Precondition
Single-threaded init context.
ra8_mstp_init and ra8_pwr_init already ran.
Postcondition
Internal state machine armed; descriptor pointer cleared.
Pipe1 / pipe2 configured at the speed's default packet size.
Note
Not thread-safe.
See also
ra8_usb_paud_set_descriptors
ra8_usb_paud_close
Since
0.1.0

Definition at line 247 of file ra8_usb_paud.c.

References internal_configure_pipes(), internal_reset_shadow(), k_ra8_err_hw_init_failed, k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_usb_speed_fs, k_ra8_usb_speed_hs, ra8_log_error_val, ra8_log_info_val, ra8_usb_device_init(), s_state, and s_tag.

Referenced by internal_usb_audio_usb_or_halt().

◆ ra8_usb_paud_recv_frame()

ra8_err_t ra8_usb_paud_recv_frame ( uint8_t * buf,
uint16_t max_len,
uint16_t * got_len )
nodiscard

Drain a playback audio frame from the iso-OUT endpoint.

Parameters
[out]bufReceive buffer.
[in]max_lenCapacity of buf, > 0.
[out]got_lenReceives the number of bytes actually placed.
Returns
ra8_err_t error code.
Return values
k_ra8_okBytes drained.
k_ra8_err_no_dataPipe was empty.
k_ra8_err_null_ptrbuf or got_len was NULL.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_invalid_argmax_len == 0.
Precondition
ra8_usb_paud_init succeeded.
Postcondition
On success *got_len reflects the actual byte count.
Note
Not thread-safe.
Since
0.1.0

Definition at line 317 of file ra8_usb_paud.c.

References k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_ok, k_ra8_paud_pipe_iso_out, RA8_CHECK_NULL_PTR, ra8_usb_queue_out(), s_state, and s_tag.

◆ ra8_usb_paud_send_frame()

ra8_err_t ra8_usb_paud_send_frame ( const uint8_t * frame,
uint16_t len )
nodiscard

Push a captured audio frame on the iso-IN endpoint.

Queues len bytes onto PIPE1. The caller is responsible for sample alignment (e.g. integer multiple of channels * bytes_per_sample) and for not exceeding the configured pipe max-packet.

Parameters
[in]frameAudio frame buffer.
[in]lenFrame byte length.
Returns
ra8_err_t error code.
Return values
k_ra8_okBytes queued onto iso-IN.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrframe was NULL with len > 0.
k_ra8_err_invalid_arglen == 0 or larger than the pipe max.
Precondition
ra8_usb_paud_init succeeded.
Postcondition
len bytes sit on PIPE1.
Note
Not thread-safe.
Since
0.1.0

Definition at line 303 of file ra8_usb_paud.c.

References k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_err_null_ptr, k_ra8_paud_pipe_iso_in, ra8_usb_queue_in(), and s_state.

Referenced by internal_usb_audio_send_one_frame().

◆ ra8_usb_paud_set_descriptors()

ra8_err_t ra8_usb_paud_set_descriptors ( const uint8_t * desc,
uint16_t desc_len )
nodiscard

Install the caller-supplied audio descriptor blob.

The class layer keeps a pointer + length pair; the application owns the storage. The descriptor blob is the concatenation of: AudioControl interface header, input/output/feature units, an IAD, and AudioStreaming alt-settings + Format-Type-I + iso EP descriptors.

Parameters
[in]descPointer to the caller-owned descriptor blob.
[in]desc_lenByte length of desc.
Returns
ra8_err_t error code.
Return values
k_ra8_okPointer + length stored.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrdesc was NULL.
k_ra8_err_invalid_argdesc_len was 0.
Precondition
ra8_usb_paud_init succeeded.
Postcondition
Subsequent GET_DESCRIPTOR(Configuration) requests can use this blob.
Note
Not thread-safe.
Since
0.1.0

Definition at line 284 of file ra8_usb_paud.c.

References k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, s_state, and s_tag.

◆ ra8_usb_paud_set_format()

ra8_err_t ra8_usb_paud_set_format ( ra8_usb_paud_format_t format)
nodiscard

Apply a SET_CUR(sampling-frequency) shadow update.

Used by the class-setup callback (or directly by the application) to reflect a new sample-rate negotiated by the host. USB Audio 1.0 sec 5.2.3.2.3.1 "Sampling Frequency Control".

Parameters
[in]formatNew format triplet.
Returns
ra8_err_t error code.
Return values
k_ra8_okShadow updated.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_invalid_argFormat fields are zero / out of range.
Precondition
ra8_usb_paud_init succeeded.
Postcondition
ra8_usb_paud_get_format reflects the new value.
Note
Not thread-safe.
Since
0.1.0

Definition at line 343 of file ra8_usb_paud.c.

References ra8_usb_paud_format_t::bytes_per_sample, ra8_usb_paud_format_t::channels, k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_ok, k_ra8_paud_max_bps, k_ra8_paud_max_channels, k_ra8_paud_min_bps, k_ra8_paud_min_channels, s_state, and ra8_usb_paud_format_t::sample_rate_hz.

Referenced by internal_usb_audio_usb_or_halt().

◆ ra8_usb_paud_set_volume()

ra8_err_t ra8_usb_paud_set_volume ( int16_t volume_q8_8)
nodiscard

Apply a SET_CUR(volume) shadow update on the feature unit.

Volume on the audio feature unit is a 16-bit signed dB value with 1/256 dB resolution (USB Audio 1.0 sec 5.2.2.4.3.2 "Volume Control"). 0x8000 means "silence" / mute floor.

Parameters
[in]volume_q8_8New volume in Q8.8 dB format.
Returns
ra8_err_t error code.
Return values
k_ra8_okShadow updated.
k_ra8_err_invalid_stateDriver not initialized.
Precondition
ra8_usb_paud_init succeeded.
Postcondition
ra8_usb_paud_get_volume reflects the new value.
Note
Not thread-safe.
Since
0.1.0

Definition at line 373 of file ra8_usb_paud.c.

References k_ra8_err_invalid_state, k_ra8_ok, and s_state.

Referenced by internal_usb_audio_usb_or_halt().

Variable Documentation

◆ s_state

ra8_usb_paud_state_t s_state = {}
static

Definition at line 108 of file ra8_usb_paud.c.

◆ s_tag

const char* s_tag = "USBPAUD"
static

Definition at line 39 of file ra8_usb_paud.c.