|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Native USB host-side Audio class layer implementation. More...
#include "ra8_usb_haud.h"#include <stdint.h>#include "ra8_attributes.h"#include "ra8_check.h"#include "ra8_err.h"#include "ra8_log.h"#include "ra8_usb.h"Go to the source code of this file.
Data Structures | |
| struct | ra8_usb_haud_state_t |
| Singleton shadow state for the host-Audio driver. 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 ra8_err_t | internal_configure_pipes (void) |
| Configure the host-Audio iso pipes against the attached device's endpoints. | |
| static ra8_err_t | internal_setup_get_descriptor (uint8_t desc_type, uint16_t length) |
| Stage a chapter-9 GET_DESCRIPTOR SETUP request. | |
| static ra8_err_t | internal_setup_set_address (uint8_t address) |
| Stage a SET_ADDRESS SETUP request. | |
| static ra8_err_t | internal_setup_set_config (uint8_t config_value) |
| Stage a SET_CONFIGURATION SETUP request. | |
| static ra8_err_t | internal_setup_set_interface (void) |
| Stage a SET_INTERFACE SETUP request to the AS interface. | |
| static void | internal_walk_config_descriptor (void) |
| Populate s_state.device with stub descriptor data. | |
| static ra8_err_t | internal_do_idle (void) |
| Step handler – bus-reset assert. | |
| static ra8_err_t | internal_do_bus_reset (void) |
| Step handler – bus-reset release + SETUP for SET_ADDRESS. | |
| static ra8_err_t | internal_do_set_address (void) |
| Step handler – store assigned address + SETUP for GET_DEVICE_DESCRIPTOR. | |
| static ra8_err_t | internal_do_get_dev_desc (void) |
| Step handler – SETUP for GET_CONFIGURATION_DESCRIPTOR. | |
| static ra8_err_t | internal_do_get_cfg_desc (void) |
| Step handler – SETUP for SET_CONFIGURATION. | |
| static ra8_err_t | internal_do_set_config (void) |
| Step handler – SETUP for SET_INTERFACE (alt 1). | |
| static ra8_err_t | internal_do_set_interface (void) |
| Step handler – pure software state move into walk_desc. | |
| static ra8_err_t | internal_do_walk_desc (void) |
| Step handler – configure pipes and finalise. | |
| static ra8_err_t | internal_step_advance (void) |
| Drive the enumeration step machine forward by one step. | |
| static ra8_err_t | internal_class_preflight (void) |
| Common pre-flight for every class control transfer. | |
| static bool | internal_format_ok (uint8_t channel_count, uint8_t bits_per_sample, uint32_t sample_rate) |
| Validate audio format against the supported ranges. | |
| ra8_err_t | ra8_usb_haud_init (ra8_usb_speed_t speed) |
| Bring up the host-Audio driver on a chosen USB controller. | |
| ra8_err_t | ra8_usb_haud_close (void) |
| Tear down the host-Audio driver and release the controller. | |
| ra8_err_t | ra8_usb_haud_attach_callback (ra8_usb_haud_attach_fn_t on_attach, void *ctx) |
| Register (or detach) the attach callback. | |
| ra8_err_t | ra8_usb_haud_set_format (uint8_t channel_count, uint8_t bits_per_sample, uint32_t sample_rate_hz) |
| Issue SET_CUR on the format-type-I descriptor (USB Audio 1.0 sec 5.2.3 "Class-Specific AS Interface Control Requests"). | |
| ra8_err_t | ra8_usb_haud_set_volume (uint8_t channel, int16_t volume) |
| Issue SET_CUR on the Feature Unit Volume control (USB Audio 1.0 sec 5.2.2.4.3 "Volume Control"). | |
| ra8_err_t | ra8_usb_haud_set_mute (uint8_t channel, bool mute) |
| Issue SET_CUR on the Feature Unit Mute control (USB Audio 1.0 sec 5.2.2.4.3.1 "Mute Control"). | |
| ra8_err_t | ra8_usb_haud_send_samples (const uint8_t *buf, uint16_t len_bytes) |
| Push isochronous-OUT samples to a speaker / headphones. | |
| ra8_err_t | ra8_usb_haud_recv_samples (uint8_t *buf, uint16_t max_len_bytes, uint16_t *got_len_bytes) |
| Drain isochronous-IN samples from a microphone. | |
| ra8_err_t | ra8_usb_haud_step (void) |
| Drive the enumeration step machine forward by one step. | |
Variables | |
| static const char * | s_tag = "USBHAUD" |
| static ra8_usb_haud_state_t | s_state = {} |
Native USB host-side Audio class layer implementation.
Glues the host-mode bring-up paths in ra8_usb to a USB Audio class peripheral - speaker / headphones / microphone - attached on the EK-RA8D2's USB-host port. This file is the native host-Audio class layer; FSP's r_usb_haud.c is reference material only – nothing is pulled in verbatim.
Mapping vs FSP (FSP function -> our entry point):
The starter does CPU-FIFO, single-device, no-hub. Enumeration is driven step-by-step from the controller's CTRT interrupt path (production) or directly via ra8_usb_haud_step (tests). Each step issues exactly one chapter-9 SETUP request via ra8_usb_host_setup_request; the next CTRT advances the step.
Definition in file ra8_usb_haud.c.
| enum ra8_usb_haud_byte_shift_t : uint8_t |
Per-byte left-shift constants for wValue / wIndex layout.
| Enumerator | |
|---|---|
| k_ra8_haud_shift_byte0 | RA8 haud shift byte0. |
| k_ra8_haud_shift_byte1 | RA8 haud shift byte1. |
Definition at line 115 of file ra8_usb_haud.c.
| enum ra8_usb_haud_default_unit_t : uint8_t |
Default Feature Unit ID applied by the descriptor-walk stub when the attached device follows the canonical USB-headphones layout (Input Terminal -> Feature Unit -> Output Terminal).
Definition at line 126 of file ra8_usb_haud.c.
| enum ra8_usb_haud_setup_field_t : uint8_t |
Standard chapter-9 + Audio class request encodings.
Definition at line 77 of file ra8_usb_haud.c.
| enum ra8_usb_haud_size_t : uint16_t |
Standard descriptor sizes and wire payloads.
Definition at line 100 of file ra8_usb_haud.c.
| enum ra8_usb_haud_step_t : uint8_t |
Enumeration step machine states.
Mirrors FSP's host-Audio enumeration sequence in r_usb_haud.c. Each step issues exactly one SETUP via ra8_usb_host_setup_request; the next CTRT interrupt advances.
Definition at line 61 of file ra8_usb_haud.c.
|
static |
Common pre-flight for every class control transfer.
See implementation.
| k_ra8_ok | Operation succeeded. |
Definition at line 625 of file ra8_usb_haud.c.
References k_ra8_err_invalid_state, k_ra8_ok, and s_state.
Referenced by ra8_usb_haud_recv_samples(), ra8_usb_haud_send_samples(), ra8_usb_haud_set_format(), ra8_usb_haud_set_mute(), and ra8_usb_haud_set_volume().
|
static |
Configure the host-Audio iso pipes against the attached device's endpoints.
Mirrors FSP's usb_haud_pipe_info. PIPE2 (iso-OUT) is configured if the device exposes a speaker; PIPE1 (iso-IN) is configured if it exposes a microphone. A device with neither endpoint is silently accepted – the class layer just won't be able to push or drain samples.
| k_ra8_ok | Operation succeeded. |
Definition at line 201 of file ra8_usb_haud.c.
References k_ra8_haud_pipe_iso_in, k_ra8_haud_pipe_iso_out, k_ra8_ok, k_ra8_usb_ep_dir_in, k_ra8_usb_ep_dir_out, k_ra8_usb_ep_type_iso, RA8_RETURN_ON_ERROR, ra8_usb_configure_endpoint(), s_state, and s_tag.
Referenced by internal_do_walk_desc(), ra8_usb_cdc_init(), ra8_usb_paud_init(), ra8_usb_phid_init(), ra8_usb_pprn_init(), and ra8_usb_pvnd_init().
|
static |
Step handler – bus-reset release + SETUP for SET_ADDRESS.
See implementation.
| k_ra8_ok | Operation succeeded. |
Definition at line 427 of file ra8_usb_haud.c.
References internal_setup_set_address(), k_ra8_haud_assigned_address, k_ra8_haud_step_set_address, RA8_RETURN_ON_ERROR, ra8_usb_host_bus_reset(), s_state, and s_tag.
Referenced by internal_step_advance().
|
static |
Step handler – SETUP for SET_CONFIGURATION.
See implementation.
| k_ra8_ok | Operation succeeded. |
Definition at line 497 of file ra8_usb_haud.c.
References internal_setup_set_config(), internal_walk_config_descriptor(), k_ra8_haud_default_config, k_ra8_haud_step_set_config, and s_state.
Referenced by internal_step_advance().
|
static |
Step handler – SETUP for GET_CONFIGURATION_DESCRIPTOR.
See implementation.
| k_ra8_ok | Operation succeeded. |
Definition at line 477 of file ra8_usb_haud.c.
References internal_setup_get_descriptor(), k_ra8_haud_cfg_desc_len, k_ra8_haud_desc_configuration, k_ra8_haud_step_get_cfg_desc, and s_state.
Referenced by internal_step_advance().
|
static |
Step handler – bus-reset assert.
See implementation.
| k_ra8_ok | Operation succeeded. |
Definition at line 407 of file ra8_usb_haud.c.
References k_ra8_haud_step_bus_reset, ra8_usb_host_bus_reset(), and s_state.
Referenced by internal_step_advance().
|
static |
Step handler – store assigned address + SETUP for GET_DEVICE_DESCRIPTOR.
See implementation.
| k_ra8_ok | Operation succeeded. |
Definition at line 452 of file ra8_usb_haud.c.
References internal_setup_get_descriptor(), k_ra8_haud_assigned_address, k_ra8_haud_desc_device, k_ra8_haud_dev_desc_len, k_ra8_haud_step_get_dev_desc, RA8_RETURN_ON_ERROR, ra8_usb_set_address(), s_state, and s_tag.
Referenced by internal_step_advance().
|
static |
Step handler – SETUP for SET_INTERFACE (alt 1).
See implementation.
| k_ra8_ok | Operation succeeded. |
Definition at line 520 of file ra8_usb_haud.c.
References internal_setup_set_interface(), k_ra8_haud_step_set_interface, and s_state.
Referenced by internal_step_advance().
|
static |
Step handler – pure software state move into walk_desc.
See implementation.
| k_ra8_ok | Operation succeeded. |
Definition at line 540 of file ra8_usb_haud.c.
References k_ra8_haud_step_walk_desc, k_ra8_ok, and s_state.
Referenced by internal_step_advance().
|
static |
Step handler – configure pipes and finalise.
See implementation.
| k_ra8_ok | Operation succeeded. |
Definition at line 560 of file ra8_usb_haud.c.
References internal_configure_pipes(), k_ra8_haud_step_done, k_ra8_ok, RA8_RETURN_ON_ERROR, s_state, and s_tag.
Referenced by internal_step_advance().
|
static |
Validate audio format against the supported ranges.
See implementation.
| [in] | channel_count | See implementation. |
| [in] | bits_per_sample | See implementation. |
| [in] | sample_rate | See implementation. |
| k_ra8_ok | Operation succeeded. |
Definition at line 653 of file ra8_usb_haud.c.
References k_ra8_haud_max_bits, k_ra8_haud_max_channels, k_ra8_haud_max_sample_rate_hz, k_ra8_haud_min_bits, k_ra8_haud_min_channels, and k_ra8_haud_min_sample_rate_hz.
Referenced by ra8_usb_haud_set_format().
|
static |
Pick the iso-max-packet ceiling matching the negotiated speed.
See implementation.
| [in] | speed | See implementation. |
| k_ra8_ok | Operation succeeded. |
Definition at line 175 of file ra8_usb_haud.c.
References k_ra8_haud_iso_max_packet_fs, k_ra8_haud_iso_max_packet_hs, and k_ra8_usb_speed_hs.
Referenced by internal_walk_config_descriptor().
|
static |
Stage a chapter-9 GET_DESCRIPTOR SETUP request.
See implementation.
| [in] | desc_type | See implementation. |
| [in] | length | See implementation. |
| k_ra8_ok | Operation succeeded. |
Definition at line 240 of file ra8_usb_haud.c.
References k_ra8_haud_bm_std_dev_in, k_ra8_haud_breq_get_descriptor, k_ra8_haud_shift_byte1, ra8_usb_host_setup_request(), and s_state.
Referenced by internal_do_get_dev_desc(), and internal_do_set_address().
|
static |
Stage a SET_ADDRESS SETUP request.
See implementation.
| [in] | address | See implementation. |
| k_ra8_ok | Operation succeeded. |
Definition at line 267 of file ra8_usb_haud.c.
References k_ra8_haud_bm_std_dev_out, k_ra8_haud_breq_set_address, ra8_usb_host_setup_request(), and s_state.
Referenced by internal_do_bus_reset().
|
static |
Stage a SET_CONFIGURATION SETUP request.
See implementation.
| [in] | config_value | See implementation. |
| k_ra8_ok | Operation succeeded. |
Definition at line 294 of file ra8_usb_haud.c.
References k_ra8_haud_bm_std_dev_out, k_ra8_haud_breq_set_config, ra8_usb_host_setup_request(), and s_state.
Referenced by internal_do_get_cfg_desc().
|
static |
Stage a SET_INTERFACE SETUP request to the AS interface.
Per USB Audio 1.0 sec 4.5 the host must select a non-zero Audio-Streaming alt setting (alt 0 is the "zero-bandwidth" default) for any iso-EP transfers to actually move data.
| k_ra8_ok | Operation succeeded. |
Definition at line 323 of file ra8_usb_haud.c.
References k_ra8_haud_bm_std_iface_out, k_ra8_haud_breq_set_interface, k_ra8_haud_default_alt, ra8_usb_host_setup_request(), and s_state.
Referenced by internal_do_set_config().
|
static |
Drive the enumeration step machine forward by one step.
See implementation.
| k_ra8_ok | Operation succeeded. |
Definition at line 586 of file ra8_usb_haud.c.
References internal_do_bus_reset(), internal_do_get_cfg_desc(), internal_do_get_dev_desc(), internal_do_idle(), internal_do_set_address(), internal_do_set_config(), internal_do_set_interface(), internal_do_walk_desc(), k_ra8_haud_step_bus_reset, k_ra8_haud_step_get_cfg_desc, k_ra8_haud_step_get_dev_desc, k_ra8_haud_step_idle, k_ra8_haud_step_set_address, k_ra8_haud_step_set_config, k_ra8_haud_step_set_interface, k_ra8_haud_step_walk_desc, k_ra8_ok, and s_state.
Referenced by ra8_usb_haud_step().
|
static |
Populate s_state.device with stub descriptor data.
In production this routine walks the configuration descriptor returned in the GET_CONFIG_DESCRIPTOR data stage. It locates:
The starter relies on the fact that a typical USB-headphones device advertises the canonical "Input Terminal -> Feature Unit (id=2) -> Output Terminal" graph, with 48 kHz / 16-bit / stereo PCM and an iso-OUT endpoint at EP address 1. If the attached device deviates, the production path will overwrite these defaults during the descriptor walk.
Definition at line 375 of file ra8_usb_haud.c.
References internal_iso_max_packet(), k_ra8_haud_assigned_address, k_ra8_haud_default_ac_interface, k_ra8_haud_default_as_interface, k_ra8_haud_default_bits, k_ra8_haud_default_channels, k_ra8_haud_default_feature_unit_id, k_ra8_haud_default_iso_in_ep, k_ra8_haud_default_iso_out_ep, k_ra8_haud_default_sample_rate_hz, and s_state.
Referenced by internal_do_get_cfg_desc().
|
nodiscard |
Register (or detach) the attach callback.
The supplied callback fires exactly once per attach event, after the descriptor walk identifies an Audio-Control interface (class=0x01 / subclass=0x01) and at least one Audio-Streaming interface (class=0x01 / subclass=0x02), and the matching isochronous IN / OUT endpoints and Feature Unit are cached. Pass NULL to detach.
| [in] | on_attach | Callback. NULL detaches. |
| [in] | ctx | Context pointer threaded back into on_attach. |
| k_ra8_ok | Callback installed. |
| k_ra8_err_invalid_state | Driver was never initialized. |
Definition at line 719 of file ra8_usb_haud.c.
References k_ra8_err_invalid_state, k_ra8_ok, and s_state.
|
nodiscard |
Tear down the host-Audio driver and release the controller.
| k_ra8_ok | Released. |
| k_ra8_err_invalid_state | Driver was never initialized. |
Definition at line 698 of file ra8_usb_haud.c.
References k_ra8_err_invalid_state, k_ra8_haud_step_idle, ra8_usb_host_deinit(), ra8_usb_host_set_uact(), and s_state.
|
nodiscard |
Bring up the host-Audio driver on a chosen USB controller.
Initialises the underlying ra8_usb driver in HOST mode for speed, leaves the bus in the "wait for attach" state (UACT cleared), and arms the internal enumeration step machine. Delegates to ra8_usb_host_init.
| [in] | speed | Which USB controller (FS or HS). |
| k_ra8_ok | Host-Audio ready, awaiting attach. |
| k_ra8_err_invalid_arg | speed out of range. |
| k_ra8_err_hw_init_failed | Underlying ra8_usb_host_init failed. |
Definition at line 675 of file ra8_usb_haud.c.
References k_ra8_err_hw_init_failed, k_ra8_err_invalid_arg, k_ra8_haud_step_idle, k_ra8_ok, k_ra8_usb_speed_fs, k_ra8_usb_speed_hs, ra8_log_error_val, ra8_log_info_val, ra8_usb_host_init(), s_state, and s_tag.
|
nodiscard |
Drain isochronous-IN samples from a microphone.
Polling / non-blocking. Pulls bytes from the configured PIPE1 (isochronous IN) into buf. Returns k_ra8_err_no_data if the pipe has no bytes ready in this micro-frame.
| [out] | buf | Destination buffer. |
| [in] | max_len_bytes | Capacity of buf, > 0. |
| [out] | got_len_bytes | Receives the number of bytes actually placed. |
| k_ra8_ok | Bytes drained; *got_len_bytes reflects the count. |
| k_ra8_err_no_data | Pipe was empty. |
| k_ra8_err_null_ptr | buf or got_len_bytes was NULL. |
| k_ra8_err_invalid_state | Driver not initialized, no device attached, or device has no iso-IN endpoint. |
| k_ra8_err_invalid_arg | max_len_bytes == 0. |
Definition at line 864 of file ra8_usb_haud.c.
References internal_class_preflight(), k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_haud_pipe_iso_in, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_usb_queue_out(), s_state, and s_tag.
|
nodiscard |
Push isochronous-OUT samples to a speaker / headphones.
Streams buf[0..len_bytes-1] onto the iso-OUT pipe configured for the attached Audio-Streaming interface. PCM byte-order matches the Audio-Streaming format (little-endian per USB Audio Data Formats 1.0 sec 2.2). Non-blocking; bytes that don't fit in the current micro-frame return k_ra8_err_busy for the caller to retry.
| [in] | buf | Sample byte buffer. |
| [in] | len_bytes | Number of bytes in buf. |
| k_ra8_ok | Bytes queued for the next iso-OUT slot. |
| k_ra8_err_null_ptr | buf == NULL and len_bytes != 0. |
| k_ra8_err_invalid_state | Driver not initialized, no device attached, or device has no iso-OUT endpoint. |
| k_ra8_err_invalid_arg | len_bytes == 0. |
| k_ra8_err_busy | iso-OUT pipe busy. |
Definition at line 843 of file ra8_usb_haud.c.
References internal_class_preflight(), k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_err_null_ptr, k_ra8_haud_pipe_iso_out, k_ra8_ok, ra8_usb_queue_in(), and s_state.
|
nodiscard |
Issue SET_CUR on the format-type-I descriptor (USB Audio 1.0 sec 5.2.3 "Class-Specific AS Interface Control Requests").
Builds an 8-byte SETUP packet with bmRequestType = 0x22 (Class | Endpoint | Host-to-Device), bRequest = 0x01 (SET_CUR), and wValue = (SAMPLING_FREQ_CONTROL << 8). The data stage payload is a 3-byte little-endian sample rate (USB Audio 1.0 sec 5.2.3.2.3.1). Channel count and bits-per-sample are validated and recorded into the cached device snapshot, but the wire transfer for those is already implicit in the chosen Audio-Streaming interface alt setting; this entry point just refreshes the iso-EP sampling-rate.
| [in] | channel_count | Channels (1..8). |
| [in] | bits_per_sample | 8..32. |
| [in] | sample_rate_hz | 8000..192000. |
| k_ra8_ok | SETUP queued. |
| k_ra8_err_invalid_state | Driver not initialized, or no device attached. |
| k_ra8_err_invalid_arg | One of channel_count / bits_per_sample / sample_rate_hz is out of range. |
| k_ra8_err_busy | Controller busy with a prior SETUP. |
Definition at line 743 of file ra8_usb_haud.c.
References internal_class_preflight(), internal_format_ok(), k_ra8_err_invalid_arg, k_ra8_haud_bm_class_ep_out, k_ra8_haud_ep_control_sampling_freq, k_ra8_haud_req_set_cur, k_ra8_haud_sample_rate_payload, k_ra8_haud_shift_byte1, k_ra8_ok, ra8_usb_host_setup_request(), and s_state.
|
nodiscard |
Issue SET_CUR on the Feature Unit Mute control (USB Audio 1.0 sec 5.2.2.4.3.1 "Mute Control").
Builds an 8-byte SETUP packet with bmRequestType = 0x21 (Class | Interface | Host-to-Device), bRequest = 0x01 (SET_CUR), and wValue = (MUTE_CONTROL << 8) | channel. wIndex packs the Feature Unit ID in the high byte and the AudioControl interface in the low byte. Mute is a one-byte boolean (0 = unmute, 1 = mute).
| [in] | channel | Logical channel (0 = main, 1..N per channel). |
| [in] | mute | true = mute, false = unmute. |
| k_ra8_ok | SETUP queued. |
| k_ra8_err_invalid_state | Driver not initialized, or no device attached. |
| k_ra8_err_busy | Controller busy with a prior SETUP. |
Definition at line 815 of file ra8_usb_haud.c.
References internal_class_preflight(), k_ra8_haud_bm_class_iface_out, k_ra8_haud_fu_control_mute, k_ra8_haud_mute_payload, k_ra8_haud_req_set_cur, k_ra8_haud_shift_byte1, k_ra8_ok, ra8_usb_host_setup_request(), and s_state.
|
nodiscard |
Issue SET_CUR on the Feature Unit Volume control (USB Audio 1.0 sec 5.2.2.4.3 "Volume Control").
Builds an 8-byte SETUP packet with bmRequestType = 0x21 (Class | Interface | Host-to-Device), bRequest = 0x01 (SET_CUR), and wValue = (VOLUME_CONTROL << 8) | channel. wIndex packs the Feature Unit ID in the high byte and the AudioControl interface in the low byte. Volume is a signed 16-bit value in 1/256 dB steps; 0x8000 is the silence sentinel.
| [in] | channel | Logical channel (0 = main, 1..N per channel). |
| [in] | volume | Signed dB in 1/256 step. |
| k_ra8_ok | SETUP queued. |
| k_ra8_err_invalid_state | Driver not initialized, or no device attached. |
| k_ra8_err_busy | Controller busy with a prior SETUP. |
Definition at line 780 of file ra8_usb_haud.c.
References internal_class_preflight(), k_ra8_haud_bm_class_iface_out, k_ra8_haud_fu_control_volume, k_ra8_haud_req_set_cur, k_ra8_haud_shift_byte1, k_ra8_haud_volume_payload, k_ra8_ok, ra8_usb_host_setup_request(), and s_state.
|
nodiscard |
Drive the enumeration step machine forward by one step.
Test / debug entry point. The production path drives this from the ra8_usb_dispatch callback when the controller fires a CTRT or BRDY interrupt; tests call it directly to walk the state machine deterministically.
| k_ra8_ok | Step advanced. |
| k_ra8_err_invalid_state | Driver not initialized. |
Definition at line 894 of file ra8_usb_haud.c.
References internal_step_advance(), k_ra8_err_invalid_state, and s_state.
|
static |
Definition at line 153 of file ra8_usb_haud.c.
|
static |
Definition at line 46 of file ra8_usb_haud.c.