Fork of https://developer.mbed.org/users/bscott/code/STM32_USBDevice/
Fork of STM32_USBDevice by
USBSerial/USBWebUSBSerial.cpp
- Committer:
- Troels Nilsson
- Date:
- 2018-07-25
- Revision:
- 79:d28244984385
- Parent:
- 78:ba3f68a86e6d
File content as of revision 79:d28244984385:
#include "USBWebUSBSerial.h" #include "CriticalSectionLock.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(); } USBWebUSBSerial::~USBWebUSBSerial() { delete[] m_manufacturerStringDesc; delete[] m_productStringDesc; delete[] m_serialStringDesc; } void USBWebUSBSerial::USBCallback_busReset() { m_terminalConnected = false; m_pendingWrite = false; setWebUSBMode(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; if (!m_webUSBMode) { m_pendingWrite = 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 setWebUSBMode(false); } else { // Enable WebUSB mode setWebUSBMode(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; } void USBWebUSBSerial::writeToActiveEndpoint() { CriticalSectionLock lock; if(!configured() || m_outputBuffer.isEmpty()) { m_pendingWrite = false; return; } uint8_t buffer[MAX_PACKET_SIZE_EPBULK]; uint16_t size = m_outputBuffer.dequeue(buffer, MAX_PACKET_SIZE_EPBULK); EP_STATUS result = endpointWrite(activeInEndpoint(), buffer, size); if (result != EP_PENDING) { return; } m_lastWriteTime = osKernelGetTickCount(); m_pendingWrite = true; } bool USBWebUSBSerial::readActiveEP() { CriticalSectionLock lock; 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; } m_inputBuffer.queue(buffer, size); 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::read(uint8_t *buf, uint16_t size) { CriticalSectionLock lock; return m_inputBuffer.dequeue(buf, size); } bool USBWebUSBSerial::writeBuffered(const uint8_t * buf, uint16_t size) { CriticalSectionLock lock; if(!m_terminalConnected && !m_webUSBMode) { return false; } m_outputBuffer.queue(buf, size); if (!m_pendingWrite) { writeToActiveEndpoint(); } else if (m_webUSBMode) { // Check if the write has timed out if (timeSinceWrite() > WEBUSB_WRITE_TIMEOUT) { // Host is no longer reading WebUSB endpoint, assume the client is gone and go back to CDC mode setWebUSBMode(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) { CriticalSectionLock lock; 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; } bool USBWebUSBSerial::EPCDC_IN_callback() { CriticalSectionLock lock; if (!m_webUSBMode) { writeToActiveEndpoint(); } return true; } bool USBWebUSBSerial::EPWEBUSB_IN_callback() { CriticalSectionLock lock; if (m_webUSBMode) { writeToActiveEndpoint(); } return true; } uint8_t USBWebUSBSerial::available() { CriticalSectionLock lock; return m_inputBuffer.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; } void USBWebUSBSerial::setWebUSBMode(bool webUSBMode) { CriticalSectionLock lock; if (webUSBMode != m_webUSBMode) { m_webUSBMode = webUSBMode; m_pendingWrite = false; // Clear buffers to clean out any left over data m_inputBuffer.flush(); m_outputBuffer.flush(); } } uint32_t USBWebUSBSerial::timeSinceWrite() const { uint32_t currentTime = osKernelGetTickCount(); if (currentTime < m_lastWriteTime) { // Tick count has wrapped around and started from 0 again return currentTime + (0xFFFFFFFF - m_lastWriteTime); } else { return currentTime - m_lastWriteTime; } }