1 /*
2  * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #pragma once
8 
9 #include <stdbool.h>
10 #include "usb_types_cdc.h"
11 #include "esp_err.h"
12 
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16 
17 typedef struct cdc_dev_s *cdc_acm_dev_hdl_t;
18 
19 /**
20  * @brief Line Coding structure
21  * @see Table 17, USB CDC-PSTN specification rev. 1.2
22  */
23 typedef struct {
24     uint32_t dwDTERate;  // in bits per second
25     uint8_t bCharFormat; // 0: 1 stopbit, 1: 1.5 stopbits, 2: 2 stopbits
26     uint8_t bParityType; // 0: None, 1: Odd, 2: Even, 3: Mark, 4: Space
27     uint8_t bDataBits;   // 5, 6, 7, 8 or 16
28 } __attribute__((packed)) cdc_acm_line_coding_t;
29 
30 /**
31  * @brief UART State Bitmap
32  * @see Table 31, USB CDC-PSTN specification rev. 1.2
33  */
34 typedef union {
35     struct {
36         uint16_t bRxCarrier : 1;  // State of receiver carrier detection mechanism of device. This signal corresponds to V.24 signal 109 and RS-232 signal DCD.
37         uint16_t bTxCarrier : 1;  // State of transmission carrier. This signal corresponds to V.24 signal 106 and RS-232 signal DSR.
38         uint16_t bBreak : 1;      // State of break detection mechanism of the device.
39         uint16_t bRingSignal : 1; // State of ring signal detection of the device.
40         uint16_t bFraming : 1;    // A framing error has occurred.
41         uint16_t bParity : 1;     // A parity error has occurred.
42         uint16_t bOverRun : 1;    // Received data has been discarded due to overrun in the device.
43         uint16_t reserved : 9;
44     };
45     uint16_t val;
46 } cdc_acm_uart_state_t;
47 
48 /**
49  * @brief CDC-ACM Device Event types to upper layer
50  *
51  */
52 typedef enum {
53     CDC_ACM_HOST_ERROR,
54     CDC_ACM_HOST_SERIAL_STATE,
55     CDC_ACM_HOST_NETWORK_CONNECTION,
56     CDC_ACM_HOST_DEVICE_DISCONNECTED
57 } cdc_acm_host_dev_event_t;
58 
59 /**
60  * @brief CDC-ACM Device Event data structure
61  *
62  */
63 typedef struct {
64     cdc_acm_host_dev_event_t type;
65     union {
66         int error;                         // Error code from USB Host
67         cdc_acm_uart_state_t serial_state; // Serial (UART) state
68         bool network_connected;            // Network connection event
69     } data;
70 } cdc_acm_host_dev_event_data_t;
71 
72 /**
73  * @brief Data receive callback type
74  */
75 typedef void (*cdc_acm_data_callback_t)(uint8_t* data, size_t data_len, void *user_arg);
76 
77 /**
78  * @brief Device event callback type
79  * @see cdc_acm_host_dev_event_t
80  */
81 typedef void (*cdc_acm_host_dev_callback_t)(cdc_acm_dev_hdl_t cdc_hdl, const cdc_acm_host_dev_event_data_t *event, void *user_ctx);
82 
83 /**
84  * @brief Configuration structure of USB Host CDC-ACM driver
85  *
86  */
87 typedef struct {
88     size_t driver_task_stack_size;         /**< Stack size of the driver's task */
89     unsigned driver_task_priority;         /**< Priority of the driver's task */
90     int  xCoreID;                          /**< Core affinity of the driver's task */
91 } cdc_acm_host_driver_config_t;
92 
93 /**
94  * @brief Configuration structure of CDC-ACM device
95  *
96  */
97 typedef struct {
98     uint32_t connection_timeout_ms;       /**< Timeout for USB device connection in [ms] */
99     size_t out_buffer_size;               /**< Maximum size of USB bulk out transfer, set to 0 for read-only devices */
100     cdc_acm_host_dev_callback_t event_cb; /**< Device's event callback function. Can be NULL */
101     cdc_acm_data_callback_t data_cb;      /**< Device's data RX callback function. Can be NULL for write-only devices */
102     void *user_arg;                       /**< User's argument that will be passed to the callbacks */
103 } cdc_acm_host_device_config_t;
104 
105 /**
106  * @brief Install CDC-ACM driver
107  *
108  * - USB Host Library must already be installed before calling this function (via usb_host_install())
109  * - This function should be called before calling any other CDC driver functions
110  *
111  * @param[in] driver_config Driver configuration structure. If set to NULL, a default configuration will be used.
112  * @return esp_err_t
113  */
114 esp_err_t cdc_acm_host_install(const cdc_acm_host_driver_config_t *driver_config);
115 
116 /**
117  * @brief Uninstall CDC-ACM driver
118  *
119  * - Users must ensure that all CDC devices must be closed via cdc_acm_host_close() before calling this function
120  *
121  * @return esp_err_t
122  */
123 esp_err_t cdc_acm_host_uninstall(void);
124 
125 /**
126  * @brief Open CDC-ACM compliant device
127  *
128  * CDC-ACM compliant device must contain either an Interface Association Descriptor or CDC-Union descriptor,
129  * which are used for the driver's configuration.
130  *
131  * @param[in] vid           Device's Vendor ID
132  * @param[in] pid           Device's Product ID
133  * @param[in] interface_idx Index of device's interface used for CDC-ACM communication
134  * @param[in] dev_config    Configuration structure of the device
135  * @param[out] cdc_hdl_ret  CDC device handle
136  * @return esp_err_t
137  */
138 esp_err_t cdc_acm_host_open(uint16_t vid, uint16_t pid, uint8_t interface_idx, const cdc_acm_host_device_config_t *dev_config, cdc_acm_dev_hdl_t *cdc_hdl_ret);
139 
140 /**
141  * @brief Open CDC-ACM non-compliant device
142  *
143  * CDC-ACM non-compliant device acts as CDC-ACM device but doesn't support all its features.
144  * User must provide the interface index that will be used (zero for non-composite devices).
145  *
146  * @param[in] vid           Device's Vendor ID
147  * @param[in] pid           Device's Product ID
148  * @param[in] interface_idx Index of device's interface used for CDC-ACM like communication
149  * @param[in] dev_config    Configuration structure of the device
150  * @param[out] cdc_hdl_ret  CDC device handle
151  * @return esp_err_t
152  */
153 esp_err_t cdc_acm_host_open_vendor_specific(uint16_t vid, uint16_t pid, uint8_t interface_num, const cdc_acm_host_device_config_t *dev_config, cdc_acm_dev_hdl_t *cdc_hdl_ret);
154 
155 /**
156  * @brief Close CDC device and release its resources
157  *
158  * @note All in-flight transfers will be prematurely canceled.
159  * @param cdc_hdl CDC handle obtained from cdc_acm_host_open()
160  * @return esp_err_t
161  */
162 esp_err_t cdc_acm_host_close(cdc_acm_dev_hdl_t cdc_hdl);
163 
164 /**
165  * @brief Transmit data - blocking mode
166  *
167  * @param cdc_hdl CDC handle obtained from cdc_acm_host_open()
168  * @param[in] data       Data to be sent
169  * @param[in] data_len   Data length
170  * @param[in] timeout_ms Timeout in [ms]
171  * @return esp_err_t
172  */
173 esp_err_t cdc_acm_host_data_tx_blocking(cdc_acm_dev_hdl_t cdc_hdl, const uint8_t *data, size_t data_len, uint32_t timeout_ms);
174 
175 /**
176  * @brief SetLineCoding function
177  *
178  * @see Chapter 6.3.10, USB CDC-PSTN specification rev. 1.2
179  *
180  * @param     cdc_hdl     CDC handle obtained from cdc_acm_host_open()
181  * @param[in] line_coding Line Coding structure
182  * @return esp_err_t
183  */
184 esp_err_t cdc_acm_host_line_coding_set(cdc_acm_dev_hdl_t cdc_hdl, const cdc_acm_line_coding_t *line_coding);
185 
186 /**
187  * @brief GetLineCoding function
188  *
189  * @see Chapter 6.3.11, USB CDC-PSTN specification rev. 1.2
190  *
191  * @param      cdc_hdl     CDC handle obtained from cdc_acm_host_open()
192  * @param[out] line_coding Line Coding structure to be filled
193  * @return esp_err_t
194  */
195 esp_err_t cdc_acm_host_line_coding_get(cdc_acm_dev_hdl_t cdc_hdl, cdc_acm_line_coding_t *line_coding);
196 
197 /**
198  * @brief SetControlLineState function
199  *
200  * @see Chapter 6.3.12, USB CDC-PSTN specification rev. 1.2
201  *
202  * @param     cdc_hdl CDC handle obtained from cdc_acm_host_open()
203  * @param[in] dtr     Indicates to DCE if DTE is present or not. This signal corresponds to V.24 signal 108/2 and RS-232 signal Data Terminal Ready.
204  * @param[in] rts     Carrier control for half duplex modems. This signal corresponds to V.24 signal 105 and RS-232 signal Request To Send.
205  * @return esp_err_t
206  */
207 esp_err_t cdc_acm_host_set_control_line_state(cdc_acm_dev_hdl_t cdc_hdl, bool dtr, bool rts);
208 
209 /**
210  * @brief SendBreak function
211  *
212  * This function will block until the duration_ms has passed.
213  *
214  * @see Chapter 6.3.13, USB CDC-PSTN specification rev. 1.2
215  *
216  * @param     cdc_hdl     CDC handle obtained from cdc_acm_host_open()
217  * @param[in] duration_ms Duration of the Break signal in [ms]
218  * @return esp_err_t
219  */
220 esp_err_t cdc_acm_host_send_break(cdc_acm_dev_hdl_t cdc_hdl, uint16_t duration_ms);
221 
222 /**
223  * @brief Print CDC-ACM specific descriptors
224  *
225  * Descriptors are printed in human readable format to stdout.
226  * Intended for debugging and for CDC-ACM compliant devices only.
227  *
228  * @param cdc_hdl CDC handle obtained from cdc_acm_host_open()
229  */
230 void cdc_acm_host_desc_print(cdc_acm_dev_hdl_t cdc_hdl);
231 
232 /**
233  * @brief Get protocols defined in USB-CDC interface descriptors
234  *
235  * @param cdc_hdl   CDC handle obtained from cdc_acm_host_open()
236  * @param[out] comm Communication protocol
237  * @param[out] data Data protocol
238  * @return esp_err_t
239  */
240 esp_err_t cdc_acm_host_protocols_get(cdc_acm_dev_hdl_t cdc_hdl, cdc_comm_protocol_t *comm, cdc_data_protocol_t *data);
241 
242 #ifdef __cplusplus
243 }
244 class CdcAcmDevice
245 {
246 public:
247     // Operators
CdcAcmDevice()248     CdcAcmDevice() : cdc_hdl(NULL){};
~CdcAcmDevice()249     ~CdcAcmDevice()
250     {
251         // Close CDC-ACM device, if it wasn't explicitly closed
252         if (this->cdc_hdl != NULL) {
253             this->close();
254         }
255     }
256 
257     inline esp_err_t tx_blocking(uint8_t *data, size_t len, uint32_t timeout_ms = 100)
258     {
259         return cdc_acm_host_data_tx_blocking(this->cdc_hdl, data, len, timeout_ms);
260     }
261 
open(uint16_t vid,uint16_t pid,uint8_t interface_idx,const cdc_acm_host_device_config_t * dev_config)262     inline esp_err_t open(uint16_t vid, uint16_t pid, uint8_t interface_idx, const cdc_acm_host_device_config_t* dev_config)
263     {
264         return cdc_acm_host_open(vid, pid, interface_idx, dev_config, &this->cdc_hdl);
265     }
266 
open_vendor_specific(uint16_t vid,uint16_t pid,uint8_t interface_idx,const cdc_acm_host_device_config_t * dev_config)267     inline esp_err_t open_vendor_specific(uint16_t vid, uint16_t pid, uint8_t interface_idx, const cdc_acm_host_device_config_t* dev_config)
268     {
269         return cdc_acm_host_open_vendor_specific(vid, pid, interface_idx, dev_config, &this->cdc_hdl);
270     }
271 
close()272     inline void close()
273     {
274         cdc_acm_host_close(this->cdc_hdl);
275         this->cdc_hdl = NULL;
276     }
277 
line_coding_get(cdc_acm_line_coding_t * line_coding)278     inline esp_err_t line_coding_get(cdc_acm_line_coding_t *line_coding)
279     {
280         return cdc_acm_host_line_coding_get(this->cdc_hdl, line_coding);
281     }
282 
line_coding_set(cdc_acm_line_coding_t * line_coding)283     inline esp_err_t line_coding_set(cdc_acm_line_coding_t *line_coding)
284     {
285         return cdc_acm_host_line_coding_set(this->cdc_hdl, line_coding);
286     }
287 
set_control_line_state(bool dtr,bool rts)288     inline esp_err_t set_control_line_state(bool dtr, bool rts)
289     {
290         return cdc_acm_host_set_control_line_state(this->cdc_hdl, dtr, rts);
291     }
292 
send_break(uint16_t duration_ms)293     inline esp_err_t send_break(uint16_t duration_ms)
294     {
295         return cdc_acm_host_send_break(this->cdc_hdl, duration_ms);
296     }
297 
298 private:
299     CdcAcmDevice(const CdcAcmDevice &Copy);
300     CdcAcmDevice &operator= (const CdcAcmDevice &Copy);
301     bool operator== (const CdcAcmDevice &param) const;
302     bool operator!= (const CdcAcmDevice &param) const;
303     cdc_acm_dev_hdl_t cdc_hdl;
304 };
305 #endif
306