119 lines
3.2 KiB
C++
119 lines
3.2 KiB
C++
#include "usb_composite.h"
|
|
#include "audio/audio_pipeline.h"
|
|
#include <Arduino.h>
|
|
#include "USB.h"
|
|
#include "USBHIDKeyboard.h"
|
|
#include "USBHIDConsumerControl.h"
|
|
|
|
static USBHIDKeyboard s_keyboard;
|
|
static USBHIDConsumerControl s_consumer;
|
|
static bool s_usb_ready = false;
|
|
|
|
extern "C" {
|
|
|
|
void usb_composite_init(void) {
|
|
USB.productName("RemoteMapper Wireless Mic & Controller");
|
|
USB.manufacturerName("RemoteMapper");
|
|
USB.serialNumber("RM-ESP32S3-001");
|
|
|
|
s_keyboard.begin();
|
|
s_consumer.begin();
|
|
USB.begin();
|
|
s_usb_ready = true;
|
|
}
|
|
|
|
void usb_composite_task(void) {
|
|
// Handled by native ESP32-S3 USB stack
|
|
usb_audio_task();
|
|
}
|
|
|
|
bool usb_hid_keyboard_press(uint8_t modifier, uint8_t keycode) {
|
|
if (!s_usb_ready) return false;
|
|
KeyReport report = {0};
|
|
report.modifiers = modifier;
|
|
report.keys[0] = keycode;
|
|
s_keyboard.sendReport(&report);
|
|
return true;
|
|
}
|
|
|
|
bool usb_hid_keyboard_release(void) {
|
|
if (!s_usb_ready) return false;
|
|
s_keyboard.releaseAll();
|
|
return true;
|
|
}
|
|
|
|
bool usb_hid_keyboard_tap(uint8_t modifier, uint8_t keycode) {
|
|
if (!s_usb_ready) return false;
|
|
usb_hid_keyboard_press(modifier, keycode);
|
|
delay(12);
|
|
usb_hid_keyboard_release();
|
|
return true;
|
|
}
|
|
|
|
bool usb_hid_consumer_press(uint16_t usage_code) {
|
|
if (!s_usb_ready) return false;
|
|
s_consumer.press(usage_code);
|
|
return true;
|
|
}
|
|
|
|
bool usb_hid_consumer_release(void) {
|
|
if (!s_usb_ready) return false;
|
|
s_consumer.release();
|
|
return true;
|
|
}
|
|
|
|
bool usb_hid_consumer_tap(uint16_t usage_code) {
|
|
if (!s_usb_ready) return false;
|
|
s_consumer.press(usage_code);
|
|
delay(10);
|
|
s_consumer.release();
|
|
return true;
|
|
}
|
|
|
|
void usb_hid_dispatch_action(const key_action_t *action) {
|
|
if (!action) return;
|
|
|
|
switch (action->type) {
|
|
case ACTION_KEYBOARD_TAP:
|
|
usb_hid_keyboard_tap(action->modifier, action->key_code);
|
|
break;
|
|
case ACTION_KEYBOARD_HOLD:
|
|
usb_hid_keyboard_press(action->modifier, action->key_code);
|
|
break;
|
|
case ACTION_KEYBOARD_RELEASE:
|
|
usb_hid_keyboard_release();
|
|
break;
|
|
case ACTION_CONSUMER_TAP:
|
|
usb_hid_consumer_tap(action->consumer_code);
|
|
break;
|
|
case ACTION_CONSUMER_HOLD:
|
|
usb_hid_consumer_press(action->consumer_code);
|
|
break;
|
|
case ACTION_CONSUMER_RELEASE:
|
|
usb_hid_consumer_release();
|
|
break;
|
|
case ACTION_VOICE_HOLD:
|
|
// Hold Voice Hotkey (Default RAlt + Comma) and start audio session
|
|
audio_pipeline_start_session(&g_audio_pipeline, 0);
|
|
usb_hid_keyboard_press(DEFAULT_VOICE_MODIFIER, DEFAULT_VOICE_KEY);
|
|
break;
|
|
case ACTION_VOICE_RELEASE:
|
|
// Release Voice Hotkey and stop audio session
|
|
usb_hid_keyboard_release();
|
|
audio_pipeline_stop_session(&g_audio_pipeline);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void usb_audio_task(void) {
|
|
if (!g_audio_pipeline.active) return;
|
|
|
|
// In Isochronous mode, pull 16 samples (1ms @ 16kHz) from ring buffer
|
|
int16_t usb_frame_samples[16];
|
|
audio_pipeline_read_for_usb(&g_audio_pipeline, usb_frame_samples, 16);
|
|
}
|
|
|
|
} // extern "C"
|