Dap-link support mode (#18)

* DAP-link usb driver
* Blackmagic glue works
* Blackmagic on wifi interface and dap on usb
* Wifi: disabled mode, USB: BM/DAP mode, SWD: access lock
* USB config via cli
* Web interface: mobile friendly
This commit is contained in:
Sergey Gavrilov 2023-02-09 17:57:03 +03:00 committed by GitHub
parent 473bdd4d09
commit b182ceffe9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 2061 additions and 396 deletions

View File

@ -11,7 +11,7 @@ on:
jobs:
build:
runs-on: [self-hosted, Office]
runs-on: ubuntu-22.04
steps:
- name: Store UID
id: uid

3
.gitmodules vendored
View File

@ -7,3 +7,6 @@
[submodule "components/tinyusb/tinyusb"]
path = components/tinyusb/tinyusb
url = https://github.com/hathach/tinyusb
[submodule "components/dap-link/free-dap"]
path = components/dap-link/free-dap
url = https://github.com/ataradov/free-dap

View File

@ -24,7 +24,7 @@ bool network_gdb_connected(void);
void network_gdb_send(uint8_t* buffer, size_t size);
/* USB-CDC */
void usb_cdc_gdb_tx_char(uint8_t c, bool flush);
void usb_gdb_tx_char(uint8_t c, bool flush);
size_t gdb_glue_get_free_size(void) {
return xStreamBufferSpacesAvailable(gdb_glue.rx_stream);
@ -94,6 +94,6 @@ void gdb_if_putchar(unsigned char c, int flush) {
}
} else {
// Not sure why, but I could not get it to work with buffer
usb_cdc_gdb_tx_char(c, flush);
usb_gdb_tx_char(c, flush);
}
}

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "free-dap/dap.c"
PRIV_INCLUDE_DIRS "."
INCLUDE_DIRS "." "free-dap")

View File

