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...");
176 tud_disconnect();
177 vTaskDelay(pdMS_TO_TICKS(50));
178 tud_connect();
179#endif
180 return true;
181 }
182
183 // Start USB stack for the first time (production mode)
184 if (!usb_start_stack()) {
185 return false;
186 }
187
188 LOG_I(TAG, "USB CDC started");
189 return true;
190}
191
196bool usb_cdc_ready(void) {
197 return g_usb_started && tud_cdc_connected();
198}
199
206size_t usb_cdc_write(const uint8_t* data, size_t len) {
207 if (!g_usb_started || !data || len == 0) return 0;
208
209 size_t written = 0;
210 while (written < len) {
211 size_t avail = tud_cdc_write_available();
212 if (avail == 0) {
213 tud_cdc_write_flush();
214 vTaskDelay(1);
215 continue;
216 }
217
218 size_t chunk = (len - written > avail) ? avail : (len - written);
219 size_t sent = tud_cdc_write(data + written, chunk);
220 written += sent;
221
222 if (sent == 0) break;
223 }
224
225 tud_cdc_write_flush();
226 return written;
227}
228
234size_t usb_cdc_print(const char* str) {
235 if (!str) return 0;
236 return usb_cdc_write((const uint8_t*)str, strlen(str));
237}
238
245size_t usb_cdc_read(uint8_t* data, size_t len) {
246 if (!g_usb_started || !data || len == 0) return 0;
247 return tud_cdc_read(data, len);
248}
249
255 if (!g_usb_started) return -1;
256
257 uint8_t c;
258 if (tud_cdc_read(&c, 1) == 1) {
259 return c;
260 }
261 return -1;
262}
263
268size_t usb_cdc_available(void) {
269 if (!g_usb_started) return 0;
270 return tud_cdc_available();
271}
272
276void usb_cdc_flush(void) {
277 if (!g_usb_started) return;
278 tud_cdc_write_flush();
279 vTaskDelay(pdMS_TO_TICKS(10));
280}
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:276
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:268
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:196
static TaskHandle_t g_usb_task
Definition usb_cdc.cpp:40
size_t usb_cdc_write(const uint8_t *data, size_t len)
Writes byte buffer to USB CDC endpoint.
Definition usb_cdc.cpp:206
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:245
size_t usb_cdc_print(const char *str)
Writes null-terminated string to USB CDC.
Definition usb_cdc.cpp:234
int usb_cdc_getchar(void)
Reads one character from USB CDC stream.
Definition usb_cdc.cpp:254
bool usb_hid_init(void)
Public USB HID/composite configuration API implementation.
Definition usb_hid.cpp:352