probe: allow for selection of CMSIS-DAP v1 and v2 protocols
CMSIS-DAP v1 is a pseudo-HID device which allows "driver-less" use on Windows. DAP v2 is a vendor-specific bulk protocol, so there needs to be a companion MS OS 2.0 descriptor for the debug interface with DeviceInterfaceGUID set to the Keil GUID. Allow for selection between these and the openocd protocol at compile time. Parts of the v1 implementation are derived from the DapperMime project, so add credit where due. Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
This commit is contained in:
91
src/main.c
91
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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user