#include "usb_descriptors.h" #include #include #include "esp_mac.h" namespace esphome { namespace grub_boot_switch { // USB constants we need without dragging in from this header constexpr uint8_t USB_DESC_DEVICE = 0x01; constexpr uint8_t USB_DESC_CONFIGURATION = 0x02; constexpr uint8_t USB_DESC_INTERFACE = 0x04; constexpr uint8_t USB_DESC_ENDPOINT = 0x05; constexpr uint8_t USB_CLASS_MSC = 0x08; constexpr uint8_t USB_MSC_SUBCLASS_SCSI = 0x06; constexpr uint8_t USB_MSC_PROTOCOL_BBB = 0x50; constexpr uint8_t EP_BULK = 0x02; // Mirrors the layout in reference/src/usb.c so the host sees the same shape // as the original STM32 firmware. constexpr uint8_t MSC_EP_IN = 0x81; constexpr uint8_t MSC_EP_OUT = 0x01; constexpr uint16_t MSC_EP_SIZE = 64; // Full-speed bulk static void put16le(uint8_t *p, uint16_t v) { p[0] = v & 0xFF; p[1] = (v >> 8) & 0xFF; } void usb_descriptors_build(UsbDescriptorBundle *b, uint16_t vid, uint16_t pid, const char *manufacturer, const char *product, const char *serial_override) { // ---- Device descriptor ---- uint8_t *d = b->device; d[0] = 18; // bLength d[1] = USB_DESC_DEVICE; // bDescriptorType put16le(d + 2, 0x0200); // bcdUSB d[4] = 0x00; // bDeviceClass (defined in interface) d[5] = 0x00; // bDeviceSubClass d[6] = 0x00; // bDeviceProtocol d[7] = 64; // bMaxPacketSize0 put16le(d + 8, vid); put16le(d + 10, pid); put16le(d + 12, 0x0200); // bcdDevice d[14] = 1; // iManufacturer (string index) d[15] = 2; // iProduct d[16] = 3; // iSerialNumber d[17] = 1; // bNumConfigurations // ---- Configuration descriptor (config + interface + 2 endpoints) ---- uint8_t *c = b->config; // Configuration c[0] = 9; c[1] = USB_DESC_CONFIGURATION; put16le(c + 2, 32); // wTotalLength c[4] = 1; // bNumInterfaces c[5] = 1; // bConfigurationValue c[6] = 0; // iConfiguration c[7] = 0x80; // bmAttributes (bus powered) c[8] = 50; // bMaxPower (100mA) // Interface c[9] = 9; c[10] = USB_DESC_INTERFACE; c[11] = 0; // bInterfaceNumber c[12] = 0; // bAlternateSetting c[13] = 2; // bNumEndpoints c[14] = USB_CLASS_MSC; c[15] = USB_MSC_SUBCLASS_SCSI; c[16] = USB_MSC_PROTOCOL_BBB; c[17] = 0; // iInterface // Endpoint OUT c[18] = 7; c[19] = USB_DESC_ENDPOINT; c[20] = MSC_EP_OUT; c[21] = EP_BULK; put16le(c + 22, MSC_EP_SIZE); c[24] = 0; // Endpoint IN c[25] = 7; c[26] = USB_DESC_ENDPOINT; c[27] = MSC_EP_IN; c[28] = EP_BULK; put16le(c + 29, MSC_EP_SIZE); c[31] = 0; // ---- Strings ---- // Index 0: language ID (English, US) — esp_tinyusb expects index 0 to be the // language; it builds the actual descriptor from a static "0x0409" string. static const char kLang[] = {0x09, 0x04, 0}; b->strings[0] = kLang; b->strings[1] = manufacturer; b->strings[2] = product; if (serial_override && serial_override[0] != '\0') { snprintf(b->serial_buf, sizeof(b->serial_buf), "%s", serial_override); } else { uint8_t mac[6] = {}; esp_read_mac(mac, ESP_MAC_WIFI_STA); snprintf(b->serial_buf, sizeof(b->serial_buf), "%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } b->strings[3] = b->serial_buf; } } // namespace grub_boot_switch } // namespace esphome