diff --git a/.gitmodules b/.gitmodules index d3328a2..cd6fcde 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "components/mlib/mlib"] path = components/mlib/mlib url = https://github.com/P-p-H-d/mlib.git +[submodule "components/tinyusb/tinyusb"] + path = components/tinyusb/tinyusb + url = https://github.com/hathach/tinyusb diff --git a/components/blackmagic/esp32-platform/gdb-glue.c b/components/blackmagic/esp32-platform/gdb-glue.c index 457e9d4..86f3cfe 100644 --- a/components/blackmagic/esp32-platform/gdb-glue.c +++ b/components/blackmagic/esp32-platform/gdb-glue.c @@ -24,7 +24,7 @@ bool network_gdb_connected(void); void network_gdb_send(uint8_t* buffer, size_t size); /* USB-CDC */ -void usb_cdc_tx_char(uint8_t c, bool flush); +void usb_cdc_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_tx_char(c, flush); + usb_cdc_gdb_tx_char(c, flush); } } \ No newline at end of file diff --git a/components/simple-uart/CMakeLists.txt b/components/simple-uart/CMakeLists.txt new file mode 100644 index 0000000..be69461 --- /dev/null +++ b/components/simple-uart/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "simple-uart.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/components/simple-uart/simple-uart.c b/components/simple-uart/simple-uart.c new file mode 100644 index 0000000..1ca861f --- /dev/null +++ b/components/simple-uart/simple-uart.c @@ -0,0 +1,189 @@ +#include +#include +#include +#include + +#include +#include + +#include "simple-uart.h" + +/***********************************************/ + +typedef struct { + uart_hal_context_t hal; /*!< UART hal context*/ + uint8_t uart_index; + void* isr_context; + uart_isr rx_isr; +} uart_context_t; + +#define UART_CONTEX_INIT_DEF(uart_num) \ + { \ + .hal.dev = UART_LL_GET_HW(uart_num), .uart_index = uart_num, .isr_context = NULL, \ + .rx_isr = NULL \ + } + +static uart_context_t uart_context[UART_NUM_MAX] = { + UART_CONTEX_INIT_DEF(UART_NUM_0), + UART_CONTEX_INIT_DEF(UART_NUM_1), +#if UART_NUM_MAX > 2 + UART_CONTEX_INIT_DEF(UART_NUM_2), +#endif +}; + +#define UART_HAL(uart_num) &(uart_context[uart_num].hal) + +/***********************************************/ + +#define UART_FIFO_LIMIT (UART_LL_FIFO_DEF_LEN) +#define UART_TX_FIFO_THRESH 0x1 +#define UART_RX_FIFO_THRESH 0x16 + +static void simple_uart_isr(void* arg); + +static void simple_uart_init_pins(uint8_t uart_num, int tx_pin_num, int rx_pin_num) { + if(tx_pin_num >= 0) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[tx_pin_num], PIN_FUNC_GPIO); + gpio_set_level(tx_pin_num, 1); + esp_rom_gpio_connect_out_signal( + tx_pin_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0); + } + + if(rx_pin_num >= 0) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rx_pin_num], PIN_FUNC_GPIO); + gpio_set_pull_mode(rx_pin_num, GPIO_PULLUP_ONLY); + gpio_set_direction(rx_pin_num, GPIO_MODE_INPUT); + esp_rom_gpio_connect_in_signal( + rx_pin_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), 0); + } +} + +static void simple_uart_init_module(uint8_t uart_num) { + periph_module_enable(uart_periph_signal[uart_num].module); + periph_module_reset(uart_periph_signal[uart_num].module); +} + +void simple_uart_init(UartConfig* cfg) { + uart_context[cfg->uart_num].rx_isr = cfg->rx_isr; + uart_context[cfg->uart_num].isr_context = cfg->isr_context; + + simple_uart_init_pins(cfg->uart_num, cfg->tx_pin_num, cfg->rx_pin_num); + simple_uart_init_module(cfg->uart_num); + + uart_hal_set_sclk(UART_HAL(cfg->uart_num), UART_SCLK_APB); + uart_hal_set_rxfifo_full_thr(UART_HAL(cfg->uart_num), UART_RX_FIFO_THRESH); + uart_hal_set_txfifo_empty_thr(UART_HAL(cfg->uart_num), UART_TX_FIFO_THRESH); + uart_hal_rxfifo_rst(UART_HAL(cfg->uart_num)); + uart_hal_set_hw_flow_ctrl(UART_HAL(cfg->uart_num), UART_HW_FLOWCTRL_DISABLE, 0); + uart_hal_set_rx_timeout(UART_HAL(cfg->uart_num), 0x16); + + simple_uart_set_baud_rate(cfg->uart_num, cfg->baud_rate); + simple_uart_set_stop_bits(cfg->uart_num, cfg->stop_bits); + simple_uart_set_parity(cfg->uart_num, cfg->parity); + simple_uart_set_data_bits(cfg->uart_num, cfg->data_bits); + + esp_intr_alloc( + uart_periph_signal[cfg->uart_num].irq, + 0, + simple_uart_isr, + &uart_context[cfg->uart_num], + NULL); + + // disable interrupts + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_RXFIFO_FULL); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_TXFIFO_EMPTY); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_PARITY_ERR); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_FRAM_ERR); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_RXFIFO_OVF); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_DSR_CHG); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_CTS_CHG); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_BRK_DET); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_RXFIFO_TOUT); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_SW_XON); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_SW_XOFF); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_GLITCH_DET); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_TX_BRK_DONE); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_TX_BRK_IDLE); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_TX_DONE); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_RS485_PARITY_ERR); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_RS485_FRM_ERR); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_RS485_CLASH); + uart_hal_clr_intsts_mask(UART_HAL(cfg->uart_num), UART_INTR_CMD_CHAR_DET); + + // enable rx interrupts + uart_hal_ena_intr_mask(UART_HAL(cfg->uart_num), UART_INTR_RXFIFO_FULL); + uart_hal_ena_intr_mask(UART_HAL(cfg->uart_num), UART_INTR_RXFIFO_TOUT); +} + +void simple_uart_write(uint8_t uart_num, const uint8_t* data, const uint32_t data_size) { + uint32_t to_write = data_size; + while(to_write > 0) { + while(uart_hal_get_txfifo_len(UART_HAL(uart_num)) == 0) { + ; /* Wait */ + } + + uint32_t write_size = 0; + uart_hal_write_txfifo( + UART_HAL(uart_num), data + (data_size - to_write), to_write, &write_size); + to_write -= write_size; + } +} + +bool simple_uart_available(uint8_t uart_num) { + const int num_rx = uart_hal_get_rxfifo_len(UART_HAL(uart_num)); + return num_rx > 0; +} + +uint32_t simple_uart_read(uint8_t uart_num, uint8_t* data, const uint32_t data_size) { + const int num_rx = uart_hal_get_rxfifo_len(UART_HAL(uart_num)); + int read = ((data_size) < (num_rx) ? (data_size) : (num_rx)); + + if(!read) { + return 0; + } + + uart_hal_read_rxfifo(UART_HAL(uart_num), data, &read); + return read; +} + +static void simple_uart_isr(void* arg) { + uart_context_t* context = arg; + uart_hal_context_t* hal_context = &context->hal; + uint8_t hal_num = context->uart_index; + + uint32_t uart_intr_status = uart_hal_get_intsts_mask(hal_context); + if(uart_intr_status == 0) { + return; + } + uart_hal_clr_intsts_mask(hal_context, uart_intr_status); + + if(uart_intr_status & UART_INTR_TXFIFO_EMPTY) { + } + if((uart_intr_status & UART_INTR_RXFIFO_TOUT) || (uart_intr_status & UART_INTR_RXFIFO_FULL)) { + if(context->rx_isr) { + context->rx_isr(context->isr_context); + } else { + // purge rx fifo + uint8_t data; + while(simple_uart_available(hal_num)) { + simple_uart_read(hal_num, &data, 1); + } + } + } +} + +void simple_uart_set_baud_rate(uint8_t uart_num, uint32_t baud_rate) { + uart_hal_set_baudrate(UART_HAL(uart_num), baud_rate); +} + +void simple_uart_set_stop_bits(uint8_t uart_num, uart_stop_bits_t stop_bits) { + uart_hal_set_stop_bits(UART_HAL(uart_num), stop_bits); +} + +void simple_uart_set_parity(uint8_t uart_num, uart_parity_t parity) { + uart_hal_set_parity(UART_HAL(uart_num), parity); +} + +void simple_uart_set_data_bits(uint8_t uart_num, uart_word_length_t data_bits) { + uart_hal_set_data_bit_num(UART_HAL(uart_num), data_bits); +} \ No newline at end of file diff --git a/components/simple-uart/simple-uart.h b/components/simple-uart/simple-uart.h new file mode 100644 index 0000000..b80b78f --- /dev/null +++ b/components/simple-uart/simple-uart.h @@ -0,0 +1,90 @@ +/** + * @file uart.h + * @author Sergey Gavrilov (who.just.the.doctor@gmail.com) + * @version 1.0 + * @date 2021-12-17 + * + * + */ +#pragma once +#include +#include +#include +#include + +#define UART_NUM_0 (0) /*!< UART port 0 */ +#define UART_NUM_1 (1) /*!< UART port 1 */ +#define UART_NUM_MAX (SOC_UART_NUM) + +typedef void (*uart_isr)(void* context); + +typedef struct { + uint8_t uart_num; /*!< UART index */ + uint32_t baud_rate; /*!< UART baud rate*/ + uart_word_length_t data_bits; /*!< UART byte size*/ + uart_parity_t parity; /*!< UART parity mode*/ + uart_stop_bits_t stop_bits; /*!< UART stop bits*/ + int tx_pin_num; /*!< UART tx pin*/ + int rx_pin_num; /*!< UART rx pin*/ + void* isr_context; /*!< UART isr context*/ + uart_isr rx_isr; /*!< UART isr callback*/ +} UartConfig; + +/** + * Init UART driver + * @param config + */ +void simple_uart_init(UartConfig* config); + +/** + * Write data to UART + * @param uart_num + * @param data + * @param data_size + */ +void simple_uart_write(uint8_t uart_num, const uint8_t* data, const uint32_t data_size); + +/** + * Check if rx data available + * @param uart_num + * @return true + * @return false + */ +bool simple_uart_available(uint8_t uart_num); + +/** + * Read rx data + * @param uart_num + * @param data + * @param data_size + * @return uint32_t + */ +uint32_t simple_uart_read(uint8_t uart_num, uint8_t* data, const uint32_t data_size); + +/** + * Set UART baud rate + * @param uart_num + * @param baud_rate + */ +void simple_uart_set_baud_rate(uint8_t uart_num, uint32_t baud_rate); + +/** + * Set UART stop bits + * @param uart_num + * @param stop_bits + */ +void simple_uart_set_stop_bits(uint8_t uart_num, uart_stop_bits_t stop_bits); + +/** + * Set UART parity + * @param uart_num + * @param parity + */ +void simple_uart_set_parity(uint8_t uart_num, uart_parity_t parity); + +/** + * Set UART data bits + * @param uart_num + * @param data_bits + */ +void simple_uart_set_data_bits(uint8_t uart_num, uart_word_length_t data_bits); \ No newline at end of file diff --git a/components/soft-uart/CMakeLists.txt b/components/soft-uart/CMakeLists.txt new file mode 100644 index 0000000..159b0d6 --- /dev/null +++ b/components/soft-uart/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "soft-uart.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/components/soft-uart/soft-uart.c b/components/soft-uart/soft-uart.c new file mode 100644 index 0000000..1b3d2e0 --- /dev/null +++ b/components/soft-uart/soft-uart.c @@ -0,0 +1,69 @@ +#include "soft-uart.h" +#include +#include +#include +#include + +struct SoftUart { + uint32_t baudrate; + uint32_t bit_time; + uint8_t tx_pin; + bool invert; +}; + +#define wait_cycles(cycles) \ + for(uint32_t start = cycle_count_get(); cycle_count_get() - start < cycles;) + +static uint32_t cycle_count_get() { + uint32_t ccount; + __asm__ __volatile__("esync; rsr %0,ccount" : "=a"(ccount)); + return ccount; +} + +void soft_uart_transmit_byte(SoftUart* uart, uint8_t byte) { + if(uart->invert) { + byte = ~byte; + } + + // disable interrupts + portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL(&mux); + + // create tx interrupts to start bit. + gpio_set_level(uart->tx_pin, 1), gpio_set_level(uart->tx_pin, 0); + wait_cycles(uart->bit_time); + + for(uint8_t i = 0; i != 8; i++) { + gpio_set_level(uart->tx_pin, (byte & 1) ? 1 : 0); + wait_cycles(uart->bit_time); + byte >>= 1; + } + + // Stop bit + gpio_set_level(uart->tx_pin, 1); + wait_cycles(uart->bit_time); + + // re-enable interrupts + portEXIT_CRITICAL(&mux); +} + +SoftUart* soft_uart_init(uint32_t baudrate, uint8_t tx_pin) { + SoftUart* uart = malloc(sizeof(SoftUart)); + + uart->baudrate = baudrate; + uart->tx_pin = tx_pin; + uart->invert = false; + + uart->bit_time = (esp_clk_cpu_freq() / uart->baudrate); + + gpio_pad_select_gpio(uart->tx_pin); + gpio_set_direction(uart->tx_pin, GPIO_MODE_OUTPUT); + gpio_set_level(uart->tx_pin, !uart->invert); + return uart; +} + +void soft_uart_transmit(SoftUart* uart, const uint8_t* data, uint32_t data_size) { + for(size_t i = 0; i < data_size; i++) { + soft_uart_transmit_byte(uart, data[i]); + } +} \ No newline at end of file diff --git a/components/soft-uart/soft-uart.h b/components/soft-uart/soft-uart.h new file mode 100644 index 0000000..519b6a6 --- /dev/null +++ b/components/soft-uart/soft-uart.h @@ -0,0 +1,16 @@ +/** + * @file soft-uart.h + * @author Sergey Gavrilov (who.just.the.doctor@gmail.com) + * @version 1.0 + * @date 2021-12-18 + * + * + */ +#pragma once +#include + +typedef struct SoftUart SoftUart; + +SoftUart* soft_uart_init(uint32_t baudrate, uint8_t tx_pin); + +void soft_uart_transmit(SoftUart* uart, const uint8_t* data, uint32_t data_size); diff --git a/components/tinyusb/CMakeLists.txt b/components/tinyusb/CMakeLists.txt new file mode 100644 index 0000000..a14c94c --- /dev/null +++ b/components/tinyusb/CMakeLists.txt @@ -0,0 +1,57 @@ +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_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" + ) +endif() + +target_include_directories(${COMPONENT_TARGET} INTERFACE + "${FREERTOS_ORIG_INCLUDE_PATH}" + "${COMPONENT_DIR}/config/" + "${COMPONENT_DIR}/dual-cdc/" + "${COMPONENT_DIR}/tinyusb/hw/bsp/" + "${COMPONENT_DIR}/tinyusb/src/" + "${COMPONENT_DIR}/tinyusb/src/device" + "${COMPONENT_DIR}/tinyusb/src/class" +) + +target_sources(${COMPONENT_TARGET} INTERFACE + "${COMPONENT_DIR}/tinyusb/src/tusb.c" + "${COMPONENT_DIR}/tinyusb/src/common/tusb_fifo.c" + "${COMPONENT_DIR}/tinyusb/src/device/usbd.c" + "${COMPONENT_DIR}/tinyusb/src/device/usbd_control.c" + "${COMPONENT_DIR}/tinyusb/src/class/audio/audio_device.c" + "${COMPONENT_DIR}/tinyusb/src/class/bth/bth_device.c" + "${COMPONENT_DIR}/tinyusb/src/class/cdc/cdc_device.c" + "${COMPONENT_DIR}/tinyusb/src/class/cdc/cdc_host.c" + "${COMPONENT_DIR}/tinyusb/src/class/cdc/cdc_rndis_host.c" + "${COMPONENT_DIR}/tinyusb/src/class/dfu/dfu_rt_device.c" + "${COMPONENT_DIR}/tinyusb/src/class/dfu/dfu_device.c" + "${COMPONENT_DIR}/tinyusb/src/class/hid/hid_device.c" + "${COMPONENT_DIR}/tinyusb/src/class/hid/hid_host.c" + "${COMPONENT_DIR}/tinyusb/src/class/midi/midi_device.c" + "${COMPONENT_DIR}/tinyusb/src/class/msc/msc_device.c" + "${COMPONENT_DIR}/tinyusb/src/class/msc/msc_host.c" + "${COMPONENT_DIR}/tinyusb/src/class/net/ncm_device.c" + "${COMPONENT_DIR}/tinyusb/src/class/net/ecm_rndis_device.c" + "${COMPONENT_DIR}/tinyusb/src/class/usbtmc/usbtmc_device.c" + "${COMPONENT_DIR}/tinyusb/src/class/vendor/vendor_device.c" + "${COMPONENT_DIR}/tinyusb/src/class/vendor/vendor_host.c" + "${COMPONENT_DIR}/tinyusb/src/class/video/video_device.c" + "${COMPONENT_DIR}/tinyusb/src/portable/espressif/esp32sx/dcd_esp32sx.c" + "${COMPONENT_DIR}/tinyusb/src/host/hub.c" + "${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" +) diff --git a/components/tinyusb/config/tusb_config.h b/components/tinyusb/config/tusb_config.h new file mode 100644 index 0000000..183e675 --- /dev/null +++ b/components/tinyusb/config/tusb_config.h @@ -0,0 +1,168 @@ +// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd. +// Copyright 2020 Mike Dunston (https://github.com/atanisoft) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//-------------------------------------------------------------------- +// COMMON CONFIGURATION +//-------------------------------------------------------------------- + +#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE +#define CFG_TUSB_OS OPT_OS_FREERTOS + +// CFG_TUSB_DEBUG is defined by compiler in DEBUG build +#define CFG_TUSB_DEBUG CONFIG_ESPUSB_DEBUG + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * TinyUSB use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__((aligned(4))) +#endif + +//-------------------------------------------------------------------- +// ENDPOINT FIFO SIZE CONFIGURATION +//-------------------------------------------------------------------- +#ifndef CFG_TUD_ENDPOINT0_SIZE +#define CFG_TUD_ENDPOINT0_SIZE 64 +#endif + +//-------------------------------------------------------------------- +// KCONFIG DEFAULT CONFIGURATION +//-------------------------------------------------------------------- +#ifndef CONFIG_ESPUSB_CDC +#define CONFIG_ESPUSB_CDC 0 +#endif + +#ifndef CONFIG_ESPUSB_MSC +#define CONFIG_ESPUSB_MSC 0 +#endif + +#ifndef CONFIG_ESPUSB_HID +#define CONFIG_ESPUSB_HID 0 +#endif + +#ifndef CONFIG_ESPUSB_MIDI +#define CONFIG_ESPUSB_MIDI 0 +#endif + +#ifndef CONFIG_ESPUSB_VENDOR +#define CONFIG_ESPUSB_VENDOR 0 +#endif + +#ifndef CONFIG_ESPUSB_DFU +#define CONFIG_ESPUSB_DFU 0 +#endif + +#ifndef CONFIG_ESPUSB_CUSTOM_CLASS +#define CONFIG_ESPUSB_CUSTOM_CLASS 0 +#endif + +#ifndef CONFIG_ESPUSB_CDC_RX_BUFSIZE +#define CONFIG_ESPUSB_CDC_RX_BUFSIZE 64 +#endif + +#ifndef CONFIG_ESPUSB_CDC_TX_BUFSIZE +#define CONFIG_ESPUSB_CDC_TX_BUFSIZE 64 +#endif + +#ifndef CONFIG_ESPUSB_MSC_BUFSIZE +#define CONFIG_ESPUSB_MSC_BUFSIZE 512 +#endif + +#ifndef CONFIG_ESPUSB_HID_BUFSIZE +#define CONFIG_ESPUSB_HID_BUFSIZE 16 +#endif + +#ifndef CONFIG_ESPUSB_VENDOR_RX_BUFSIZE +#define CONFIG_ESPUSB_VENDOR_RX_BUFSIZE 64 +#endif + +#ifndef CONFIG_ESPUSB_VENDOR_TX_BUFSIZE +#define CONFIG_ESPUSB_VENDOR_TX_BUFSIZE 64 +#endif + +#ifndef CONFIG_ESPUSB_MIDI_RX_BUFSIZE +#define CONFIG_ESPUSB_MIDI_RX_BUFSIZE 64 +#endif + +#ifndef CONFIG_ESPUSB_MIDI_TX_BUFSIZE +#define CONFIG_ESPUSB_MIDI_TX_BUFSIZE 64 +#endif + +#ifndef CONFIG_ESPUSB_DFU_BUFSIZE +#define CONFIG_ESPUSB_DFU_BUFSIZE 1024 +#endif + +//-------------------------------------------------------------------- +// DEVICE CONFIGURATION +//-------------------------------------------------------------------- +#define CFG_TUD_CDC 2 +#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_CUSTOM_CLASS CONFIG_ESPUSB_CUSTOM_CLASS +#define CFG_TUD_DFU_RT CONFIG_ESPUSB_DFU + +//-------------------------------------------------------------------- +// CDC FIFO CONFIGURATION +//-------------------------------------------------------------------- +#define CFG_TUD_CDC_RX_BUFSIZE CONFIG_ESPUSB_CDC_RX_BUFSIZE +#define CFG_TUD_CDC_TX_BUFSIZE CONFIG_ESPUSB_CDC_TX_BUFSIZE + +//-------------------------------------------------------------------- +// MSC BUFFER CONFIGURATION +// +// NOTE: This is the block size for read/write operations via all +// defined callbacks. +//-------------------------------------------------------------------- +#define CFG_TUD_MSC_BUFSIZE CONFIG_ESPUSB_MSC_BUFSIZE + +//-------------------------------------------------------------------- +// HID BUFFER CONFIGURATION +// +// NOTE: This should be sufficient to hold ID (if any) + Data +//-------------------------------------------------------------------- +#define CFG_TUD_HID_BUFSIZE CONFIG_ESPUSB_HID_BUFSIZE + +//-------------------------------------------------------------------- +// 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 + +//-------------------------------------------------------------------- +// MIDI FIFO CONFIGURATION +//-------------------------------------------------------------------- +#define CFG_TUD_MIDI_RX_BUFSIZE CONFIG_ESPUSB_MIDI_RX_BUFSIZE +#define CFG_TUD_MIDI_TX_BUFSIZE CONFIG_ESPUSB_MIDI_TX_BUFSIZE + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/tinyusb/dual-cdc/dual-cdc-driver.c b/components/tinyusb/dual-cdc/dual-cdc-driver.c new file mode 100644 index 0000000..03a8dfe --- /dev/null +++ b/components/tinyusb/dual-cdc/dual-cdc-driver.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} \ No newline at end of file diff --git a/components/tinyusb/dual-cdc/dual-cdc-driver.h b/components/tinyusb/dual-cdc/dual-cdc-driver.h new file mode 100644 index 0000000..ea776b7 --- /dev/null +++ b/components/tinyusb/dual-cdc/dual-cdc-driver.h @@ -0,0 +1,22 @@ +/** + * @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 +#include +#include + +#define CDC_IF_COUNT CFG_TUD_CDC + +/** + * + * @return esp_err_t + */ +esp_err_t dual_cdc_driver_install(void); diff --git a/components/tinyusb/dual-cdc/usb_descriptors.c b/components/tinyusb/dual-cdc/usb_descriptors.c new file mode 100644 index 0000000..9e1af52 --- /dev/null +++ b/components/tinyusb/dual-cdc/usb_descriptors.c @@ -0,0 +1,222 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * 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 +#include +#include "tusb_config.h" + +#include + +//--------------------------------------------------------------------+ +// Device Descriptors +//--------------------------------------------------------------------+ +tusb_desc_device_t const blackmagic_desc_device = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + + // 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 = 0x4001, // USB_TUSB_PID, + .bcdDevice = 0x0100, + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .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 +//--------------------------------------------------------------------+ +enum { ITF_NUM_CDC_0 = 0, ITF_NUM_CDC_0_DATA, ITF_NUM_CDC_1, ITF_NUM_CDC_1_DATA, ITF_NUM_TOTAL }; + +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_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_0_NOTIF 0x81 +#define EPNUM_CDC_0_DATA 0x02 + +#define EPNUM_CDC_1_NOTIF 0x84 +#define EPNUM_CDC_1_DATA 0x05 +#else +#define EPNUM_CDC_0_NOTIF 0x81 +#define EPNUM_CDC_0_DATA 0x02 + +#define EPNUM_CDC_1_NOTIF 0x83 +#define EPNUM_CDC_1_DATA 0x04 +#endif + +uint8_t const blackmagic_desc_fs_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), + + // 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_CDC_DESCRIPTOR( + ITF_NUM_CDC_0, + 4, + EPNUM_CDC_0_NOTIF, + 8, + EPNUM_CDC_0_DATA, + 0x80 | EPNUM_CDC_0_DATA, + 64), + + // 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_CDC_DESCRIPTOR( + ITF_NUM_CDC_1, + 4, + EPNUM_CDC_1_NOTIF, + 8, + EPNUM_CDC_1_DATA, + 0x80 | EPNUM_CDC_1_DATA, + 64), +}; + +#if TUD_OPT_HIGH_SPEED +uint8_t const blackmagic_desc_hs_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), + + // 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_CDC_DESCRIPTOR( + ITF_NUM_CDC_0, + 4, + EPNUM_CDC_0_NOTIF, + 8, + EPNUM_CDC_0_DATA, + 0x80 | EPNUM_CDC_0_DATA, + 512), + + // 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_CDC_DESCRIPTOR( + ITF_NUM_CDC_1, + 4, + EPNUM_CDC_1_NOTIF, + 8, + EPNUM_CDC_1_DATA, + 0x80 | EPNUM_CDC_1_DATA, + 512), +}; +#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) + "Flipper Devices Inc.", // 1: Manufacturer + "Blackmagic ESP32", // 2: Product + "blackmagic", // 3: Serials, should use chip ID + "Blackmagic ESP32", // 4: CDC Interface + "", // 5: MSC Interface + "", // 6: HIDs +}; + +#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) { + (void)langid; + + uint8_t chr_count; + + if(index == 0) { + memcpy(&_desc_str[1], blackmagic_string_desc[0], 2); + chr_count = 1; + } else { + // Convert ASCII string into UTF-16 + + if(index >= sizeof(blackmagic_string_desc) / sizeof(blackmagic_string_desc[0])) { + // ESP_LOGI("usb-str", "answer NULL"); + return NULL; + } + + const char* str = blackmagic_string_desc[index]; + + // Cap at max char + chr_count = strlen(str); + if(chr_count > MAX_DESC_BUF_SIZE - 1) { + chr_count = MAX_DESC_BUF_SIZE - 1; + } + + 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] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2); + + // ESP_LOG_BUFFER_HEXDUMP("usb-str", _desc_str, (2 * chr_count + 2), ESP_LOG_INFO); + + return _desc_str; +} diff --git a/components/tinyusb/tinyusb b/components/tinyusb/tinyusb new file mode 160000 index 0000000..dd30f2c --- /dev/null +++ b/components/tinyusb/tinyusb @@ -0,0 +1 @@ +Subproject commit dd30f2c648b984949b858d7dcc914297985a20bb diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 00f0499..cf7f3a5 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,6 +1,7 @@ set(SOURCES "main.c" "usb-cdc.c" + "usb-uart.c" "nvs.c" "nvs-config.c" "led.c" @@ -9,16 +10,16 @@ set(SOURCES "delay.c" "network.c" "network-http.c" - "network-uart.c" "network-gdb.c" - "cli.c" "cli-uart.c" - "cli-commands.c" - "cli-commands-gpio.c" - "cli-commands-wifi.c" - "cli-commands-config.c" - "cli-commands-device-info.c" - "cli-args.c" + "cli/cli.c" + "cli/cli-commands.c" + "cli/cli-commands-gpio.c" + "cli/cli-commands-wifi.c" + "cli/cli-commands-config.c" + "cli/cli-commands-device-info.c" + "cli/cli-args.c" + "soft-uart-log.c" ) set(INCLUDES @@ -74,4 +75,4 @@ message(STATUS "FW branch: ${FW_GIT_BRANCH}") message(STATUS "FW branch num: ${FW_GIT_BRANCH_NUM}") message(STATUS "FW version: ${FW_GIT_VERSION}") -set_property(SOURCE "cli-commands-device-info.c" APPEND PROPERTY COMPILE_OPTIONS ${INFO_FLAGS}) \ No newline at end of file +set_property(SOURCE "cli/cli-commands-device-info.c" APPEND PROPERTY COMPILE_OPTIONS ${INFO_FLAGS}) \ No newline at end of file diff --git a/main/cli-uart.c b/main/cli-uart.c index 3b0be7b..3c55d35 100644 --- a/main/cli-uart.c +++ b/main/cli-uart.c @@ -1,52 +1,41 @@ -#include -#include +// #include +// #include #include -#include "cli.h" +#include "led.h" +#include "cli/cli.h" +#include +#include +#include +#include #define CLI_UART_PORT_NUM UART_NUM_1 #define CLI_UART_TXD_PIN (17) #define CLI_UART_RXD_PIN (18) -#define CLI_UART_RTS_PIN (UART_PIN_NO_CHANGE) -#define CLI_UART_CTS_PIN (UART_PIN_NO_CHANGE) #define CLI_UART_BAUD_RATE (115200) -#define CLI_UART_BUF_SIZE (128) +#define CLI_UART_TX_BUF_SIZE (64) #define CLI_UART_RX_BUF_SIZE (64) static Cli* cli_uart; -static QueueHandle_t cli_uart_queue; -static uint8_t cli_rx_buffer[CLI_UART_RX_BUF_SIZE]; -static size_t cli_rx_index = 0; +static uint8_t uart_tx_buffer[CLI_UART_TX_BUF_SIZE]; +static size_t uart_tx_index = 0; +static StreamBufferHandle_t uart_rx_stream; static void cli_uart_write(const uint8_t* data, size_t data_size, void* context); static void cli_uart_flush(void* context); +static void cli_uart_rx_isr(void* context); + static void cli_uart_rx_task(void* pvParameters) { - uart_event_t event; - uint8_t* rx_buffer = (uint8_t*)malloc(CLI_UART_BUF_SIZE); - int received = 0; - - for(;;) { - //Waiting for UART event. - if(xQueueReceive(cli_uart_queue, (void*)&event, (portTickType)portMAX_DELAY)) { - bzero(rx_buffer, CLI_UART_BUF_SIZE); - switch(event.type) { - case UART_DATA: - received = - uart_read_bytes(CLI_UART_PORT_NUM, rx_buffer, event.size, portMAX_DELAY); - for(int i = 0; i < received; i++) { - cli_handle_char(cli_uart, rx_buffer[i]); - } - - break; - default: - break; + while(1) { + uint8_t data[CLI_UART_RX_BUF_SIZE]; + size_t length = + xStreamBufferReceive(uart_rx_stream, data, CLI_UART_RX_BUF_SIZE, portMAX_DELAY); + if(length > 0) { + for(size_t i = 0; i < length; i++) { + cli_handle_char(cli_uart, data[i]); } } } - - free(rx_buffer); - rx_buffer = NULL; - vTaskDelete(NULL); } void cli_uart_init() { @@ -54,49 +43,59 @@ void cli_uart_init() { cli_set_write_cb(cli_uart, cli_uart_write); cli_set_flush_cb(cli_uart, cli_uart_flush); - uart_config_t uart_config = { + uart_rx_stream = xStreamBufferCreate(CLI_UART_RX_BUF_SIZE * 4, 1); + + xTaskCreate(cli_uart_rx_task, "cli_uart_rx", 4096, NULL, 5, NULL); + + UartConfig config = { + .uart_num = CLI_UART_PORT_NUM, .baud_rate = CLI_UART_BAUD_RATE, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, - .source_clk = UART_SCLK_APB, + .tx_pin_num = CLI_UART_TXD_PIN, + .rx_pin_num = CLI_UART_RXD_PIN, + .isr_context = uart_rx_stream, + .rx_isr = cli_uart_rx_isr, }; - int intr_alloc_flags = 0; -#if CONFIG_UART_ISR_IN_IRAM - intr_alloc_flags = ESP_INTR_FLAG_IRAM; -#endif + simple_uart_init(&config); - ESP_ERROR_CHECK(uart_driver_install( - CLI_UART_PORT_NUM, - CLI_UART_BUF_SIZE * 4, - 0, - 10, - &cli_uart_queue, - intr_alloc_flags)); - ESP_ERROR_CHECK(uart_param_config(CLI_UART_PORT_NUM, &uart_config)); - ESP_ERROR_CHECK(uart_set_pin( - CLI_UART_PORT_NUM, CLI_UART_TXD_PIN, CLI_UART_RXD_PIN, CLI_UART_RTS_PIN, CLI_UART_CTS_PIN)); - - xTaskCreate(cli_uart_rx_task, "cli_uart_rx", 4096, NULL, 5, NULL); + cli_force_motd(cli_uart); } static void cli_uart_write(const uint8_t* data, size_t data_size, void* context) { for(size_t i = 0; i < data_size; i++) { - cli_rx_buffer[cli_rx_index] = data[i]; - cli_rx_index++; + uart_tx_buffer[uart_tx_index] = data[i]; + uart_tx_index++; - if(cli_rx_index == CLI_UART_RX_BUF_SIZE) { + if(uart_tx_index == CLI_UART_TX_BUF_SIZE) { cli_uart_flush(NULL); } } } static void cli_uart_flush(void* context) { - if(cli_rx_index > 0) { - uart_write_bytes(CLI_UART_PORT_NUM, cli_rx_buffer, cli_rx_index); + if(uart_tx_index > 0) { + simple_uart_write(CLI_UART_PORT_NUM, uart_tx_buffer, uart_tx_index); } - cli_rx_index = 0; + uart_tx_index = 0; +} + +static void cli_uart_rx_isr(void* context) { + StreamBufferHandle_t stream = context; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + uint8_t data; + while(simple_uart_available(CLI_UART_PORT_NUM)) { + simple_uart_read(CLI_UART_PORT_NUM, &data, 1); + + size_t ret __attribute__((unused)); + ret = xStreamBufferSendFromISR(stream, &data, 1, &xHigherPriorityTaskWoken); + // we will drop data if the stream overflows + // ESP_ERROR_CHECK(ret != 1); + } + + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } \ No newline at end of file diff --git a/main/cli-args.c b/main/cli/cli-args.c similarity index 100% rename from main/cli-args.c rename to main/cli/cli-args.c diff --git a/main/cli-args.h b/main/cli/cli-args.h similarity index 100% rename from main/cli-args.h rename to main/cli/cli-args.h diff --git a/main/cli-commands-config.c b/main/cli/cli-commands-config.c similarity index 100% rename from main/cli-commands-config.c rename to main/cli/cli-commands-config.c diff --git a/main/cli-commands-device-info.c b/main/cli/cli-commands-device-info.c similarity index 100% rename from main/cli-commands-device-info.c rename to main/cli/cli-commands-device-info.c diff --git a/main/cli-commands-gpio.c b/main/cli/cli-commands-gpio.c similarity index 100% rename from main/cli-commands-gpio.c rename to main/cli/cli-commands-gpio.c diff --git a/main/cli-commands-wifi.c b/main/cli/cli-commands-wifi.c similarity index 100% rename from main/cli-commands-wifi.c rename to main/cli/cli-commands-wifi.c diff --git a/main/cli-commands.c b/main/cli/cli-commands.c similarity index 100% rename from main/cli-commands.c rename to main/cli/cli-commands.c diff --git a/main/cli-commands.h b/main/cli/cli-commands.h similarity index 100% rename from main/cli-commands.h rename to main/cli/cli-commands.h diff --git a/main/cli.c b/main/cli/cli.c similarity index 77% rename from main/cli.c rename to main/cli/cli.c index 8e601a1..51193de 100644 --- a/main/cli.c +++ b/main/cli/cli.c @@ -96,13 +96,44 @@ void cli_printf(Cli* cli, char* format, ...) { } static void cli_write_motd(Cli* cli) { - cli_write_str(cli, "Hello!\r\nThis is MOTD\r\n"); + cli_write_str(cli, " \r\n"); + cli_write_str(cli, " ____ BLACK \r\n"); + cli_write_str(cli, " / /\\ MAGIC \r\n"); + cli_write_str(cli, " / /\\ \\ \r\n"); + cli_write_str(cli, " ( / \\ \\ ' \r\n"); + cli_write_str(cli, " _/ (___/ /_ . ' \r\n"); + cli_write_str(cli, " ( _____._.__ ) ,'o \r\n"); + cli_write_str(cli, " // / 'o' | O . \r\n"); + cli_write_str(cli, " // / ' ' |\\ ,,, \r\n"); + cli_write_str(cli, " // /\\ ' '| \\_/''/ \r\n"); + cli_write_str(cli, " // / )______/\\ \\_/ \r\n"); + cli_write_str(cli, "// \\ ( ) `---' \r\n"); + cli_write_str(cli, "\\\\___/ | \\ \r\n"); + cli_write_str(cli, " \\( \\ | \\ \r\n"); + cli_write_str(cli, " / \\_@ | ) \r\n"); + cli_write_str(cli, " \\ , | \\ \r\n"); + cli_write_str(cli, " / / / | / \r\n"); + cli_write_str(cli, " \\ \\ : /\\ / \r\n"); + cli_write_str(cli, " \\ \\ \\ : / |\\) \r\n"); + cli_write_str(cli, " \\ / |\\/| | \r\n"); + cli_write_str(cli, " / / | |- \r\n"); + cli_write_str(cli, " \\ /|__| \r\n"); + cli_write_str(cli, " \\ / |''| \r\n"); + cli_write_str(cli, " \\ \\ -- \r\n"); + cli_write_str(cli, " \\/ \r\n"); } static void cli_write_prompt(Cli* cli) { cli_write_str(cli, ">: "); } +void cli_force_motd(Cli* cli) { + cli_write_motd(cli); + cli_write_eol(cli); + cli_write_prompt(cli); + cli_flush(cli); +} + static const CliItem* cli_search_item(Cli* cli, const mstring_t* command) { const CliItem* item = NULL; @@ -199,9 +230,7 @@ void cli_handle_char(Cli* cli, uint8_t c) { break; case CliSymbolAsciiSOH: delay(33); - cli_write_motd(cli); - cli_write_eol(cli); - cli_write_prompt(cli); + cli_force_motd(cli); break; case CliSymbolAsciiETX: cli_reset(cli); diff --git a/main/cli.h b/main/cli/cli.h similarity index 91% rename from main/cli.h rename to main/cli/cli.h index 3e92ec1..804717a 100644 --- a/main/cli.h +++ b/main/cli/cli.h @@ -37,4 +37,6 @@ void cli_handle_char(Cli* cli, uint8_t c); void cli_write_eol(Cli* cli); -void cli_printf(Cli* cli, char* format, ...); \ No newline at end of file +void cli_printf(Cli* cli, char* format, ...); + +void cli_force_motd(Cli* cli); \ No newline at end of file diff --git a/main/cli/cli.motd.art b/main/cli/cli.motd.art new file mode 100644 index 0000000..bd82ee2 --- /dev/null +++ b/main/cli/cli.motd.art @@ -0,0 +1,26 @@ + + ____ BLACK + / /\ MAGIC + / /\ \ + ( / \ \ ' + _/ (___/ /_ . ' + ( _____._.__ ) ,'o + // / '"' | O . + // / ' ' |\ ,,, + // /\ ' '| \_/''/ + // / )______/\ \_/ +// \ ( ) `---' +\\___/ | \ + \( \ | \ + / \_@ | ) + \ , | \ + / / / | / + \ \ : /\ / + \ \ \ : / |\) + \ / |\/| | + / / | |- + \ /|__| + \ / |''| + \ \ -- + \/ + \ No newline at end of file diff --git a/main/main.c b/main/main.c index 9e9d137..54dd67c 100644 --- a/main/main.c +++ b/main/main.c @@ -16,6 +16,7 @@ #include "network-gdb.h" #include +#include static const char* TAG = "main"; @@ -46,10 +47,10 @@ void pins_init() { gpio_config(&io_conf); } -void tcp_uart_init(void); -void tcp_web_log(void); - void app_main(void) { + // Software UART logging at pin 7, 57600 baud + soft_uart_log_init(7, 57600); + ESP_LOGI(TAG, "start"); gdb_glue_init(); @@ -60,11 +61,10 @@ void app_main(void) { nvs_init(); network_init(); network_http_server_init(); - network_uart_server_init(); + // network_uart_server_init(); network_gdb_server_init(); usb_cdc_init(); - cli_uart_init(); // TODO uart and i2c share the same pins, need switching mechanics diff --git a/main/network-uart.c b/main/network-uart.c deleted file mode 100644 index ac723da..0000000 --- a/main/network-uart.c +++ /dev/null @@ -1,198 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "led.h" -#include "delay.h" - -#include -#include - -#define PORT 4444 -#define KEEPALIVE_IDLE 5 -#define KEEPALIVE_INTERVAL 5 -#define KEEPALIVE_COUNT 3 -#define BUF_SIZE (128) -#define RD_BUF_SIZE (128) -#define TAG "network-uart" - -static int socket_id; -static bool connected; -static QueueHandle_t uart0_queue; - -static void receive_and_send_to_uart(const int socket_id) { - int received; - char rx_buffer[BUF_SIZE]; - - do { - received = recv(socket_id, rx_buffer, sizeof(rx_buffer) - 1, 0); - led_set_green(255); - if(received > 0) { - uart_write_bytes(UART_NUM_0, rx_buffer, received); - } - led_set_green(0); - - } while(received > 0); -} - -static void network_uart_rx_task(void* pvParameters) { - uart_event_t event; - uint8_t* rx_buffer = (uint8_t*)malloc(BUF_SIZE); - int received = 0; - - for(;;) { - //Waiting for UART event. - if(xQueueReceive(uart0_queue, (void*)&event, (portTickType)portMAX_DELAY)) { - bzero(rx_buffer, BUF_SIZE); - switch(event.type) { - case UART_DATA: - received = uart_read_bytes(UART_NUM_0, rx_buffer, event.size, portMAX_DELAY); - if(connected) { - int to_write = received; - while(to_write > 0) { - led_set_green(255); - int written = - send(socket_id, rx_buffer + (received - to_write), to_write, 0); - led_set_green(0); - to_write -= written; - } - } - break; - default: - break; - } - } - } - - free(rx_buffer); - rx_buffer = NULL; - vTaskDelete(NULL); -} - -static void network_uart_server_task(void* pvParameters) { - char addr_str[128]; - int addr_family = (int)pvParameters; - int ip_protocol = 0; - int keepAlive = 1; - int keepIdle = KEEPALIVE_IDLE; - int keepInterval = KEEPALIVE_INTERVAL; - int keepCount = KEEPALIVE_COUNT; - connected = false; - struct sockaddr_storage dest_addr; - - if(addr_family == AF_INET) { - struct sockaddr_in* dest_addr_ip4 = (struct sockaddr_in*)&dest_addr; - dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY); - dest_addr_ip4->sin_family = AF_INET; - dest_addr_ip4->sin_port = htons(PORT); - ip_protocol = IPPROTO_IP; - } - - int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol); - if(listen_sock < 0) { - ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); - vTaskDelete(NULL); - return; - } - int opt = 1; - setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); - - ESP_LOGI(TAG, "Socket created"); - - int err = bind(listen_sock, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); - if(err != 0) { - ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); - ESP_LOGE(TAG, "IPPROTO: %d", addr_family); - goto CLEAN_UP; - } - ESP_LOGI(TAG, "Socket bound, port %d", PORT); - - err = listen(listen_sock, 1); - if(err != 0) { - ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno); - goto CLEAN_UP; - } - - while(1) { - ESP_LOGI(TAG, "Socket listening"); - - struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6 - socklen_t addr_len = sizeof(source_addr); - int sock = accept(listen_sock, (struct sockaddr*)&source_addr, &addr_len); - if(sock < 0) { - ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno); - break; - } - - // Set tcp keepalive option - setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(int)); - setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(int)); - setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(int)); - setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(int)); - - // Convert ip address to string - if(source_addr.ss_family == PF_INET) { - inet_ntoa_r( - ((struct sockaddr_in*)&source_addr)->sin_addr, addr_str, sizeof(addr_str) - 1); - } - - ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str); - - esp_log_level_set("*", ESP_LOG_NONE); - - led_set_green(255); - delay(10); - led_set_green(0); - - socket_id = sock; - connected = true; - - receive_and_send_to_uart(sock); - - connected = false; - socket_id = -1; - - led_set_green(255); - delay(10); - led_set_green(0); - - esp_log_level_set("*", CONFIG_LOG_DEFAULT_LEVEL); - - shutdown(sock, 0); - close(sock); - } - -CLEAN_UP: - close(listen_sock); - vTaskDelete(NULL); -} - -void network_uart_server_init(void) { - xTaskCreate(network_uart_server_task, "network_uart_server", 4096, (void*)AF_INET, 5, NULL); - - uart_config_t uart_config = { - .baud_rate = 115200, - .data_bits = UART_DATA_8_BITS, - .parity = UART_PARITY_DISABLE, - .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, - .source_clk = UART_SCLK_APB, - }; - - uart_driver_install(UART_NUM_0, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0); - uart_param_config(UART_NUM_0, &uart_config); - - xTaskCreate(network_uart_rx_task, "tcp_uart_rx", 4096, (void*)AF_INET, 5, NULL); -} \ No newline at end of file diff --git a/main/soft-uart-log.c b/main/soft-uart-log.c new file mode 100644 index 0000000..28ff11b --- /dev/null +++ b/main/soft-uart-log.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include + +#define LOG_BUFFER_SIZE (128) + +static SoftUart* log_uart = NULL; +static char log_buffer[LOG_BUFFER_SIZE]; + +static int soft_uart_log_vprintf(const char* str, va_list l) { + portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL(&myMutex); + + int len = vsnprintf(log_buffer, LOG_BUFFER_SIZE, str, l); + soft_uart_transmit(log_uart, (uint8_t*)log_buffer, strlen(log_buffer)); + + portEXIT_CRITICAL(&myMutex); + return len; +} + +void soft_uart_log_init(uint8_t pin, uint32_t baudrate) { + log_uart = soft_uart_init(baudrate, pin); + + esp_log_set_vprintf(soft_uart_log_vprintf); +} \ No newline at end of file diff --git a/main/soft-uart-log.h b/main/soft-uart-log.h new file mode 100644 index 0000000..69861f6 --- /dev/null +++ b/main/soft-uart-log.h @@ -0,0 +1,12 @@ +/** + * @file soft-uart-log.h + * @author Sergey Gavrilov (who.just.the.doctor@gmail.com) + * @version 1.0 + * @date 2021-12-18 + * + * + */ +#pragma once +#include + +void soft_uart_log_init(uint8_t pin, uint32_t baudrate); \ No newline at end of file diff --git a/main/usb-cdc.c b/main/usb-cdc.c index 5bd71a4..0eb1227 100644 --- a/main/usb-cdc.c +++ b/main/usb-cdc.c @@ -11,141 +11,150 @@ #include #include #include -#include -#include #include #include #include "usb-cdc.h" +#include "usb-uart.h" #include "led.h" #include "delay.h" #include +#include +#include #define USB_DN_PIN (19) #define USB_DP_PIN (20) -#define CDC_USB_DEV (TINYUSB_USBDEV_0) + +#define GDB_BUF_RX_SIZE 64 +#define UART_BUF_RX_SIZE 64 static const char* TAG = "usb-cdc"; -static uint8_t buffer_rx[CONFIG_USB_CDC_RX_BUFSIZE]; +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; - volatile bool dtr; - volatile bool rts; } USBCDC; static USBCDC usb_cdc; -void usb_cdc_tx_char(uint8_t c, bool flush) { - tinyusb_cdcacm_write_queue(CDC_USB_DEV, &c, 1); +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) { - // SOME GDB MAGIC - // We need to send an empty packet for some hosts to accept this as a complete transfer. - uint8_t zero_byte = 0; - tinyusb_cdcacm_write_queue(CDC_USB_DEV, &zero_byte, 1); - - // TODO: timeout size - ESP_ERROR_CHECK_WITHOUT_ABORT(tinyusb_cdcacm_write_flush(CDC_USB_DEV, 1000)); + tud_cdc_n_write_flush(type); } } -void usb_cdc_rx_callback(int itf, cdcacm_event_t* event) { +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 > CONFIG_USB_CDC_RX_BUFSIZE) max_len = CONFIG_USB_CDC_RX_BUFSIZE; - size_t rx_size = 0; - esp_err_t err = tinyusb_cdcacm_read(itf, buffer_rx, max_len, &rx_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(err == ESP_OK) { - if(rx_size > 0) { - gdb_glue_receive(buffer_rx, rx_size); - } - } else { - ESP_LOGE(TAG, "Read error"); + 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_line_state_changed_callback(int itf, cdcacm_event_t* event) { - usb_cdc.dtr = event->line_state_changed_data.dtr; - usb_cdc.rts = event->line_state_changed_data.rts; +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); - ESP_LOGI(TAG, "Line state changed! dtr:%d, rst:%d", usb_cdc.dtr, usb_cdc.rts); + if(rx_size > 0) { + usb_uart_write(uart_buffer_rx, rx_size); + } } -void usb_cdc_line_coding_changed_callback(int itf, cdcacm_event_t* event) { - uint32_t bit_rate = event->line_coding_changed_data.p_line_coding->bit_rate; - uint8_t stop_bits = event->line_coding_changed_data.p_line_coding->stop_bits; - uint8_t parity = event->line_coding_changed_data.p_line_coding->parity; - uint8_t data_bits = event->line_coding_changed_data.p_line_coding->data_bits; +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); +} - ESP_LOGI( - TAG, - "Line coding changed! bit_rate:%d, stop_bits:%d, parity:%d, data_bits:%d", - bit_rate, - stop_bits, - parity, - data_bits); +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 //--------------------------------------------------------------------+ -// It seems like a reliable way is to rely on tud_mount_cb on connect and tud_suspend_cb on disconnect -void tud_mount_cb(void) { - ESP_LOGI(TAG, "Mount"); +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) { - led_set_blue(255); - delay(10); - led_set_blue(0); + 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 = true; + usb_cdc.connected = false; + ESP_LOGI(TAG, "disconnect"); +} + +void tud_mount_cb(void) { + usb_cdc_to_connected(); } void tud_umount_cb(void) { - ESP_LOGI(TAG, "Unmount"); - - if(usb_cdc.connected) { - led_set_blue(255); - delay(10); - led_set_blue(0); - } - - usb_cdc.connected = false; + usb_cdc_from_connected(); } void tud_resume_cb(void) { - ESP_LOGI(TAG, "Resume"); - - if(usb_cdc.connected) { - led_set_blue(255); - delay(10); - led_set_blue(0); - } - - usb_cdc.connected = true; + usb_cdc_to_connected(); } void tud_suspend_cb(bool remote_wakeup_en) { - ESP_LOGI(TAG, "Suspend"); - - if(usb_cdc.connected) { - led_set_blue(255); - delay(10); - led_set_blue(0); - } - - usb_cdc.connected = false; + usb_cdc_from_connected(); } -void usb_cdc_init(void) { - usb_cdc.connected = false; - - ESP_LOGI(TAG, "init"); - +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; @@ -159,25 +168,15 @@ void usb_cdc_init(void) { delay(100); gpio_set_level(USB_DN_PIN, 1); gpio_set_level(USB_DP_PIN, 1); +} - tinyusb_config_t tusb_cfg = { - .descriptor = NULL, //Uses default descriptor specified in Menuconfig - .string_descriptor = NULL, //Uses default string specified in Menuconfig - .external_phy = false, - }; - - ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); - - tinyusb_config_cdcacm_t amc_cfg = { - .usb_dev = CDC_USB_DEV, - .cdc_port = TINYUSB_CDC_ACM_0, - .rx_unread_buf_sz = 64, - .callback_rx = &usb_cdc_rx_callback, - .callback_rx_wanted_char = NULL, - .callback_line_state_changed = &usb_cdc_line_state_changed_callback, - .callback_line_coding_changed = &usb_cdc_line_coding_changed_callback}; - - ESP_ERROR_CHECK(tusb_cdc_acm_init(&amc_cfg)); +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"); } diff --git a/main/usb-cdc.h b/main/usb-cdc.h index a11099f..deba5f2 100644 --- a/main/usb-cdc.h +++ b/main/usb-cdc.h @@ -5,10 +5,6 @@ */ void usb_cdc_init(void); -/** - * Send data - * @param buffer data - * @param size data size - * @param flush - */ -void usb_cdc_send(uint8_t* buffer, size_t size, bool flush); \ No newline at end of file +void usb_cdc_gdb_tx_char(uint8_t c, bool flush); + +void usb_cdc_uart_tx_char(uint8_t c, bool flush); \ No newline at end of file diff --git a/main/usb-uart.c b/main/usb-uart.c new file mode 100644 index 0000000..f57580e --- /dev/null +++ b/main/usb-uart.c @@ -0,0 +1,168 @@ +#include +#include +#include +#include +#include +#include "usb-cdc.h" +#include "usb-uart.h" + +#define USB_UART_PORT_NUM UART_NUM_0 +#define USB_UART_TXD_PIN (43) +#define USB_UART_RXD_PIN (44) +#define USB_UART_BAUD_RATE (115200) +#define USB_UART_BUF_SIZE (128) +#define USB_UART_TX_BUF_SIZE (64) +#define USB_UART_RX_BUF_SIZE (64) + +static StreamBufferHandle_t uart_rx_stream; + +static void usb_uart_rx_isr(void* context); +static void usb_uart_rx_task(void* pvParameters); + +static const char* TAG = "usb-uart"; + +void usb_uart_init() { + ESP_LOGI(TAG, "init"); + + uart_rx_stream = xStreamBufferCreate(USB_UART_BUF_SIZE * 4, 1); + + xTaskCreate(usb_uart_rx_task, "usb_uart_rx", 4096, NULL, 5, NULL); + + // esp_log_level_set("*", ESP_LOG_NONE); + + UartConfig config = { + .uart_num = USB_UART_PORT_NUM, + .baud_rate = USB_UART_BAUD_RATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .tx_pin_num = USB_UART_TXD_PIN, + .rx_pin_num = USB_UART_RXD_PIN, + .isr_context = uart_rx_stream, + .rx_isr = usb_uart_rx_isr, + }; + + simple_uart_init(&config); + + usb_uart_write((const uint8_t*)"Go", 2); + + ESP_LOGI(TAG, "init done"); +} + +void usb_uart_write(const uint8_t* data, size_t data_size) { + /*for(size_t i = 0; i < data_size; i++) { + uart_tx_buffer[uart_tx_index] = data[i]; + uart_tx_index++; + + if(uart_tx_index == USB_UART_TX_BUF_SIZE) { + //cli_uart_flush(NULL); + + } + }*/ + + simple_uart_write(USB_UART_PORT_NUM, data, data_size); +} + +void usb_uart_set_line_state(bool dtr, bool rts) { + // do nothing, we don't have rts and dtr pins +} + +void usb_uart_set_line_coding( + uint32_t bit_rate, + uint8_t stop_bits, + uint8_t parity, + uint8_t data_bits) { + simple_uart_set_baud_rate(USB_UART_PORT_NUM, bit_rate); + + // cdc.h + // 0: 1 stop bit + // 1: 1.5 stop bits + // 2: 2 stop bits + switch(stop_bits) { + case 0: + simple_uart_set_stop_bits(USB_UART_PORT_NUM, UART_STOP_BITS_1); + break; + case 1: + simple_uart_set_stop_bits(USB_UART_PORT_NUM, UART_STOP_BITS_1_5); + break; + case 2: + simple_uart_set_stop_bits(USB_UART_PORT_NUM, UART_STOP_BITS_2); + break; + default: + break; + } + + // cdc.h + // 0: None + // 1: Odd + // 2: Even + // 3: Mark + // 4: Space + switch(parity) { + case 0: + simple_uart_set_parity(USB_UART_PORT_NUM, UART_PARITY_DISABLE); + break; + case 1: + simple_uart_set_parity(USB_UART_PORT_NUM, UART_PARITY_ODD); + break; + case 2: + simple_uart_set_parity(USB_UART_PORT_NUM, UART_PARITY_EVEN); + break; + default: + break; + } + + // cdc.h + // 5, 6, 7, 8 or 16 + switch(parity) { + case 5: + simple_uart_set_data_bits(USB_UART_PORT_NUM, UART_DATA_5_BITS); + break; + case 6: + simple_uart_set_data_bits(USB_UART_PORT_NUM, UART_DATA_6_BITS); + break; + case 7: + simple_uart_set_data_bits(USB_UART_PORT_NUM, UART_DATA_7_BITS); + break; + case 8: + simple_uart_set_data_bits(USB_UART_PORT_NUM, UART_DATA_8_BITS); + break; + default: + break; + } +} + +static void usb_uart_rx_task(void* pvParameters) { + while(1) { + uint8_t data[USB_UART_RX_BUF_SIZE]; + size_t length = + xStreamBufferReceive(uart_rx_stream, data, USB_UART_RX_BUF_SIZE, portMAX_DELAY); + + if(length > 0) { + for(size_t i = 0; i < length; i++) { + if((i + 1) == length) { + usb_cdc_uart_tx_char(data[i], true); + } else { + usb_cdc_uart_tx_char(data[i], false); + } + } + } + } +} + +static void usb_uart_rx_isr(void* context) { + StreamBufferHandle_t stream = context; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + uint8_t data; + while(simple_uart_available(USB_UART_PORT_NUM)) { + simple_uart_read(USB_UART_PORT_NUM, &data, 1); + + size_t ret __attribute__((unused)); + ret = xStreamBufferSendFromISR(stream, &data, 1, &xHigherPriorityTaskWoken); + // we will drop data if the stream overflows + // ESP_ERROR_CHECK(ret != 1); + } + + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} \ No newline at end of file diff --git a/main/usb-uart.h b/main/usb-uart.h new file mode 100644 index 0000000..5f5f98a --- /dev/null +++ b/main/usb-uart.h @@ -0,0 +1,21 @@ +/** + * @file usb-uart.h + * @author Sergey Gavrilov (who.just.the.doctor@gmail.com) + * @version 1.0 + * @date 2021-12-17 + * + * + */ +#pragma once + +void usb_uart_init(); + +void usb_uart_write(const uint8_t* data, size_t data_size); + +void usb_uart_set_line_state(bool dtr, bool rts); + +void usb_uart_set_line_coding( + uint32_t bit_rate, + uint8_t stop_bits, + uint8_t parity, + uint8_t data_bits); \ No newline at end of file diff --git a/sdkconfig b/sdkconfig index 7234572..db424e5 100644 --- a/sdkconfig +++ b/sdkconfig @@ -43,13 +43,13 @@ CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set -# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set +CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y # CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set # CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set -CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y +# CONFIG_BOOTLOADER_LOG_LEVEL_INFO is not set # CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set # CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set -CONFIG_BOOTLOADER_LOG_LEVEL=3 +CONFIG_BOOTLOADER_LOG_LEVEL=0 CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y # CONFIG_BOOTLOADER_FACTORY_RESET is not set # CONFIG_BOOTLOADER_APP_TEST is not set @@ -462,14 +462,12 @@ CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y # CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 -CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_UART_DEFAULT is not set # CONFIG_ESP_CONSOLE_USB_CDC is not set # CONFIG_ESP_CONSOLE_UART_CUSTOM is not set -# CONFIG_ESP_CONSOLE_NONE is not set -CONFIG_ESP_CONSOLE_UART=y +CONFIG_ESP_CONSOLE_NONE=y CONFIG_ESP_CONSOLE_MULTIPLE_UART=y -CONFIG_ESP_CONSOLE_UART_NUM=0 -CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_CONSOLE_UART_NUM=-1 # CONFIG_ESP_INT_WDT is not set # CONFIG_ESP_TASK_WDT is not set # CONFIG_ESP_PANIC_HANDLER_IRAM is not set @@ -1095,47 +1093,6 @@ CONFIG_WS_BUFFER_SIZE=1024 # end of Websocket # end of TCP Transport -# -# TinyUSB Stack -# -CONFIG_TINYUSB=y -CONFIG_TINYUSB_DEBUG_LEVEL=0 - -# -# TinyUSB task configuration -# -# CONFIG_TINYUSB_NO_DEFAULT_TASK is not set -CONFIG_TINYUSB_TASK_PRIORITY=17 -CONFIG_TINYUSB_TASK_STACK_SIZE=4096 -# end of TinyUSB task configuration - -# -# Descriptor configuration -# -CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID=y -CONFIG_TINYUSB_DESC_USE_DEFAULT_PID=y -CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100 -CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Flipper Devices Inc." -CONFIG_TINYUSB_DESC_PRODUCT_STRING="Blackmagic ESP32" -CONFIG_TINYUSB_DESC_SERIAL_STRING="blackmagic" -CONFIG_TINYUSB_DESC_CDC_STRING="Blackmagic ESP32" -# end of Descriptor configuration - -# -# Massive Storage Class (MSC) -# -# CONFIG_TINYUSB_MSC_ENABLED is not set -# end of Massive Storage Class (MSC) - -# -# Communication Device Class (CDC) -# -CONFIG_TINYUSB_CDC_ENABLED=y -CONFIG_TINYUSB_CDC_RX_BUFSIZE=64 -CONFIG_TINYUSB_CDC_TX_BUFSIZE=64 -# end of Communication Device Class (CDC) -# end of TinyUSB Stack - # # Unity unit testing library # @@ -1211,13 +1168,13 @@ CONFIG_WPA_MBEDTLS_CRYPTO=y # Deprecated options for backward compatibility CONFIG_TOOLPREFIX="xtensa-esp32s2-elf-" -# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set +CONFIG_LOG_BOOTLOADER_LEVEL_NONE=y # CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set # CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set -CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y +# CONFIG_LOG_BOOTLOADER_LEVEL_INFO is not set # CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set # CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set -CONFIG_LOG_BOOTLOADER_LEVEL=3 +CONFIG_LOG_BOOTLOADER_LEVEL=0 # CONFIG_APP_ROLLBACK_ENABLE is not set # CONFIG_FLASH_ENCRYPTION_ENABLED is not set # CONFIG_FLASHMODE_QIO is not set @@ -1270,12 +1227,10 @@ CONFIG_ESP32H2_MEMPROT_FEATURE_LOCK=y CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 CONFIG_MAIN_TASK_STACK_SIZE=3584 -CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_DEFAULT is not set # CONFIG_CONSOLE_UART_CUSTOM is not set -# CONFIG_ESP_CONSOLE_UART_NONE is not set -CONFIG_CONSOLE_UART=y -CONFIG_CONSOLE_UART_NUM=0 -CONFIG_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_CONSOLE_UART_NONE=y +CONFIG_CONSOLE_UART_NUM=-1 # CONFIG_INT_WDT is not set # CONFIG_TASK_WDT is not set CONFIG_TIMER_TASK_STACK_SIZE=3584 @@ -1333,21 +1288,6 @@ CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y # CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set # CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set -CONFIG_USB_ENABLED=y -CONFIG_USB_DEBUG_LEVEL=0 -# CONFIG_USB_DO_NOT_CREATE_TASK is not set -CONFIG_USB_TASK_PRIORITY=17 -CONFIG_USB_DESC_USE_ESPRESSIF_VID=y -CONFIG_USB_DESC_USE_DEFAULT_PID=y -CONFIG_USB_DESC_BCDDEVICE=0x0100 -CONFIG_USB_DESC_MANUFACTURER_STRING="Flipper Devices Inc." -CONFIG_USB_DESC_PRODUCT_STRING="Blackmagic ESP32" -CONFIG_USB_DESC_SERIAL_STRING="blackmagic" -CONFIG_USB_DESC_CDC_STRING="Blackmagic ESP32" -# CONFIG_USB_MSC_ENABLED is not set -CONFIG_USB_CDC_ENABLED=y -CONFIG_USB_CDC_RX_BUFSIZE=64 -CONFIG_USB_CDC_TX_BUFSIZE=64 CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y CONFIG_SUPPORT_TERMIOS=y CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1