@ -0,0 +1,195 @@
#pragma once
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2022, Alex Taradov <alex@taradov.com>. All rights reserved.
/*- Includes ----------------------------------------------------------------*/
#include <stdint.h>
#include <driver/gpio.h>
#include <rom/ets_sys.h>
#include <hal/gpio_ll.h>
#include <esp_rom_gpio.h>
/*- Definitions -------------------------------------------------------------*/
// #define DAP_CONFIG_ENABLE_JTAG
#define DAP_CONFIG_DEFAULT_PORT DAP_PORT_SWD
#define DAP_CONFIG_DEFAULT_CLOCK 8000000 // Hz
#define DAP_CONFIG_PACKET_SIZE 64
#define DAP_CONFIG_PACKET_COUNT 1
#define DAP_CONFIG_JTAG_DEV_COUNT 8
// DAP_CONFIG_PRODUCT_STR must contain "CMSIS-DAP" to be compatible with the standard
#define DAP_CONFIG_VENDOR_STR "Flipper Devices"
#define DAP_CONFIG_PRODUCT_STR "ESP32S2 CMSIS-DAP Adapter"
#define DAP_CONFIG_SER_NUM_STR dap_serial_number
#define DAP_CONFIG_CMSIS_DAP_VER_STR "2.0.0"
// Attribute to use for performance-critical functions
#define DAP_CONFIG_PERFORMANCE_ATTR IRAM_ATTR
// A value at which dap_clock_test() produces 1 kHz output on the SWCLK pin
#define DAP_CONFIG_DELAY_CONSTANT 24000
// A threshold for switching to fast clock (no added delays)
// This is the frequency produced by dap_clock_test(1) on the SWCLK pin
#define DAP_CONFIG_FAST_CLOCK 8000000 // Hz
#define ESP_SWCLK_PIN (1)
#define ESP_SWDIO_PIN (2)
/*- Prototypes --------------------------------------------------------------*/
void dap_callback_connect(void);
void dap_callback_disconnect(void);
extern char dap_serial_number[32];
/*- Implementations ---------------------------------------------------------*/
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_SWCLK_TCK_write(int value) {
if(value) {
GPIO.out_w1ts = (1 << ESP_SWCLK_PIN);
} else {
GPIO.out_w1tc = (1 << ESP_SWCLK_PIN);
}
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_SWDIO_TMS_write(int value) {
if(value) {
GPIO.out_w1ts = (1 << ESP_SWDIO_PIN);
} else {
GPIO.out_w1tc = (1 << ESP_SWDIO_PIN);
}
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_TDI_write(int value) {
// Do nothing
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_TDO_write(int value) {
// Do nothing
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_nTRST_write(int value) {
// Do nothing
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_nRESET_write(int value) {
// Do nothing
}
//-----------------------------------------------------------------------------
static inline int DAP_CONFIG_SWCLK_TCK_read(void) {
int level = (GPIO.in >> ESP_SWCLK_PIN) & 0x1;
return level;
}
//-----------------------------------------------------------------------------
static inline int DAP_CONFIG_SWDIO_TMS_read(void) {
int level = (GPIO.in >> ESP_SWDIO_PIN) & 0x1;
return level;
}
//-----------------------------------------------------------------------------
static inline int DAP_CONFIG_TDO_read(void) {
// Do nothing
return 0;
}
//-----------------------------------------------------------------------------
static inline int DAP_CONFIG_TDI_read(void) {
// Do nothing
return 0;
}
//-----------------------------------------------------------------------------
static inline int DAP_CONFIG_nTRST_read(void) {
// Do nothing
return 0;
}
//-----------------------------------------------------------------------------
static inline int DAP_CONFIG_nRESET_read(void) {
// Do nothing
return 0;
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_SWCLK_TCK_set(void) {
GPIO.out_w1ts = (1 << ESP_SWCLK_PIN);
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_SWCLK_TCK_clr(void) {
GPIO.out_w1tc = (1 << ESP_SWCLK_PIN);
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_SWDIO_TMS_in(void) {
gpio_ll_output_disable(&GPIO, ESP_SWDIO_PIN);
gpio_ll_input_enable(&GPIO, ESP_SWDIO_PIN);
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_SWDIO_TMS_out(void) {
GPIO.enable_w1ts = (0x1 << ESP_SWDIO_PIN);
esp_rom_gpio_connect_out_signal(ESP_SWDIO_PIN, SIG_GPIO_OUT_IDX, false, false);
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_SETUP(void) {
// since the blackmagic probe is not have connect and disconnect callbacks
// we can't enable the gpio
// gpio_ll_output_disable(&GPIO, ESP_SWDIO_PIN);
// gpio_ll_input_enable(&GPIO, ESP_SWDIO_PIN);
// gpio_ll_output_disable(&GPIO, ESP_SWCLK_PIN);
// gpio_ll_input_enable(&GPIO, ESP_SWCLK_PIN);
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_DISCONNECT(void) {
// since the blackmagic probe is not have connect and disconnect callbacks
// we can't disable the gpio
// gpio_ll_output_disable(&GPIO, ESP_SWDIO_PIN);
// gpio_ll_input_enable(&GPIO, ESP_SWDIO_PIN);
// gpio_ll_output_disable(&GPIO, ESP_SWCLK_PIN);
// gpio_ll_input_enable(&GPIO, ESP_SWCLK_PIN);
dap_callback_disconnect();
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_CONNECT_SWD(void) {
GPIO.enable_w1ts = (0x1 << ESP_SWDIO_PIN);
esp_rom_gpio_connect_out_signal(ESP_SWDIO_PIN, SIG_GPIO_OUT_IDX, false, false);
GPIO.enable_w1ts = (0x1 << ESP_SWCLK_PIN);
esp_rom_gpio_connect_out_signal(ESP_SWCLK_PIN, SIG_GPIO_OUT_IDX, false, false);
dap_callback_connect();
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_CONNECT_JTAG(void) {
// Do nothing
}
//-----------------------------------------------------------------------------
static inline void DAP_CONFIG_LED(int index, int state) {
// Do nothing
}
//-----------------------------------------------------------------------------
__attribute__((always_inline)) static inline void DAP_CONFIG_DELAY(uint32_t cycles) {
register int32_t cnt;
for(cnt = cycles; --cnt > 0;)
;
}

@ -0,0 +1 @@
Subproject commit e7752beb5e8a69119af67b70b9179cb3c90f3ac5

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@
let server = "";
if (development_mode) {
server = "http://192.168.31.81";
server = "http://172.30.1.223";
}
async function api_post(api, data) {
@ -36,6 +36,7 @@
let popup_message_text;
let mode_select;
let usb_mode_select;
let ap_ssid_input;
let ap_pass_input;
let sta_ssid_input;
@ -53,6 +54,7 @@
await api_post(server + "/api/v1/wifi/set_credentials", {
wifi_mode: mode_select.get_value(),
usb_mode: usb_mode_select.get_value(),
ap_ssid: ap_ssid_input.get_value(),
ap_pass: ap_pass_input.get_value(),
sta_ssid: sta_ssid_input.get_value(),
@ -138,34 +140,50 @@
<div class="grid">
{#await api_get(server + "/api/v1/wifi/get_credentials")}
<div class="value-name">Mode:</div>
<div><Spinner /></div>
<div class="value"><Spinner /></div>
<div class="value-name splitter">STA</div>
<div class="value mobile-hidden">(join another network)</div>
<div class="value-name">SSID:</div>
<div><Spinner /></div>
<div class="value"><Spinner /></div>
<div class="value-name">Pass:</div>
<div><Spinner /></div>
<div class="value"><Spinner /></div>
<div class="value-name splitter">AP</div>
<div class="value mobile-hidden">(own access point)</div>
<div class="value-name">SSID:</div>
<div><Spinner /></div>
<div class="value"><Spinner /></div>
<div class="value-name">Pass:</div>
<div><Spinner /></div>
<div>class="value"<Spinner /></div>
<div class="value-name">Hostname:</div>
<div><Spinner /></div>
<div class="value"><Spinner /></div>
<div class="value-name">USB mode:</div>
<div class="value"><Spinner /></div>
{:then json}
<div class="value-name">Mode:</div>
<div>
<div class="value">
<Select
bind:this={mode_select}
items={[
{ text: "STA (join another network)", value: "STA" },
{ text: "AP (own access point)", value: "AP" },
{ text: "Disabled (do not use WiFi)", value: "Disabled" },
]}
value={json.wifi_mode}
/>
</div>
<div class="value-name">STA</div>
<div>(join another network)</div>
<div class="value-name splitter">STA</div>
<div class="value mobile-hidden">(join another network)</div>
<div class="value-name">SSID:</div>
<div>
<div class="value">
<Input
value={json.sta_ssid}
bind:this={sta_ssid_input}
@ -173,26 +191,39 @@
</div>
<div class="value-name">Pass:</div>
<div>
<div class="value">
<Input value={json.sta_pass} bind:this={sta_pass_input} />
</div>
<div class="value-name">AP</div>
<div>(own access point)</div>
<div class="value-name splitter">AP</div>
<div class="value mobile-hidden">(own access point)</div>
<div class="value-name">SSID:</div>
<div>
<div class="value">
<Input value={json.ap_ssid} bind:this={ap_ssid_input} />
</div>
<div class="value-name">Pass:</div>
<div>
<div class="value">
<Input value={json.ap_pass} bind:this={ap_pass_input} />
</div>
<div class="value-name">Hostname:</div>
<div>
<div class="value">
<Input value={json.hostname} bind:this={hostname_input} />
</div>
<div class="value-name">USB mode:</div>
<div class="value">
<Select
bind:this={usb_mode_select}
items={[
{ text: "BlackMagicProbe", value: "BM" },
{ text: "DapLink", value: "DAP" },
]}
value={json.usb_mode}
/>
</div>
{:catch error}
<error>{error.message}</error>
{/await}
@ -209,24 +240,27 @@
<div class="grid">
{#await api_get(server + "/api/v1/system/info")}
<div class="value-name">IP:</div>
<div><Spinner /></div>
<div class="value"><Spinner /></div>
{:then json}
<div class="value-name">IP:</div>
<div>{print_ip(json.ip)}</div>
<div class="value">{print_ip(json.ip)}</div>
<div class="value-name">Mac:</div>
<div>{print_mac(json.mac)}</div>
<div class="value">{print_mac(json.mac)}</div>
<div class="value-name">IDF ver:</div>
<div>{json.idf_version}</div>
<div class="value">{json.idf_version}</div>
<div class="value-name">Model:</div>
<div>{json.model}.{json.revision} {json.cores}-core</div>
<div class="value">
{json.model}.{json.revision}
{json.cores}-core
</div>
<div class="value-name">Min free:</div>
<div>{json.heap.minimum_free_bytes}</div>
<div class="value">{json.heap.minimum_free_bytes}</div>
<div class="value-name">Free:</div>
<div>{json.heap.total_free_bytes}</div>
<div class="value">{json.heap.total_free_bytes}</div>
<div class="value-name">Alloc:</div>
<div>{json.heap.total_allocated_bytes}</div>
<div class="value">{json.heap.total_allocated_bytes}</div>
<div class="value-name">Max block:</div>
<div>{json.heap.largest_free_block}</div>
<div class="value">{json.heap.largest_free_block}</div>
{:catch error}
<error>{error.message}</error>
{/await}
@ -241,11 +275,11 @@
<span><Spinner /></span>
{:then json}
<task-list>
<span>Name</span>
<span>State</span>
<span>Handle</span>
<span>Stack base</span>
<span>WMRK</span>
<span class="mobile-hidden">Name</span>
<span class="mobile-hidden">State</span>
<span class="mobile-hidden">Handle</span>
<span class="mobile-hidden">Stack base</span>
<span class="mobile-hidden">WMRK</span>
{#each json.list.sort(function (a, b) {
return a.number - b.number;
}) as task}
@ -390,4 +424,59 @@
grid-template-columns: auto auto auto auto auto;
width: 100%;
}
@media (max-width: 768px) {
task-list {
grid-template-columns: auto auto auto auto;
}
task-list > span:nth-child(5n + 3) {
display: none;
}
}
@media (max-width: 600px) {
task-list {
grid-template-columns: auto auto auto;
}
task-list > span:nth-child(5n + 4) {
display: none;
}
}
@media (max-width: 520px) {
.grid {
grid-template-columns: auto;
width: 100%;
}
.mobile-hidden {
display: none;
}
.value-name {
text-align: left;
}
.splitter {
background-color: #000;
width: 100%;
color: #ffa21d;
text-align: center;
}
task-list {
grid-template-columns: auto;
text-align: center;
}
task-list > span:nth-child(5n + 1) {
padding-top: 10px;
}
task-list > span:nth-child(5n + 5) {
border-bottom: 4px dashed #000;
}
}
</style>

View File

@ -21,13 +21,12 @@
autocomplete="off"
type="text"
{value}
class="input-text-css"
size={value.length > 3 ? value.length : 3}
on:input={text_input}
/>
<style>
.input-text-css {
input {
display: inline-block;
color: #000;
font-size: 28px;
@ -47,9 +46,15 @@
height: 32px;
}
.input-text-css:focus-visible,
.input-text-css:hover {
input:focus-visible,
input:hover {
outline: 0;
background-color: white;
}
@media (max-width: 520px) {
input {
max-width: 100%;
}
}
</style>

View File

@ -55,4 +55,10 @@
select option {
font-weight: normal;
}
@media (max-width: 520px) {
select {
width: 100%;
}
}
</style>

View File

@ -1,13 +1,15 @@
idf_component_register(REQUIRES esp_rom app_update spi_flash freertos soc driver)
idf_component_get_property( FREERTOS_ORIG_INCLUDE_PATH freertos ORIG_INCLUDE_PATH)
idf_component_get_property(FREERTOS_ORIG_INCLUDE_PATH freertos ORIG_INCLUDE_PATH)
idf_build_get_property(idf_target IDF_TARGET)
if(${idf_target} STREQUAL "esp32s2")
target_compile_options(${COMPONENT_TARGET} INTERFACE
"-DCFG_TUSB_MCU=OPT_MCU_ESP32S2"
)
endif()
if(${idf_target} STREQUAL "esp32s3")
target_compile_options(${COMPONENT_TARGET} INTERFACE
"-DCFG_TUSB_MCU=OPT_MCU_ESP32S3"
@ -17,7 +19,8 @@ endif()
target_include_directories(${COMPONENT_TARGET} INTERFACE
"${FREERTOS_ORIG_INCLUDE_PATH}"
"${COMPONENT_DIR}/config/"
"${COMPONENT_DIR}/dual-cdc/"
"${COMPONENT_DIR}/drivers/"
"${COMPONENT_DIR}/drivers/dual-cdc/"
"${COMPONENT_DIR}/tinyusb/hw/bsp/"
"${COMPONENT_DIR}/tinyusb/src/"
"${COMPONENT_DIR}/tinyusb/src/device"
@ -52,6 +55,11 @@ target_sources(${COMPONENT_TARGET} INTERFACE
"${COMPONENT_DIR}/tinyusb/src/host/usbh.c"
"${COMPONENT_DIR}/tinyusb/src/host/usbh_control.c"
"${COMPONENT_DIR}/dual-cdc/dual-cdc-driver.c"
"${COMPONENT_DIR}/dual-cdc/usb_descriptors.c"
"${COMPONENT_DIR}/drivers/usb-glue.c"
# "${COMPONENT_DIR}/drivers/dual-cdc/dual-cdc-driver.c"
"${COMPONENT_DIR}/drivers/dual-cdc/dual-cdc-descriptors.c"
# "${COMPONENT_DIR}/drivers/dap-link/vendor_device.c"
"${COMPONENT_DIR}/drivers/dap-link/dap-link-descriptors.c"
)

View File

@ -126,7 +126,7 @@ extern "C" {
#define CFG_TUD_MSC CONFIG_ESPUSB_MSC
#define CFG_TUD_HID CONFIG_ESPUSB_HID
#define CFG_TUD_MIDI CONFIG_ESPUSB_MIDI
#define CFG_TUD_VENDOR CONFIG_ESPUSB_VENDOR
#define CFG_TUD_VENDOR 1
#define CFG_TUD_CUSTOM_CLASS CONFIG_ESPUSB_CUSTOM_CLASS
#define CFG_TUD_DFU_RT CONFIG_ESPUSB_DFU
@ -154,8 +154,8 @@ extern "C" {
//--------------------------------------------------------------------
// VENDOR FIFO CONFIGURATION
//--------------------------------------------------------------------
#define CFG_TUD_VENDOR_RX_BUFSIZE CONFIG_ESPUSB_VENDOR_RX_BUFSIZE
#define CFG_TUD_VENDOR_TX_BUFSIZE CONFIG_ESPUSB_VENDOR_TX_BUFSIZE
#define CFG_TUD_VENDOR_RX_BUFSIZE (CONFIG_ESPUSB_VENDOR_RX_BUFSIZE * 2)
#define CFG_TUD_VENDOR_TX_BUFSIZE (CONFIG_ESPUSB_VENDOR_TX_BUFSIZE * 2)
//--------------------------------------------------------------------
// MIDI FIFO CONFIGURATION

View File

@ -0,0 +1,375 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (c) 2022 Koji KITAYAMA
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. */
#include <tusb.h>
#include "dap-link-descriptors.h"
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const dap_link_desc_device = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0210, // at least 2.1 or 3.x for BOS & webUSB
// Use Interface Association Descriptor (IAD) for CDC
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0x303A, // USB_ESPRESSIF_VID,
.idProduct = 0x4002, // USB_TUSB_PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01,
};
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
enum {
ITF_NUM_CDC = 0,
ITF_NUM_CDC_DATA,
ITF_NUM_VENDOR,
ITF_NUM_TOTAL,
};
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_VENDOR_DESC_LEN)
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || \
CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
#define EPNUM_CDC_IN 2
#define EPNUM_CDC_OUT 2
#define EPNUM_VENDOR_IN 5
#define EPNUM_VENDOR_OUT 5
#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_CDC_IN 2
#define EPNUM_CDC_OUT 3
#define EPNUM_VENDOR_IN 4
#define EPNUM_VENDOR_OUT 5
#else
#define EPNUM_CDC_IN 2
#define EPNUM_CDC_OUT 2
#define EPNUM_VENDOR_IN 3
#define EPNUM_VENDOR_OUT 3
#endif
uint8_t const dap_link_desc_configuration[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(
1,
ITF_NUM_TOTAL,
0,
CONFIG_TOTAL_LEN,
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(
ITF_NUM_CDC,
4,
0x81,
8,
EPNUM_CDC_OUT,
0x80 | EPNUM_CDC_IN,
TUD_OPT_HIGH_SPEED ? 512 : 64),
// Interface number, string index, EP Out & IN address, EP size
TUD_VENDOR_DESCRIPTOR(
ITF_NUM_VENDOR,
5,
EPNUM_VENDOR_OUT,
0x80 | EPNUM_VENDOR_IN,
TUD_OPT_HIGH_SPEED ? 512 : 64),
};
//--------------------------------------------------------------------+
// 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.
GUID is freshly generated and should be OK to use.
https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/
(Section Microsoft OS compatibility descriptors)
*/
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
#define MS_OS_20_DESC_LEN 0xB2
// BOS Descriptor is required for webUSB
uint8_t const dap_link_desc_bos[] = {
// total length, number of device caps
TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2),
// Vendor Code, iLandingPage
TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1),
// Microsoft OS 2.0 descriptor
TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT),
};
TU_VERIFY_STATIC(sizeof(dap_link_desc_bos) == BOS_TOTAL_LEN, "Incorrect size");
uint8_t const dap_link_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_VENDOR,
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}”.
'{',
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(dap_link_desc_ms_os_20) == MS_OS_20_DESC_LEN, "Incorrect size");
static char* string_desc_arr[] = {
(char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
"CMSIS-DAP", // 1: Manufacturer
"CMSIS-DAP ESP32S2 Device", // 2: Product
"DAP", // 3: Serials, should use chip ID
"CMSIS-DAP CDC", // 4: CDC Interface
"CMSIS-DAP DAP" // 5: Vendor Interface
};
void dap_link_set_serial_number(const char* serial_number) {
string_desc_arr[3] = malloc(strlen("DAP_") + strlen(serial_number) + 1);
strcpy(string_desc_arr[3], "DAP_");
strcat(string_desc_arr[3], serial_number);
}
static uint16_t _desc_str[32];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* dap_link_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void)langid;
uint8_t chr_count;
if(index == 0) {
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
} else {
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if(!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) return NULL;
const char* str = string_desc_arr[index];
// Cap at max char
chr_count = (uint8_t)strlen(str);
if(chr_count > 31) chr_count = 31;
// Convert ASCII string into UTF-16
for(uint8_t i = 0; i < chr_count; i++) {
_desc_str[1 + i] = str[i];
}
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}

View File

@ -0,0 +1,10 @@
#include <tusb.h>
enum { VENDOR_REQUEST_WEBUSB = 1, VENDOR_REQUEST_MICROSOFT = 2 };
extern tusb_desc_device_t const dap_link_desc_device;
extern uint8_t const dap_link_desc_configuration[];
extern uint8_t const dap_link_desc_bos[];
extern uint8_t const dap_link_desc_ms_os_20[];
uint16_t const* dap_link_descriptor_string_cb(uint8_t index, uint16_t langid);
void dap_link_set_serial_number(const char* serial_number);

View File

@ -0,0 +1,257 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (c) 2022 Koji KITAYAMA
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. */
#include "tusb_option.h"
#include "device/usbd.h"
#include "device/usbd_pvt.h"
#include "vendor_device.h"
// #include "DAP_config.h"
// #include "DAP.h"
#define DAP_PACKET_SIZE 64U
#define DAP_PACKET_COUNT 8U
#define ID_DAP_QueueCommands 0x7EU
#define ID_DAP_ExecuteCommands 0x7FU
#define ID_DAP_TransferAbort 0x07U
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
typedef struct {
uint8_t itf_num;
uint8_t ep_in;
uint8_t ep_out;
/*------------- From this point, data is not cleared by bus reset -------------*/
uint8_t request_wp;
uint8_t request_rp;
uint8_t response_wp;
uint8_t response_rp;
uint8_t epout_sz[DAP_PACKET_COUNT];
uint8_t epin_sz[DAP_PACKET_COUNT];
// Endpoint Transfer buffer
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[DAP_PACKET_COUNT][CFG_TUD_VENDOR_EPSIZE];
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[DAP_PACKET_COUNT][CFG_TUD_VENDOR_EPSIZE];
} vendord_interface_t;
CFG_TUSB_MEM_SECTION static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR];
#define ITF_MEM_RESET_SIZE offsetof(vendord_interface_t, epout_sz)
bool tud_vendor_n_mounted(uint8_t itf) {
return _vendord_itf[itf].ep_in && _vendord_itf[itf].ep_out;
}
//--------------------------------------------------------------------+
// Read API
//--------------------------------------------------------------------+
static void _prep_out_transaction(vendord_interface_t* p_itf) {
uint8_t const rhport = 0;
// skip if previous transfer not complete
if(usbd_edpt_busy(rhport, p_itf->ep_out)) return;
unsigned occupancy = p_itf->request_wp - p_itf->request_rp;
if(occupancy < DAP_PACKET_COUNT) {
unsigned idx = p_itf->request_wp % DAP_PACKET_COUNT;
usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf[idx], CFG_TUD_VENDOR_EPSIZE);
}
}
uint32_t tud_vendor_n_acquire_request_buffer(uint8_t itf, const uint8_t** pbuf) {
TU_ASSERT(pbuf, 0);
vendord_interface_t* p_itf = &_vendord_itf[itf];
uint8_t rp = p_itf->request_rp;
uint8_t wp = p_itf->request_wp;
if(wp == rp) return 0;
unsigned idx = rp % DAP_PACKET_COUNT;
unsigned n = idx;
// Check if the last packet was received.
while((wp != rp) && (p_itf->epout_buf[n][0] == ID_DAP_QueueCommands)) {
++rp;
++n;
if(n == DAP_PACKET_COUNT) n = 0U;
}
if(wp == rp) // not received
return 0;
// Replace consecutive QueueCommands to ExecuteCommands
rp = p_itf->request_rp;
n = idx;
while((wp != rp) && (p_itf->epout_buf[n][0] == ID_DAP_QueueCommands)) {
p_itf->epout_buf[n][0] = ID_DAP_ExecuteCommands;
++rp;
++n;
if(n == DAP_PACKET_COUNT) n = 0U;
}
*pbuf = p_itf->epout_buf[idx];
return p_itf->epout_sz[idx];
}
void tud_vendor_n_release_request_buffer(uint8_t itf) {
vendord_interface_t* p_itf = &_vendord_itf[itf];
++p_itf->request_rp;
_prep_out_transaction(p_itf);
}
//--------------------------------------------------------------------+
// Write API
//--------------------------------------------------------------------+
static void maybe_transmit(vendord_interface_t* p_itf) {
uint8_t const rhport = 0;
// skip if previous transfer not complete
TU_VERIFY(!usbd_edpt_busy(rhport, p_itf->ep_in), );
if(p_itf->response_wp != p_itf->response_rp) {
unsigned idx = p_itf->response_rp % DAP_PACKET_COUNT;
TU_ASSERT(
usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf[idx], p_itf->epin_sz[idx]), );
++p_itf->response_rp;
}
}
uint32_t tud_vendor_n_acquire_response_buffer(uint8_t itf, uint8_t** pbuf) {
TU_ASSERT(pbuf, 0);
vendord_interface_t* p_itf = &_vendord_itf[itf];
unsigned occupancy = p_itf->response_wp - p_itf->response_rp;
if(occupancy < DAP_PACKET_COUNT) {
unsigned idx = p_itf->response_wp % DAP_PACKET_COUNT;
*pbuf = p_itf->epin_buf[idx];
return DAP_PACKET_SIZE;
}
return 0;
}
void tud_vendor_n_release_response_buffer(uint8_t itf, uint32_t bufsize) {
vendord_interface_t* p_itf = &_vendord_itf[itf];
unsigned idx = p_itf->response_wp % DAP_PACKET_COUNT;
p_itf->epin_sz[idx] = bufsize;
++p_itf->response_wp;
maybe_transmit(p_itf);
}
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
void vendord_init(void) {
tu_memclr(_vendord_itf, sizeof(_vendord_itf));
}
void vendord_reset(uint8_t rhport) {
(void)rhport;
for(uint8_t i = 0; i < CFG_TUD_VENDOR; i++) {
vendord_interface_t* p_itf = &_vendord_itf[i];
tu_memclr(p_itf, ITF_MEM_RESET_SIZE);
}
}
uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const* desc_itf, uint16_t max_len) {
TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0);
uint8_t const* p_desc = tu_desc_next(desc_itf);
uint8_t const* desc_end = p_desc + max_len;
// Find available interface
vendord_interface_t* p_vendor = NULL;
for(uint8_t i = 0; i < CFG_TUD_VENDOR; i++) {
if(_vendord_itf[i].ep_in == 0 && _vendord_itf[i].ep_out == 0) {
p_vendor = &_vendord_itf[i];
break;
}
}
TU_VERIFY(p_vendor, 0);
p_vendor->itf_num = desc_itf->bInterfaceNumber;
if(desc_itf->bNumEndpoints) {
// skip non-endpoint descriptors
while((TUSB_DESC_ENDPOINT != tu_desc_type(p_desc)) && (p_desc < desc_end)) {
p_desc = tu_desc_next(p_desc);
}
// Open endpoint pair with usbd helper
TU_ASSERT(
usbd_open_edpt_pair(
rhport,
p_desc,
desc_itf->bNumEndpoints,
TUSB_XFER_BULK,
&p_vendor->ep_out,
&p_vendor->ep_in),
0);
p_desc += desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t);
// Prepare for incoming data
if(p_vendor->ep_out) {
TU_ASSERT(
usbd_edpt_xfer(
rhport, p_vendor->ep_out, p_vendor->epout_buf[0], sizeof(p_vendor->epout_buf)),
0);
}
if(p_vendor->ep_in) maybe_transmit(p_vendor);
}
return (uint16_t)((uintptr_t)p_desc - (uintptr_t)desc_itf);
}
bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
(void)rhport;
(void)result;
uint8_t itf = 0;
vendord_interface_t* p_itf = _vendord_itf;
for(;; itf++, p_itf++) {
if(itf >= TU_ARRAY_SIZE(_vendord_itf)) return false;
if((ep_addr == p_itf->ep_out) || (ep_addr == p_itf->ep_in)) break;
}
if(ep_addr == p_itf->ep_out) {
if(xferred_bytes) {
unsigned idx = p_itf->request_wp % DAP_PACKET_COUNT;
p_itf->epout_sz[idx] = xferred_bytes;
if(ID_DAP_TransferAbort == p_itf->epout_buf[idx][0]) {
if(tud_vendor_transfer_abort_cb) tud_vendor_transfer_abort_cb(itf);
} else {
++p_itf->request_wp;
}
}
_prep_out_transaction(p_itf);
} else if(ep_addr == p_itf->ep_in) {
// Send complete, try to send more if possible
maybe_transmit(p_itf);
}
return true;
}

View File

@ -0,0 +1,97 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (c) 2022 Koji KITAYAMA
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. */
#ifndef _TUSB_VENDOR_DEVICE_H_
#define _TUSB_VENDOR_DEVICE_H_
#include "common/tusb_common.h"
#ifndef CFG_TUD_VENDOR_EPSIZE
#define CFG_TUD_VENDOR_EPSIZE 64
#endif
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// Application API (Multiple Interfaces)
//--------------------------------------------------------------------+
bool tud_vendor_n_mounted(uint8_t itf);
uint32_t tud_vendor_n_acquire_request_buffer(uint8_t itf, const uint8_t** pbuf);
void tud_vendor_n_release_request_buffer(uint8_t itf);
uint32_t tud_vendor_n_acquire_response_buffer(uint8_t itf, uint8_t** pbuf);
void tud_vendor_n_release_response_buffer(uint8_t itf, uint32_t bufsize);
//--------------------------------------------------------------------+
// Application API (Single Port)
//--------------------------------------------------------------------+
static inline bool tud_vendor_mounted(void);
static inline uint32_t tud_vendor_acquire_request_buffer(const uint8_t** pbuf);
static inline void tud_vendor_release_request_buffer(void);
static inline uint32_t tud_vendor_acquire_response_buffer(uint8_t** pbuf);
static inline void tud_vendor_release_response_buffer(uint32_t bufsize);
//--------------------------------------------------------------------+
// Application Callback API (weak is optional)
//--------------------------------------------------------------------+
// Invoked when received new data
TU_ATTR_WEAK void tud_vendor_transfer_abort_cb(uint8_t itf);
//--------------------------------------------------------------------+
// Inline Functions
//--------------------------------------------------------------------+
static inline bool tud_vendor_mounted(void) {
return tud_vendor_n_mounted(0);
}
static inline uint32_t tud_vendor_acquire_request_buffer(const uint8_t** pbuf) {
return tud_vendor_n_acquire_request_buffer(0, pbuf);
}
static inline void tud_vendor_release_request_buffer(void) {
return tud_vendor_n_release_request_buffer(0);
}
static inline uint32_t tud_vendor_acquire_response_buffer(uint8_t** pbuf) {
return tud_vendor_n_acquire_response_buffer(0, pbuf);
}
static inline void tud_vendor_release_response_buffer(uint32_t bufsize) {
return tud_vendor_n_release_response_buffer(0, bufsize);
}
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
void vendord_init(void);
void vendord_reset(uint8_t rhport);
uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const* itf_desc, uint16_t max_len);
bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_VENDOR_DEVICE_H_ */

View File

@ -55,12 +55,6 @@ tusb_desc_device_t const blackmagic_desc_device = {
.bNumConfigurations = 0x01,
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const* tud_descriptor_device_cb(void) {
return (uint8_t const*)&blackmagic_desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
@ -149,28 +143,13 @@ uint8_t const blackmagic_desc_hs_configuration[] = {
};
#endif
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const* tud_descriptor_configuration_cb(uint8_t index) {
(void)index; // for multiple configurations
#if TUD_OPT_HIGH_SPEED
// Although we are highspeed, host may be fullspeed.
return (tud_speed_get() == TUSB_SPEED_HIGH) ? blackmagic_desc_hs_configuration :
blackmagic_desc_fs_configuration;
#else
return blackmagic_desc_fs_configuration;
#endif
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* blackmagic_string_desc[] = {
(const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
static char* blackmagic_string_desc[] = {
(char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
"Flipper Devices Inc.", // 1: Manufacturer
"Blackmagic ESP32", // 2: Product
"blackmagic", // 3: Serials, should use chip ID
@ -179,12 +158,18 @@ char const* blackmagic_string_desc[] = {
"", // 6: HIDs
};
void blackmagic_set_serial_number(const char* serial_number) {
blackmagic_string_desc[3] = malloc(strlen("blackmagic_") + strlen(serial_number) + 1);
strcpy(blackmagic_string_desc[3], "blackmagic_");
strcat(blackmagic_string_desc[3], serial_number);
}
#define MAX_DESC_BUF_SIZE 32
static uint16_t _desc_str[MAX_DESC_BUF_SIZE];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
uint16_t const* blackmagic_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void)langid;
uint8_t chr_count;

View File

@ -0,0 +1,6 @@
#include <tusb.h>
extern tusb_desc_device_t const blackmagic_desc_device;
extern uint8_t const blackmagic_desc_fs_configuration[];
uint16_t const* blackmagic_descriptor_string_cb(uint8_t index, uint16_t langid);
void blackmagic_set_serial_number(const char* serial_number);

View File

@ -0,0 +1,449 @@
#include <tusb.h>
#include "dap-link/dap-link-descriptors.h"
#include "dual-cdc/dual-cdc-descriptors.h"
#include "usb-glue.h"
#define TAG "usb-glue"
#define CONFIG_TINYUSB_TASK_STACK_SIZE 4096
#define CONFIG_TINYUSB_TASK_PRIORITY 17
typedef struct {
uint8_t const* desc_device;
uint8_t const* desc_config;
uint16_t const* (*desc_string_cb)(uint8_t, uint16_t);
} USBDevice;
const USBDevice usb_device[] = {
[USBDeviceTypeDapLink] =
{
.desc_device = (uint8_t const*)&dap_link_desc_device,
.desc_config = dap_link_desc_configuration,
.desc_string_cb = dap_link_descriptor_string_cb,
},
[USBDeviceTypeDualCDC] =
{
.desc_device = (uint8_t const*)&blackmagic_desc_device,
.desc_config = blackmagic_desc_fs_configuration,
.desc_string_cb = blackmagic_descriptor_string_cb,
},
};
static USBDeviceType usb_device_type = USBDeviceTypeDualCDC;
typedef enum {
BlackmagicCDCTypeGDB = 0,
BlackmagicCDCTypeUART = 1,
} BlackmagicCDCType;
typedef enum {
DapCDCTypeUART = 0,
} DapCDCType;
typedef struct {
void (*connected)(void* context);
void* connected_context;
void (*disconnected)(void* context);
void* disconnected_context;
void (*cdc_receive)(void* context);
void* cdc_receive_context;
void (*cdc_line_coding)(cdc_line_coding_t const* p_line_coding, void* context);
void* cdc_line_coding_context;
void (*cdc_line_state)(bool dtr, bool rts, void* context);
void* cdc_line_state_context;
void (*gdb_receive)(void* context);
void* gdb_receive_context;
void (*dap_receive)(void* context);
void* dap_receive_context;
} USBGlueCallbacks;
static USBGlueCallbacks callbacks = {
.connected = NULL,
.connected_context = NULL,
.disconnected = NULL,
.disconnected_context = NULL,
.cdc_receive = NULL,
.cdc_receive_context = NULL,
.cdc_line_coding = NULL,
.cdc_line_coding_context = NULL,
.cdc_line_state = NULL,
.cdc_line_state_context = NULL,
.gdb_receive = NULL,
.gdb_receive_context = NULL,
.dap_receive = NULL,
.dap_receive_context = NULL,
};
/***** Callbacks *****/
static void callback_connected(void) {
if(callbacks.connected) {
callbacks.connected(callbacks.connected_context);
}
}
static void callback_disconnected(void) {
if(callbacks.disconnected) {
callbacks.disconnected(callbacks.disconnected_context);
}
}
static void callback_cdc_receive() {
if(callbacks.cdc_receive) {
callbacks.cdc_receive(callbacks.cdc_receive_context);
}
}
static void callback_cdc_line_coding(cdc_line_coding_t const* p_line_coding) {
if(callbacks.cdc_line_coding) {
callbacks.cdc_line_coding(p_line_coding, callbacks.cdc_line_coding_context);
}
}
static void callback_cdc_line_state(bool dtr, bool rts) {
if(callbacks.cdc_line_state) {
callbacks.cdc_line_state(dtr, rts, callbacks.cdc_line_state_context);
}
}
static void callback_gdb_receive() {
if(callbacks.gdb_receive) {
callbacks.gdb_receive(callbacks.gdb_receive_context);
}
}
static void callback_dap_receive() {
if(callbacks.dap_receive) {
callbacks.dap_receive(callbacks.dap_receive_context);
}
}
/***** Tiny USB *****/
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const* tud_descriptor_device_cb(void) {
return usb_device[usb_device_type].desc_device;
}
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const* tud_descriptor_configuration_cb(uint8_t index) {
(void)index; // for multiple configurations
return usb_device[usb_device_type].desc_config;
}
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
return usb_device[usb_device_type].desc_string_cb(index, langid);
}
uint8_t const* tud_descriptor_bos_cb(void) {
// return NULL;
return dap_link_desc_bos;
}
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->bRequest) {
case VENDOR_REQUEST_MICROSOFT:
if(request->wIndex == 7) {
// Get Microsoft OS 2.0 compatible descriptor
uint16_t total_len;
memcpy(&total_len, dap_link_desc_ms_os_20 + 8, 2);
return tud_control_xfer(rhport, request, (void*)dap_link_desc_ms_os_20, total_len);
} else {
return false;
}
default:
// stall unknown request
return false;
}
return true;
}
void tud_vendor_rx_cb(uint8_t itf) {
(void)itf;
callback_dap_receive();
}
void tud_mount_cb(void) {
callback_connected();
}
void tud_umount_cb(void) {
callback_disconnected();
}
void tud_resume_cb(void) {
callback_connected();
}
void tud_suspend_cb(bool remote_wakeup_en) {
callback_disconnected();
}
void tud_cdc_rx_cb(uint8_t interface) {
do {
if(usb_device_type == USBDeviceTypeDualCDC) {
if(interface == BlackmagicCDCTypeGDB) {
callback_gdb_receive();
break;
} else if(interface == BlackmagicCDCTypeUART) {
callback_cdc_receive();
break;
}
} else if(usb_device_type == USBDeviceTypeDapLink) {
if(interface == DapCDCTypeUART) {
callback_cdc_receive();
break;
}
}
tud_cdc_n_read_flush(interface);
} while(false);
}
void tud_cdc_line_state_cb(uint8_t interface, bool dtr, bool rts) {
if(usb_device_type == USBDeviceTypeDualCDC) {
if(interface == BlackmagicCDCTypeUART) {
callback_cdc_line_state(dtr, rts);
}
} else if(usb_device_type == USBDeviceTypeDapLink) {
if(interface == DapCDCTypeUART) {
callback_cdc_line_state(dtr, rts);
}
}
}
void tud_cdc_line_coding_cb(uint8_t interface, cdc_line_coding_t const* p_line_coding) {
if(usb_device_type == USBDeviceTypeDualCDC) {
if(interface == BlackmagicCDCTypeUART) {
callback_cdc_line_coding(p_line_coding);
}
} else if(usb_device_type == USBDeviceTypeDapLink) {
if(interface == DapCDCTypeUART) {
callback_cdc_line_coding(p_line_coding);
}
}
}
/***** HAL *****/
#include <driver/gpio.h>
#include <driver/periph_ctrl.h>
#include <hal/usb_hal.h>
#include <soc/usb_periph.h>
#include <esp_rom_gpio.h>
#include <hal/gpio_ll.h>
#include <delay.h>
#include <esp_log.h>
#include <esp_check.h>
static void usb_hal_init_pins(usb_hal_context_t* usb) {
/* usb_periph_iopins currently configures USB_OTG as USB Device.
* Introduce additional parameters in usb_hal_context_t when adding support
* for USB Host.
*/
for(const usb_iopin_dsc_t* iopin = usb_periph_iopins; iopin->pin != -1; ++iopin) {
if((usb->use_external_phy) || (iopin->ext_phy_only == 0)) {
esp_rom_gpio_pad_select_gpio(iopin->pin);
if(iopin->is_output) {
esp_rom_gpio_connect_out_signal(iopin->pin, iopin->func, false, false);
} else {
esp_rom_gpio_connect_in_signal(iopin->pin, iopin->func, false);
if((iopin->pin != GPIO_FUNC_IN_LOW) && (iopin->pin != GPIO_FUNC_IN_HIGH)) {
gpio_ll_input_enable(&GPIO, iopin->pin);
}
}
esp_rom_gpio_pad_unhold(iopin->pin);
}
}
if(!usb->use_external_phy) {
gpio_set_drive_capability(USBPHY_DM_NUM, GPIO_DRIVE_CAP_3);
gpio_set_drive_capability(USBPHY_DP_NUM, GPIO_DRIVE_CAP_3);
}
}
static void usb_hal_bus_reset() {
gpio_config_t io_conf;
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT_OD;
io_conf.pin_bit_mask = ((1 << USBPHY_DM_NUM) | (1 << USBPHY_DP_NUM));
io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
gpio_config(&io_conf);
gpio_set_level(USBPHY_DM_NUM, 0);
gpio_set_level(USBPHY_DP_NUM, 0);
delay(100);
gpio_set_level(USBPHY_DM_NUM, 1);
gpio_set_level(USBPHY_DP_NUM, 1);
}
static void usb_hal_tusb_device_task(void* arg) {
ESP_LOGD(TAG, "tinyusb task started");
while(1) { // RTOS forever loop
tud_task();
}
}
/***** Glue *****/
char* serial_desc = NULL;
char dap_serial_number[32];
static void usb_glue_set_serial_number(uint8_t* serial_number, uint8_t length) {
if(serial_desc != NULL) {
free(serial_desc);
}
serial_desc = malloc(length * 2 + 1);
for(uint8_t i = 0; i < length; i++) {
uint8_t nibble = serial_number[i] >> 4;
serial_desc[i * 2 + 0] = nibble < 10 ? '0' + nibble : 'A' + nibble - 10;
nibble = serial_number[i] & 0x0F;
serial_desc[i * 2 + 1] = nibble < 10 ? '0' + nibble : 'A' + nibble - 10;
}
serial_desc[length * 2] = 0;
}
const char* usb_glue_get_serial_number() {
return serial_desc;
}
esp_err_t usb_glue_init(USBDeviceType device_type) {
usb_device_type = device_type;
uint8_t mac[8] = {0, 0, 0, 0, 0, 0, 0, 0};
if(esp_efuse_mac_get_default(mac) == ESP_OK) {
usb_glue_set_serial_number(mac, 6);
dap_link_set_serial_number(usb_glue_get_serial_number());
blackmagic_set_serial_number(usb_glue_get_serial_number());
strncpy(dap_serial_number, usb_glue_get_serial_number(), sizeof(dap_serial_number) - 1);
dap_serial_number[sizeof(dap_serial_number) - 1] = '\0';
ESP_LOGI(TAG, "Serial number: %s", usb_glue_get_serial_number());
ESP_LOGI(TAG, "Dap serial number: %s", dap_serial_number);
}
usb_hal_bus_reset();
// Enable APB CLK to USB peripheral
periph_module_enable(PERIPH_USB_MODULE);
periph_module_reset(PERIPH_USB_MODULE);
// Initialize HAL layer
usb_hal_context_t hal = {.use_external_phy = false};
usb_hal_init(&hal);
usb_hal_init_pins(&hal);
ESP_RETURN_ON_FALSE(tusb_init(), ESP_FAIL, TAG, "init TinyUSB failed");
TaskHandle_t s_tusb_tskh;
xTaskCreate(
usb_hal_tusb_device_task,
"TinyUSB",
CONFIG_TINYUSB_TASK_STACK_SIZE,
NULL,
CONFIG_TINYUSB_TASK_PRIORITY,
&s_tusb_tskh);
ESP_RETURN_ON_FALSE(s_tusb_tskh, ESP_FAIL, TAG, "create TinyUSB main task failed");
ESP_LOGI(TAG, "TinyUSB Driver installed");
return ESP_OK;
}
void usb_glue_reset_bus() {
usb_hal_bus_reset();
}
void usb_glue_set_connected_callback(void (*callback)(void* context), void* context) {
callbacks.connected = callback;
callbacks.connected_context = context;
}
void usb_glue_set_disconnected_callback(void (*callback)(void* context), void* context) {
callbacks.disconnected = callback;
callbacks.disconnected_context = context;
}
void usb_glue_cdc_set_receive_callback(void (*callback)(void* context), void* context) {
callbacks.cdc_receive = callback;
callbacks.cdc_receive_context = context;
}
void usb_glue_cdc_set_line_coding_callback(
void (*callback)(cdc_line_coding_t const* p_line_coding, void* context),
void* context) {
callbacks.cdc_line_coding = callback;
callbacks.cdc_line_coding_context = context;
}
void usb_glue_cdc_set_line_state_callback(
void (*callback)(bool dtr, bool rts, void* context),
void* context) {
callbacks.cdc_line_state = callback;
callbacks.cdc_line_state_context = context;
}
void usb_glue_gdb_set_receive_callback(void (*callback)(void* context), void* context) {
callbacks.gdb_receive = callback;
callbacks.gdb_receive_context = context;
}
void usb_glue_dap_set_receive_callback(void (*callback)(void* context), void* context) {
callbacks.dap_receive = callback;
callbacks.dap_receive_context = context;
}
void usb_glue_cdc_send(const uint8_t* buf, size_t len, bool flush) {
if(usb_device_type == USBDeviceTypeDualCDC) {
tud_cdc_n_write(BlackmagicCDCTypeUART, buf, len);
if(flush) {
tud_cdc_n_write_flush(BlackmagicCDCTypeUART);
}
} else {
tud_cdc_n_write(DapCDCTypeUART, buf, len);
if(flush) {
tud_cdc_n_write_flush(DapCDCTypeUART);
}
}
}
size_t usb_glue_cdc_receive(uint8_t* buf, size_t len) {
return tud_cdc_n_read(BlackmagicCDCTypeUART, buf, len);
}
void usb_glue_gdb_send(const uint8_t* buf, size_t len, bool flush) {
if(usb_device_type == USBDeviceTypeDualCDC) {
tud_cdc_n_write(BlackmagicCDCTypeGDB, buf, len);
if(flush) {
tud_cdc_n_write_flush(BlackmagicCDCTypeGDB);
}
} else {
esp_system_abort("Wrong USB device type");
}
}
size_t usb_glue_gdb_receive(uint8_t* buf, size_t len) {
return tud_cdc_n_read(BlackmagicCDCTypeGDB, buf, len);
}
void usb_glue_dap_send(const uint8_t* buf, size_t len, bool flush) {
if(usb_device_type == USBDeviceTypeDapLink) {
tud_vendor_write(buf, len);
} else {
esp_system_abort("Wrong USB device type");
}
}
size_t usb_glue_dap_receive(uint8_t* buf, size_t len) {
return tud_vendor_read(buf, len);
}

View File

@ -0,0 +1,54 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <esp_err.h>
#include <tusb.h>
typedef enum {
USBDeviceTypeDapLink,
USBDeviceTypeDualCDC,
} USBDeviceType;
/***** Common *****/
esp_err_t usb_glue_init(USBDeviceType device_type);
void usb_glue_reset_bus();
void usb_glue_set_connected_callback(void (*callback)(void* context), void* context);
void usb_glue_set_disconnected_callback(void (*callback)(void* context), void* context);
const char* usb_glue_get_serial_number();
/***** USB-UART *****/
void usb_glue_cdc_send(const uint8_t* buf, size_t len, bool flush);
void usb_glue_cdc_set_receive_callback(void (*callback)(void* context), void* context);
size_t usb_glue_cdc_receive(uint8_t* buf, size_t len);
void usb_glue_cdc_set_line_coding_callback(
void (*callback)(cdc_line_coding_t const* p_line_coding, void* context),
void* context);
void usb_glue_cdc_set_line_state_callback(
void (*callback)(bool dtr, bool rts, void* context),
void* context);
/***** USB-GDB *****/
void usb_glue_gdb_send(const uint8_t* buf, size_t len, bool flush);
void usb_glue_gdb_set_receive_callback(void (*callback)(void* context), void* context);
size_t usb_glue_gdb_receive(uint8_t* buf, size_t len);
/***** USB-DAP *****/
void usb_glue_dap_send(const uint8_t* buf, size_t len, bool flush);
void usb_glue_dap_set_receive_callback(void (*callback)(void* context), void* context);
size_t usb_glue_dap_receive(uint8_t* buf, size_t len);

View File

@ -1,76 +0,0 @@
#include <tusb.h>
#include <class/cdc/cdc_device.h>
#include <driver/gpio.h>
#include <driver/periph_ctrl.h>
#include <hal/usb_hal.h>
#include <soc/gpio_periph.h>
#include <soc/usb_periph.h>
#include <esp_rom_gpio.h>
#include <hal/gpio_ll.h>
#include <esp_log.h>
#include <esp_check.h>
#include "dual-cdc-driver.h"
#define TAG "usb-dual-cdc"
#define CONFIG_TINYUSB_TASK_STACK_SIZE 4096
#define CONFIG_TINYUSB_TASK_PRIORITY 17
static void configure_pins(usb_hal_context_t* usb) {
/* usb_periph_iopins currently configures USB_OTG as USB Device.
* Introduce additional parameters in usb_hal_context_t when adding support
* for USB Host.
*/
for(const usb_iopin_dsc_t* iopin = usb_periph_iopins; iopin->pin != -1; ++iopin) {
if((usb->use_external_phy) || (iopin->ext_phy_only == 0)) {
esp_rom_gpio_pad_select_gpio(iopin->pin);
if(iopin->is_output) {
esp_rom_gpio_connect_out_signal(iopin->pin, iopin->func, false, false);
} else {
esp_rom_gpio_connect_in_signal(iopin->pin, iopin->func, false);
if((iopin->pin != GPIO_FUNC_IN_LOW) && (iopin->pin != GPIO_FUNC_IN_HIGH)) {
gpio_ll_input_enable(&GPIO, iopin->pin);
}
}
esp_rom_gpio_pad_unhold(iopin->pin);
}
}
if(!usb->use_external_phy) {
gpio_set_drive_capability(USBPHY_DM_NUM, GPIO_DRIVE_CAP_3);
gpio_set_drive_capability(USBPHY_DP_NUM, GPIO_DRIVE_CAP_3);
}
}
static void tusb_device_task(void* arg) {
ESP_LOGD(TAG, "tinyusb task started");
while(1) { // RTOS forever loop
tud_task();
}
}
esp_err_t dual_cdc_driver_install(void) {
// Enable APB CLK to USB peripheral
periph_module_enable(PERIPH_USB_MODULE);
periph_module_reset(PERIPH_USB_MODULE);
// Initialize HAL layer
usb_hal_context_t hal = {.use_external_phy = false};
usb_hal_init(&hal);
configure_pins(&hal);
ESP_RETURN_ON_FALSE(tusb_init(), ESP_FAIL, TAG, "init TinyUSB failed");
TaskHandle_t s_tusb_tskh;
xTaskCreate(
tusb_device_task,
"TinyUSB",
CONFIG_TINYUSB_TASK_STACK_SIZE,
NULL,
CONFIG_TINYUSB_TASK_PRIORITY,
&s_tusb_tskh);
ESP_RETURN_ON_FALSE(s_tusb_tskh, ESP_FAIL, TAG, "create TinyUSB main task failed");
ESP_LOGI(TAG, "TinyUSB Driver installed");
return ESP_OK;
}

View File

@ -1,22 +0,0 @@
/**
* @file dual-cdc-driver.h
* @author Sergey Gavrilov (who.just.the.doctor@gmail.com)
* @version 1.0
* @date 2021-12-16
*
* Dual CDC driver
*/
#pragma once
#include <stdint.h>
#include <esp_err.h>
#include <tusb_config.h>
#define CDC_IF_COUNT CFG_TUD_CDC
/**
*
* @return esp_err_t
*/
esp_err_t dual_cdc_driver_install(void);

View File

@ -1,6 +1,6 @@
set(SOURCES
set(SOURCES
"main.c"
"usb-cdc.c"
"usb.c"
"usb-uart.c"
"nvs.c"
"nvs-config.c"
@ -23,12 +23,12 @@ set(SOURCES
"factory-reset-service.c"
)
set(INCLUDES
set(INCLUDES
"."
)
idf_component_register(SRCS ${SOURCES}
INCLUDE_DIRS ${INCLUDES})
INCLUDE_DIRS ${INCLUDES})
# Commit
execute_process(

View File

@ -9,6 +9,7 @@
void cli_config_get(Cli* cli, mstring_t* args) {
mstring_t* value = mstring_alloc();
WiFiMode wifi_mode;
UsbMode usb_mode;
nvs_config_get_ap_ssid(value);
cli_printf(cli, "ap_ssid: %s", mstring_get_cstr(value));
@ -33,24 +34,45 @@ void cli_config_get(Cli* cli, mstring_t* args) {
nvs_config_get_wifi_mode(&wifi_mode);
switch(wifi_mode) {
case WiFiModeAP:
mstring_set(value, "AP");
mstring_set(value, CFG_WIFI_MODE_AP);
break;
case WiFiModeSTA:
mstring_set(value, "STA");
mstring_set(value, CFG_WIFI_MODE_STA);
break;
case WiFiModeDisabled:
mstring_set(value, CFG_WIFI_MODE_DISABLED);
break;
}
cli_printf(cli, "wifi_mode: %s", mstring_get_cstr(value));
cli_write_eol(cli);
nvs_config_get_usb_mode(&usb_mode);
switch(usb_mode) {
case UsbModeBM:
mstring_set(value, CFG_USB_MODE_BM);
break;
case UsbModeDAP:
mstring_set(value, CFG_USB_MODE_DAP);
break;
}
cli_printf(cli, "usb_mode: %s", mstring_get_cstr(value));
mstring_free(value);
}
void cli_config_set_wifi_mode_usage(Cli* cli) {
cli_write_str(cli, "config_set_wifi_mode <AP|STA>");
static void cli_config_set_wifi_mode_usage(Cli* cli) {
cli_write_str(
cli,
"config_set_wifi_mode"
" <" CFG_WIFI_MODE_AP "|" CFG_WIFI_MODE_STA "|" CFG_WIFI_MODE_DISABLED ">");
cli_write_eol(cli);
cli_write_str(cli, " AP (make own WiFi AP)");
cli_write_str(cli, " " CFG_WIFI_MODE_AP " (make own WiFi AP)");
cli_write_eol(cli);
cli_write_str(cli, " STA (connect to WiFi)");
cli_write_str(cli, " " CFG_WIFI_MODE_STA " (connect to WiFi)");
cli_write_eol(cli);
cli_write_str(cli, " " CFG_WIFI_MODE_DISABLED " (disable WiFi)");
cli_write_eol(cli);
}
@ -64,10 +86,12 @@ void cli_config_set_wifi_mode(Cli* cli, mstring_t* args) {
break;
}
if(mstring_cmp_cstr(mode, "AP") == 0) {
if(mstring_cmp_cstr(mode, CFG_WIFI_MODE_AP) == 0) {
wifi_mode = WiFiModeAP;
} else if(mstring_cmp_cstr(mode, "STA") == 0) {
} else if(mstring_cmp_cstr(mode, CFG_WIFI_MODE_STA) == 0) {
wifi_mode = WiFiModeSTA;
} else if(mstring_cmp_cstr(mode, CFG_WIFI_MODE_DISABLED) == 0) {
wifi_mode = WiFiModeDisabled;
} else {
cli_config_set_wifi_mode_usage(cli);
break;
@ -85,6 +109,46 @@ void cli_config_set_wifi_mode(Cli* cli, mstring_t* args) {
mstring_free(mode);
}
static void cli_config_set_usb_mode_usage(Cli* cli) {
cli_write_str(cli, "config_set_usb_mode <" CFG_USB_MODE_BM "|" CFG_USB_MODE_DAP ">");
cli_write_eol(cli);
cli_write_str(cli, " " CFG_USB_MODE_BM " (Black Magic Probe mode)");
cli_write_eol(cli);
cli_write_str(cli, " " CFG_USB_MODE_DAP " (DAPLink mode)");
cli_write_eol(cli);
}
void cli_config_set_usb_mode(Cli* cli, mstring_t* args) {
mstring_t* mode = mstring_alloc();
UsbMode usb_mode;
do {
if(!cli_args_read_string_and_trim(args, mode)) {
cli_config_set_usb_mode_usage(cli);
break;
}
if(mstring_cmp_cstr(mode, CFG_USB_MODE_BM) == 0) {
usb_mode = UsbModeBM;
} else if(mstring_cmp_cstr(mode, CFG_USB_MODE_DAP) == 0) {
usb_mode = UsbModeDAP;
} else {
cli_config_set_usb_mode_usage(cli);
break;
}
if(nvs_config_set_usb_mode(usb_mode) == ESP_OK) {
cli_write_str(cli, "OK");
cli_write_eol(cli);
cli_write_str(cli, "Reboot to apply");
} else {
cli_write_str(cli, "ERR");
}
} while(false);
mstring_free(mode);
}
void cli_config_set_ap_pass(Cli* cli, mstring_t* args) {
mstring_t* pass = mstring_alloc();

View File

@ -24,6 +24,7 @@ void cli_wifi_sta_info(Cli* cli, mstring_t* args);
void cli_config_get(Cli* cli, mstring_t* args);
void cli_config_set_wifi_mode(Cli* cli, mstring_t* args);
void cli_config_set_usb_mode(Cli* cli, mstring_t* args);
void cli_config_set_ap_pass(Cli* cli, mstring_t* args);
void cli_config_set_ap_ssid(Cli* cli, mstring_t* args);
void cli_config_set_sta_pass(Cli* cli, mstring_t* args);
@ -54,6 +55,11 @@ const CliItem cli_items[] = {
"set Wi-Fi mode, AP (own access point) or STA (join another network), requires a reboot to apply",
.callback = cli_config_set_wifi_mode,
},
{
.name = "config_set_usb_mode",
.desc = "set USB mode, requires a reboot to apply",
.callback = cli_config_set_usb_mode,
},
{
.name = "config_set_ap_pass",
.desc = "set AP mode password, requires a reboot to apply",

View File

@ -4,7 +4,7 @@
#include <freertos/task.h>
#include <rom/ets_sys.h>
#include "usb-cdc.h"
#include "usb.h"
#include "nvs.h"
#include "gdb_main.h"
#include "led.h"
@ -67,7 +67,7 @@ void app_main(void) {
// network_uart_server_init();
network_gdb_server_init();
usb_cdc_init();
usb_init();
cli_uart_init();
// TODO uart and i2c share the same pins, need switching mechanics

View File

@ -16,6 +16,7 @@
#include <lwip/netdb.h>
#include "led.h"
#include "usb.h"
#include "delay.h"
#include "network-gdb.h"
#include <gdb-glue.h>
@ -136,21 +137,28 @@ static void network_gdb_server_task(void* pvParameters) {
ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str);
led_set_blue(255);
delay(10);
led_set_blue(0);
// continue only if DAP-Link is not connected
if(!dap_is_connected()) {
led_set_blue(255);
delay(10);
led_set_blue(0);
network_gdb.socket_id = sock;
network_gdb.connected = true;
ESP_LOGI(TAG, "DAP-Link is connected, not accepting connection");
receive_and_send_to_gdb();
network_gdb.socket_id = sock;
network_gdb.connected = true;
network_gdb.connected = false;
network_gdb.socket_id = -1;
receive_and_send_to_gdb();
led_set_blue(255);
delay(10);
led_set_blue(0);
network_gdb.connected = false;
network_gdb.socket_id = -1;
led_set_blue(255);
delay(10);
led_set_blue(0);
} else {
ESP_LOGE(TAG, "DAP-Link is connected, not accepting connection");
}
shutdown(sock, 0);
close(sock);

View File

@ -307,8 +307,10 @@ static esp_err_t wifi_get_credentials_handler(httpd_req_t* req) {
mstring_t* sta_pass = mstring_alloc();
mstring_t* hostname = mstring_alloc();
WiFiMode wifi_mode;
UsbMode usb_mode;
nvs_config_get_wifi_mode(&wifi_mode);
nvs_config_get_usb_mode(&usb_mode);
nvs_config_get_ap_ssid(ap_ssid);
nvs_config_get_ap_pass(ap_pass);
nvs_config_get_sta_ssid(sta_ssid);
@ -328,6 +330,18 @@ static esp_err_t wifi_get_credentials_handler(httpd_req_t* req) {
case WiFiModeSTA:
cJSON_AddStringToObject(root, "wifi_mode", CFG_WIFI_MODE_STA);
break;
case WiFiModeDisabled:
cJSON_AddStringToObject(root, "wifi_mode", CFG_WIFI_MODE_DISABLED);
break;
}
switch(usb_mode) {
case UsbModeBM:
cJSON_AddStringToObject(root, "usb_mode", CFG_USB_MODE_BM);
break;
case UsbModeDAP:
cJSON_AddStringToObject(root, "usb_mode", CFG_USB_MODE_DAP);
break;
}
const char* json_text = cJSON_Print(root);
@ -352,6 +366,7 @@ static esp_err_t wifi_set_credentials_handler(httpd_req_t* req) {
mstring_t* sta_ssid = mstring_alloc();
mstring_t* sta_pass = mstring_alloc();
mstring_t* wifi_mode = mstring_alloc();
mstring_t* usb_mode = mstring_alloc();
mstring_t* hostname = mstring_alloc();
const char* error_text = JSON_ERROR("unknown error");
int received = 0;
@ -413,6 +428,14 @@ static esp_err_t wifi_set_credentials_handler(httpd_req_t* req) {
goto err_fail;
}
if(cJSON_GetObjectItem(root, "usb_mode") != NULL) {
mstring_set(usb_mode, cJSON_GetObjectItem(root, "usb_mode")->valuestring);
} else {
cJSON_Delete(root);
error_text = JSON_ERROR("request dont have [usb_mode] field");
goto err_fail;
}
if(cJSON_GetObjectItem(root, "hostname") != NULL) {
mstring_set(hostname, cJSON_GetObjectItem(root, "hostname")->valuestring);
} else {
@ -423,10 +446,16 @@ static esp_err_t wifi_set_credentials_handler(httpd_req_t* req) {
cJSON_Delete(root);
if(strcmp(mstring_get_cstr(wifi_mode), CFG_WIFI_MODE_AP) != 0 &&
strcmp(mstring_get_cstr(wifi_mode), CFG_WIFI_MODE_STA) != 0) {
strcmp(mstring_get_cstr(wifi_mode), CFG_WIFI_MODE_STA) != 0 &&
strcmp(mstring_get_cstr(wifi_mode), CFG_WIFI_MODE_DISABLED) != 0) {
error_text = JSON_ERROR("invalid value in [wifi_mode]");
goto err_fail;
}
if(strcmp(mstring_get_cstr(usb_mode), CFG_USB_MODE_BM) != 0 &&
strcmp(mstring_get_cstr(usb_mode), CFG_USB_MODE_DAP) != 0) {
error_text = JSON_ERROR("invalid value in [usb_mode]");
goto err_fail;
}
if(nvs_config_set_ap_ssid(ap_ssid) != ESP_OK) {
error_text = JSON_ERROR("invalid value in [ap_ssid]");
@ -447,12 +476,29 @@ static esp_err_t wifi_set_credentials_handler(httpd_req_t* req) {
if(strcmp(mstring_get_cstr(wifi_mode), CFG_WIFI_MODE_AP) == 0) {
if(nvs_config_set_wifi_mode(WiFiModeAP) != ESP_OK) {
error_text = JSON_ERROR("invalid value in [sta_pass]");
error_text = JSON_ERROR("cannot set [wifi_mode]");
goto err_fail;
}
} else if(strcmp(mstring_get_cstr(wifi_mode), CFG_WIFI_MODE_DISABLED) == 0) {
if(nvs_config_set_wifi_mode(WiFiModeDisabled) != ESP_OK) {
error_text = JSON_ERROR("cannot set [wifi_mode]");
goto err_fail;
}
} else {
if(nvs_config_set_wifi_mode(WiFiModeSTA) != ESP_OK) {
error_text = JSON_ERROR("invalid value in [sta_pass]");
error_text = JSON_ERROR("cannot set [wifi_mode]");
goto err_fail;
}
}
if(strcmp(mstring_get_cstr(usb_mode), CFG_USB_MODE_DAP) == 0) {
if(nvs_config_set_usb_mode(UsbModeDAP) != ESP_OK) {
error_text = JSON_ERROR("cannot set [usb_mode]");
goto err_fail;
}
} else {
if(nvs_config_set_usb_mode(UsbModeBM) != ESP_OK) {
error_text = JSON_ERROR("cannot set [usb_mode]");
goto err_fail;
}
}
@ -469,6 +515,7 @@ static esp_err_t wifi_set_credentials_handler(httpd_req_t* req) {
mstring_free(sta_ssid);
mstring_free(sta_pass);
mstring_free(wifi_mode);
mstring_free(usb_mode);
mstring_free(hostname);
return ESP_OK;

View File

@ -201,6 +201,8 @@ WiFiMode network_init(void) {
nvs_config_get_sta_pass(pass);
network_connect_ap(ssid, pass);
break;
case WiFiModeDisabled:
break;
}
mstring_free(ssid);

View File

@ -9,6 +9,8 @@
#define WIFI_STA_PASS_KEY "wifi_sta_pass"
#define WIFI_HOSTNAME "wifi_hostname"
#define USB_MODE_KEY "usb_mode"
#define ESP_WIFI_DEFAULT_SSID "blackmagic"
#define ESP_WIFI_DEFAULT_PASS "iamwitcher"
#define ESP_WIFI_DEFAULT_HOSTNAME "blackmagic"
@ -23,6 +25,9 @@ esp_err_t nvs_config_set_wifi_mode(WiFiMode value) {
case WiFiModeSTA:
mstring_set(mode, CFG_WIFI_MODE_STA);
break;
case WiFiModeDisabled:
mstring_set(mode, CFG_WIFI_MODE_DISABLED);
break;
}
esp_err_t err = nvs_save_string(WIFI_MODE_KEY, mode);
@ -31,6 +36,24 @@ esp_err_t nvs_config_set_wifi_mode(WiFiMode value) {
return err;
}
esp_err_t nvs_config_set_usb_mode(UsbMode value) {
mstring_t* mode = mstring_alloc();
switch(value) {
case UsbModeBM:
mstring_set(mode, CFG_USB_MODE_BM);
break;
case UsbModeDAP:
mstring_set(mode, CFG_USB_MODE_DAP);
break;
}
esp_err_t err = nvs_save_string(USB_MODE_KEY, mode);
mstring_free(mode);
return err;
}
esp_err_t nvs_config_set_ap_ssid(const mstring_t* ssid) {
esp_err_t err = ESP_FAIL;
@ -87,6 +110,8 @@ esp_err_t nvs_config_get_wifi_mode(WiFiMode* value) {
if(err == ESP_OK && mstring_cmp_cstr(mode, CFG_WIFI_MODE_STA) == 0) {
*value = WiFiModeSTA;
} else if(err == ESP_OK && mstring_cmp_cstr(mode, CFG_WIFI_MODE_DISABLED) == 0) {
*value = WiFiModeDisabled;
} else {
// AP mode by default
*value = WiFiModeAP;
@ -96,6 +121,21 @@ esp_err_t nvs_config_get_wifi_mode(WiFiMode* value) {
return err;
}
esp_err_t nvs_config_get_usb_mode(UsbMode* value) {
mstring_t* mode = mstring_alloc();
esp_err_t err = nvs_load_string(USB_MODE_KEY, mode);
if(err == ESP_OK && mstring_cmp_cstr(mode, CFG_USB_MODE_DAP) == 0) {
*value = UsbModeDAP;
} else {
// USB mode by default
*value = UsbModeBM;
}
mstring_free(mode);
return err;
}
esp_err_t nvs_config_get_ap_ssid(mstring_t* ssid) {
esp_err_t err = nvs_load_string(WIFI_AP_SSID_KEY, ssid);

View File

@ -13,13 +13,24 @@
#define CFG_WIFI_MODE_AP "AP"
#define CFG_WIFI_MODE_STA "STA"
#define CFG_WIFI_MODE_DISABLED "Disabled"
#define CFG_USB_MODE_BM "BM"
#define CFG_USB_MODE_DAP "DAP"
typedef enum {
UsbModeBM, // Blackmagic-probe
UsbModeDAP, // Dap-link
} UsbMode;
typedef enum {
WiFiModeAP, // host of a WiFi network
WiFiModeSTA, // connected to existing WiFi AP
WiFiModeDisabled, // disabled
} WiFiMode;
esp_err_t nvs_config_set_wifi_mode(WiFiMode value);
esp_err_t nvs_config_set_usb_mode(UsbMode value);
esp_err_t nvs_config_set_ap_ssid(const mstring_t* ssid);
esp_err_t nvs_config_set_ap_pass(const mstring_t* pass);
esp_err_t nvs_config_set_sta_ssid(const mstring_t* ssid);
@ -27,6 +38,7 @@ esp_err_t nvs_config_set_sta_pass(const mstring_t* pass);
esp_err_t nvs_config_set_hostname(const mstring_t* hostname);
esp_err_t nvs_config_get_wifi_mode(WiFiMode* value);
esp_err_t nvs_config_get_usb_mode(UsbMode* value);
esp_err_t nvs_config_get_ap_ssid(mstring_t* ssid);
esp_err_t nvs_config_get_ap_pass(mstring_t* pass);
esp_err_t nvs_config_get_sta_ssid(mstring_t* ssid);

View File

@ -1,182 +0,0 @@
/**
* @file usb-cdc.c
* Do not forget to take pid's when implement own USB device class
*
* https://github.com/espressif/usb-pids
*
*/
#include <stdint.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/stream_buffer.h>
#include <sdkconfig.h>
#include <driver/gpio.h>
#include "usb-cdc.h"
#include "usb-uart.h"
#include "led.h"
#include "delay.h"
#include <gdb-glue.h>
#include <dual-cdc-driver.h>
#include <class/cdc/cdc_device.h>
#define USB_DN_PIN (19)
#define USB_DP_PIN (20)
#define GDB_BUF_RX_SIZE 64
#define UART_BUF_RX_SIZE 64
static const char* TAG = "usb-cdc";
static uint8_t gdb_buffer_rx[GDB_BUF_RX_SIZE];
static uint8_t uart_buffer_rx[UART_BUF_RX_SIZE];
typedef struct {
volatile bool connected;
} USBCDC;
static USBCDC usb_cdc;
typedef enum {
CDCTypeGDB = 0,
CDCTypeUART = 1,
} CDCType;
static void usb_cdc_tx_char(CDCType type, uint8_t c, bool flush) {
tud_cdc_n_write(type, &c, 1);
if(flush) {
tud_cdc_n_write_flush(type);
}
}
void usb_cdc_gdb_tx_char(uint8_t c, bool flush) {
usb_cdc_tx_char(CDCTypeGDB, c, flush);
}
void usb_cdc_uart_tx_char(uint8_t c, bool flush) {
usb_cdc_tx_char(CDCTypeUART, c, flush);
}
void usb_cdc_gdb_rx_callback(void) {
if(gdb_glue_can_receive()) {
size_t max_len = gdb_glue_get_free_size();
if(max_len > GDB_BUF_RX_SIZE) max_len = GDB_BUF_RX_SIZE;
uint32_t rx_size = tud_cdc_n_read(CDCTypeGDB, gdb_buffer_rx, max_len);
if(rx_size > 0) {
gdb_glue_receive(gdb_buffer_rx, rx_size);
}
} else {
esp_system_abort("No free space in GDB buffer");
}
}
void usb_cdc_uart_rx_callback(void) {
size_t max_len = gdb_glue_get_free_size();
if(max_len > UART_BUF_RX_SIZE) max_len = UART_BUF_RX_SIZE;
uint32_t rx_size = tud_cdc_n_read(CDCTypeUART, uart_buffer_rx, max_len);
if(rx_size > 0) {
usb_uart_write(uart_buffer_rx, rx_size);
}
}
void tud_cdc_rx_cb(uint8_t interface) {
do {
if(interface == CDCTypeGDB) {
usb_cdc_gdb_rx_callback();
} else if(interface == CDCTypeUART) {
usb_cdc_uart_rx_callback();
} else {
tud_cdc_n_read_flush(interface);
}
} while(false);
}
void tud_cdc_line_state_cb(uint8_t interface, bool dtr, bool rts) {
if(interface == CDCTypeUART) {
usb_uart_set_line_state(dtr, rts);
}
}
void tud_cdc_line_coding_cb(uint8_t interface, cdc_line_coding_t const* p_line_coding) {
uint32_t bit_rate = p_line_coding->bit_rate;
uint8_t stop_bits = p_line_coding->stop_bits;
uint8_t parity = p_line_coding->parity;
uint8_t data_bits = p_line_coding->data_bits;
if(interface == CDCTypeUART) {
usb_uart_set_line_coding(bit_rate, stop_bits, parity, data_bits);
}
}
//--------------------------------------------------------------------+
// Device callbacks
//--------------------------------------------------------------------+
static void usb_cdc_event_blink(void) {
led_set_blue(255);
delay(10);
led_set_blue(0);
}
static void usb_cdc_to_connected(void) {
if(!usb_cdc.connected) {
usb_cdc_event_blink();
}
usb_cdc.connected = true;
ESP_LOGI(TAG, "connect");
}
static void usb_cdc_from_connected(void) {
if(usb_cdc.connected) {
usb_cdc_event_blink();
}
usb_cdc.connected = false;
ESP_LOGI(TAG, "disconnect");
}
void tud_mount_cb(void) {
usb_cdc_to_connected();
}
void tud_umount_cb(void) {
usb_cdc_from_connected();
}
void tud_resume_cb(void) {
usb_cdc_to_connected();
}
void tud_suspend_cb(bool remote_wakeup_en) {
usb_cdc_from_connected();
}
static void usb_cdc_bus_reset() {
gpio_config_t io_conf;
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT_OD;
io_conf.pin_bit_mask = ((1 << USB_DN_PIN) | (1 << USB_DP_PIN));
io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
gpio_config(&io_conf);
gpio_set_level(USB_DN_PIN, 0);
gpio_set_level(USB_DP_PIN, 0);
delay(100);
gpio_set_level(USB_DN_PIN, 1);
gpio_set_level(USB_DP_PIN, 1);
}
void usb_cdc_init(void) {
ESP_LOGI(TAG, "init");
usb_cdc.connected = false;
usb_uart_init();
usb_cdc_bus_reset();
dual_cdc_driver_install();
ESP_LOGI(TAG, "init done");
}

View File

@ -1,10 +0,0 @@
#pragma once
/**
* Init usb subsystem
*/
void usb_cdc_init(void);
void usb_cdc_gdb_tx_char(uint8_t c, bool flush);
void usb_cdc_uart_tx_char(uint8_t c, bool flush);

View File

@ -3,7 +3,7 @@
#include <freertos/task.h>
#include <freertos/stream_buffer.h>
#include <esp_log.h>
#include "usb-cdc.h"
#include "usb.h"
#include "usb-uart.h"
#define USB_UART_PORT_NUM UART_NUM_0
@ -41,9 +41,6 @@ void usb_uart_init() {
};
simple_uart_init(&config);
usb_uart_write((const uint8_t*)"Go", 2);
ESP_LOGI(TAG, "init done");
}
@ -129,9 +126,9 @@ static void usb_uart_rx_task(void* pvParameters) {
if(length > 0) {
for(size_t i = 0; i < length; i++) {
if((i + 1) == length) {
usb_cdc_uart_tx_char(data[i], true);
usb_uart_tx_char(data[i], true);
} else {
usb_cdc_uart_tx_char(data[i], false);
usb_uart_tx_char(data[i], false);
}
}
}

224
main/usb.c Normal file
View File

@ -0,0 +1,224 @@
/**
* @file usb.c
* Do not forget to take pid's when implement own USB device class
*
* https://github.com/espressif/usb-pids
*
*/
#include <stdint.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/stream_buffer.h>
#include <sdkconfig.h>
#include <driver/gpio.h>
#include "usb.h"
#include "usb-uart.h"
#include "led.h"
#include "delay.h"
#include "nvs-config.h"
#include <gdb-glue.h>
#include <usb-glue.h>
#include <class/cdc/cdc_device.h>
#define USB_DN_PIN (19)
#define USB_DP_PIN (20)
#define GDB_BUF_RX_SIZE 64
#define UART_BUF_RX_SIZE 64
static const char* TAG = "usb";
static uint8_t gdb_buffer_rx[GDB_BUF_RX_SIZE];
static uint8_t uart_buffer_rx[UART_BUF_RX_SIZE];
typedef struct {
volatile bool connected;
} UsbState;
static UsbState usb_state;
void usb_gdb_tx_char(uint8_t c, bool flush) {
usb_glue_gdb_send(&c, 1, flush);
}
void usb_uart_tx_char(uint8_t c, bool flush) {
usb_glue_cdc_send(&c, 1, flush);
}
static void usb_gdb_rx_callback(void* context) {
if(gdb_glue_can_receive()) {
size_t max_len = gdb_glue_get_free_size();
if(max_len > GDB_BUF_RX_SIZE) max_len = GDB_BUF_RX_SIZE;
uint32_t rx_size = usb_glue_gdb_receive(gdb_buffer_rx, max_len);
if(rx_size > 0) {
gdb_glue_receive(gdb_buffer_rx, rx_size);
}
} else {
esp_system_abort("No free space in GDB buffer");
}
}
static void usb_uart_rx_callback(void* context) {
size_t max_len = gdb_glue_get_free_size();
if(max_len > UART_BUF_RX_SIZE) max_len = UART_BUF_RX_SIZE;
uint32_t rx_size = usb_glue_cdc_receive(uart_buffer_rx, max_len);
if(rx_size > 0) {
usb_uart_write(uart_buffer_rx, rx_size);
}
}
static void usb_line_state_cb(bool dtr, bool rts, void* context) {
usb_uart_set_line_state(dtr, rts);
}
static void usb_set_line_coding_callback(cdc_line_coding_t const* p_line_coding, void* context) {
uint32_t bit_rate = p_line_coding->bit_rate;
uint8_t stop_bits = p_line_coding->stop_bits;
uint8_t parity = p_line_coding->parity;
uint8_t data_bits = p_line_coding->data_bits;
usb_uart_set_line_coding(bit_rate, stop_bits, parity, data_bits);
}
//--------------------------------------------------------------------+
// Device callbacks
//--------------------------------------------------------------------+
static void usb_event_blink(void) {
led_set_blue(255);
delay(10);
led_set_blue(0);
}
static void usb_to_connected(void* context) {
if(!usb_state.connected) {
usb_event_blink();
}
usb_state.connected = true;
ESP_LOGI(TAG, "connect");
}
static void usb_from_connected(void* context) {
if(usb_state.connected) {
usb_event_blink();
}
usb_state.connected = false;
ESP_LOGI(TAG, "disconnect");
}
#define CONFIG_DAP_TASK_STACK_SIZE 4096
#define CONFIG_DAP_TASK_PRIORITY 5
#define DAP_RECEIVE_FLAG (1 << 0)
#define DAP_TAG "dap_task"
#include "dap.h"
#include "dap_config.h"
#include "network-gdb.h"
TaskHandle_t dap_task_handle;
bool dap_link_connected = false;
static void dap_rx_callback(void* context) {
xTaskNotify(dap_task_handle, DAP_RECEIVE_FLAG, eSetBits);
}
void dap_callback_connect(void) {
ESP_LOGI(DAP_TAG, "connected");
led_set(0, 0, 0);
dap_link_connected = true;
}
void dap_callback_disconnect(void) {
ESP_LOGI(DAP_TAG, "disconnected");
led_set(255, 0, 0);
dap_link_connected = false;
}
bool dap_is_connected(void) {
return dap_link_connected;
}
static void dap_task(void* arg) {
ESP_LOGI(DAP_TAG, "started");
uint32_t notified_value;
size_t counter = 0;
dap_init();
while(1) {
BaseType_t xResult = xTaskNotifyWait(pdFALSE, ULONG_MAX, &notified_value, portMAX_DELAY);
if(xResult == pdPASS) {
// continue only if network-gdb is not connected
if(!network_gdb_connected()) {
if((notified_value & DAP_RECEIVE_FLAG) != 0) {
uint8_t rx_data[DAP_CONFIG_PACKET_SIZE];
uint8_t tx_data[DAP_CONFIG_PACKET_SIZE];
memset(tx_data, 0, DAP_CONFIG_PACKET_SIZE);
memset(rx_data, 0, DAP_CONFIG_PACKET_SIZE);
if(counter % 512 == 0) {
led_set_blue(255);
} else if(counter % 512 == 256) {
led_set_blue(0);
}
size_t rx_size = usb_glue_dap_receive(rx_data, sizeof(rx_data));
size_t tx_size =
dap_process_request(rx_data, rx_size, tx_data, sizeof(tx_data));
usb_glue_dap_send(tx_data, tx_size, true);
counter++;
}
} else {
ESP_LOGE(TAG, "GDB is connected, DAP is disabled");
}
}
}
}
static void usb_dap_init() {
ESP_LOGI(DAP_TAG, "init");
xTaskCreate(
dap_task,
"dap_thread",
CONFIG_DAP_TASK_STACK_SIZE,
NULL,
CONFIG_DAP_TASK_PRIORITY,
&dap_task_handle);
ESP_LOGI(DAP_TAG, "init done");
}
void usb_init(void) {
ESP_LOGI(TAG, "init");
// TODO get from config
UsbMode usb_mode = UsbModeBM;
nvs_config_get_usb_mode(&usb_mode);
usb_glue_set_connected_callback(usb_to_connected, NULL);
usb_glue_set_disconnected_callback(usb_from_connected, NULL);
usb_glue_cdc_set_line_coding_callback(usb_set_line_coding_callback, NULL);
usb_glue_cdc_set_line_state_callback(usb_line_state_cb, NULL);
usb_glue_cdc_set_receive_callback(usb_uart_rx_callback, NULL);
if(usb_mode == UsbModeBM) {
usb_glue_gdb_set_receive_callback(usb_gdb_rx_callback, NULL);
usb_state.connected = false;
usb_uart_init();
usb_glue_init(USBDeviceTypeDualCDC);
} else {
usb_glue_dap_set_receive_callback(dap_rx_callback, NULL);
usb_state.connected = false;
usb_uart_init();
usb_dap_init();
usb_glue_init(USBDeviceTypeDapLink);
}
ESP_LOGI(TAG, "init done");
}

12
main/usb.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
/**
* Init usb subsystem
*/
void usb_init(void);
void usb_gdb_tx_char(uint8_t c, bool flush);
void usb_uart_tx_char(uint8_t c, bool flush);
bool dap_is_connected(void);