diff --git a/src/main.c b/src/main.c index 21439a1..44204c7 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2021 Raspberry Pi (Trading) Ltd. + * Copyright (c) 2021 Peter Lawrence * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,17 +36,27 @@ #include "cdc_uart.h" #include "get_serial.h" #include "led.h" +#include "DAP.h" // UART0 for Picoprobe debug // UART1 for picoprobe to target device +static uint8_t TxDataBuffer[CFG_TUD_HID_EP_BUFSIZE]; +static uint8_t RxDataBuffer[CFG_TUD_HID_EP_BUFSIZE]; + +void dap_task(void); + int main(void) { board_init(); usb_serial_init(); cdc_uart_init(); tusb_init(); +#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_OPENOCD_CUSTOM) probe_init(); +#else + DAP_Setup(); +#endif led_init(); picoprobe_info("Welcome to Picoprobe!\n"); @@ -53,9 +64,87 @@ int main(void) { while (1) { tud_task(); // tinyusb device task cdc_task(); +#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_OPENOCD_CUSTOM) probe_task(); led_task(); +#elif (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V2) + dap_task(); +#endif } return 0; -} \ No newline at end of file +} + +void dap_task(void) +{ + uint32_t count; + uint32_t resp_len; + if (tud_vendor_available()) { + count = tud_vendor_read(RxDataBuffer, sizeof(RxDataBuffer)); + resp_len = DAP_ProcessCommand(RxDataBuffer, TxDataBuffer); + tud_vendor_write(TxDataBuffer, resp_len); + } +} + +uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) +{ + // TODO not Implemented + (void) itf; + (void) report_id; + (void) report_type; + (void) buffer; + (void) reqlen; + + return 0; +} + +void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* RxDataBuffer, uint16_t bufsize) +{ + uint32_t response_size = TU_MIN(CFG_TUD_HID_EP_BUFSIZE, bufsize); + + // This doesn't use multiple report and report ID + (void) itf; + (void) report_id; + (void) report_type; + + DAP_ProcessCommand(RxDataBuffer, TxDataBuffer); + + tud_hid_report(0, TxDataBuffer, response_size); +} + +#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V2) +extern uint8_t const desc_ms_os_20[]; + +bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + // nothing to with DATA & ACK stage + if (stage != CONTROL_STAGE_SETUP) return true; + + switch (request->bmRequestType_bit.type) + { + case TUSB_REQ_TYPE_VENDOR: + switch (request->bRequest) + { + case 1: + if ( request->wIndex == 7 ) + { + // Get Microsoft OS 2.0 compatible descriptor + uint16_t total_len; + memcpy(&total_len, desc_ms_os_20+8, 2); + + return tud_control_xfer(rhport, request, (void*) desc_ms_os_20, total_len); + }else + { + return false; + } + + default: break; + } + break; + default: break; + } + + // stall unknown request + return false; +} +#endif diff --git a/src/picoprobe_config.h b/src/picoprobe_config.h index 87be47b..4bca6c5 100644 --- a/src/picoprobe_config.h +++ b/src/picoprobe_config.h @@ -72,6 +72,15 @@ #define PICOPROBE_LED PICO_DEFAULT_LED_PIN #endif +#define PROTO_OPENOCD_CUSTOM 0 +#define PROTO_DAP_V1 1 +#define PROTO_DAP_V2 2 + +// Interface config +#ifndef PICOPROBE_DEBUG_PROTOCOL +#define PICOPROBE_DEBUG_PROTOCOL PROTO_OPENOCD_CUSTOM +#endif + #endif #endif diff --git a/src/tusb_config.h b/src/tusb_config.h index b4dc45c..ad0e1fa 100644 --- a/src/tusb_config.h +++ b/src/tusb_config.h @@ -62,7 +62,7 @@ #endif //------------- CLASS -------------// -#define CFG_TUD_HID 0 +#define CFG_TUD_HID 1 #define CFG_TUD_CDC 1 #define CFG_TUD_MSC 0 #define CFG_TUD_MIDI 0 diff --git a/src/usb_descriptors.c b/src/usb_descriptors.c index dd6b4f0..49a783e 100644 --- a/src/usb_descriptors.c +++ b/src/usb_descriptors.c @@ -2,6 +2,8 @@ * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2021 Peter Lawrence + * Copyright (c) 2022 Raspberry Pi Ltd * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,7 +27,7 @@ #include "tusb.h" #include "get_serial.h" - +#include "picoprobe_config.h" //--------------------------------------------------------------------+ // Device Descriptors @@ -34,14 +36,22 @@ tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0110, // // USB Specification version 1.1 +#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V2) + .bcdUSB = 0x0210, // USB Specification version 2.1 for BOS +#else + .bcdUSB = 0x0110, +#endif .bDeviceClass = 0x00, // Each interface specifies its own .bDeviceSubClass = 0x00, // Each interface specifies its own .bDeviceProtocol = 0x00, .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, .idVendor = 0x2E8A, // Pi +#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_OPENOCD_CUSTOM) .idProduct = 0x0004, // Picoprobe +#else + .idProduct = 0x000c, // CMSIS-DAP adapter +#endif .bcdDevice = 0x0100, // Version 01.00 .iManufacturer = 0x01, .iProduct = 0x02, @@ -62,9 +72,9 @@ uint8_t const * tud_descriptor_device_cb(void) enum { + ITF_NUM_PROBE, // Old versions of Keil MDK only look at interface 0 ITF_NUM_CDC_COM, ITF_NUM_CDC_DATA, - ITF_NUM_PROBE, ITF_NUM_TOTAL }; @@ -74,18 +84,39 @@ enum #define PROBE_OUT_EP_NUM 0x04 #define PROBE_IN_EP_NUM 0x85 +#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V1) +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_HID_INOUT_DESC_LEN) +#else #define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_VENDOR_DESC_LEN) +#endif + +static uint8_t const desc_hid_report[] = +{ + TUD_HID_REPORT_DESC_GENERIC_INOUT(CFG_TUD_HID_EP_BUFSIZE) +}; + +uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf) +{ + (void) itf; + return desc_hid_report; +} uint8_t const desc_configuration[] = { TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), - - // Interface 0 + 1 - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_COM, 0, CDC_NOTIFICATION_EP_NUM, 64, CDC_DATA_OUT_EP_NUM, CDC_DATA_IN_EP_NUM, 64), - - // Interface 2 - TUD_VENDOR_DESCRIPTOR(ITF_NUM_PROBE, 0, PROBE_OUT_EP_NUM, PROBE_IN_EP_NUM, 64) - + // Interface 0 +#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V1) + // HID (named interface) + TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_PROBE, 4, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), PROBE_OUT_EP_NUM, PROBE_IN_EP_NUM, CFG_TUD_HID_EP_BUFSIZE, 1), +#elif (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V2) + // Bulk (named interface) + TUD_VENDOR_DESCRIPTOR(ITF_NUM_PROBE, 5, PROBE_OUT_EP_NUM, PROBE_IN_EP_NUM, 64), +#elif (PICOPROBE_DEBUG_PROTOCOL == PROTO_OPENOCD_CUSTOM) + // Bulk + TUD_VENDOR_DESCRIPTOR(ITF_NUM_PROBE, 0, PROBE_OUT_EP_NUM, PROBE_IN_EP_NUM, 64), +#endif + // Interface 1 + 2 + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_COM, 6, CDC_NOTIFICATION_EP_NUM, 64, CDC_DATA_OUT_EP_NUM, CDC_DATA_IN_EP_NUM, 64), }; // Invoked when received GET CONFIGURATION DESCRIPTOR @@ -108,6 +139,9 @@ char const* string_desc_arr [] = "Raspberry Pi", // 1: Manufacturer "Picoprobe", // 2: Product usb_serial, // 3: Serial, uses flash unique ID + "Picoprobe CMSIS-DAP v1", // Interface descriptor for HID transport + "Picoprobe CMSIS-DAP v2", // Interface descriptor for Bulk transport + "Picoprobe CDC-ACM UART", // Interface descriptor for CDC }; static uint16_t _desc_str[32]; @@ -147,3 +181,69 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) return _desc_str; } + +/* [incoherent gibbering to make Windows happy] */ + +//--------------------------------------------------------------------+ +// BOS Descriptor +//--------------------------------------------------------------------+ + +/* Microsoft OS 2.0 registry property descriptor +Per MS requirements https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx +device should create DeviceInterfaceGUIDs. It can be done by driver and +in case of real PnP solution device should expose MS "Microsoft OS 2.0 +registry property descriptor". Such descriptor can insert any record +into Windows registry per device/configuration/interface. In our case it +will insert "DeviceInterfaceGUIDs" multistring property. + + +https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/ +(Section Microsoft OS compatibility descriptors) +*/ +#define MS_OS_20_DESC_LEN 0xB2 + +#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN) + +uint8_t const desc_bos[] = +{ + // total length, number of device caps + TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 1), + + // Microsoft OS 2.0 descriptor + TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, 1) +}; + +uint8_t const 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(MS_OS_20_DESC_LEN), + + // Configuration subset header: length, type, configuration index, reserved, configuration total length + U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A), + + // 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), ITF_NUM_PROBE, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08), + + // 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(MS_OS_20_DESC_LEN-0x0A-0x08-0x08-0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY), + U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" 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, 's', 0x00, 0x00, 0x00, + U16_TO_U8S_LE(0x0050), // wPropertyDataLength + // bPropertyData "{CDB3B5AD-293B-4663-AA36-1AAE46463776}" as a UTF-16 string (b doesn't mean bytes) + '{', 0x00, 'C', 0x00, 'D', 0x00, 'B', 0x00, '3', 0x00, 'B', 0x00, '5', 0x00, 'A', 0x00, 'D', 0x00, '-', 0x00, + '2', 0x00, '9', 0x00, '3', 0x00, 'B', 0x00, '-', 0x00, '4', 0x00, '6', 0x00, '6', 0x00, '3', 0x00, '-', 0x00, + 'A', 0x00, 'A', 0x00, '3', 0x00, '6', 0x00, '-', 0x00, '1', 0x00, 'A', 0x00, 'A', 0x00, 'E', 0x00, '4', 0x00, + '6', 0x00, '4', 0x00, '6', 0x00, '3', 0x00, '7', 0x00, '7', 0x00, '6', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +TU_VERIFY_STATIC(sizeof(desc_ms_os_20) == MS_OS_20_DESC_LEN, "Incorrect size"); + +uint8_t const * tud_descriptor_bos_cb(void) +{ + return desc_bos; +}