Fork of https://developer.mbed.org/users/bscott/code/STM32_USBDevice/
Fork of STM32_USBDevice by
Diff: USBSerial/USBWebUSBSerial.cpp
- Branch:
- feature_WebUSB
- Revision:
- 76:eef92651f52f
- Child:
- 77:a98f786d05d4
diff -r 43bf95761b38 -r eef92651f52f USBSerial/USBWebUSBSerial.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBSerial/USBWebUSBSerial.cpp Thu Jul 19 12:57:27 2018 +0200 @@ -0,0 +1,662 @@ +#include "USBWebUSBSerial.h" + +static uint8_t cdc_line_coding[7]= {0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x08}; + +#define DEFAULT_CONFIGURATION (1) + +#define CDC_SET_LINE_CODING 0x20 +#define CDC_GET_LINE_CODING 0x21 +#define CDC_SET_CONTROL_LINE_STATE 0x22 + +// USB standard values +#define USB_CS_INTERFACE 0x24 +#define USB_HEADER_FUNCTION_DESCRIPTOR_TYPE 0x00 +#define USB_CALL_MANAGEMENT_FUNCTION_DESCRIPTOR_TYPE 0x01 +#define USB_ABSTRACT_CONTROL_MANAGEMENT_FUNCTION_DESCRIPTOR_TYPE 0x02 +#define USB_UNION_INTERFACE_FUNCTION_DESCRIPTOR_TYPE 0x06 +#define PLATFORM_DEVICE_CAPABILITY_TYPE 0x05 + +#define USB_CDC_CLASS 0x02 +#define USB_ACM_SUBCLASS 0x02 +#define USB_CDC_DATA_CLASS 0x0A +#define USB_CUSTOM_CLASS 0xFF + +// MS OS 2.0 descriptor types +#define MS_OS_20_SET_HEADER_DESCRIPTOR 0x00 +#define MS_OS_20_SUBSET_HEADER_CONFIGURATION 0x01 +#define MS_OS_20_SUBSET_HEADER_FUNCTION 0x02 +#define MS_OS_20_FEATURE_COMPATIBLE_ID 0x03 +#define MS_OS_20_FEATURE_REG_PROPERTY 0x04 +#define MS_OS_20_FEATURE_MIN_RESUME_TIME 0x05 +#define MS_OS_20_FEATURE_MODEL_ID 0x06 +#define MS_OS_20_FEATURE_CCGP_DEVICE 0x07 + +#define MS_OS_20_DESCRIPTOR_INDEX 0x07 +#define MS_OS_20_DESCRIPTOR_LENGTH 178 + +// Vendor commands +#define WINUSB_VENDOR_CODE 0x01 +#define SET_WEBUSB_ACTIVE_VENDOR_CODE 0xAA + +// Control Line State bits +#define CLS_DTR (1 << 0) +#define CLS_RTS (1 << 1) + +#ifdef USB_DEVICE_WRITE_BLOCKING_TIMEOUT_MS +#define WEBUSB_WRITE_TIMEOUT (USB_DEVICE_WRITE_BLOCKING_TIMEOUT_MS) +#else +#define WEBUSB_WRITE_TIMEOUT 1000 +#endif + + +uint8_t USBWebUSBSerial::s_MSOS2Descriptor[] = +{ + // Microsoft OS 2.0 descriptor set header (table 10) + 0x0A, 0x00, // Header size (always 10 bytes) + LSB(MS_OS_20_SET_HEADER_DESCRIPTOR), + MSB(MS_OS_20_SET_HEADER_DESCRIPTOR), + 0x00, 0x00, 0x03, 0x06, // Windows version (8.1) (0x06030000) + LSB(MS_OS_20_DESCRIPTOR_LENGTH), + MSB(MS_OS_20_DESCRIPTOR_LENGTH), + + // Configuration subset header (table 11) + 0x08, 0x00, // wLength, always 8 + LSB(MS_OS_20_SUBSET_HEADER_CONFIGURATION), + MSB(MS_OS_20_SUBSET_HEADER_CONFIGURATION), + 0x00, // "bConfigurationValue" - actually the index of the configuration, see https://social.msdn.microsoft.com/Forums/sqlserver/en-US/ae64282c-3bc3-49af-8391-4d174479d9e7/microsoft-os-20-descriptors-not-working-on-an-interface-of-a-composite-usb-device%3Fforum%3Dwdk+&cd=1&hl=da&ct=clnk&gl=dk&client=firefox-b + 0x00, // reserved + LSB(MS_OS_20_DESCRIPTOR_LENGTH - 10), // wTotalLength (length of subset including this header) + MSB(MS_OS_20_DESCRIPTOR_LENGTH - 10), + + // Function subset (table 12) + 0x08, 0x00, // wLength, always 8 + LSB(MS_OS_20_SUBSET_HEADER_FUNCTION), + MSB(MS_OS_20_SUBSET_HEADER_FUNCTION), + 0x02, // bFirstInterface + 0x00, // reserved + LSB(MS_OS_20_DESCRIPTOR_LENGTH - 18), // wSubSetLength (length of subset including this header) + MSB(MS_OS_20_DESCRIPTOR_LENGTH - 18), + + // Microsoft OS 2.0 compatible ID descriptor (table 13) + // Ties the winusb driver to the webusb interface + 0x14, 0x00, // wLength, always 20 + LSB(MS_OS_20_FEATURE_COMPATIBLE_ID), + MSB(MS_OS_20_FEATURE_COMPATIBLE_ID), + 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, // CompatibleID (string) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SubCompatibleID (string) + + // Registry property descriptor (table 14) + // Sets a registry key named DeviceInterfaceGUIDs with a GUID for the WebUSB interface (apparently required before libusb can enumerate it...) + 0x84, 0x00, // wLength (132) + LSB(MS_OS_20_FEATURE_REG_PROPERTY), + MSB(MS_OS_20_FEATURE_REG_PROPERTY), + 0x07, 0x00, // wPropertyDataType (REG_MULTI_SZ) - see table 15 + 0x2A, 0x00, // wPropertyNameLength (42) + // Property name (wide string) : DeviceInterfaceGUIDs + 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, 'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0, 'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0, + 0x50, 0x00, // wPropertyDataLength (80) + // Property data (wide string): {307A82E9-227E-48C3-8C4E-627BE96A7A78} (randomly generated for this device) + '{', 0, '3', 0, '0', 0, '7', 0, 'A', 0, '8', 0, '2', 0, 'E', 0, '9', 0, '-', 0, + '2', 0, '2', 0, '7', 0, 'E', 0, '-', 0, + '4', 0, '8', 0, 'C', 0, '3', 0, '-', 0, + '8', 0, 'C', 0, '4', 0, 'E', 0, '-', 0, + '6', 0, '2', 0, '7', 0, 'B', 0, 'E', 0, '9', 0, '6', 0, 'A', 0, '7', 0, 'A', 0, '7', 0, '8', 0, '}', 0, 0, 0, 0, 0 +}; + + +USBWebUSBSerial::USBWebUSBSerial(uint16_t vendor_id, uint16_t product_id, uint16_t product_release, bool connect_blocking) + : USBDevice(vendor_id, product_id, product_release) +{ + m_terminalConnected = false; + USBDevice::connect(connect_blocking); + createDynamicDescriptors(); +} + +void USBWebUSBSerial::USBCallback_busReset() +{ + m_terminalConnected = false; + m_webUSBMode = false; +} + +bool USBWebUSBSerial::USBCallback_request() +{ + /* Called in ISR context */ + + bool success = false; + CONTROL_TRANSFER * transfer = getTransferPtr(); + + /* Process class-specific requests */ + if (transfer->setup.bmRequestType.Type == CLASS_TYPE) + { + switch (transfer->setup.bRequest) + { + case CDC_GET_LINE_CODING: + transfer->remaining = 7; + transfer->ptr = cdc_line_coding; + transfer->direction = DEVICE_TO_HOST; + success = true; + break; + case CDC_SET_LINE_CODING: + transfer->remaining = 7; + transfer->notify = true; + success = true; + break; + case CDC_SET_CONTROL_LINE_STATE: + if (transfer->setup.wValue & CLS_DTR) { + m_terminalConnected = true; + } else { + m_terminalConnected = false; + } + success = true; + break; + default: + break; + } + } + else if (transfer->setup.bmRequestType.Type == VENDOR_TYPE && transfer->setup.bRequest == WINUSB_VENDOR_CODE && transfer->setup.wIndex == MS_OS_20_DESCRIPTOR_INDEX) + { + // Request for the MS OS 2.0 descriptor + transfer->remaining = MS_OS_20_DESCRIPTOR_LENGTH; + transfer->ptr = s_MSOS2Descriptor; + transfer->direction = DEVICE_TO_HOST; + success = true; + } + else if (transfer->setup.bmRequestType.Type == VENDOR_TYPE && transfer->setup.bRequest == SET_WEBUSB_ACTIVE_VENDOR_CODE) + { + if (transfer->setup.wValue == 0) + { + // Disable WebUSB mode + m_webUSBMode = false; + } + else + { + // Enable WebUSB mode + m_webUSBMode = true; + } + success = true; + } + + return success; +} + +void USBWebUSBSerial::USBCallback_requestCompleted(uint8_t *buf, uint32_t length) +{ + // Request of setting line coding has 7 bytes + if (length != 7) + { + return; + } + + CONTROL_TRANSFER * transfer = getTransferPtr(); + + /* Process class-specific requests */ + if (transfer->setup.bmRequestType.Type == CLASS_TYPE) + { + if (transfer->setup.bRequest == CDC_SET_LINE_CODING) + { + if (memcmp(cdc_line_coding, buf, 7)) + { + memcpy(cdc_line_coding, buf, 7); + + int baud = buf[0] + (buf[1] << 8) + + (buf[2] << 16) + (buf[3] << 24); + int stop = buf[4]; + int bits = buf[6]; + int parity = buf[5]; + + lineCodingChanged(baud, bits, parity, stop); + } + } + } +} + +// Called in ISR context +// Set configuration. Return false if the +// configuration is not supported. +bool USBWebUSBSerial::USBCallback_setConfiguration(uint8_t configuration) +{ + if (configuration != DEFAULT_CONFIGURATION) + { + return false; + } + + if (configured()) + { + // Already configured, nothing to do + return true; + } + + // Configure endpoints > 0 + addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT); + addEndpoint(EPCDC_IN, MAX_PACKET_SIZE_EPBULK); + addEndpoint(EPCDC_OUT, MAX_PACKET_SIZE_EPBULK); + addEndpoint(EPWEBUSB_IN, MAX_PACKET_SIZE_EPBULK); + addEndpoint(EPWEBUSB_OUT, MAX_PACKET_SIZE_EPBULK); + + // We activate the endpoints to be able to receive data + readStart(EPCDC_OUT, MAX_PACKET_SIZE_EPBULK); + readStart(EPWEBUSB_OUT, MAX_PACKET_SIZE_EPBULK); + return true; +} + +bool USBWebUSBSerial::send(const uint8_t * buffer, uint32_t size) +{ + if (!m_webUSBMode) + { + return USBDevice::write(EPCDC_IN, buffer, size, MAX_PACKET_SIZE_EPBULK); + } + else + { + EP_STATUS result; + if (size > MAX_PACKET_SIZE_EPBULK) + { + return false; + } + + if(!configured()) { + return false; + } + + result = endpointWrite(EPWEBUSB_IN, buffer, size); + + if (result != EP_PENDING) + { + return false; + } + + // Wait for completion (or until timeout is reached) + uint32_t tstart = osKernelGetTickCount(); + do { + result = endpointWriteResult(EPWEBUSB_IN); + + if ((osKernelGetTickCount()-tstart) > (WEBUSB_WRITE_TIMEOUT)) { + // Host is not reading from the endpoint, assume the WebUSB client is no longer active and switch back to CDC mode + m_webUSBMode = false; + break; + } + } while (result == EP_PENDING); + + return (result == EP_COMPLETED); + } +} + +bool USBWebUSBSerial::readActiveEP() +{ + uint8_t buffer[MAX_PACKET_SIZE_EPBULK]; + uint32_t size = 0; + if (!USBDevice::readEP_NB(activeOutEndpoint(), buffer, &size, MAX_PACKET_SIZE_EPBULK)) + { + return false; + } + if (!readStart(activeOutEndpoint(), MAX_PACKET_SIZE_EPBULK)) + { + return false; + } + + for (uint32_t i = 0; i < size; i++) + { + m_buffer.queue(buffer[i]); + } + + if (size != 0 && activeOutEndpoint() == EPCDC_OUT) + { + // terminal must be connected now since we received packets + m_terminalConnected = true; + } + + // call a potential handler + if (m_rx) + { + m_rx.call(); + } + + return true; +} + +uint8_t * USBWebUSBSerial::deviceDesc() +{ + static uint8_t deviceDescriptor[] = { + DEVICE_DESCRIPTOR_LENGTH, // bLength + DEVICE_DESCRIPTOR, // bDescriptorType + 0x10, 0x02, // bcdUSB = 2.10 + 0, // bDeviceClass: composite (unspecified on device level) + 0, // bDeviceSubClass + 0, // bDeviceProtocol + MAX_PACKET_SIZE_EP0, // bMaxPacketSize0 + (uint8_t)(LSB(VENDOR_ID)), (uint8_t)(MSB(VENDOR_ID)), // idVendor + (uint8_t)(LSB(PRODUCT_ID)), (uint8_t)(MSB(PRODUCT_ID)),// idProduct + 0x00, 0x01, // bcdDevice + STRING_OFFSET_IMANUFACTURER, // iManufacturer + STRING_OFFSET_IPRODUCT, // iProduct + STRING_OFFSET_ISERIAL, // iSerialNumber + 1 // bNumConfigurations + }; + return deviceDescriptor; +} + +uint8_t * USBWebUSBSerial::stringImanufacturerDesc() +{ + return m_manufacturerStringDesc; +} + +uint8_t * USBWebUSBSerial::stringIproductDesc() +{ + return m_productStringDesc; +} + +uint8_t * USBWebUSBSerial::stringIserialDesc() +{ + return m_serialStringDesc; +} + +#define CONFIG1_DESC_SIZE (CONFIGURATION_DESCRIPTOR_LENGTH + \ + INTERFACE_ASSOCIATION_DESCRIPTOR_LENGTH + \ + INTERFACE_DESCRIPTOR_LENGTH + \ + 5+5+4+5 + \ + ENDPOINT_DESCRIPTOR_LENGTH + \ + INTERFACE_DESCRIPTOR_LENGTH + \ + ENDPOINT_DESCRIPTOR_LENGTH + \ + ENDPOINT_DESCRIPTOR_LENGTH + \ + INTERFACE_DESCRIPTOR_LENGTH + \ + ENDPOINT_DESCRIPTOR_LENGTH + \ + ENDPOINT_DESCRIPTOR_LENGTH) + +uint8_t * USBWebUSBSerial::configurationDesc() +{ + static uint8_t configDescriptor[] = { + // configuration descriptor + CONFIGURATION_DESCRIPTOR_LENGTH, // bLength + CONFIGURATION_DESCRIPTOR, // bDescriptorType + LSB(CONFIG1_DESC_SIZE), // wTotalLength + MSB(CONFIG1_DESC_SIZE), + 3, // bNumInterfaces + 1, // bConfigurationValue + 0, // iConfiguration + 0x80, // bmAttributes + 50, // bMaxPower + + // IAD to associate the two CDC interfaces + INTERFACE_ASSOCIATION_DESCRIPTOR_LENGTH, // bLength + INTERFACE_ASSOCIATION_DESCRIPTOR, // bDescriptorType + 0x00, // bFirstInterface + 0x02, // bInterfaceCount + USB_CDC_CLASS, // bFunctionClass + USB_ACM_SUBCLASS, // bFunctionSubClass + 0, // bFunctionProtocol + 0, // iFunction + + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + INTERFACE_DESCRIPTOR_LENGTH, // bLength + INTERFACE_DESCRIPTOR, // bDescriptorType + 0, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + USB_CDC_CLASS, // bInterfaceClass + USB_ACM_SUBCLASS, // bInterfaceSubClass + 0x01, // bInterfaceProtocol + 0, // iInterface + + // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 + 5, // bFunctionLength + USB_CS_INTERFACE, // bDescriptorType + USB_HEADER_FUNCTION_DESCRIPTOR_TYPE, // bDescriptorSubtype + 0x10, 0x01, // bcdCDC + + // Call Management Functional Descriptor, CDC PSTN Spec 5.3.1, Table 3 + 5, // bFunctionLength + USB_CS_INTERFACE, // bDescriptorType + USB_CALL_MANAGEMENT_FUNCTION_DESCRIPTOR_TYPE, // bDescriptorSubtype + 0x03, // bmCapabilities + 1, // bDataInterface + + // Abstract Control Management Functional Descriptor, CDC PSTN Spec 5.3.2, Table 4 + 4, // bFunctionLength + USB_CS_INTERFACE, // bDescriptorType + USB_ABSTRACT_CONTROL_MANAGEMENT_FUNCTION_DESCRIPTOR_TYPE, // bDescriptorSubtype + 0x06, // bmCapabilities + + // Union Functional Descriptor, CDC Spec 5.2.3.2, Table 16 + 5, // bFunctionLength + USB_CS_INTERFACE, // bDescriptorType + USB_UNION_INTERFACE_FUNCTION_DESCRIPTOR_TYPE, // bDescriptorSubtype + 0, // bMasterInterface + 1, // bSlaveInterface0 + + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(EPINT_IN), // bEndpointAddress + E_INTERRUPT, // bmAttributes (0x03=intr) + LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB) + 16, // bInterval + + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + INTERFACE_DESCRIPTOR_LENGTH, // bLength + INTERFACE_DESCRIPTOR, // bDescriptorType + 1, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + USB_CDC_DATA_CLASS, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0, // iInterface + + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(EPCDC_IN), // bEndpointAddress + E_BULK, // bmAttributes (0x02=bulk) + LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB) + 0, // bInterval + + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(EPCDC_OUT), // bEndpointAddress + E_BULK, // bmAttributes (0x02=bulk) + LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB) + 0, // bInterval + + // WebUSB interface + INTERFACE_DESCRIPTOR_LENGTH, // bLength + INTERFACE_DESCRIPTOR, // bDescriptorType + 2, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + USB_CUSTOM_CLASS, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0, // iInterface + + // WebUSB IN endpoint + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(EPWEBUSB_IN), // bEndpointAddress + E_BULK, // bmAttributes (0x02=bulk) + LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB) + 0, // bInterval + + // WebUSB OUT endpoint + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(EPWEBUSB_OUT), // bEndpointAddress + E_BULK, // bmAttributes (0x02=bulk) + LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB) + 0 // bInterval + }; + return configDescriptor; +} + +#define BOS_MSOS2_PLATFORM_DESCRIPTOR_LENGTH 28 +#define BOS_TOTAL_LENGTH (BOS_DESCRIPTOR_LENGTH + BOS_MSOS2_PLATFORM_DESCRIPTOR_LENGTH) + +uint8_t * USBWebUSBSerial::bosDesc() +{ + static uint8_t bosDescriptor[] = { + BOS_DESCRIPTOR_LENGTH, // bLength + BOS_DESCRIPTOR, // bDescriptorType + LSB(BOS_TOTAL_LENGTH), // wTotalLength (LSB) + MSB(BOS_TOTAL_LENGTH), // wTotalLength (MSB) + 0x01, // bNumDeviceCaps + + // MS OS 2.0 descriptors information + BOS_MSOS2_PLATFORM_DESCRIPTOR_LENGTH, + DEVICE_CAPABILITY_DESCRIPTOR, + PLATFORM_DEVICE_CAPABILITY_TYPE, + 0x00, // bReserved + 0xDF, 0x60, 0xDD, 0xD8, // PlatformCapabilityUUID ({D8DD60DF-4589-4CC7-9CD2-659D9E648A9F}) + 0x89, 0x45, + 0xC7, 0x4C, + 0x9C, 0xD2, + 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F, + + 0x00, 0x00, 0x03, 0x06, // Windows version (8.1 = 0x06030000) + LSB(MS_OS_20_DESCRIPTOR_LENGTH), // wMSOSDecriptorSetTotalLength (LSB) + MSB(MS_OS_20_DESCRIPTOR_LENGTH), // wMSOSDecriptorSetTotalLength (MSB) + WINUSB_VENDOR_CODE, // bMS_VendorCode + 0x00 // bAltEnum + }; + return bosDescriptor; +} + + +int USBWebUSBSerial::_putc(int c) +{ + if (!m_terminalConnected && !m_webUSBMode) + { + return 0; + } + send((uint8_t *)&c, 1); + return 1; +} + +int USBWebUSBSerial::_getc() +{ + uint8_t c = 0; + while (m_buffer.isEmpty()); + m_buffer.dequeue(&c); + return c; +} + +bool USBWebUSBSerial::writeBlock(const uint8_t * buf, uint16_t size) +{ + if(!m_terminalConnected && !m_webUSBMode) + { + return false; + } + if(size > MAX_PACKET_SIZE_EPBULK) + { + return false; + } + if(!send(buf, size)) + { + return false; + } + return true; +} + +bool USBWebUSBSerial::EPCDC_OUT_callback() +{ + EPOUTCallbackHandler(EPCDC_OUT); + return true; +} + +bool USBWebUSBSerial::EPWEBUSB_OUT_callback() +{ + EPOUTCallbackHandler(EPWEBUSB_OUT); + return true; +} + +bool USBWebUSBSerial::EPOUTCallbackHandler(uint8_t endpoint) +{ + if (endpoint == activeOutEndpoint()) + { + return readActiveEP(); + } + else + { + // Read out the data but ignore it since it is on the inactive endpoint + uint8_t buffer[MAX_PACKET_SIZE_EPBULK]; + uint32_t size = 0; + if (!USBDevice::readEP_NB(endpoint, buffer, &size, MAX_PACKET_SIZE_EPBULK)) + { + return false; + } + if (!readStart(endpoint, MAX_PACKET_SIZE_EPBULK)) + { + return false; + } + + if (size != 0 && endpoint == EPCDC_OUT) + { + // terminal must be connected now since we received packets + m_terminalConnected = true; + } + } + return true; +} + +uint8_t USBWebUSBSerial::available() +{ + return m_buffer.available(); +} + +void USBWebUSBSerial::setManufacturerName(const std::string &manufacturerName) +{ + m_manufacturerName = manufacturerName; + delete m_manufacturerStringDesc; + m_manufacturerStringDesc = nullptr; + createDynamicDescriptors(); +} + +void USBWebUSBSerial::setProductName(const std::string &productName) +{ + m_productName = productName; + delete m_productStringDesc; + m_productStringDesc = nullptr; + createDynamicDescriptors(); +} + +void USBWebUSBSerial::setSerialNumber(const std::string &serialNumber) +{ + m_serialNumber = serialNumber; + delete m_serialStringDesc; + m_serialStringDesc = nullptr; + createDynamicDescriptors(); +} + +void USBWebUSBSerial::createDynamicDescriptors() +{ + if (!m_manufacturerStringDesc) + { + m_manufacturerStringDesc = createStringDescriptor(m_manufacturerName); + } + if (!m_productStringDesc) + { + m_productStringDesc = createStringDescriptor(m_productName); + } + if (!m_serialStringDesc) + { + m_serialStringDesc = createStringDescriptor(m_serialNumber); + } +} + +uint8_t *USBWebUSBSerial::createStringDescriptor(const std::string &string) const +{ + uint8_t stringSize = string.size()*2; + uint8_t descriptorSize = 2 + stringSize; + uint8_t *descriptor = new uint8_t[descriptorSize]; + descriptor[0] = descriptorSize; // bLength + descriptor[1] = STRING_DESCRIPTOR; // bDescriptorType + for (int i = 0; i < stringSize/2; i++) + { + descriptor[(i*2)+2] = string[i]; + descriptor[(i*2)+3] = 0; + } + return descriptor; +} \ No newline at end of file