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:
parent
473bdd4d09
commit
b182ceffe9
|
@ -11,7 +11,7 @@ on:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: [self-hosted, Office]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Store UID
|
||||
id: uid
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
idf_component_register(SRCS "free-dap/dap.c"
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
INCLUDE_DIRS "." "free-dap")
|
|
@ -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
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -55,4 +55,10 @@
|
|||
select option {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
@media (max-width: 520px) {
|
||||
select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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(
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
182
main/usb-cdc.c
182
main/usb-cdc.c
|
@ -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");
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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, ¬ified_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");
|
||||
}
|
|
@ -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);
|
Loading…
Reference in New Issue