CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
Loading...
Searching...
No Matches
usb_cdc.cpp
Go to the documentation of this file.
1
7
8#include "usb_badge/usb_cdc.h"
9#include "usb_badge/usb_hid.h"
11
12#include "cdc_log.h"
13#include "esp_err.h"
14#include "esp_idf_version.h"
15#include "esp_rom_sys.h"
16#include "esp_system.h"
17
18#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) && defined(CONFIG_SOC_USB_OTG_SUPPORTED) && CONFIG_SOC_USB_OTG_SUPPORTED
19#include "esp_private/usb_phy.h"
20#endif
21
22#include "freertos/FreeRTOS.h"
23#include "freertos/task.h"
24
25extern "C" {
26#include "tusb.h"
27#include "class/cdc/cdc.h"
28}
29
30#include <cstring>
31
32static const char* TAG = "USB";
33
37
38static bool g_usb_prepared = false; // PHY and descriptors ready
39static bool g_usb_started = false; // TinyUSB running
40static TaskHandle_t g_usb_task = nullptr;
41
42#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) && defined(CONFIG_SOC_USB_OTG_SUPPORTED) && CONFIG_SOC_USB_OTG_SUPPORTED
43static usb_phy_handle_t g_usb_phy = nullptr;
44
49static bool usb_phy_init_once(void) {
50 if (g_usb_phy) return true;
51
52 usb_phy_config_t phy_conf = {
53 .controller = USB_PHY_CTRL_OTG,
54 .target = USB_PHY_TARGET_INT,
55 .otg_mode = USB_OTG_MODE_DEVICE,
56 .otg_speed = USB_PHY_SPEED_UNDEFINED,
57 .ext_io_conf = nullptr,
58 .otg_io_conf = nullptr,
59 };
60
61 esp_err_t err = usb_new_phy(&phy_conf, &g_usb_phy);
62 if (err != ESP_OK) {
63 LOG_E(TAG, "USB PHY init failed: %s", esp_err_to_name(err));
64 return false;
65 }
66 return true;
67}
68#endif
69
73
78static void usb_device_task(void* arg) {
79 (void)arg;
80 while (1) {
81 tud_task();
82 vTaskDelay(1);
83 }
84}
85
89
94static void usb_shutdown_handler(void) {
95 if (tud_inited()) {
96 tud_disconnect();
97 esp_rom_delay_us(50000);
98 }
99#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) && defined(CONFIG_SOC_USB_OTG_SUPPORTED) && CONFIG_SOC_USB_OTG_SUPPORTED
100 if (g_usb_phy) {
101 usb_del_phy(g_usb_phy);
102 g_usb_phy = nullptr;
103 }
104#endif
105 esp_rom_delay_us(50000);
106}
107
108static bool usb_start_stack(void) {
109 if (g_usb_started) return true;
110
111 if (!tusb_init()) {
112 LOG_E(TAG, "TinyUSB init failed");
113 return false;
114 }
115
116 vTaskDelay(pdMS_TO_TICKS(10));
117
118 // Stack sized for worst case mbedTLS ECP P-256 keypair generation
119 // and ECDH point multiplication invoked from CCID APDU handlers.
120 xTaskCreate(usb_device_task, "usbd", 8192, nullptr,
121 configMAX_PRIORITIES - 1, &g_usb_task);
122
123 esp_register_shutdown_handler(usb_shutdown_handler);
124
125 g_usb_started = true;
126 return true;
127}
128
129bool usb_cdc_init(void) {
130 if (g_usb_prepared) return true;
131
132 // Prepare USB descriptors and PHY
133 if (!usb_hid_init()) {
134 LOG_E(TAG, "USB HID init failed");
135 return false;
136 }
137
138#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) && defined(CONFIG_SOC_USB_OTG_SUPPORTED) && CONFIG_SOC_USB_OTG_SUPPORTED
139 if (!usb_phy_init_once()) {
140 LOG_E(TAG, "USB PHY init failed");
141 return false;
142 }
143#endif
144
145 g_usb_prepared = true;
146
147#ifdef CONFIG_USB_EARLY_DEBUG
148 // Early debug mode: Start USB immediately
149 LOG_I(TAG, "USB CDC init (early debug mode)");
150 if (!usb_start_stack()) {
151 return false;
152 }
153 LOG_I(TAG, "USB CDC ready (will re-enumerate after modules load)");
154#else
155 // Production mode: Defer USB start until usb_cdc_start() is called
156 // Note: No logging here as USB is not yet available!
157#endif
158
159 return true;
160}
161
166bool usb_cdc_start(void) {
167 if (!g_usb_prepared) {
168 // Not initialized yet
169 return false;
170 }
171
172 if (g_usb_started) {
173#ifdef CONFIG_USB_EARLY_DEBUG
174 // In early debug mode, we need to re-enumerate after modules loaded
175 LOG_I(TAG, "USB re-enumerating with final configuration...");
177#endif
178 return true;
179 }
180
181 // Start USB stack for the first time (production mode)
182 if (!usb_start_stack()) {
183 return false;
184 }
185
186 LOG_I(TAG, "USB CDC started");
187 return true;
188}
189
194 if (!g_usb_started || !tud_inited()) return;
195 tud_disconnect();
196 vTaskDelay(pdMS_TO_TICKS(50));
197 tud_connect();
198}
199
204bool usb_cdc_ready(void) {
205 return g_usb_started && tud_cdc_connected();
206}
207
214size_t usb_cdc_write(const uint8_t* data, size_t len) {
215 if (!g_usb_started || !data || len == 0) return 0;
216
217 size_t written = 0;
218 while (written < len) {
219 size_t avail = tud_cdc_write_available();
220 if (avail == 0) {
221 tud_cdc_write_flush();
222 vTaskDelay(1);
223 continue;
224 }
225
226 size_t chunk = (len - written > avail) ? avail : (len - written);
227 size_t sent = tud_cdc_write(data + written, chunk);
228 written += sent;
229
230 if (sent == 0) break;
231 }
232
233 tud_cdc_write_flush();
234 return written;
235}
236
242size_t usb_cdc_print(const char* str) {
243 if (!str) return 0;
244 return usb_cdc_write((const uint8_t*)str, strlen(str));
245}
246
253size_t usb_cdc_read(uint8_t* data, size_t len) {
254 if (!g_usb_started || !data || len == 0) return 0;
255 return tud_cdc_read(data, len);
256}
257
263 if (!g_usb_started) return -1;
264
265 uint8_t c;
266 if (tud_cdc_read(&c, 1) == 1) {
267 return c;
268 }
269 return -1;
270}
271
276size_t usb_cdc_available(void) {
277 if (!g_usb_started) return 0;
278 return tud_cdc_available();
279}
280
284void usb_cdc_flush(void) {
285 if (!g_usb_started) return;
286 tud_cdc_write_flush();
287 vTaskDelay(pdMS_TO_TICKS(10));
288}
static const char * TAG
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_I(tag, fmt,...)
Definition cdc_log.h:147
#define LOG_E(tag, fmt,...)
Definition cdc_log.h:145
void usb_cdc_flush(void)
Flushes pending USB CDC writes.
Definition usb_cdc.cpp:284
static void usb_shutdown_handler(void)
Public USB CDC API implementation.
Definition usb_cdc.cpp:94
static bool g_usb_started
Definition usb_cdc.cpp:39
size_t usb_cdc_available(void)
Returns number of bytes available for read.
Definition usb_cdc.cpp:276
static bool usb_start_stack(void)
Definition usb_cdc.cpp:108
static bool g_usb_prepared
Internal USB CDC startup and task state.
Definition usb_cdc.cpp:38
bool usb_cdc_ready(void)
Returns whether USB CDC is connected and ready.
Definition usb_cdc.cpp:204
static TaskHandle_t g_usb_task
Definition usb_cdc.cpp:40
void usb_cdc_reenumerate(void)
Forces a USB re-enumeration by toggling the bus connection.
Definition usb_cdc.cpp:193
size_t usb_cdc_write(const uint8_t *data, size_t len)
Writes byte buffer to USB CDC endpoint.
Definition usb_cdc.cpp:214
static void usb_device_task(void *arg)
TinyUSB device task.
Definition usb_cdc.cpp:78
bool usb_cdc_start(void)
Starts USB CDC runtime (or triggers re-enumeration in early-debug mode).
Definition usb_cdc.cpp:166
bool usb_cdc_init(void)
Definition usb_cdc.cpp:129
size_t usb_cdc_read(uint8_t *data, size_t len)
Reads bytes from USB CDC endpoint.
Definition usb_cdc.cpp:253
size_t usb_cdc_print(const char *str)
Writes null-terminated string to USB CDC.
Definition usb_cdc.cpp:242
int usb_cdc_getchar(void)
Reads one character from USB CDC stream.
Definition usb_cdc.cpp:262
bool usb_hid_init(void)
Public USB HID/composite configuration API implementation.
Definition usb_hid.cpp:373