It's connecting!!
This commit is contained in:
parent
bb5e51330a
commit
2225e70e5e
7 changed files with 322 additions and 45 deletions
|
|
@ -23,6 +23,7 @@ if (EXISTS ${picoVscode})
|
||||||
include(${picoVscode})
|
include(${picoVscode})
|
||||||
endif()
|
endif()
|
||||||
# ====================================================================================
|
# ====================================================================================
|
||||||
|
option(SWITCH_PICO_AUTOTEST "Auto-play grip-screen connection sequence on startup" OFF)
|
||||||
set(PICO_BOARD pico CACHE STRING "Board type")
|
set(PICO_BOARD pico CACHE STRING "Board type")
|
||||||
|
|
||||||
# Pull in Raspberry Pi Pico SDK (must be before project)
|
# Pull in Raspberry Pi Pico SDK (must be before project)
|
||||||
|
|
@ -44,7 +45,8 @@ pico_set_program_name(switch-pico "switch-pico")
|
||||||
pico_set_program_version(switch-pico "0.1")
|
pico_set_program_version(switch-pico "0.1")
|
||||||
|
|
||||||
# Modify the below lines to enable/disable output over UART/USB
|
# Modify the below lines to enable/disable output over UART/USB
|
||||||
pico_enable_stdio_uart(switch-pico 0)
|
# UART0 is enabled for debug logging; USB stdio remains off.
|
||||||
|
pico_enable_stdio_uart(switch-pico 1)
|
||||||
pico_enable_stdio_usb(switch-pico 0)
|
pico_enable_stdio_usb(switch-pico 0)
|
||||||
|
|
||||||
# Add the standard library to the build
|
# Add the standard library to the build
|
||||||
|
|
@ -56,6 +58,10 @@ target_link_libraries(switch-pico
|
||||||
pico_rand
|
pico_rand
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (SWITCH_PICO_AUTOTEST)
|
||||||
|
target_compile_definitions(switch-pico PRIVATE SWITCH_PICO_AUTOTEST=1)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Add the standard include files to the build
|
# Add the standard include files to the build
|
||||||
target_include_directories(switch-pico PRIVATE
|
target_include_directories(switch-pico PRIVATE
|
||||||
${CMAKE_CURRENT_LIST_DIR}
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
|
|
|
||||||
33
host_uart_logger.py
Normal file
33
host_uart_logger.py
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import argparse
|
||||||
|
import datetime
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
import serial
|
||||||
|
except ImportError:
|
||||||
|
print("pyserial not installed. Install with: pip install pyserial", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Read debug logs from Pico UART")
|
||||||
|
parser.add_argument("-p", "--port", required=True, help="Serial port (e.g. /dev/ttyUSB0 or COM3)")
|
||||||
|
parser.add_argument("-b", "--baud", type=int, default=115200, help="Baud rate (default: 115200)")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
with serial.Serial(args.port, args.baud, timeout=1) as ser:
|
||||||
|
print(f"Opened {args.port} @ {args.baud}")
|
||||||
|
while True:
|
||||||
|
line = ser.readline()
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
ts = datetime.datetime.now().strftime("%H:%M:%S.%f")[:-3]
|
||||||
|
try:
|
||||||
|
text = line.decode(errors="replace").rstrip()
|
||||||
|
except Exception:
|
||||||
|
text = repr(line)
|
||||||
|
print(f"{ts} | {text}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
126
switch-pico.cpp
126
switch-pico.cpp
|
|
@ -11,6 +11,20 @@
|
||||||
#define UART_TX_PIN 4
|
#define UART_TX_PIN 4
|
||||||
#define UART_RX_PIN 5
|
#define UART_RX_PIN 5
|
||||||
|
|
||||||
|
static bool g_last_mounted = false;
|
||||||
|
static bool g_last_ready = false;
|
||||||
|
|
||||||
|
// Track the latest state provided by UART or the autopilot.
|
||||||
|
static SwitchInputState g_user_state;
|
||||||
|
|
||||||
|
#ifdef SWITCH_PICO_AUTOTEST
|
||||||
|
static bool g_autopilot_active = true;
|
||||||
|
static uint32_t g_autopilot_counter = 0;
|
||||||
|
static absolute_time_t g_autopilot_last_tick = {0};
|
||||||
|
static bool g_uart_activity = false;
|
||||||
|
static bool g_ready_logged = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
static void init_uart_input() {
|
static void init_uart_input() {
|
||||||
uart_init(UART_ID, BAUD_RATE);
|
uart_init(UART_ID, BAUD_RATE);
|
||||||
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
|
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
|
||||||
|
|
@ -52,12 +66,104 @@ static void poll_uart_frames() {
|
||||||
|
|
||||||
buffer[index++] = byte;
|
buffer[index++] = byte;
|
||||||
if (index >= sizeof(buffer)) {
|
if (index >= sizeof(buffer)) {
|
||||||
switch_pro_apply_uart_packet(buffer, sizeof(buffer));
|
SwitchInputState parsed{};
|
||||||
|
if (switch_pro_apply_uart_packet(buffer, sizeof(buffer), &parsed)) {
|
||||||
|
g_user_state = parsed;
|
||||||
|
printf("[UART] packet buttons=0x%04x hat=%u lx=%u ly=%u rx=%u ry=%u\n",
|
||||||
|
(parsed.button_a ? SWITCH_PRO_MASK_A : 0) |
|
||||||
|
(parsed.button_b ? SWITCH_PRO_MASK_B : 0) |
|
||||||
|
(parsed.button_x ? SWITCH_PRO_MASK_X : 0) |
|
||||||
|
(parsed.button_y ? SWITCH_PRO_MASK_Y : 0) |
|
||||||
|
(parsed.button_l ? SWITCH_PRO_MASK_L : 0) |
|
||||||
|
(parsed.button_r ? SWITCH_PRO_MASK_R : 0) |
|
||||||
|
(parsed.button_zl ? SWITCH_PRO_MASK_ZL : 0) |
|
||||||
|
(parsed.button_zr ? SWITCH_PRO_MASK_ZR : 0) |
|
||||||
|
(parsed.button_plus? SWITCH_PRO_MASK_PLUS: 0) |
|
||||||
|
(parsed.button_minus?SWITCH_PRO_MASK_MINUS:0) |
|
||||||
|
(parsed.button_home?SWITCH_PRO_MASK_HOME:0) |
|
||||||
|
(parsed.button_capture?SWITCH_PRO_MASK_CAPTURE:0) |
|
||||||
|
(parsed.button_l3 ? SWITCH_PRO_MASK_L3 : 0) |
|
||||||
|
(parsed.button_r3 ? SWITCH_PRO_MASK_R3 : 0),
|
||||||
|
parsed.dpad_up ? SWITCH_PRO_HAT_UP :
|
||||||
|
parsed.dpad_down ? SWITCH_PRO_HAT_DOWN :
|
||||||
|
parsed.dpad_left ? SWITCH_PRO_HAT_LEFT :
|
||||||
|
parsed.dpad_right ? SWITCH_PRO_HAT_RIGHT : SWITCH_PRO_HAT_NOTHING,
|
||||||
|
parsed.lx >> 8, parsed.ly >> 8, parsed.rx >> 8, parsed.ry >> 8);
|
||||||
|
}
|
||||||
|
#ifdef SWITCH_PICO_AUTOTEST
|
||||||
|
g_uart_activity = true;
|
||||||
|
#endif
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SWITCH_PICO_AUTOTEST
|
||||||
|
// Replays the Switch-Fightstick grip-screen sequence: press L+R twice, then A twice.
|
||||||
|
static SwitchInputState autopilot_state(const SwitchInputState& fallback) {
|
||||||
|
if (!g_autopilot_active || g_uart_activity) {
|
||||||
|
g_autopilot_active = false;
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tud_mounted()) {
|
||||||
|
g_autopilot_counter = 0;
|
||||||
|
g_autopilot_last_tick = {0};
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
absolute_time_t now = get_absolute_time();
|
||||||
|
if (!to_us_since_boot(g_autopilot_last_tick)) {
|
||||||
|
g_autopilot_last_tick = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run at ~1ms cadence similar to the LUFA fightstick timing.
|
||||||
|
if (absolute_time_diff_us(g_autopilot_last_tick, now) < 1000) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
g_autopilot_last_tick = now;
|
||||||
|
|
||||||
|
SwitchInputState state = fallback;
|
||||||
|
state.lx = SWITCH_PRO_JOYSTICK_MID;
|
||||||
|
state.ly = SWITCH_PRO_JOYSTICK_MID;
|
||||||
|
state.rx = SWITCH_PRO_JOYSTICK_MID;
|
||||||
|
state.ry = SWITCH_PRO_JOYSTICK_MID;
|
||||||
|
|
||||||
|
// Fire L+R twice then A twice, loop every ~300ms to keep trying.
|
||||||
|
uint32_t step = g_autopilot_counter % 300;
|
||||||
|
if (step == 25 || step == 50) {
|
||||||
|
state.button_l = true;
|
||||||
|
state.button_r = true;
|
||||||
|
} else if (step == 75 || step == 100) {
|
||||||
|
state.button_a = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_autopilot_counter++;
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void log_usb_state() {
|
||||||
|
bool mounted = tud_mounted();
|
||||||
|
bool ready = switch_pro_is_ready();
|
||||||
|
|
||||||
|
if (mounted != g_last_mounted) {
|
||||||
|
g_last_mounted = mounted;
|
||||||
|
printf("[USB] %s\n", mounted ? "mounted" : "unmounted");
|
||||||
|
}
|
||||||
|
if (ready != g_last_ready) {
|
||||||
|
g_last_ready = ready;
|
||||||
|
printf("[SWITCH] driver %s\n", ready ? "ready (handshake OK)" : "not ready");
|
||||||
|
}
|
||||||
|
#ifdef SWITCH_PICO_AUTOTEST
|
||||||
|
if (ready && !g_ready_logged) {
|
||||||
|
g_ready_logged = true;
|
||||||
|
printf("[AUTO] ready -> autopilot active=%s\n", g_autopilot_active ? "true" : "false");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
board_init();
|
board_init();
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
|
|
@ -66,11 +172,27 @@ int main() {
|
||||||
|
|
||||||
tusb_init();
|
tusb_init();
|
||||||
switch_pro_init();
|
switch_pro_init();
|
||||||
switch_pro_set_input(neutral_input());
|
g_user_state = neutral_input();
|
||||||
|
switch_pro_set_input(g_user_state);
|
||||||
|
|
||||||
|
printf("[BOOT] switch-pico starting (UART0 log @ 115200)\n");
|
||||||
|
printf("[INFO] AUTOTEST=%s UART1 pins TX=%d RX=%d baud=%d\n",
|
||||||
|
#ifdef SWITCH_PICO_AUTOTEST
|
||||||
|
"ON"
|
||||||
|
#else
|
||||||
|
"OFF"
|
||||||
|
#endif
|
||||||
|
, UART_TX_PIN, UART_RX_PIN, BAUD_RATE);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
tud_task(); // USB device tasks
|
tud_task(); // USB device tasks
|
||||||
poll_uart_frames(); // Pull controller state from UART1
|
poll_uart_frames(); // Pull controller state from UART1
|
||||||
|
SwitchInputState state = g_user_state;
|
||||||
|
#ifdef SWITCH_PICO_AUTOTEST
|
||||||
|
state = autopilot_state(state);
|
||||||
|
#endif
|
||||||
|
switch_pro_set_input(state);
|
||||||
switch_pro_task(); // Push state to the Switch host
|
switch_pro_task(); // Push state to the Switch host
|
||||||
|
log_usb_state();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -322,8 +322,10 @@ typedef struct
|
||||||
} SwitchProOutReport;
|
} SwitchProOutReport;
|
||||||
|
|
||||||
static const uint8_t switch_pro_string_language[] = { 0x09, 0x04 };
|
static const uint8_t switch_pro_string_language[] = { 0x09, 0x04 };
|
||||||
static const uint8_t switch_pro_string_manufacturer[] = "Open Stick Community";
|
static const uint8_t switch_pro_string_manufacturer[] = "Nintendo Co., Ltd.";
|
||||||
static const uint8_t switch_pro_string_product[] = "GP2040-CE (Pro Controller)";
|
static const uint8_t switch_pro_string_product[] = "Pro Controller";
|
||||||
|
// static const uint8_t switch_pro_string_manufacturer[] = "Open Stick Community";
|
||||||
|
// static const uint8_t switch_pro_string_product[] = "GP2040-CE (Pro Controller)";
|
||||||
static const uint8_t switch_pro_string_version[] = "000000000001";
|
static const uint8_t switch_pro_string_version[] = "000000000001";
|
||||||
|
|
||||||
static const uint8_t *switch_pro_string_descriptors[] __attribute__((unused)) =
|
static const uint8_t *switch_pro_string_descriptors[] __attribute__((unused)) =
|
||||||
|
|
@ -340,8 +342,8 @@ static const uint8_t switch_pro_device_descriptor[] =
|
||||||
0x01, // bDescriptorType (Device)
|
0x01, // bDescriptorType (Device)
|
||||||
0x00, 0x02, // bcdUSB 2.00
|
0x00, 0x02, // bcdUSB 2.00
|
||||||
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
|
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
|
||||||
0x00, // bDeviceSubClass
|
0x00, // bDeviceSubClass
|
||||||
0x00, // bDeviceProtocol
|
0x00, // bDeviceProtocol
|
||||||
0x40, // bMaxPacketSize0 64
|
0x40, // bMaxPacketSize0 64
|
||||||
0x7E, 0x05, // idVendor 0x057E
|
0x7E, 0x05, // idVendor 0x057E
|
||||||
0x09, 0x20, // idProduct 0x2009
|
0x09, 0x20, // idProduct 0x2009
|
||||||
|
|
@ -394,7 +396,7 @@ static const uint8_t switch_pro_configuration_descriptor[] =
|
||||||
|
|
||||||
0x07, // bLength
|
0x07, // bLength
|
||||||
0x05, // bDescriptorType (Endpoint)
|
0x05, // bDescriptorType (Endpoint)
|
||||||
0x05, // bEndpointAddress (IN/D2H)
|
0x81, // bEndpointAddress (IN/D2H)
|
||||||
0x03, // bmAttributes (Interrupt)
|
0x03, // bmAttributes (Interrupt)
|
||||||
0x40, 0x00, // wMaxPacketSize 64
|
0x40, 0x00, // wMaxPacketSize 64
|
||||||
0x08, // bInterval 8 (unit depends on device speed)
|
0x08, // bInterval 8 (unit depends on device speed)
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,14 @@ static uint8_t last_report[SWITCH_PRO_ENDPOINT_SIZE] = {};
|
||||||
static SwitchProReport switch_report{};
|
static SwitchProReport switch_report{};
|
||||||
static uint8_t last_report_counter = 0;
|
static uint8_t last_report_counter = 0;
|
||||||
static uint32_t last_report_timer = 0;
|
static uint32_t last_report_timer = 0;
|
||||||
|
static uint32_t last_host_activity_ms = 0;
|
||||||
static bool is_ready = false;
|
static bool is_ready = false;
|
||||||
static bool is_initialized = false;
|
static bool is_initialized = false;
|
||||||
static bool is_report_queued = false;
|
static bool is_report_queued = false;
|
||||||
static bool report_sent = false;
|
static bool report_sent = false;
|
||||||
static uint8_t queued_report_id = 0;
|
static uint8_t queued_report_id = 0;
|
||||||
|
static bool forced_ready = false;
|
||||||
|
static bool host_sent_out = false;
|
||||||
static uint8_t handshake_counter = 0;
|
static uint8_t handshake_counter = 0;
|
||||||
|
|
||||||
static SwitchDeviceInfo device_info{};
|
static SwitchDeviceInfo device_info{};
|
||||||
|
|
@ -47,31 +50,31 @@ static const uint8_t factory_config_data[0xEFF] = {
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
|
||||||
0xFF, 0xFF,
|
0xFF, 0xFF,
|
||||||
|
|
||||||
// device type
|
// device type
|
||||||
SWITCH_TYPE_PRO_CONTROLLER,
|
SWITCH_TYPE_PRO_CONTROLLER,
|
||||||
|
|
||||||
// unknown
|
// unknown
|
||||||
0xA0,
|
0xA0,
|
||||||
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
|
||||||
// color options
|
// color options
|
||||||
0x02,
|
0x02,
|
||||||
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF,
|
0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
|
||||||
// config & calibration 1
|
// config & calibration 1
|
||||||
0xE3, 0xFF, 0x39, 0xFF, 0xED, 0x01, 0x00, 0x40,
|
0xE3, 0xFF, 0x39, 0xFF, 0xED, 0x01, 0x00, 0x40,
|
||||||
0x00, 0x40, 0x00, 0x40, 0x09, 0x00, 0xEA, 0xFF,
|
0x00, 0x40, 0x00, 0x40, 0x09, 0x00, 0xEA, 0xFF,
|
||||||
0xA1, 0xFF, 0x3B, 0x34, 0x3B, 0x34, 0x3B, 0x34,
|
0xA1, 0xFF, 0x3B, 0x34, 0x3B, 0x34, 0x3B, 0x34,
|
||||||
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
|
||||||
// config & calibration 2
|
// config & calibration 2
|
||||||
// left stick
|
// left stick
|
||||||
0xa4, 0x46, 0x6a, 0x00, 0x08, 0x80, 0xa4, 0x46,
|
0xa4, 0x46, 0x6a, 0x00, 0x08, 0x80, 0xa4, 0x46,
|
||||||
0x6a,
|
0x6a,
|
||||||
|
|
||||||
// right stick
|
// right stick
|
||||||
|
|
@ -92,32 +95,32 @@ static const uint8_t factory_config_data[0xEFF] = {
|
||||||
// right grip color
|
// right grip color
|
||||||
0xEC, 0x00, 0x8C,
|
0xEC, 0x00, 0x8C,
|
||||||
|
|
||||||
0x01,
|
0x01,
|
||||||
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
0xFF, 0xFF, 0xFF,
|
0xFF, 0xFF, 0xFF,
|
||||||
|
|
||||||
0x50, 0xFD, 0x00, 0x00, 0xC6, 0x0F,
|
0x50, 0xFD, 0x00, 0x00, 0xC6, 0x0F,
|
||||||
0x0F, 0x30, 0x61, 0xAE, 0x90, 0xD9, 0xD4, 0x14,
|
0x0F, 0x30, 0x61, 0xAE, 0x90, 0xD9, 0xD4, 0x14,
|
||||||
0x54, 0x41, 0x15, 0x54, 0xC7, 0x79, 0x9C, 0x33,
|
0x54, 0x41, 0x15, 0x54, 0xC7, 0x79, 0x9C, 0x33,
|
||||||
0x36, 0x63,
|
0x36, 0x63,
|
||||||
|
|
||||||
0x0F, 0x30, 0x61, 0xAE, 0x90, 0xD9, 0xD4, 0x14,
|
0x0F, 0x30, 0x61, 0xAE, 0x90, 0xD9, 0xD4, 0x14,
|
||||||
0x54, 0x41, 0x15, 0x54,
|
0x54, 0x41, 0x15, 0x54,
|
||||||
|
|
||||||
0xC7,
|
0xC7,
|
||||||
|
|
||||||
0x79,
|
0x79,
|
||||||
|
|
||||||
0x9C,
|
0x9C,
|
||||||
|
|
||||||
|
0x33,
|
||||||
|
|
||||||
|
0x36,
|
||||||
|
|
||||||
0x33,
|
|
||||||
|
|
||||||
0x36,
|
|
||||||
|
|
||||||
0x63, 0xFF, 0xFF, 0xFF,
|
0x63, 0xFF, 0xFF, 0xFF,
|
||||||
0xFF, 0xFF, 0xFF
|
0xFF, 0xFF, 0xFF
|
||||||
};
|
};
|
||||||
|
|
@ -125,9 +128,9 @@ static const uint8_t factory_config_data[0xEFF] = {
|
||||||
static const uint8_t user_calibration_data[0x3F] = {
|
static const uint8_t user_calibration_data[0x3F] = {
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
|
||||||
// Left Stick
|
// Left Stick
|
||||||
0xB2, 0xA1, 0xa4, 0x46, 0x6a, 0x00, 0x08, 0x80,
|
0xB2, 0xA1, 0xa4, 0x46, 0x6a, 0x00, 0x08, 0x80,
|
||||||
0xa4, 0x46, 0x6a,
|
0xa4, 0x46, 0x6a,
|
||||||
|
|
||||||
// Right Stick
|
// Right Stick
|
||||||
|
|
@ -176,6 +179,9 @@ static bool send_report(uint8_t reportID, const void* reportData, uint16_t repor
|
||||||
} else {
|
} else {
|
||||||
last_report_counter = 0;
|
last_report_counter = 0;
|
||||||
}
|
}
|
||||||
|
if (!result) {
|
||||||
|
printf("[HID] send_report failed id=%u len=%u\n", reportID, reportLength);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,21 +200,26 @@ static void read_spi_flash(uint8_t* dest, uint32_t address, uint8_t size) {
|
||||||
|
|
||||||
static void handle_config_report(uint8_t switchReportID, uint8_t switchReportSubID, const uint8_t *reportData, uint16_t reportLength) {
|
static void handle_config_report(uint8_t switchReportID, uint8_t switchReportSubID, const uint8_t *reportData, uint16_t reportLength) {
|
||||||
bool canSend = false;
|
bool canSend = false;
|
||||||
|
last_host_activity_ms = to_ms_since_boot(get_absolute_time());
|
||||||
|
host_sent_out = true;
|
||||||
|
|
||||||
switch (switchReportSubID) {
|
switch (switchReportSubID) {
|
||||||
case IDENTIFY:
|
case IDENTIFY:
|
||||||
send_identify();
|
send_identify();
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] CONFIG IDENTIFY\n");
|
||||||
break;
|
break;
|
||||||
case HANDSHAKE:
|
case HANDSHAKE:
|
||||||
report_buffer[0] = REPORT_USB_INPUT_81;
|
report_buffer[0] = REPORT_USB_INPUT_81;
|
||||||
report_buffer[1] = HANDSHAKE;
|
report_buffer[1] = HANDSHAKE;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] CONFIG HANDSHAKE\n");
|
||||||
break;
|
break;
|
||||||
case BAUD_RATE:
|
case BAUD_RATE:
|
||||||
report_buffer[0] = REPORT_USB_INPUT_81;
|
report_buffer[0] = REPORT_USB_INPUT_81;
|
||||||
report_buffer[1] = BAUD_RATE;
|
report_buffer[1] = BAUD_RATE;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] CONFIG BAUD_RATE\n");
|
||||||
break;
|
break;
|
||||||
case DISABLE_USB_TIMEOUT:
|
case DISABLE_USB_TIMEOUT:
|
||||||
report_buffer[0] = REPORT_OUTPUT_30;
|
report_buffer[0] = REPORT_OUTPUT_30;
|
||||||
|
|
@ -219,16 +230,19 @@ static void handle_config_report(uint8_t switchReportID, uint8_t switchReportSub
|
||||||
is_ready = true;
|
is_ready = true;
|
||||||
//}
|
//}
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] CONFIG DISABLE_USB_TIMEOUT -> ready\n");
|
||||||
break;
|
break;
|
||||||
case ENABLE_USB_TIMEOUT:
|
case ENABLE_USB_TIMEOUT:
|
||||||
report_buffer[0] = REPORT_OUTPUT_30;
|
report_buffer[0] = REPORT_OUTPUT_30;
|
||||||
report_buffer[1] = switchReportSubID;
|
report_buffer[1] = switchReportSubID;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] CONFIG ENABLE_USB_TIMEOUT\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
report_buffer[0] = REPORT_OUTPUT_30;
|
report_buffer[0] = REPORT_OUTPUT_30;
|
||||||
report_buffer[1] = switchReportSubID;
|
report_buffer[1] = switchReportSubID;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] CONFIG unknown subid=0x%02x\n", switchReportSubID);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -240,6 +254,8 @@ static void handle_feature_report(uint8_t switchReportID, uint8_t switchReportSu
|
||||||
uint32_t spiReadAddress = 0;
|
uint32_t spiReadAddress = 0;
|
||||||
uint8_t spiReadSize = 0;
|
uint8_t spiReadSize = 0;
|
||||||
bool canSend = false;
|
bool canSend = false;
|
||||||
|
last_host_activity_ms = to_ms_since_boot(get_absolute_time());
|
||||||
|
host_sent_out = true;
|
||||||
|
|
||||||
report_buffer[0] = REPORT_OUTPUT_21;
|
report_buffer[0] = REPORT_OUTPUT_21;
|
||||||
report_buffer[1] = last_report_counter;
|
report_buffer[1] = last_report_counter;
|
||||||
|
|
@ -251,18 +267,21 @@ static void handle_feature_report(uint8_t switchReportID, uint8_t switchReportSu
|
||||||
report_buffer[14] = commandID;
|
report_buffer[14] = commandID;
|
||||||
report_buffer[15] = 0x03;
|
report_buffer[15] = 0x03;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE GET_CONTROLLER_STATE\n");
|
||||||
break;
|
break;
|
||||||
case BLUETOOTH_PAIR_REQUEST:
|
case BLUETOOTH_PAIR_REQUEST:
|
||||||
report_buffer[13] = 0x81;
|
report_buffer[13] = 0x81;
|
||||||
report_buffer[14] = commandID;
|
report_buffer[14] = commandID;
|
||||||
report_buffer[15] = 0x03;
|
report_buffer[15] = 0x03;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE BLUETOOTH_PAIR_REQUEST\n");
|
||||||
break;
|
break;
|
||||||
case REQUEST_DEVICE_INFO:
|
case REQUEST_DEVICE_INFO:
|
||||||
report_buffer[13] = 0x82;
|
report_buffer[13] = 0x82;
|
||||||
report_buffer[14] = 0x02;
|
report_buffer[14] = 0x02;
|
||||||
memcpy(&report_buffer[15], &device_info, sizeof(device_info));
|
memcpy(&report_buffer[15], &device_info, sizeof(device_info));
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE REQUEST_DEVICE_INFO\n");
|
||||||
break;
|
break;
|
||||||
case SET_MODE:
|
case SET_MODE:
|
||||||
input_mode = reportData[11];
|
input_mode = reportData[11];
|
||||||
|
|
@ -270,16 +289,19 @@ static void handle_feature_report(uint8_t switchReportID, uint8_t switchReportSu
|
||||||
report_buffer[14] = 0x03;
|
report_buffer[14] = 0x03;
|
||||||
report_buffer[15] = input_mode;
|
report_buffer[15] = input_mode;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE SET_MODE 0x%02x\n", input_mode);
|
||||||
break;
|
break;
|
||||||
case TRIGGER_BUTTONS:
|
case TRIGGER_BUTTONS:
|
||||||
report_buffer[13] = 0x83;
|
report_buffer[13] = 0x83;
|
||||||
report_buffer[14] = 0x04;
|
report_buffer[14] = 0x04;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE TRIGGER_BUTTONS\n");
|
||||||
break;
|
break;
|
||||||
case SET_SHIPMENT:
|
case SET_SHIPMENT:
|
||||||
report_buffer[13] = 0x80;
|
report_buffer[13] = 0x80;
|
||||||
report_buffer[14] = commandID;
|
report_buffer[14] = commandID;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE SET_SHIPMENT\n");
|
||||||
break;
|
break;
|
||||||
case SPI_READ:
|
case SPI_READ:
|
||||||
spiReadAddress = (reportData[14] << 24) | (reportData[13] << 16) | (reportData[12] << 8) | (reportData[11]);
|
spiReadAddress = (reportData[14] << 24) | (reportData[13] << 16) | (reportData[12] << 8) | (reportData[11]);
|
||||||
|
|
@ -293,22 +315,26 @@ static void handle_feature_report(uint8_t switchReportID, uint8_t switchReportSu
|
||||||
report_buffer[19] = reportData[15];
|
report_buffer[19] = reportData[15];
|
||||||
read_spi_flash(&report_buffer[20], spiReadAddress, spiReadSize);
|
read_spi_flash(&report_buffer[20], spiReadAddress, spiReadSize);
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE SPI_READ addr=0x%08lx size=%u\n", (unsigned long)spiReadAddress, spiReadSize);
|
||||||
break;
|
break;
|
||||||
case SET_NFC_IR_CONFIG:
|
case SET_NFC_IR_CONFIG:
|
||||||
report_buffer[13] = 0x80;
|
report_buffer[13] = 0x80;
|
||||||
report_buffer[14] = commandID;
|
report_buffer[14] = commandID;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE SET_NFC_IR_CONFIG\n");
|
||||||
break;
|
break;
|
||||||
case SET_NFC_IR_STATE:
|
case SET_NFC_IR_STATE:
|
||||||
report_buffer[13] = 0x80;
|
report_buffer[13] = 0x80;
|
||||||
report_buffer[14] = commandID;
|
report_buffer[14] = commandID;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE SET_NFC_IR_STATE\n");
|
||||||
break;
|
break;
|
||||||
case SET_PLAYER_LIGHTS:
|
case SET_PLAYER_LIGHTS:
|
||||||
player_id = reportData[11];
|
player_id = reportData[11];
|
||||||
report_buffer[13] = 0x80;
|
report_buffer[13] = 0x80;
|
||||||
report_buffer[14] = commandID;
|
report_buffer[14] = commandID;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE SET_PLAYER_LIGHTS player=%u\n", player_id);
|
||||||
break;
|
break;
|
||||||
case GET_PLAYER_LIGHTS:
|
case GET_PLAYER_LIGHTS:
|
||||||
player_id = reportData[11];
|
player_id = reportData[11];
|
||||||
|
|
@ -316,18 +342,21 @@ static void handle_feature_report(uint8_t switchReportID, uint8_t switchReportSu
|
||||||
report_buffer[14] = commandID;
|
report_buffer[14] = commandID;
|
||||||
report_buffer[15] = player_id;
|
report_buffer[15] = player_id;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE GET_PLAYER_LIGHTS player=%u\n", player_id);
|
||||||
break;
|
break;
|
||||||
case COMMAND_UNKNOWN_33:
|
case COMMAND_UNKNOWN_33:
|
||||||
report_buffer[13] = 0x80;
|
report_buffer[13] = 0x80;
|
||||||
report_buffer[14] = commandID;
|
report_buffer[14] = commandID;
|
||||||
report_buffer[15] = 0x03;
|
report_buffer[15] = 0x03;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE COMMAND_UNKNOWN_33\n");
|
||||||
break;
|
break;
|
||||||
case SET_HOME_LIGHT:
|
case SET_HOME_LIGHT:
|
||||||
report_buffer[13] = 0x80;
|
report_buffer[13] = 0x80;
|
||||||
report_buffer[14] = commandID;
|
report_buffer[14] = commandID;
|
||||||
report_buffer[15] = 0x00;
|
report_buffer[15] = 0x00;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE SET_HOME_LIGHT\n");
|
||||||
break;
|
break;
|
||||||
case TOGGLE_IMU:
|
case TOGGLE_IMU:
|
||||||
is_imu_enabled = reportData[11];
|
is_imu_enabled = reportData[11];
|
||||||
|
|
@ -335,11 +364,13 @@ static void handle_feature_report(uint8_t switchReportID, uint8_t switchReportSu
|
||||||
report_buffer[14] = commandID;
|
report_buffer[14] = commandID;
|
||||||
report_buffer[15] = 0x00;
|
report_buffer[15] = 0x00;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE TOGGLE_IMU %u\n", is_imu_enabled);
|
||||||
break;
|
break;
|
||||||
case IMU_SENSITIVITY:
|
case IMU_SENSITIVITY:
|
||||||
report_buffer[13] = 0x80;
|
report_buffer[13] = 0x80;
|
||||||
report_buffer[14] = commandID;
|
report_buffer[14] = commandID;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE IMU_SENSITIVITY\n");
|
||||||
break;
|
break;
|
||||||
case ENABLE_VIBRATION:
|
case ENABLE_VIBRATION:
|
||||||
is_vibration_enabled = reportData[11];
|
is_vibration_enabled = reportData[11];
|
||||||
|
|
@ -347,6 +378,7 @@ static void handle_feature_report(uint8_t switchReportID, uint8_t switchReportSu
|
||||||
report_buffer[14] = commandID;
|
report_buffer[14] = commandID;
|
||||||
report_buffer[15] = 0x00;
|
report_buffer[15] = 0x00;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE ENABLE_VIBRATION %u\n", is_vibration_enabled);
|
||||||
break;
|
break;
|
||||||
case READ_IMU:
|
case READ_IMU:
|
||||||
report_buffer[13] = 0xC0;
|
report_buffer[13] = 0xC0;
|
||||||
|
|
@ -354,6 +386,7 @@ static void handle_feature_report(uint8_t switchReportID, uint8_t switchReportSu
|
||||||
report_buffer[15] = reportData[11];
|
report_buffer[15] = reportData[11];
|
||||||
report_buffer[16] = reportData[12];
|
report_buffer[16] = reportData[12];
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE READ_IMU addr=%u size=%u\n", reportData[11], reportData[12]);
|
||||||
break;
|
break;
|
||||||
case GET_VOLTAGE:
|
case GET_VOLTAGE:
|
||||||
report_buffer[13] = 0xD0;
|
report_buffer[13] = 0xD0;
|
||||||
|
|
@ -361,12 +394,14 @@ static void handle_feature_report(uint8_t switchReportID, uint8_t switchReportSu
|
||||||
report_buffer[15] = 0x83;
|
report_buffer[15] = 0x83;
|
||||||
report_buffer[16] = 0x06;
|
report_buffer[16] = 0x06;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE GET_VOLTAGE\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
report_buffer[13] = 0x80;
|
report_buffer[13] = 0x80;
|
||||||
report_buffer[14] = commandID;
|
report_buffer[14] = commandID;
|
||||||
report_buffer[15] = 0x03;
|
report_buffer[15] = 0x03;
|
||||||
canSend = true;
|
canSend = true;
|
||||||
|
printf("[HID] FEATURE unknown cmd=0x%02x\n", commandID);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -404,7 +439,7 @@ static void update_switch_report_from_state() {
|
||||||
uint16_t scaleLeftStickY = scale16To12(g_input_state.ly);
|
uint16_t scaleLeftStickY = scale16To12(g_input_state.ly);
|
||||||
uint16_t scaleRightStickX = scale16To12(g_input_state.rx);
|
uint16_t scaleRightStickX = scale16To12(g_input_state.rx);
|
||||||
uint16_t scaleRightStickY = scale16To12(g_input_state.ry);
|
uint16_t scaleRightStickY = scale16To12(g_input_state.ry);
|
||||||
|
|
||||||
switch_report.inputs.leftStick.setX(std::min(std::max(scaleLeftStickX,leftMinX), leftMaxX));
|
switch_report.inputs.leftStick.setX(std::min(std::max(scaleLeftStickX,leftMinX), leftMaxX));
|
||||||
switch_report.inputs.leftStick.setY(-std::min(std::max(scaleLeftStickY,leftMinY), leftMaxY));
|
switch_report.inputs.leftStick.setY(-std::min(std::max(scaleLeftStickY,leftMinY), leftMaxY));
|
||||||
switch_report.inputs.rightStick.setX(std::min(std::max(scaleRightStickX,rightMinX), rightMaxX));
|
switch_report.inputs.rightStick.setX(std::min(std::max(scaleRightStickX,rightMinX), rightMaxX));
|
||||||
|
|
@ -421,6 +456,8 @@ void switch_pro_init() {
|
||||||
is_initialized = false;
|
is_initialized = false;
|
||||||
is_report_queued = false;
|
is_report_queued = false;
|
||||||
report_sent = false;
|
report_sent = false;
|
||||||
|
forced_ready = false;
|
||||||
|
host_sent_out = false;
|
||||||
|
|
||||||
device_info = {
|
device_info = {
|
||||||
.majorVersion = 0x04,
|
.majorVersion = 0x04,
|
||||||
|
|
@ -437,8 +474,8 @@ void switch_pro_init() {
|
||||||
.timestamp = 0,
|
.timestamp = 0,
|
||||||
|
|
||||||
.inputs {
|
.inputs {
|
||||||
.connectionInfo = 0,
|
.connectionInfo = 0x08, // wired connection
|
||||||
.batteryLevel = 0x08,
|
.batteryLevel = 0x0F, // full battery
|
||||||
|
|
||||||
.buttonY = 0,
|
.buttonY = 0,
|
||||||
.buttonX = 0,
|
.buttonX = 0,
|
||||||
|
|
@ -475,6 +512,7 @@ void switch_pro_init() {
|
||||||
};
|
};
|
||||||
|
|
||||||
last_report_timer = to_ms_since_boot(get_absolute_time());
|
last_report_timer = to_ms_since_boot(get_absolute_time());
|
||||||
|
last_host_activity_ms = last_report_timer;
|
||||||
|
|
||||||
factory_config->leftStickCalibration.getRealMin(leftMinX, leftMinY);
|
factory_config->leftStickCalibration.getRealMin(leftMinX, leftMinY);
|
||||||
factory_config->leftStickCalibration.getCenter(leftCenX, leftCenY);
|
factory_config->leftStickCalibration.getCenter(leftCenX, leftCenY);
|
||||||
|
|
@ -508,7 +546,8 @@ void switch_pro_task() {
|
||||||
report_sent = true;
|
report_sent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_ready && !report_sent) {
|
// If the host never sends feature/config reports (seen on Switch), force readiness after a timeout.
|
||||||
|
if (is_ready && !report_sent && host_sent_out) {
|
||||||
if ((now - last_report_timer) > SWITCH_PRO_KEEPALIVE_TIMER) {
|
if ((now - last_report_timer) > SWITCH_PRO_KEEPALIVE_TIMER) {
|
||||||
switch_report.timestamp = last_report_counter;
|
switch_report.timestamp = last_report_counter;
|
||||||
void * inputReport = &switch_report;
|
void * inputReport = &switch_report;
|
||||||
|
|
@ -535,7 +574,7 @@ void switch_pro_task() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool switch_pro_apply_uart_packet(const uint8_t* packet, uint8_t length) {
|
bool switch_pro_apply_uart_packet(const uint8_t* packet, uint8_t length, SwitchInputState* out_state) {
|
||||||
// Packet format: 0xAA, buttons(2 LE), hat, lx, ly, rx, ry
|
// Packet format: 0xAA, buttons(2 LE), hat, lx, ly, rx, ry
|
||||||
if (length < 8 || packet[0] != 0xAA) {
|
if (length < 8 || packet[0] != 0xAA) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -587,18 +626,33 @@ bool switch_pro_apply_uart_packet(const uint8_t* packet, uint8_t length) {
|
||||||
state.rx = expand_axis(out.rx);
|
state.rx = expand_axis(out.rx);
|
||||||
state.ry = expand_axis(out.ry);
|
state.ry = expand_axis(out.ry);
|
||||||
|
|
||||||
switch_pro_set_input(state);
|
if (out_state) {
|
||||||
|
*out_state = state;
|
||||||
|
} else {
|
||||||
|
switch_pro_set_input(state);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool switch_pro_is_ready() {
|
||||||
|
return is_ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
void switch_pro_mark_host_active() {
|
||||||
|
host_sent_out = true;
|
||||||
|
}
|
||||||
|
|
||||||
// HID callbacks
|
// HID callbacks
|
||||||
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
|
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
|
||||||
(void)instance;
|
(void)instance;
|
||||||
(void)report_id;
|
printf("[HID] get_report id=%u type=%u len=%u\n", report_id, report_type, reqlen);
|
||||||
(void)report_type;
|
if (!buffer) return 0;
|
||||||
(void)buffer;
|
|
||||||
(void)reqlen;
|
// Serve the current input report for any GET_REPORT request.
|
||||||
return 0;
|
uint16_t report_size = sizeof(switch_report);
|
||||||
|
if (reqlen < report_size) report_size = reqlen;
|
||||||
|
memcpy(buffer, &switch_report, report_size);
|
||||||
|
return report_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {
|
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {
|
||||||
|
|
@ -609,7 +663,12 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_
|
||||||
|
|
||||||
uint8_t switchReportID = buffer[0];
|
uint8_t switchReportID = buffer[0];
|
||||||
uint8_t switchReportSubID = buffer[1];
|
uint8_t switchReportSubID = buffer[1];
|
||||||
|
printf("[HID] set_report type=%d id=%u switchRID=0x%02x sub=0x%02x len=%u\n",
|
||||||
|
report_type, report_id, switchReportID, switchReportSubID, bufsize);
|
||||||
|
host_sent_out = true;
|
||||||
if (switchReportID == REPORT_OUTPUT_00) {
|
if (switchReportID == REPORT_OUTPUT_00) {
|
||||||
|
// No-op, just acknowledge to clear any stalls.
|
||||||
|
return;
|
||||||
} else if (switchReportID == REPORT_FEATURE) {
|
} else if (switchReportID == REPORT_FEATURE) {
|
||||||
queued_report_id = report_id;
|
queued_report_id = report_id;
|
||||||
handle_feature_report(switchReportID, switchReportSubID, buffer, bufsize);
|
handle_feature_report(switchReportID, switchReportSubID, buffer, bufsize);
|
||||||
|
|
@ -620,6 +679,26 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tud_hid_report_received_cb(uint8_t instance, uint8_t report_id, uint8_t const* buffer, uint16_t bufsize) {
|
||||||
|
(void)instance;
|
||||||
|
// Host sent data on interrupt OUT; mirror the control path handling.
|
||||||
|
memset(report_buffer, 0x00, bufsize);
|
||||||
|
uint8_t switchReportID = buffer[0];
|
||||||
|
uint8_t switchReportSubID = buffer[1];
|
||||||
|
printf("[HID] report_received id=%u switchRID=0x%02x sub=0x%02x len=%u\n",
|
||||||
|
report_id, switchReportID, switchReportSubID, bufsize);
|
||||||
|
host_sent_out = true;
|
||||||
|
if (switchReportID == REPORT_OUTPUT_00) {
|
||||||
|
return;
|
||||||
|
} else if (switchReportID == REPORT_FEATURE) {
|
||||||
|
queued_report_id = report_id;
|
||||||
|
handle_feature_report(switchReportID, switchReportSubID, buffer, bufsize);
|
||||||
|
} else if (switchReportID == REPORT_CONFIGURATION) {
|
||||||
|
queued_report_id = report_id;
|
||||||
|
handle_config_report(switchReportID, switchReportSubID, buffer, bufsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf) {
|
uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf) {
|
||||||
(void)itf;
|
(void)itf;
|
||||||
return switch_pro_report_descriptor;
|
return switch_pro_report_descriptor;
|
||||||
|
|
@ -634,6 +713,30 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index) {
|
||||||
return switch_pro_configuration_descriptor;
|
return switch_pro_configuration_descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool tud_control_request_cb(uint8_t rhport, tusb_control_request_t const * request) {
|
||||||
|
(void)rhport;
|
||||||
|
printf("[CTRL] bmReq=0x%02x bReq=0x%02x wValue=0x%04x wIndex=0x%04x wLen=%u\n",
|
||||||
|
request->bmRequestType, request->bRequest, request->wValue, request->wIndex, request->wLength);
|
||||||
|
return false; // let TinyUSB handle it normally
|
||||||
|
}
|
||||||
|
|
||||||
|
void tud_mount_cb(void) {
|
||||||
|
printf("[USB] mount_cb\n");
|
||||||
|
last_host_activity_ms = to_ms_since_boot(get_absolute_time());
|
||||||
|
forced_ready = false;
|
||||||
|
is_ready = false;
|
||||||
|
is_initialized = false;
|
||||||
|
host_sent_out = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tud_umount_cb(void) {
|
||||||
|
printf("[USB] umount_cb\n");
|
||||||
|
forced_ready = false;
|
||||||
|
is_ready = false;
|
||||||
|
is_initialized = false;
|
||||||
|
host_sent_out = false;
|
||||||
|
}
|
||||||
|
|
||||||
static uint16_t desc_str[32];
|
static uint16_t desc_str[32];
|
||||||
|
|
||||||
uint16_t const * tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
uint16_t const * tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||||
|
|
|
||||||
|
|
@ -47,4 +47,11 @@ void switch_pro_set_input(const SwitchInputState& state);
|
||||||
void switch_pro_task();
|
void switch_pro_task();
|
||||||
|
|
||||||
// Convert a packed UART message into controller state (returns true if parsed).
|
// Convert a packed UART message into controller state (returns true if parsed).
|
||||||
bool switch_pro_apply_uart_packet(const uint8_t* packet, uint8_t length);
|
// If out_state is null the parsed state is written directly to the driver.
|
||||||
|
bool switch_pro_apply_uart_packet(const uint8_t* packet, uint8_t length, SwitchInputState* out_state = nullptr);
|
||||||
|
|
||||||
|
// Driver state helpers
|
||||||
|
bool switch_pro_is_ready();
|
||||||
|
|
||||||
|
// Mark that the host has sent any OUT traffic (allows starting IN reports).
|
||||||
|
void switch_pro_mark_host_active();
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,10 @@ extern "C" {
|
||||||
#define CFG_TUD_MSC 0
|
#define CFG_TUD_MSC 0
|
||||||
#define CFG_TUD_MIDI 0
|
#define CFG_TUD_MIDI 0
|
||||||
#define CFG_TUD_VENDOR 0
|
#define CFG_TUD_VENDOR 0
|
||||||
|
#ifdef CFG_TUSB_DEBUG
|
||||||
|
#undef CFG_TUSB_DEBUG
|
||||||
|
#endif
|
||||||
|
#define CFG_TUSB_DEBUG 2
|
||||||
|
|
||||||
#define CFG_TUD_HID_EP_BUFSIZE 64
|
#define CFG_TUD_HID_EP_BUFSIZE 64
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue