1 /*
2  * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: CC0-1.0
5  */
6 
7 #include <stdio.h>
8 #include <string.h>
9 #include "esp_system.h"
10 #include "freertos/FreeRTOS.h"
11 #include "freertos/task.h"
12 #include "esp_log.h"
13 #include "esp_err.h"
14 #include "usb/usb_host.h"
15 #include "usb/cdc_acm_host.h"
16 
17 #define EXAMPLE_USB_HOST_PRIORITY 20
18 #define EXAMPLE_USB_DEVICE_VID    0x303A  // 0x303A:0x4001 (TinyUSB CDC device)
19 #define EXAMPLE_USB_DEVICE_PID    0x4001
20 
21 static const char *TAG = "USB-CDC";
22 
23 /* ------------------------------- Callbacks -------------------------------- */
handle_rx(uint8_t * data,size_t data_len,void * arg)24 static void handle_rx(uint8_t *data, size_t data_len, void *arg)
25 {
26     ESP_LOGI(TAG, "Data received");
27     ESP_LOG_BUFFER_HEXDUMP(TAG, data, data_len, ESP_LOG_INFO);
28 }
29 
usb_lib_task(void * arg)30 void usb_lib_task(void *arg)
31 {
32     while (1) {
33         //Start handling system events
34         uint32_t event_flags;
35         usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
36         if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
37             ESP_LOGI(TAG, "All clients deregistered");
38             ESP_ERROR_CHECK(usb_host_device_free_all());
39         }
40         if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
41             break;
42         }
43     }
44 
45     //Clean up USB Host
46     ESP_ERROR_CHECK(usb_host_uninstall());
47     vTaskDelete(NULL);
48 }
49 
50 /* ---------------------------------- Main ---------------------------------- */
app_main(void)51 void app_main(void)
52 {
53     //Install USB Host driver. Should only be called once in entire application
54     ESP_LOGI(TAG, "Installing USB Host");
55     usb_host_config_t host_config = {
56         .skip_phy_setup = false,
57         .intr_flags = ESP_INTR_FLAG_LEVEL1,
58     };
59     ESP_ERROR_CHECK(usb_host_install(&host_config));
60 
61     // Create a task that will handle USB library events
62     xTaskCreate(usb_lib_task, "usb_lib", 4096, xTaskGetCurrentTaskHandle(), EXAMPLE_USB_HOST_PRIORITY, NULL);
63 
64     ESP_LOGI(TAG, "Installing CDC-ACM driver");
65     ESP_ERROR_CHECK(cdc_acm_host_install(NULL));
66 
67     ESP_LOGI(TAG, "Opening CDC ACM device 0x%04X:0x%04X", EXAMPLE_USB_DEVICE_VID, EXAMPLE_USB_DEVICE_PID);
68     cdc_acm_dev_hdl_t cdc_dev;
69     const cdc_acm_host_device_config_t dev_config = {
70         .connection_timeout_ms = 5000,
71         .out_buffer_size = 64,
72         .user_arg = NULL,
73         .event_cb = NULL,
74         .data_cb = handle_rx
75     };
76     ESP_ERROR_CHECK(cdc_acm_host_open(EXAMPLE_USB_DEVICE_VID, EXAMPLE_USB_DEVICE_PID, 0, &dev_config, &cdc_dev));
77     assert(cdc_dev);
78     cdc_acm_host_desc_print(cdc_dev);
79     vTaskDelay(100);
80 
81     // Test sending and receiving: Send AT commands, responses are handled in handle_rx callback
82     static char text1[] = "AT\r";
83     ESP_ERROR_CHECK(cdc_acm_host_data_tx_blocking(cdc_dev, (uint8_t *)text1, strlen(text1), 1000));
84     vTaskDelay(100);
85 
86     static char text2[] = "AT+GSN\r";
87     ESP_ERROR_CHECK(cdc_acm_host_data_tx_blocking(cdc_dev, (uint8_t *)text2, strlen(text2), 1000));
88     vTaskDelay(100);
89 
90     // Test Line Coding commands: Get current line coding, change it 9600 7N1 and read again
91     ESP_LOGI(TAG, "Setting up line coding");
92 
93     cdc_acm_line_coding_t line_coding;
94     ESP_ERROR_CHECK(cdc_acm_host_line_coding_get(cdc_dev, &line_coding));
95     ESP_LOGI(TAG, "Line Get: Rate: %d, Stop bits: %d, Parity: %d, Databits: %d", line_coding.dwDTERate,
96              line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
97 
98     line_coding.dwDTERate = 9600;
99     line_coding.bDataBits = 7;
100     line_coding.bParityType = 1;
101     line_coding.bCharFormat = 1;
102     ESP_ERROR_CHECK(cdc_acm_host_line_coding_set(cdc_dev, &line_coding));
103     ESP_LOGI(TAG, "Line Set: Rate: %d, Stop bits: %d, Parity: %d, Databits: %d", line_coding.dwDTERate,
104              line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
105 
106     ESP_ERROR_CHECK(cdc_acm_host_line_coding_get(cdc_dev, &line_coding));
107     ESP_LOGI(TAG, "Line Get: Rate: %d, Stop bits: %d, Parity: %d, Databits: %d", line_coding.dwDTERate,
108              line_coding.bCharFormat, line_coding.bParityType, line_coding.bDataBits);
109 
110     ESP_ERROR_CHECK(cdc_acm_host_set_control_line_state(cdc_dev, true, false));
111 
112     ESP_LOGI(TAG, "Example finished successfully!");
113 }
114