Просмотр исходного кода

Merge branch 'feature/usb/update_cdc_examples' into 'master'

usb: Update host CDC examples

See merge request espressif/esp-idf!22825
Tomas Rezucha 2 лет назад
Родитель
Сommit
9f2012156c

+ 2 - 2
docs/en/api-reference/peripherals/usb_host.rst

@@ -363,8 +363,8 @@ CDC-ACM
 
 * A host class driver for the Communication Device Class (Abstract Control Model) is deployed to `IDF component registry <https://components.espressif.com/component/espressif/usb_host_cdc_acm>`__.
 * The :example:`peripherals/usb/host/cdc/cdc_acm_host` example uses the CDC-ACM host driver component to communicate with CDC-ACM devices
-* The :example:`peripherals/usb/host/cdc/cdc_acm_bg96` example uses the CDC-ACM host driver component to communicate with non-compliant CDC-ACM devices (i.e., vendor-specific classes that support a subset of CDC-ACM features) such as the Quectel BG96 modem.
 * The :example:`peripherals/usb/host/cdc/cdc_acm_vcp` example shows how can you extend the CDC-ACM host driver to interface Virtual COM Port devices.
+* The CDC-ACM driver is also used in `esp_modem examples <https://github.com/espressif/esp-protocols/tree/master/components/esp_modem/examples>`__, where it is used for communication with cellular modems.
 
 MSC
 """
@@ -405,4 +405,4 @@ Maintainers Notes
     :hidden:
     :maxdepth: 0
 
-    usb_host/usb_host_notes_index
+    usb_host/usb_host_notes_index

+ 0 - 8
examples/peripherals/usb/host/cdc/cdc_acm_bg96/CMakeLists.txt

@@ -1,8 +0,0 @@
-# For more information about build system see
-# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
-# The following five lines of boilerplate have to be in your project's
-# CMakeLists in this exact order for cmake to work correctly
-cmake_minimum_required(VERSION 3.16)
-
-include($ENV{IDF_PATH}/tools/cmake/project.cmake)
-project(cdc_acm_host_bg96)

+ 0 - 99
examples/peripherals/usb/host/cdc/cdc_acm_bg96/README.md

@@ -1,99 +0,0 @@
-| Supported Targets | ESP32-S2 | ESP32-S3 |
-| ----------------- | -------- | -------- |
-
-# USB CDC-ACM Host Driver BG96 Example
-
-(See the README.md file in the upper level 'examples' directory for more information about examples.)
-
-This example shows how to set up ESP chip to interface with CDC-like device by using the CDC-ACM Host Driver. CDC-like devices implement a Vendor-specific class, and support a subset of the functions of a fully compliant CDC-ACM device.
-
-## How to use example
-
-### Hardware Required
-
-Any ESP board with USB-OTG supported and a Quectel BG96 LTE/GPS modem.
-
-Connect USB_D+, USB_D-, GND and +5V signals of ESP board to BG96.
-
-_Note:_ Quectel BG96 modem must be started after power-up by applying low pulse on PWRKEY (pin 15).
-
-#### Pin Assignment
-
-See common pin assignments for USB Device examples from [upper level](../../../README.md#common-pin-assignments).
-
-### Build and Flash
-
-Build the project and flash it to the board, then run monitor tool to view serial output:
-
-```bash
-idf.py -p PORT flash monitor
-```
-
-(Replace PORT with the name of the serial port to use.)
-
-(To exit the serial monitor, type ``Ctrl-]``.)
-
-See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
-
-## Example Output
-
-After the flashing you should see the output at idf monitor:
-
-```
-I (276) BG96: USB Host installed
-I (24446) AT: ATE0
-I (24446) AT: 
-OK
-
-I (24526) AT: 
-+QIND: SMS DONE
-
-I (24646) AT: 
-APP RDY
-
-I (25446) BG96: Sending AT
-I (25446) AT: 
-OK
-
-I (26446) BG96: Enabling GNSS
-I (26446) AT: 
-OK
-
-GPVTG Sentence:
-  Track [deg]:   0.00
-  Speed [kmph]:  0.00
-  Speed [knots]: 0.00
-GPGSA Sentence:
-  Mode: A
-  Fix:  1
-  PDOP: 0.00
-  HDOP: 0.00
-  VDOP: 0.00
-GPGGA sentence
-Number of satellites: 0
-Altitude: 0.000000
-GPRMC sentence
-Longitude:
-  Degrees: 0
-  Minutes: 0.000000
-  Cardinal:
-Latitude:
-  Degrees: 0
-  Minutes: 0.000000
-  Cardinal: 
-Date & Time: 00 Jan 00:00:00 1900
-Speed, in Knots: 0.000000
-Track, in degrees: 0.000000
-Magnetic Variation:
-  Degrees: 0.000000
-  Cardinal: 
-Invalid Magnetic Variation Direction!
-Adjusted Track (heading): 0.000000
-I (27446) BG96: Sending AT+GSN
-I (27446) AT: 
-860517045660414
-
-OK
-...
-
-```

+ 0 - 2
examples/peripherals/usb/host/cdc/cdc_acm_bg96/main/CMakeLists.txt

@@ -1,2 +0,0 @@
-idf_component_register(SRCS "cdc_acm_host_bg96.cpp"
-                    INCLUDE_DIRS ".")

+ 0 - 84
examples/peripherals/usb/host/cdc/cdc_acm_bg96/main/bg96_usb.hpp

@@ -1,84 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: CC0-1.0
- */
-
-#pragma once
-
-#include "usb/cdc_acm_host.h"
-#include "esp_log.h"
-
-#define BG96_VID            (0x2C7C)
-#define BG96_PID            (0x0296)
-#define BG96_AT_INTERFACE   (2)
-#define BG96_NMEA_INTERFACE (1)
-
-class Bg96Usb {
-public:
-
-    explicit  Bg96Usb() : at_opened(false) {
-    };
-
-    esp_err_t at_start(cdc_acm_data_callback_t data_cb, void *user_arg)
-    {
-        // This driver doesn't support CDC notifications. This can lead to silent failures
-        const cdc_acm_host_device_config_t dev_config = {
-            .connection_timeout_ms = 10000,
-            .out_buffer_size = 64,
-            .event_cb = NULL,
-            .data_cb = data_cb,
-            .user_arg = user_arg,
-        };
-        ESP_ERROR_CHECK(this->at_port.open_vendor_specific(BG96_VID, BG96_PID, BG96_AT_INTERFACE, &dev_config));
-        this->at_opened = true;
-
-        // Some FW versions have Echo enabled by default. Disable it with ATE0 command
-        ESP_LOGD("BG96_USB", "Turning off echo with ATE0");
-        ESP_ERROR_CHECK(this->at_port.tx_blocking((uint8_t *)"ATE0\r", 5, 1000));
-        vTaskDelay(100);
-        return ESP_OK;
-    }
-
-    void at_stop()
-    {
-        this->at_port.close();
-        this->at_opened = false;
-    }
-
-    esp_err_t at_write(uint8_t *data, size_t len)
-    {
-        ESP_LOG_BUFFER_HEXDUMP("BG96_USB", data, len, ESP_LOG_DEBUG);
-        return this->at_port.tx_blocking(data, len, 1000);
-    }
-
-    esp_err_t gnss_start(cdc_acm_data_callback_t data_cb)
-    {
-        if (!this->at_opened) {
-            return  ESP_ERR_INVALID_STATE;
-        }
-
-        const cdc_acm_host_device_config_t dev_config = {
-            .connection_timeout_ms = 1000,
-            .out_buffer_size = 0, // Read-only
-            .event_cb = NULL,
-            .data_cb = data_cb,
-            .user_arg = this,
-        };
-        ESP_ERROR_CHECK(this->nmea_port.open_vendor_specific(BG96_VID, BG96_PID, BG96_NMEA_INTERFACE, &dev_config));
-        return this->at_port.tx_blocking((uint8_t*)"AT+QGPS=1\r", 10, 1000);
-    }
-
-    esp_err_t gnss_stop()
-    {
-        esp_err_t ret = this->at_port.tx_blocking((uint8_t*)"AT+QGPSEND\r", 11, 1000);
-        this->nmea_port.close();
-        return ret;
-    }
-
-protected:
-    CdcAcmDevice at_port;   // Main control port for AT commands
-    CdcAcmDevice nmea_port; // Read only port for NMEA messages
-private:
-    bool at_opened;
-};

+ 0 - 208
examples/peripherals/usb/host/cdc/cdc_acm_bg96/main/cdc_acm_host_bg96.cpp

@@ -1,208 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: CC0-1.0
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "esp_system.h"
-#include "freertos/FreeRTOS.h"
-#include "freertos/task.h"
-#include "esp_log.h"
-
-#include "usb/usb_host.h"
-#include "bg96_usb.hpp"
-
-#include "nmea.h"
-#include "gpgll.h"
-#include "gpgga.h"
-#include "gprmc.h"
-#include "gpgsa.h"
-#include "gpvtg.h"
-#include "gptxt.h"
-#include "gpgsv.h"
-
-#define EXAMPLE_USB_HOST_PRIORITY 20
-
-static const char* TAG = "BG96";
-
-static char fmt_buf[32];
-
-/* ------------------------------- Callbacks -------------------------------- */
-
-static void handle_rx(uint8_t *data, size_t data_len, void *user_arg)
-{
-    data[data_len] = '\0';
-    ESP_LOGI("AT", "%s", data);
-}
-
-static void handle_gps(uint8_t* data, size_t data_len, void *user_arg)
-{
-    // handle nmea_data
-    nmea_s *nmea_data = nmea_parse((char *)data, data_len, 0);
-    if (nmea_data == NULL) {
-        printf("Failed to parse the sentence!\n");
-        printf("  Type: %.5s (%d)\n", data + 1, nmea_get_type((const char *)data));
-    } else {
-        if (nmea_data->errors != 0) {
-            printf("WARN: The sentence struct contains parse errors!\n");
-        }
-
-        if (NMEA_GPGGA == nmea_data->type) {
-            printf("GPGGA sentence\n");
-            nmea_gpgga_s *gpgga = (nmea_gpgga_s *)nmea_data;
-            printf("Number of satellites: %d\n", gpgga->n_satellites);
-            printf("Altitude: %f %c\n", gpgga->altitude, gpgga->altitude_unit);
-        }
-
-        if (NMEA_GPGLL == nmea_data->type) {
-            printf("GPGLL sentence\n");
-            nmea_gpgll_s *pos = (nmea_gpgll_s *)nmea_data;
-            printf("Longitude:\n");
-            printf("  Degrees: %d\n", pos->longitude.degrees);
-            printf("  Minutes: %f\n", pos->longitude.minutes);
-            printf("  Cardinal: %c\n", (char)pos->longitude.cardinal);
-            printf("Latitude:\n");
-            printf("  Degrees: %d\n", pos->latitude.degrees);
-            printf("  Minutes: %f\n", pos->latitude.minutes);
-            printf("  Cardinal: %c\n", (char)pos->latitude.cardinal);
-            strftime(fmt_buf, sizeof(fmt_buf), "%H:%M:%S", &pos->time);
-            printf("Time: %s\n", fmt_buf);
-        }
-
-        if (NMEA_GPRMC == nmea_data->type) {
-            printf("GPRMC sentence\n");
-            nmea_gprmc_s *pos = (nmea_gprmc_s *)nmea_data;
-            printf("Longitude:\n");
-            printf("  Degrees: %d\n", pos->longitude.degrees);
-            printf("  Minutes: %f\n", pos->longitude.minutes);
-            printf("  Cardinal: %c\n", (char)pos->longitude.cardinal);
-            printf("Latitude:\n");
-            printf("  Degrees: %d\n", pos->latitude.degrees);
-            printf("  Minutes: %f\n", pos->latitude.minutes);
-            printf("  Cardinal: %c\n", (char)pos->latitude.cardinal);
-            strftime(fmt_buf, sizeof(fmt_buf), "%d %b %T %Y", &pos->date_time);
-            printf("Date & Time: %s\n", fmt_buf);
-            printf("Speed, in Knots: %f\n", pos->gndspd_knots);
-            printf("Track, in degrees: %f\n", pos->track_deg);
-            printf("Magnetic Variation:\n");
-            printf("  Degrees: %f\n", pos->magvar_deg);
-            printf("  Cardinal: %c\n", (char)pos->magvar_cardinal);
-            double adjusted_course = pos->track_deg;
-            if (NMEA_CARDINAL_DIR_EAST == pos->magvar_cardinal) {
-                adjusted_course -= pos->magvar_deg;
-            } else if (NMEA_CARDINAL_DIR_WEST == pos->magvar_cardinal) {
-                adjusted_course += pos->magvar_deg;
-            } else {
-                printf("Invalid Magnetic Variation Direction!\n");
-            }
-
-            printf("Adjusted Track (heading): %f\n", adjusted_course);
-        }
-
-        if (NMEA_GPGSA == nmea_data->type) {
-            nmea_gpgsa_s *gpgsa = (nmea_gpgsa_s *)nmea_data;
-
-            printf("GPGSA Sentence:\n");
-            printf("  Mode: %c\n", gpgsa->mode);
-            printf("  Fix:  %d\n", gpgsa->fixtype);
-            printf("  PDOP: %.2lf\n", gpgsa->pdop);
-            printf("  HDOP: %.2lf\n", gpgsa->hdop);
-            printf("  VDOP: %.2lf\n", gpgsa->vdop);
-        }
-
-        if (NMEA_GPGSV == nmea_data->type) {
-            nmea_gpgsv_s *gpgsv = (nmea_gpgsv_s *)nmea_data;
-
-            printf("GPGSV Sentence:\n");
-            printf("  Num: %d\n", gpgsv->sentences);
-            printf("  ID:  %d\n", gpgsv->sentence_number);
-            printf("  SV:  %d\n", gpgsv->satellites);
-            printf("  #1:  %d %d %d %d\n", gpgsv->sat[0].prn, gpgsv->sat[0].elevation, gpgsv->sat[0].azimuth,
-                   gpgsv->sat[0].snr);
-            printf("  #2:  %d %d %d %d\n", gpgsv->sat[1].prn, gpgsv->sat[1].elevation, gpgsv->sat[1].azimuth,
-                   gpgsv->sat[1].snr);
-            printf("  #3:  %d %d %d %d\n", gpgsv->sat[2].prn, gpgsv->sat[2].elevation, gpgsv->sat[2].azimuth,
-                   gpgsv->sat[2].snr);
-            printf("  #4:  %d %d %d %d\n", gpgsv->sat[3].prn, gpgsv->sat[3].elevation, gpgsv->sat[3].azimuth,
-                   gpgsv->sat[3].snr);
-        }
-
-        if (NMEA_GPTXT == nmea_data->type) {
-            nmea_gptxt_s *gptxt = (nmea_gptxt_s *)nmea_data;
-
-            printf("GPTXT Sentence:\n");
-            printf("  ID: %d %d %d\n", gptxt->id_00, gptxt->id_01, gptxt->id_02);
-            printf("  %s\n", gptxt->text);
-        }
-
-        if (NMEA_GPVTG == nmea_data->type) {
-            nmea_gpvtg_s *gpvtg = (nmea_gpvtg_s *)nmea_data;
-
-            printf("GPVTG Sentence:\n");
-            printf("  Track [deg]:   %.2lf\n", gpvtg->track_deg);
-            printf("  Speed [kmph]:  %.2lf\n", gpvtg->gndspd_kmph);
-            printf("  Speed [knots]: %.2lf\n", gpvtg->gndspd_knots);
-        }
-
-        nmea_free(nmea_data);
-    }
-}
-
-void usb_lib_task(void *arg)
-{
-    while (1) {
-        //Start handling system events
-        uint32_t event_flags;
-        usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
-        if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
-            printf("No more clients\n");
-            ESP_ERROR_CHECK(usb_host_device_free_all());
-        }
-        if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
-            break;
-        }
-    }
-
-    //Short delay to allow task to be cleaned up
-    vTaskDelay(10);
-    //Clean up USB Host
-    ESP_ERROR_CHECK(usb_host_uninstall());
-    vTaskDelete(NULL);
-}
-
-/* ---------------------------------- Main ---------------------------------- */
-extern "C" void app_main(void)
-{
-    //Install USB Host driver. Should only be called once in entire application
-    ESP_LOGI(TAG, "Installing USB Host");
-    usb_host_config_t host_config = {
-        .skip_phy_setup = false,
-        .intr_flags = ESP_INTR_FLAG_LEVEL1,
-    };
-    ESP_ERROR_CHECK(usb_host_install(&host_config));
-
-    // Create a task that will handle USB library events
-    xTaskCreate(usb_lib_task, "usb_lib", 4096, NULL, EXAMPLE_USB_HOST_PRIORITY, NULL);
-
-    ESP_LOGI(TAG, "Installing CDC-ACM driver");
-    ESP_ERROR_CHECK(cdc_acm_host_install(NULL));
-
-    Bg96Usb *bg96 = new Bg96Usb();
-    bg96->at_start(handle_rx, NULL);
-
-    static char text1[] = "AT\r";
-    static char text2[] = "AT+GSN\r";
-
-    ESP_LOGI(TAG, "Sending AT");
-    bg96->at_write((uint8_t *)text1, strlen(text1));
-    vTaskDelay(100);
-
-    ESP_LOGI(TAG, "Enabling GNSS");
-    bg96->gnss_start(handle_gps);
-
-    vTaskDelay(100);
-    ESP_LOGI(TAG, "Sending AT+GSN");
-    bg96->at_write((uint8_t *)text2, strlen(text2));
-}

+ 0 - 5
examples/peripherals/usb/host/cdc/cdc_acm_bg96/main/idf_component.yml

@@ -1,5 +0,0 @@
-## IDF Component Manager Manifest File
-dependencies:
-  idf: ">=4.4"
-  igrr/libnmea: "^0.1.1"
-  usb_host_cdc_acm: "1.*"

+ 0 - 9
examples/peripherals/usb/host/cdc/cdc_acm_host/README.md

@@ -33,15 +33,6 @@ idf.py -p PORT flash monitor
 
 See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
 
-### Running with dual USB CDC device
-USB CDC device example [tusb_serial_device example](../../../device/tusb_serial_device)
-can be configured to act as dual CDC device.
-
-In the device example project, enter command `idf.py menuconfig` and set Component config->TinyUSB Stack->Communication Device Class (CDC)->CDC channel Count to `2`.
-
-This settings also changes device's PID, so `EXAMPLE_USB_DEVICE_PID` in [usb-cdc.c](./main/usb-cdc.c) must be changed to `0x4002`.
-
-
 ## Example Output
 
 After the flashing you should see the output at idf monitor:

+ 1 - 2
examples/peripherals/usb/host/cdc/cdc_acm_host/main/CMakeLists.txt

@@ -1,3 +1,2 @@
-idf_component_register(SRCS "usb-cdc.c"
+idf_component_register(SRCS "usb_cdc_example_main.c"
                     INCLUDE_DIRS ".")
-target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

+ 1 - 1
examples/peripherals/usb/host/cdc/cdc_acm_host/main/idf_component.yml

@@ -1,4 +1,4 @@
 ## IDF Component Manager Manifest File
 dependencies:
-  usb_host_cdc_acm: "1.*"
+  usb_host_cdc_acm: "2.*"
   idf: ">=4.4"

+ 0 - 113
examples/peripherals/usb/host/cdc/cdc_acm_host/main/usb-cdc.c

@@ -1,113 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: CC0-1.0
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "esp_system.h"
-#include "freertos/FreeRTOS.h"
-#include "freertos/task.h"
-#include "esp_log.h"
-#include "esp_err.h"
-#include "usb/usb_host.h"
-#include "usb/cdc_acm_host.h"
-
-#define EXAMPLE_USB_HOST_PRIORITY 20
-#define EXAMPLE_USB_DEVICE_VID    0x303A  // 0x303A:0x4001 (TinyUSB CDC device)
-#define EXAMPLE_USB_DEVICE_PID    0x4001  // Change this to 0x4002 for dual CDC device
-
-static const char *TAG = "USB-CDC";
-
-/* ------------------------------- Callbacks -------------------------------- */
-static void handle_rx(uint8_t *data, size_t data_len, void *arg)
-{
-    ESP_LOGI(TAG, "Data received");
-    ESP_LOG_BUFFER_HEXDUMP(TAG, data, data_len, ESP_LOG_INFO);
-}
-
-void usb_lib_task(void *arg)
-{
-    while (1) {
-        //Start handling system events
-        uint32_t event_flags;
-        usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
-        if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
-            ESP_LOGI(TAG, "All clients deregistered");
-            ESP_ERROR_CHECK(usb_host_device_free_all());
-        }
-        if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
-            break;
-        }
-    }
-
-    //Clean up USB Host
-    ESP_ERROR_CHECK(usb_host_uninstall());
-    vTaskDelete(NULL);
-}
-
-/* ---------------------------------- Main ---------------------------------- */
-void app_main(void)
-{
-    //Install USB Host driver. Should only be called once in entire application
-    ESP_LOGI(TAG, "Installing USB Host");
-    usb_host_config_t host_config = {
-        .skip_phy_setup = false,
-        .intr_flags = ESP_INTR_FLAG_LEVEL1,
-    };
-    ESP_ERROR_CHECK(usb_host_install(&host_config));
-
-    // Create a task that will handle USB library events
-    xTaskCreate(usb_lib_task, "usb_lib", 4096, xTaskGetCurrentTaskHandle(), EXAMPLE_USB_HOST_PRIORITY, NULL);
-
-    ESP_LOGI(TAG, "Installing CDC-ACM driver");
-    ESP_ERROR_CHECK(cdc_acm_host_install(NULL));
-
-    ESP_LOGI(TAG, "Opening CDC ACM device 0x%04X:0x%04X", EXAMPLE_USB_DEVICE_VID, EXAMPLE_USB_DEVICE_PID);
-    cdc_acm_dev_hdl_t cdc_dev;
-    const cdc_acm_host_device_config_t dev_config = {
-        .connection_timeout_ms = 5000,
-        .out_buffer_size = 64,
-        .user_arg = NULL,
-        .event_cb = NULL,
-        .data_cb = handle_rx
-    };
-    ESP_ERROR_CHECK(cdc_acm_host_open(EXAMPLE_USB_DEVICE_VID, EXAMPLE_USB_DEVICE_PID, 0, &dev_config, &cdc_dev));
-    assert(cdc_dev);
-    cdc_acm_host_desc_print(cdc_dev);
-    vTaskDelay(100);
-
-    // Test sending and receiving: Send AT commands, responses are handled in handle_rx callback
-    static char text1[] = "AT\r";
-    ESP_ERROR_CHECK(cdc_acm_host_data_tx_blocking(cdc_dev, (uint8_t *)text1, strlen(text1), 1000));
-    vTaskDelay(100);
-
-    static char text2[] = "AT+GSN\r";
-    ESP_ERROR_CHECK(cdc_acm_host_data_tx_blocking(cdc_dev, (uint8_t *)text2, strlen(text2), 1000));
-    vTaskDelay(100);
-
-    // Test Line Coding commands: Get current line coding, change it 9600 7N1 and read again
-    ESP_LOGI(TAG, "Setting up line coding");
-
-    cdc_acm_line_coding_t line_coding;
-    ESP_ERROR_CHECK(cdc_acm_host_line_coding_get(cdc_dev, &line_coding));
-    ESP_LOGI(TAG, "Line Get: Rate: %d, Stop bits: %d, Parity: %d, Databits: %d", line_coding.dwDTERate,
-             line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
-
-    line_coding.dwDTERate = 9600;
-    line_coding.bDataBits = 7;
-    line_coding.bParityType = 1;
-    line_coding.bCharFormat = 1;
-    ESP_ERROR_CHECK(cdc_acm_host_line_coding_set(cdc_dev, &line_coding));
-    ESP_LOGI(TAG, "Line Set: Rate: %d, Stop bits: %d, Parity: %d, Databits: %d", line_coding.dwDTERate,
-             line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
-
-    ESP_ERROR_CHECK(cdc_acm_host_line_coding_get(cdc_dev, &line_coding));
-    ESP_LOGI(TAG, "Line Get: Rate: %d, Stop bits: %d, Parity: %d, Databits: %d", line_coding.dwDTERate,
-             line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
-
-    ESP_ERROR_CHECK(cdc_acm_host_set_control_line_state(cdc_dev, true, false));
-
-    ESP_LOGI(TAG, "Example finished successfully!");
-}

+ 179 - 0
examples/peripherals/usb/host/cdc/cdc_acm_host/main/usb_cdc_example_main.c

@@ -0,0 +1,179 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include "esp_system.h"
+#include "esp_log.h"
+#include "esp_err.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+
+#include "usb/usb_host.h"
+#include "usb/cdc_acm_host.h"
+
+#define EXAMPLE_USB_HOST_PRIORITY   (20)
+#define EXAMPLE_USB_DEVICE_VID      (0x303A)
+#define EXAMPLE_USB_DEVICE_PID      (0x4001) // 0x303A:0x4001 (TinyUSB CDC device)
+#define EXAMPLE_USB_DEVICE_DUAL_PID (0x4002) // 0x303A:0x4002 (TinyUSB Dual CDC device)
+#define EXAMPLE_TX_STRING           ("CDC test string!")
+#define EXAMPLE_TX_TIMEOUT_MS       (1000)
+
+static const char *TAG = "USB-CDC";
+static SemaphoreHandle_t device_disconnected_sem;
+
+/**
+ * @brief Data received callback
+ *
+ * @param[in] data     Pointer to received data
+ * @param[in] data_len Length of received data in bytes
+ * @param[in] arg      Argument we passed to the device open function
+ * @return
+ *   true:  We have processed the received data
+ *   false: We expect more data
+ */
+static bool handle_rx(const uint8_t *data, size_t data_len, void *arg)
+{
+    ESP_LOGI(TAG, "Data received");
+    ESP_LOG_BUFFER_HEXDUMP(TAG, data, data_len, ESP_LOG_INFO);
+    return true;
+}
+
+/**
+ * @brief Device event callback
+ *
+ * Apart from handling device disconnection it doesn't do anything useful
+ *
+ * @param[in] event    Device event type and data
+ * @param[in] user_ctx Argument we passed to the device open function
+ */
+static void handle_event(const cdc_acm_host_dev_event_data_t *event, void *user_ctx)
+{
+    switch (event->type) {
+        case CDC_ACM_HOST_ERROR:
+            ESP_LOGE(TAG, "CDC-ACM error has occurred, err_no = %i", event->data.error);
+            break;
+        case CDC_ACM_HOST_DEVICE_DISCONNECTED:
+            ESP_LOGI(TAG, "Device suddenly disconnected");
+            ESP_ERROR_CHECK(cdc_acm_host_close(event->data.cdc_hdl));
+            xSemaphoreGive(device_disconnected_sem);
+            break;
+        case CDC_ACM_HOST_SERIAL_STATE:
+            ESP_LOGI(TAG, "Serial state notif 0x%04X", event->data.serial_state.val);
+            break;
+        case CDC_ACM_HOST_NETWORK_CONNECTION:
+        default:
+            ESP_LOGW(TAG, "Unsupported CDC event: %i", event->type);
+            break;
+    }
+}
+
+/**
+ * @brief USB Host library handling task
+ *
+ * @param arg Unused
+ */
+static void usb_lib_task(void *arg)
+{
+    while (1) {
+        // Start handling system events
+        uint32_t event_flags;
+        usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
+        if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
+            ESP_ERROR_CHECK(usb_host_device_free_all());
+        }
+        if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
+            ESP_LOGI(TAG, "USB: All devices freed");
+            // Continue handling USB events to allow device reconnection
+        }
+    }
+}
+
+/**
+ * @brief Main application
+ *
+ * Here we open a USB CDC device and send some data to it
+ */
+void app_main(void)
+{
+    device_disconnected_sem = xSemaphoreCreateBinary();
+    assert(device_disconnected_sem);
+
+    // Install USB Host driver. Should only be called once in entire application
+    ESP_LOGI(TAG, "Installing USB Host");
+    const usb_host_config_t host_config = {
+        .skip_phy_setup = false,
+        .intr_flags = ESP_INTR_FLAG_LEVEL1,
+    };
+    ESP_ERROR_CHECK(usb_host_install(&host_config));
+
+    // Create a task that will handle USB library events
+    BaseType_t task_created = xTaskCreate(usb_lib_task, "usb_lib", 4096, xTaskGetCurrentTaskHandle(), EXAMPLE_USB_HOST_PRIORITY, NULL);
+    assert(task_created == pdTRUE);
+
+    ESP_LOGI(TAG, "Installing CDC-ACM driver");
+    ESP_ERROR_CHECK(cdc_acm_host_install(NULL));
+
+    const cdc_acm_host_device_config_t dev_config = {
+        .connection_timeout_ms = 1000,
+        .out_buffer_size = 512,
+        .in_buffer_size = 512,
+        .user_arg = NULL,
+        .event_cb = handle_event,
+        .data_cb = handle_rx
+    };
+
+    while (true) {
+        cdc_acm_dev_hdl_t cdc_dev = NULL;
+
+        // Open USB device from tusb_serial_device example example. Either single or dual port configuration.
+        ESP_LOGI(TAG, "Opening CDC ACM device 0x%04X:0x%04X...", EXAMPLE_USB_DEVICE_VID, EXAMPLE_USB_DEVICE_PID);
+        esp_err_t err = cdc_acm_host_open(EXAMPLE_USB_DEVICE_VID, EXAMPLE_USB_DEVICE_PID, 0, &dev_config, &cdc_dev);
+        if (ESP_OK != err) {
+            ESP_LOGI(TAG, "Opening CDC ACM device 0x%04X:0x%04X...", EXAMPLE_USB_DEVICE_VID, EXAMPLE_USB_DEVICE_DUAL_PID);
+            err = cdc_acm_host_open(EXAMPLE_USB_DEVICE_VID, EXAMPLE_USB_DEVICE_DUAL_PID, 0, &dev_config, &cdc_dev);
+            if (ESP_OK != err) {
+                ESP_LOGI(TAG, "Failed to open device");
+                continue;
+            }
+        }
+        cdc_acm_host_desc_print(cdc_dev);
+        vTaskDelay(pdMS_TO_TICKS(100));
+
+        // Test sending and receiving: responses are handled in handle_rx callback
+        ESP_ERROR_CHECK(cdc_acm_host_data_tx_blocking(cdc_dev, (const uint8_t *)EXAMPLE_TX_STRING, strlen(EXAMPLE_TX_STRING), EXAMPLE_TX_TIMEOUT_MS));
+        vTaskDelay(pdMS_TO_TICKS(100));
+
+        // Test Line Coding commands: Get current line coding, change it 9600 7N1 and read again
+        ESP_LOGI(TAG, "Setting up line coding");
+
+        cdc_acm_line_coding_t line_coding;
+        ESP_ERROR_CHECK(cdc_acm_host_line_coding_get(cdc_dev, &line_coding));
+        ESP_LOGI(TAG, "Line Get: Rate: %"PRIu32", Stop bits: %"PRIu8", Parity: %"PRIu8", Databits: %"PRIu8"",
+                 line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
+
+        line_coding.dwDTERate = 9600;
+        line_coding.bDataBits = 7;
+        line_coding.bParityType = 1;
+        line_coding.bCharFormat = 1;
+        ESP_ERROR_CHECK(cdc_acm_host_line_coding_set(cdc_dev, &line_coding));
+        ESP_LOGI(TAG, "Line Set: Rate: %"PRIu32", Stop bits: %"PRIu8", Parity: %"PRIu8", Databits: %"PRIu8"",
+                 line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
+
+        ESP_ERROR_CHECK(cdc_acm_host_line_coding_get(cdc_dev, &line_coding));
+        ESP_LOGI(TAG, "Line Get: Rate: %"PRIu32", Stop bits: %"PRIu8", Parity: %"PRIu8", Databits: %"PRIu8"",
+                 line_coding.dwDTERate, line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
+
+        ESP_ERROR_CHECK(cdc_acm_host_set_control_line_state(cdc_dev, true, false));
+
+        // We are done. Wait for device disconnection and start over
+        ESP_LOGI(TAG, "Example finished successfully! You can reconnect the device to run again.");
+        xSemaphoreTake(device_disconnected_sem, portMAX_DELAY);
+    }
+}

+ 3 - 3
examples/peripherals/usb/host/cdc/cdc_acm_vcp/README.md

@@ -1,18 +1,18 @@
 | Supported Targets | ESP32-S2 | ESP32-S3 |
 | ----------------- | -------- | -------- |
 
-# USB CDC-ACM Virtual Com Port example
+# USB CDC-ACM Virtual COM Port example
 
 (See the README.md file in the upper level 'examples' directory for more information about examples.)
 
 This example shows how to extend CDC-ACM driver for Virtual Communication Port (VCP) devices,
-such as CP210x, FTDI FT23x or CP34x devices.
+such as CP210x, FTDI FT23x or CH34x devices.
 
 The drivers are fetched from [IDF Component Registry](https://components.espressif.com/) together with VCP service that automatically loads correct driver for plugged-in device.
 
 ## How to use example
 
-1. Connect your USB<->UART converter to ESP32-S2/S3, the device will be automatically enumerated and correct driver will be picked
+1. Connect your USB<->UART converter to ESP32-S2/S3, the device will be automatically enumerated and correct driver will be loaded
 2. Change baudrate and other line coding parameters in [cdc_acm_vcp_example_main.cpp](main/cdc_acm_vcp_example_main.cpp) to match your needs
 3. Now you can use the usual CDC-ACM API to control the device and send data. Data are received in `handle_rx` callback
 4. Try disconnecting and then reconnecting of the USB device to experiment with USB hotplugging

+ 23 - 11
examples/peripherals/usb/host/cdc/cdc_acm_vcp/main/cdc_acm_vcp_example_main.cpp

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: CC0-1.0
  */
@@ -28,25 +28,36 @@ using namespace esp_usb;
 #define EXAMPLE_DATA_BITS    (8)
 
 namespace {
-const char *TAG = "VCP example";
-SemaphoreHandle_t device_disconnected_sem;
+static const char *TAG = "VCP example";
+static SemaphoreHandle_t device_disconnected_sem;
 
 /**
  * @brief Data received callback
  *
  * Just pass received data to stdout
+ *
+ * @param[in] data     Pointer to received data
+ * @param[in] data_len Length of received data in bytes
+ * @param[in] arg      Argument we passed to the device open function
+ * @return
+ *   true:  We have processed the received data
+ *   false: We expect more data
  */
-void handle_rx(uint8_t *data, size_t data_len, void *arg)
+static bool handle_rx(const uint8_t *data, size_t data_len, void *arg)
 {
     printf("%.*s", data_len, data);
+    return true;
 }
 
 /**
  * @brief Device event callback
  *
  * Apart from handling device disconnection it doesn't do anything useful
+ *
+ * @param[in] event    Device event type and data
+ * @param[in] user_ctx Argument we passed to the device open function
  */
-void handle_event(const cdc_acm_host_dev_event_data_t *event, void *user_ctx)
+static void handle_event(const cdc_acm_host_dev_event_data_t *event, void *user_ctx)
 {
     switch (event->type) {
         case CDC_ACM_HOST_ERROR:
@@ -69,7 +80,7 @@ void handle_event(const cdc_acm_host_dev_event_data_t *event, void *user_ctx)
  *
  * @param arg Unused
  */
-void usb_lib_task(void *arg)
+static void usb_lib_task(void *arg)
 {
     while (1) {
         // Start handling system events
@@ -89,14 +100,14 @@ void usb_lib_task(void *arg)
 /**
  * @brief Main application
  *
- * This function shows how you can use VCP drivers
+ * This function shows how you can use Virtual COM Port drivers
  */
 extern "C" void app_main(void)
 {
     device_disconnected_sem = xSemaphoreCreateBinary();
     assert(device_disconnected_sem);
 
-    //Install USB Host driver. Should only be called once in entire application
+    // Install USB Host driver. Should only be called once in entire application
     ESP_LOGI(TAG, "Installing USB Host");
     const usb_host_config_t host_config = {
         .skip_phy_setup = false,
@@ -111,7 +122,7 @@ extern "C" void app_main(void)
     ESP_LOGI(TAG, "Installing CDC-ACM driver");
     ESP_ERROR_CHECK(cdc_acm_host_install(NULL));
 
-    // Register VCP drivers to VCP service.
+    // Register VCP drivers to VCP service
     VCP::register_driver<FT23x>();
     VCP::register_driver<CP210x>();
     VCP::register_driver<CH34x>();
@@ -120,13 +131,14 @@ extern "C" void app_main(void)
     while (true) {
         const cdc_acm_host_device_config_t dev_config = {
             .connection_timeout_ms = 5000, // 5 seconds, enough time to plug the device in or experiment with timeout
-            .out_buffer_size = 64,
+            .out_buffer_size = 512,
+            .in_buffer_size = 512,
             .event_cb = handle_event,
             .data_cb = handle_rx,
             .user_arg = NULL,
         };
 
-        // You don't need to know the device's VID and PID. Just plug in any device and the VCP service will pick correct (already registered) driver for the device
+        // You don't need to know the device's VID and PID. Just plug in any device and the VCP service will load correct (already registered) driver for the device
         ESP_LOGI(TAG, "Opening any VCP device...");
         auto vcp = std::unique_ptr<CdcAcmDevice>(VCP::open(&dev_config));
 

+ 3 - 3
examples/peripherals/usb/host/cdc/cdc_acm_vcp/main/idf_component.yml

@@ -1,7 +1,7 @@
 ## IDF Component Manager Manifest File
 dependencies:
-  usb_host_ch34x_vcp: "^1"
-  usb_host_cp210x_vcp: "^1"
-  usb_host_ftdi_vcp: "^1"
+  usb_host_ch34x_vcp: "^2"
+  usb_host_cp210x_vcp: "^2"
+  usb_host_ftdi_vcp: "^2"
   usb_host_vcp: "^1"
   idf: ">=5.1.0"