// // Created by awalol on 2026/3/4. // #include "tusb.h" #include "bsp/board_api.h" uint8_t mute[2]; // 0: SPEAKER(0x02) 1: MIC(0x05) float volume[2] = {1.0f}; // 0: SPEAKER(0x02) 1: MIC(0x05) #define UAC1_ENTITY_SPK_FEATURE_UNIT 0x02 #define UAC1_ENTITY_MIC_FEATURE_UNIT 0x05 /*int main() { board_init(); tusb_rhport_init_t dev_init = { .role = TUSB_ROLE_DEVICE, .speed = TUSB_SPEED_AUTO }; tusb_init(BOARD_TUD_RHPORT, &dev_init); board_init_after_tusb(); while (1) { tud_task(); } }*/ //--------------------------------------------------------------------+ // Audio Callback Functions //--------------------------------------------------------------------+ //--------------------------------------------------------------------+ // UAC1 Helper Functions //--------------------------------------------------------------------+ static bool audio10_set_req_entity(tusb_control_request_t const *p_request, uint8_t *pBuff) { uint8_t channelNum = TU_U16_LOW(p_request->wValue); uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); uint8_t entityID = TU_U16_HIGH(p_request->wIndex); uint8_t index = entityID == UAC1_ENTITY_SPK_FEATURE_UNIT ? 0 : 1; // If request is for our speaker feature unit if (entityID == UAC1_ENTITY_SPK_FEATURE_UNIT || entityID == UAC1_ENTITY_MIC_FEATURE_UNIT) { switch (ctrlSel) { case AUDIO10_FU_CTRL_MUTE: switch (p_request->bRequest) { case AUDIO10_CS_REQ_SET_CUR: // Only 1st form is supported TU_VERIFY(p_request->wLength == 1); mute[index] = pBuff[0]; TU_LOG2(" Set Mute: %d of entity: %u\r\n", mute[index], entityID); return true; default: return false; // not supported } case AUDIO10_FU_CTRL_VOLUME: switch (p_request->bRequest) { case AUDIO10_CS_REQ_SET_CUR: // Only 1st form is supported TU_VERIFY(p_request->wLength == 2); volume[index] = static_cast(tu_unaligned_read16(pBuff)) / 256; TU_LOG2(" Set Volume: %d dB of entity: %u\r\n", volume[index], entityID); return true; default: return false; // not supported } // Unknown/Unsupported control default: TU_BREAKPOINT(); return false; } } return false; } static bool audio10_get_req_entity(uint8_t rhport, tusb_control_request_t const *p_request) { uint8_t channelNum = TU_U16_LOW(p_request->wValue); uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); uint8_t entityID = TU_U16_HIGH(p_request->wIndex); uint8_t index = entityID == UAC1_ENTITY_SPK_FEATURE_UNIT ? 0 : 1; // If request is for our speaker feature unit if (entityID == UAC1_ENTITY_SPK_FEATURE_UNIT || entityID == UAC1_ENTITY_MIC_FEATURE_UNIT) { switch (ctrlSel) { case AUDIO10_FU_CTRL_MUTE: // Audio control mute cur parameter block consists of only one byte - we thus can send it right away // There does not exist a range parameter block for mute TU_LOG2(" Get Mute of entity: %u\r\n", entityID); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &mute[index], 1); case AUDIO10_FU_CTRL_VOLUME: switch (p_request->bRequest) { case AUDIO10_CS_REQ_GET_CUR: TU_LOG2(" Get Volume of entity: %u\r\n", entityID); { int16_t vol = volume[index]; vol = vol * 256; // convert to 1/256 dB units return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &vol, sizeof(vol)); } case AUDIO10_CS_REQ_GET_MIN: TU_LOG2(" Get Volume min of entity: %u\r\n", entityID); { int16_t min = 1; // 1 dB min = min * 256; // convert to 1/256 dB units return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &min, sizeof(min)); } case AUDIO10_CS_REQ_GET_MAX: TU_LOG2(" Get Volume max of entity: %u\r\n", entityID); { int16_t max = 2; // 2 dB max = max * 256; // convert to 1/256 dB units return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &max, sizeof(max)); } case AUDIO10_CS_REQ_GET_RES: TU_LOG2(" Get Volume res of entity: %u\r\n", entityID); { int16_t res = 0.1 * 256; // 0.1 dB return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &res, sizeof(res)); } // Unknown/Unsupported control default: TU_BREAKPOINT(); return false; } break; // Unknown/Unsupported control default: TU_BREAKPOINT(); return false; } } return false; } // Invoked when audio class specific get request received for an entity bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { (void) rhport; return audio10_get_req_entity(rhport, p_request); } // Invoked when audio class specific set request received for an entity bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *buf) { (void) rhport; return audio10_set_req_entity(p_request, buf); } void tud_hid_report_complete_cb(uint8_t instance, uint8_t const *report, uint16_t len) { (void) instance; (void) len; }