diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 1891415..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "libs/pico-sdk"] - path = libs/pico-sdk - url = https://github.com/raspberrypi/pico-sdk.git diff --git a/CMakeLists.txt b/CMakeLists.txt index d894a6a..ded08aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,17 @@ cmake_minimum_required(VERSION 3.13) -include(libs/pico-sdk/pico_sdk_init.cmake) +if((NOT DEFINED ENV{PICO_SDK_PATH}) AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_TAG "2.0.0") + set(PICO_SDK_FETCH_FROM_GIT ON) +endif() -project(DonCon2040 VERSION 0.1.0) +if((NOT DEFINED ENV{PICO_BOARD}) AND (NOT PICO_BOARD)) + set(PICO_BOARD "seeed_xiao_rp2040") +endif() + +include(pico_sdk_import.cmake) + +project(DonCon2040 VERSION 0.39.0) pico_sdk_init() @@ -13,8 +22,16 @@ add_compile_options(-Wall -Wextra -Werror) add_subdirectory(libs) -file(GLOB ${PROJECT_NAME}_SOURCES src/*.cpp src/usb/*.c src/utils/*.cpp - src/peripherals/*.cpp) +file( + GLOB + ${PROJECT_NAME}_SOURCES + src/*.cpp + src/usb/*.c + src/usb/device/*.c + src/usb/device/hid/*.c + src/usb/device/vendor/*.c + src/utils/*.cpp + src/peripherals/*.cpp) add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_SOURCES}) diff --git a/libs/pico-sdk b/libs/pico-sdk deleted file mode 160000 index 6a7db34..0000000 --- a/libs/pico-sdk +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6a7db34ff63345a7badec79ebea3aaef1712f374 diff --git a/pico_sdk_import.cmake b/pico_sdk_import.cmake new file mode 100644 index 0000000..a0721d0 --- /dev/null +++ b/pico_sdk_import.cmake @@ -0,0 +1,84 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + ) + else () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + endif () + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + FetchContent_Populate(pico_sdk) + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/src/usb/debug_driver.c b/src/usb/debug_driver.c index 45e5bf2..df87a75 100644 --- a/src/usb/debug_driver.c +++ b/src/usb/debug_driver.c @@ -1,10 +1,10 @@ #include "usb/debug_driver.h" -#include "usb/usb_driver.h" +#include "device/usbd_pvt.h" +#include "hardware/watchdog.h" #include "pico/bootrom.h" #include "pico/stdio_usb.h" #include "pico/usb_reset_interface.h" - #include "tusb.h" #define USBD_CDC_EP_CMD (0x81) @@ -16,7 +16,7 @@ const tusb_desc_device_t debug_desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0200, + .bcdUSB = 0x0210, .bDeviceClass = TUSB_CLASS_MISC, .bDeviceSubClass = MISC_SUBCLASS_COMMON, .bDeviceProtocol = MISC_PROTOCOL_IAD, @@ -37,47 +37,71 @@ enum { USBD_ITF_MAX, }; -bool send_debug_report(usb_report_t report) { - printf((char *)report.data); - return true; -} - -#if !PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE -#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN) -#else #define TUD_RPI_RESET_DESC_LEN 9 #define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_RPI_RESET_DESC_LEN) #define TUD_RPI_RESET_DESCRIPTOR(_itfnum, _stridx) \ 9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_VENDOR_SPECIFIC, RESET_INTERFACE_SUBCLASS, \ RESET_INTERFACE_PROTOCOL, _stridx -#endif const uint8_t debug_desc_cfg[USBD_DESC_LEN] = { TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_LANGUAGE, USBD_DESC_LEN, 0, USBD_MAX_POWER_MAX), TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE), -#if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE TUD_RPI_RESET_DESCRIPTOR(USBD_ITF_RPI_RESET, USBD_STR_RPI_RESET), -#endif }; -#if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE && !(PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL || \ - PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT) -#warning PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE has been selected but neither PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL nor PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT have been selected. -#endif +#define TUD_DEBUG_MS_OS_20_DESC_LEN 166 -#if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE -#include "device/usbd_pvt.h" -#include "hardware/watchdog.h" -#include "pico/stdio_usb/reset_interface.h" +static const uint8_t debug_desc_ms_os_20[] = { + // Set header: length, type, windows version, total length + U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), + U16_TO_U8S_LE(TUD_DEBUG_MS_OS_20_DESC_LEN), + + // Function Subset header: length, type, first interface, reserved, subset length + U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), USBD_ITF_RPI_RESET, 0, U16_TO_U8S_LE(0x009C), + + // MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID + U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible + + // MS OS 2.0 Registry property descriptor: length, type + U16_TO_U8S_LE(0x0080), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY), U16_TO_U8S_LE(0x0001), + U16_TO_U8S_LE(0x0028), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUID" in UTF-16 + 'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00, 'r', + 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 0x00, 0x00, + U16_TO_U8S_LE(0x004E), // wPropertyDataLength + // Vendor-defined Property Data: {bc7398c1-73cd-4cb7-98b8-913a8fca7bf6} + '{', 0, 'b', 0, 'c', 0, '7', 0, '3', 0, '9', 0, '8', 0, 'c', 0, '1', 0, '-', 0, '7', 0, '3', 0, 'c', 0, 'd', 0, '-', + 0, '4', 0, 'c', 0, 'b', 0, '7', 0, '-', 0, '9', 0, '8', 0, 'b', 0, '8', 0, '-', 0, '9', 0, '1', 0, '3', 0, 'a', 0, + '8', 0, 'f', 0, 'c', 0, 'a', 0, '7', 0, 'b', 0, 'f', 0, '6', 0, '}', 0, 0, 0}; + +#define TUD_PDLOADER_BOS_VENDOR_REQUEST_MICROSOFT 1 +#define TUD_DEBUG_BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN) + +const uint8_t debug_desc_bos[] = { + TUD_BOS_DESCRIPTOR(TUD_DEBUG_BOS_TOTAL_LEN, 1), + TUD_BOS_MS_OS_20_DESCRIPTOR(TUD_DEBUG_MS_OS_20_DESC_LEN, TUD_PDLOADER_BOS_VENDOR_REQUEST_MICROSOFT), +}; static uint8_t itf_num; -static void resetd_init(void) {} +bool send_debug_report(usb_report_t report) { + stdio_printf((char *)report.data); + stdio_flush(); -static void resetd_reset(uint8_t __unused rhport) { itf_num = 0; } + return true; +} + +static void debug_init(void) {} + +static void debug_reset(uint8_t rhport) { + (void)rhport; + itf_num = 0; +} + +static uint16_t debug_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { + (void)rhport; -static uint16_t resetd_open(uint8_t __unused rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass && RESET_INTERFACE_SUBCLASS == itf_desc->bInterfaceSubClass && RESET_INTERFACE_PROTOCOL == itf_desc->bInterfaceProtocol, @@ -91,67 +115,54 @@ static uint16_t resetd_open(uint8_t __unused rhport, tusb_desc_interface_t const } // Support for parameterized reset via vendor interface control request -static bool resetd_control_xfer_cb(uint8_t __unused rhport, uint8_t stage, tusb_control_request_t const *request) { +bool debug_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { // nothing to do with DATA & ACK stage if (stage != CONTROL_STAGE_SETUP) return true; - if (request->wIndex == itf_num) { -#if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL + if (request->bRequest == 1 && request->wIndex == 7) { + // Get Microsoft OS 2.0 compatible descriptor + return tud_control_xfer(rhport, request, (void *)(uintptr_t)debug_desc_ms_os_20, sizeof(debug_desc_ms_os_20)); + } else if (request->wIndex == itf_num) { if (request->bRequest == RESET_REQUEST_BOOTSEL) { -#ifdef PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED - uint gpio_mask = 1u << PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED; -#else - uint gpio_mask = 0u; -#endif -#if !PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED - if (request->wValue & 0x100) { - gpio_mask = 1u << (request->wValue >> 9u); - } -#endif - reset_usb_boot(gpio_mask, (request->wValue & 0x7f) | PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK); + reset_usb_boot(0, (request->wValue & 0x7f) | PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK); // does not return, otherwise we'd return true } -#endif -#if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT if (request->bRequest == RESET_REQUEST_FLASH) { watchdog_reboot(0, 0, PICO_STDIO_USB_RESET_RESET_TO_FLASH_DELAY_MS); return true; } -#endif } + return false; } -static bool resetd_xfer_cb(uint8_t __unused rhport, uint8_t __unused ep_addr, xfer_result_t __unused result, - uint32_t __unused xferred_bytes) { +static bool debug_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { + (void)rhport; + (void)ep_addr; + (void)result; + (void)xferred_bytes; + return true; } -usbd_class_driver_t const debug_app_driver = { +const usbd_class_driver_t debug_app_driver = { #if CFG_TUSB_DEBUG >= 2 - .name = "RESET", + .name = "DEBUG", #endif - .init = resetd_init, - .reset = resetd_reset, - .open = resetd_open, - .control_xfer_cb = resetd_control_xfer_cb, - .xfer_cb = resetd_xfer_cb, + .init = debug_init, + .reset = debug_reset, + .open = debug_open, + .control_xfer_cb = debug_control_xfer_cb, + .xfer_cb = debug_xfer_cb, .sof = NULL}; -#endif - -#if PICO_STDIO_USB_ENABLE_RESET_VIA_BAUD_RATE // Support for default BOOTSEL reset by changing baud rate -void tud_cdc_line_coding_cb(__unused uint8_t itf, cdc_line_coding_t const *p_line_coding) { +void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const *p_line_coding) { + (void)itf; + if (p_line_coding->bit_rate == PICO_STDIO_USB_RESET_MAGIC_BAUD_RATE) { -#ifdef PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED - const uint gpio_mask = 1u << PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED; -#else - const uint gpio_mask = 0u; -#endif - reset_usb_boot(gpio_mask, PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK); + reset_usb_boot(0, PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK); } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/usb/hid_ps3_driver.c b/src/usb/hid_ps3_driver.c index e752d6b..33893de 100644 --- a/src/usb/hid_ps3_driver.c +++ b/src/usb/hid_ps3_driver.c @@ -180,12 +180,14 @@ void hid_ps3_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep uint16_t bufsize) { (void)itf; - if (report_type == HID_REPORT_TYPE_INVALID) { - if (bufsize > 0) { - report_id = buffer[0]; - buffer = &buffer[1]; - bufsize--; - } + if (report_type != HID_REPORT_TYPE_OUTPUT) { + return; + } + + if (report_id == 0 && bufsize > 0) { + report_id = buffer[0]; + buffer = &buffer[1]; + bufsize--; } switch (report_id) { diff --git a/src/usb/hid_ps4_driver.c b/src/usb/hid_ps4_driver.c index 853f7d7..ff388b1 100644 --- a/src/usb/hid_ps4_driver.c +++ b/src/usb/hid_ps4_driver.c @@ -385,12 +385,14 @@ void hid_ps4_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep uint16_t bufsize) { (void)itf; - if (report_type == HID_REPORT_TYPE_INVALID) { - if (bufsize > 0) { - report_id = buffer[0]; - buffer = &buffer[1]; - bufsize--; - } + if (report_type != HID_REPORT_TYPE_OUTPUT) { + return; + } + + if (report_id == 0 && bufsize > 0) { + report_id = buffer[0]; + buffer = &buffer[1]; + bufsize--; } switch (report_id) { diff --git a/src/utils/Menu.cpp b/src/utils/Menu.cpp index b8b3990..36849fa 100644 --- a/src/utils/Menu.cpp +++ b/src/utils/Menu.cpp @@ -11,7 +11,7 @@ const std::map Menu::descriptors = { {"Sensitvty", Menu::Descriptor::Action::GotoPageTriggerThreshold}, // {"Hold Time", Menu::Descriptor::Action::GotoPageDebounceDelay}, // {"Reset", Menu::Descriptor::Action::GotoPageReset}, // - {"BOOTSEL", Menu::Descriptor::Action::GotoPageBootsel}}, // + {"USB Flash", Menu::Descriptor::Action::GotoPageBootsel}}, // 0}}, // {Menu::Page::DeviceMode, // @@ -85,7 +85,7 @@ const std::map Menu::descriptors = { {Menu::Page::Bootsel, // {Menu::Descriptor::Type::Selection, // - "Reboot to BOOTSEL", // + "Reboot to Flash Mode", // {{"Reboot?", Menu::Descriptor::Action::DoRebootToBootsel}}, // 0}}, // diff --git a/src/utils/SettingsStore.cpp b/src/utils/SettingsStore.cpp index c0008e1..6e88f6b 100644 --- a/src/utils/SettingsStore.cpp +++ b/src/utils/SettingsStore.cpp @@ -99,19 +99,17 @@ void SettingsStore::store() { m_dirty = false; - restore_interrupts(interrupts); + restore_interrupts_from_disabled(interrupts); multicore_lockout_end_blocking(); } switch (m_scheduled_reboot) { case RebootType::Normal: - watchdog_enable(1, 1); - while (1) - ; + watchdog_reboot(0, 0, 1); break; case RebootType::Bootsel: sleep_ms(100); - reset_usb_boot(0, 0); + reset_usb_boot(0, PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK); break; case RebootType::None: break;