audio_device: Update explicit feedback support

Feedback can be specified by the user code and will be
sent at feedback endpoint specified interval.
This commit is contained in:
Jerzy Kasenberg 2020-09-14 11:28:05 +02:00
parent 6b52330969
commit 2ace98e943
3 changed files with 68 additions and 18 deletions

View File

@ -121,10 +121,9 @@ typedef struct
#if CFG_TUD_AUDIO_EPSIZE_OUT
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_AUDIO_EPSIZE_OUT]; // Bigger makes no sense for isochronous EP's (but technically possible here)
// TODO: required?
//#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
// uint16_t fb_val; // Feedback value for asynchronous mode!
//#endif
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
uint32_t fb_val; // Feedback value for asynchronous mode (in 16.16 format).
#endif
#endif
@ -643,18 +642,51 @@ static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t*
// This function is called once a transmit of an feedback packet was successfully completed. Here, we get the next feedback value to be sent
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
static uint16_t audio_fb_done_cb(uint8_t rhport, audiod_interface_t* audio)
static bool audio_fb_send(uint8_t rhport, audiod_interface_t *audio)
{
(void) rhport;
(void) audio;
uint8_t fb[4];
uint16_t len;
// Here we need to return the feedback value
#error RETURN YOUR FEEDBACK VALUE HERE!
if (audio->fb_val == 0)
{
len = 0;
return true;
}
else
{
len = 4;
// Here we need to return the feedback value
if (rhport == 0)
{
// For FS format is 10.14
fb[0] = (audio->fb_val >> 2) & 0xFF;
fb[1] = (audio->fb_val >> 10) & 0xFF;
fb[2] = (audio->fb_val >> 18) & 0xFF;
// 4th byte is needed to work correctly with MS Windows
fb[3] = 0;
}
else
{
// For HS format is 16.16
fb[0] = (audio->fb_val >> 0) & 0xFF;
fb[1] = (audio->fb_val >> 8) & 0xFF;
fb[2] = (audio->fb_val >> 16) & 0xFF;
fb[3] = (audio->fb_val >> 24) & 0xFF;
}
return usbd_edpt_xfer(rhport, audio->ep_fb, fb, len);
}
if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport));
return 0;
}
//static uint16_t audio_fb_done_cb(uint8_t rhport, audiod_interface_t* audio)
//{
// (void) rhport;
// (void) audio;
//
// if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport));
// return 0;
//}
#endif
// This function is called once a transmit of an interrupt control packet was successfully completed. Here, we get the remaining bytes to send
@ -918,7 +950,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
}
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && ((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.usage == 0x10) // Check if usage is implicit data feedback
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && ((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.usage == 1) // Check if usage is explicit data feedback
{
_audiod_itf[idxDriver].ep_fb = ep_addr;
@ -1215,13 +1247,9 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
// Transmission of feedback EP finished
if (_audiod_itf[idxDriver].ep_fb == ep_addr)
{
if (!audio_fb_done_cb(rhport, &_audiod_itf[idxDriver]))
{
// Load with ZLP
return usbd_edpt_xfer(rhport, ep_addr, NULL, 0);
}
if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport));
return true;
return audio_fb_send(rhport, &_audiod_itf[idxDriver]);
}
#endif
#endif
@ -1403,4 +1431,16 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *idxDriver)
return false;
}
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
bool tud_audio_fb_set(uint8_t rhport, uint32_t feedback)
{
audiod_interface_t *audio = &_audiod_itf[0];
audio->fb_val = feedback;
TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_fb), true);
return audio_fb_send(rhport, audio);
}
#endif
#endif //TUSB_OPT_DEVICE_ENABLED && CFG_TUD_AUDIO

View File

@ -259,6 +259,11 @@ TU_ATTR_WEAK bool tud_audio_rx_done_cb(uint8_t rhport, uint8_t * buffer, uint16_
#if CFG_TUD_AUDIO_EPSIZE_OUT > 0 && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
TU_ATTR_WEAK bool tud_audio_fb_done_cb(uint8_t rhport);
// User code should call this function with feedback value in 16.16 format for FS and HS.
// Value will be corrected for FS to 10.14 format automatically.
// (see Universal Serial Bus Specification Revision 2.0 5.12.4.2).
// Feedback value will be sent at FB endpoint interval till it's changed.
bool tud_audio_fb_set(uint8_t rhport, uint32_t feedback);
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN

View File

@ -377,6 +377,11 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
#define TUD_AUDIO_DESC_CS_AS_ISO_EP(_attr, _ctrl, _lockdelayunit, _lockdelay) \
TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN, TUSB_DESC_CS_ENDPOINT, AUDIO_CS_EP_SUBTYPE_GENERAL, _attr, _ctrl, _lockdelayunit, U16_TO_U8S_LE(_lockdelay)
/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */
#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN 7
#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _interval) \
TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval
// AUDIO simple descriptor (UAC2) for 1 microphone input
// - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source