Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of STM32_USBDevice by
Revision 79:d28244984385, committed 2018-07-25
- Comitter:
- Troels Nilsson
- Date:
- Wed Jul 25 14:04:48 2018 +0200
- Parent:
- 75:43bf95761b38
- Parent:
- 78:ba3f68a86e6d
- Commit message:
- Merge feature_WebUSB into default
Changed in this revision
diff -r 43bf95761b38 -r d28244984385 USBDevice/USBDescriptor.h --- a/USBDevice/USBDescriptor.h Fri Oct 27 17:22:45 2017 +0200 +++ b/USBDevice/USBDescriptor.h Wed Jul 25 14:04:48 2018 +0200 @@ -23,13 +23,17 @@ #define INTERFACE_DESCRIPTOR (4) #define ENDPOINT_DESCRIPTOR (5) #define QUALIFIER_DESCRIPTOR (6) +#define INTERFACE_ASSOCIATION_DESCRIPTOR (11) +#define BOS_DESCRIPTOR (15) +#define DEVICE_CAPABILITY_DESCRIPTOR (16) /* Standard descriptor lengths */ #define DEVICE_DESCRIPTOR_LENGTH (0x12) #define CONFIGURATION_DESCRIPTOR_LENGTH (0x09) #define INTERFACE_DESCRIPTOR_LENGTH (0x09) #define ENDPOINT_DESCRIPTOR_LENGTH (0x07) - +#define INTERFACE_ASSOCIATION_DESCRIPTOR_LENGTH (0x08) +#define BOS_DESCRIPTOR_LENGTH (0x05) /*string offset*/ #define STRING_OFFSET_LANGID (0)
diff -r 43bf95761b38 -r d28244984385 USBDevice/USBDevice.cpp --- a/USBDevice/USBDevice.cpp Fri Oct 27 17:22:45 2017 +0200 +++ b/USBDevice/USBDevice.cpp Wed Jul 25 14:04:48 2018 +0200 @@ -155,6 +155,24 @@ #endif /* TODO: Support is optional, not implemented here */ break; + + case BOS_DESCRIPTOR: +#ifdef DEBUG + printf("BOS descr\r\n"); +#endif + { + uint8_t *descriptor = bosDesc(); + if (descriptor) + { + /* Get wTotalLength */ + transfer.remaining = descriptor[2] | (descriptor[3] << 8); + transfer.ptr = descriptor; + transfer.direction = DEVICE_TO_HOST; + success = true; + } + } + break; + default: #ifdef DEBUG printf("ERROR\r\n"); @@ -835,7 +853,7 @@ } -bool USBDevice::write(uint8_t endpoint, uint8_t * buffer, uint32_t size, uint32_t maxSize) +bool USBDevice::write(uint8_t endpoint, const uint8_t * buffer, uint32_t size, uint32_t maxSize) { EP_STATUS result; @@ -876,7 +894,7 @@ } -bool USBDevice::writeNB(uint8_t endpoint, uint8_t * buffer, uint32_t size, uint32_t maxSize) +bool USBDevice::writeNB(uint8_t endpoint, const uint8_t * buffer, uint32_t size, uint32_t maxSize) { EP_STATUS result;
diff -r 43bf95761b38 -r d28244984385 USBDevice/USBDevice.h --- a/USBDevice/USBDevice.h Fri Oct 27 17:22:45 2017 +0200 +++ b/USBDevice/USBDevice.h Wed Jul 25 14:04:48 2018 +0200 @@ -103,7 +103,7 @@ * @param size the number of bytes to write * @param maxSize the maximum length that can be written on this endpoint */ - bool write(uint8_t endpoint, uint8_t * buffer, uint32_t size, uint32_t maxSize); + bool write(uint8_t endpoint, const uint8_t * buffer, uint32_t size, uint32_t maxSize); /* @@ -116,7 +116,7 @@ * @param size the number of bytes to write * @param maxSize the maximum length that can be written on this endpoint */ - bool writeNB(uint8_t endpoint, uint8_t * buffer, uint32_t size, uint32_t maxSize); + bool writeNB(uint8_t endpoint, const uint8_t * buffer, uint32_t size, uint32_t maxSize); /* @@ -179,6 +179,13 @@ virtual uint8_t * configurationDesc(){return NULL;}; /* + * Get BOS descriptor + * + * @returns pointer to the BOS descriptor + */ + virtual uint8_t * bosDesc() { return nullptr; } + + /* * Get string lang id descriptor * * @return pointer to the string lang id descriptor
diff -r 43bf95761b38 -r d28244984385 USBDevice/USBEndpoints_STM32L1.h --- a/USBDevice/USBEndpoints_STM32L1.h Fri Oct 27 17:22:45 2017 +0200 +++ b/USBDevice/USBEndpoints_STM32L1.h Wed Jul 25 14:04:48 2018 +0200 @@ -46,22 +46,34 @@ /* Generic endpoints - intended to be portable accross devices */ /* and be suitable for simple USB devices. */ -/* Bulk endpoint */ +/* Bulk/CDC endpoint */ #define EPBULK_OUT (EP2OUT) #define EPBULK_IN (EP2IN) #define EPBULK_OUT_callback EP2_OUT_callback #define EPBULK_IN_callback EP2_IN_callback +#define EPCDC_OUT (EP2OUT) +#define EPCDC_IN (EP2IN) +#define EPCDC_OUT_callback EP2_OUT_callback +#define EPCDC_IN_callback EP2_IN_callback /* Interrupt endpoint */ #define EPINT_OUT (EP1OUT) #define EPINT_IN (EP1IN) #define EPINT_OUT_callback EP1_OUT_callback #define EPINT_IN_callback EP1_IN_callback -/* Isochronous endpoint */ -#define EPISO_OUT (EP3OUT) +/* Isochronous endpoint - not used, replaced by WebUSB endpoint */ +/*#define EPISO_OUT (EP3OUT) #define EPISO_IN (EP3IN) #define EPISO_OUT_callback EP3_OUT_callback -#define EPISO_IN_callback EP3_IN_callback +#define EPISO_IN_callback EP3_IN_callback*/ + +/* WebUSB endpoint (bulk) */ +#define EPWEBUSB_OUT (EP3OUT) +#define EPWEBUSB_IN (EP3IN) +#define EPWEBUSB_OUT_callback EP3_OUT_callback +#define EPWEBUSB_IN_callback EP3_IN_callback #define MAX_PACKET_SIZE_EPBULK (MAX_PACKET_SIZE_EP2) +#define MAX_PACKET_SIZE_EPCDC (MAX_PACKET_SIZE_EP2) #define MAX_PACKET_SIZE_EPINT (MAX_PACKET_SIZE_EP1) #define MAX_PACKET_SIZE_EPISO (MAX_PACKET_SIZE_EP3_ISO) +#define MAX_PACKET_SIZE_EPWEBUSB (MAX_PACKET_SIZE_EP3)
diff -r 43bf95761b38 -r d28244984385 USBDevice/USBHAL.h --- a/USBDevice/USBHAL.h Fri Oct 27 17:22:45 2017 +0200 +++ b/USBDevice/USBHAL.h Wed Jul 25 14:04:48 2018 +0200 @@ -51,7 +51,7 @@ /* Other endpoints */ EP_STATUS endpointRead(uint8_t endpoint, uint32_t maximumSize); EP_STATUS endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead); - EP_STATUS endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size); + EP_STATUS endpointWrite(uint8_t endpoint, const uint8_t *data, uint32_t size); EP_STATUS endpointWriteResult(uint8_t endpoint); void stallEndpoint(uint8_t endpoint); void unstallEndpoint(uint8_t endpoint);
diff -r 43bf95761b38 -r d28244984385 USBDevice/USBHAL_KL25Z.cpp --- a/USBDevice/USBHAL_KL25Z.cpp Fri Oct 27 17:22:45 2017 +0200 +++ b/USBDevice/USBHAL_KL25Z.cpp Wed Jul 25 14:04:48 2018 +0200 @@ -370,7 +370,7 @@ return EP_COMPLETED; } -EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) { +EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, const uint8_t *data, uint32_t size) { uint32_t idx, n; uint8_t * ep_buf;
diff -r 43bf95761b38 -r d28244984385 USBDevice/USBHAL_LPC11U.cpp --- a/USBDevice/USBHAL_LPC11U.cpp Fri Oct 27 17:22:45 2017 +0200 +++ b/USBDevice/USBHAL_LPC11U.cpp Wed Jul 25 14:04:48 2018 +0200 @@ -386,7 +386,7 @@ LPC_USB->DEVCMDSTAT = devCmdStat; } -EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) { +EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, const uint8_t *data, uint32_t size) { uint32_t flags = 0; uint32_t bf;
diff -r 43bf95761b38 -r d28244984385 USBDevice/USBHAL_LPC17.cpp --- a/USBDevice/USBHAL_LPC17.cpp Fri Oct 27 17:22:45 2017 +0200 +++ b/USBDevice/USBHAL_LPC17.cpp Wed Jul 25 14:04:48 2018 +0200 @@ -472,7 +472,7 @@ return EP_COMPLETED; } -EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) { +EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, const uint8_t *data, uint32_t size) { if (getEndpointStallState(endpoint)) { return EP_STALLED; }
diff -r 43bf95761b38 -r d28244984385 USBDevice/USBHAL_LPC40.cpp --- a/USBDevice/USBHAL_LPC40.cpp Fri Oct 27 17:22:45 2017 +0200 +++ b/USBDevice/USBHAL_LPC40.cpp Wed Jul 25 14:04:48 2018 +0200 @@ -477,7 +477,7 @@ return EP_COMPLETED; } -EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) { +EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, const uint8_t *data, uint32_t size) { if (getEndpointStallState(endpoint)) { return EP_STALLED; }
diff -r 43bf95761b38 -r d28244984385 USBDevice/USBHAL_Maxim.cpp --- a/USBDevice/USBHAL_Maxim.cpp Fri Oct 27 17:22:45 2017 +0200 +++ b/USBDevice/USBHAL_Maxim.cpp Wed Jul 25 14:04:48 2018 +0200 @@ -305,7 +305,7 @@ return EP_COMPLETED; } -EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) +EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, const uint8_t *data, uint32_t size) { uint8_t epnum = EP_NUM(endpoint);
diff -r 43bf95761b38 -r d28244984385 USBDevice/USBHAL_RZ_A1H.cpp --- a/USBDevice/USBHAL_RZ_A1H.cpp Fri Oct 27 17:22:45 2017 +0200 +++ b/USBDevice/USBHAL_RZ_A1H.cpp Wed Jul 25 14:04:48 2018 +0200 @@ -1117,7 +1117,7 @@ /*************************************************************************/ -EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) +EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, const uint8_t *data, uint32_t size) { uint32_t pipe = EP2PIPE(endpoint); uint32_t pipe_size;
diff -r 43bf95761b38 -r d28244984385 USBDevice/USBHAL_STM32F4.cpp --- a/USBDevice/USBHAL_STM32F4.cpp Fri Oct 27 17:22:45 2017 +0200 +++ b/USBDevice/USBHAL_STM32F4.cpp Wed Jul 25 14:04:48 2018 +0200 @@ -249,7 +249,7 @@ return EP_COMPLETED; } -EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) { +EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, const uint8_t *data, uint32_t size) { uint32_t epIndex = endpoint >> 1; OTG_FS->INEP_REGS[epIndex].DIEPTSIZ = (1 << 19) | // 1 packet (size << 0); // Size of packet
diff -r 43bf95761b38 -r d28244984385 USBDevice/USBHAL_STM32L1.cpp --- a/USBDevice/USBHAL_STM32L1.cpp Fri Oct 27 17:22:45 2017 +0200 +++ b/USBDevice/USBHAL_STM32L1.cpp Wed Jul 25 14:04:48 2018 +0200 @@ -255,9 +255,9 @@ return EP_COMPLETED; } -EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) { +EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, const uint8_t *data, uint32_t size) { core_util_critical_section_enter(); - HAL_PCD_EP_Transmit(&hpcd_USB_FS, endpoint>>1, data, size); + HAL_PCD_EP_Transmit(&hpcd_USB_FS, endpoint>>1, const_cast<uint8_t*>(data), size); epComplete &= ~(1 << endpoint); core_util_critical_section_exit(); return EP_PENDING;
diff -r 43bf95761b38 -r d28244984385 USBSerial/CircBuffer.h --- a/USBSerial/CircBuffer.h Fri Oct 27 17:22:45 2017 +0200 +++ b/USBSerial/CircBuffer.h Wed Jul 25 14:04:48 2018 +0200 @@ -53,6 +53,79 @@ return(!empty); }; + void flush() + { + write = 0; + read = 0; + } + + // Queue a block of data of blockSize items + void queue(const T *block, uint16_t blockSize) + { + if (blockSize >= size) + { + // Block is too big to fit in buffer, take the last size-1 items + block = &block[blockSize - (size-1)]; + blockSize = size-1; + } + + if (write + blockSize > size) + { + // Need to wrap around + std::memcpy(&buf[write], block, sizeof(T)*(size-write)); + std::memcpy(buf, &block[size-write], sizeof(T)*(blockSize - (size-write))); + } + else + { + std::memcpy(&buf[write], block, sizeof(T)*blockSize); + } + + // Update write position + uint16_t wasFree = available() - size - 1; + write = write + blockSize; + write %= size; + if (wasFree < blockSize) + { + // Update read position as well + read = write + 1; + read %= size; + } + } + + // Dequeue a block of data of at most blockSize items, writing them into block + // Returns the number of items dequeued + uint16_t dequeue(T *block, uint16_t blockSize) + { + if (isEmpty()) + { + return 0; + } + + uint16_t isAvailable = available(); + if (isAvailable < blockSize) + { + // Only return what we have + blockSize = isAvailable; + } + + if (read + blockSize > size) + { + // Need to wrap around + std::memcpy(block, &buf[read], sizeof(T)*(size-read)); + std::memcpy(&block[size-read], buf, sizeof(T)*(blockSize - (size-read))); + } + else + { + std::memcpy(block, &buf[read], sizeof(T)*blockSize); + } + + // Update read position + read = read + blockSize; + read %= size; + + return blockSize; + } + private: volatile uint16_t write; volatile uint16_t read;
diff -r 43bf95761b38 -r d28244984385 USBSerial/USBWebUSBSerial.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBSerial/USBWebUSBSerial.cpp Wed Jul 25 14:04:48 2018 +0200 @@ -0,0 +1,703 @@ +#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; + } +} \ No newline at end of file
diff -r 43bf95761b38 -r d28244984385 USBSerial/USBWebUSBSerial.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBSerial/USBWebUSBSerial.h Wed Jul 25 14:04:48 2018 +0200 @@ -0,0 +1,258 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software +* and associated documentation files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef USBWEBUSBSERIAL_H +#define USBWEBUSBSERIAL_H + +#include <string> +#include "USBDevice.h" +#include "CircBuffer.h" +#include "USBEndpoints.h" +#include "USBDescriptor.h" +#include "USBDevice_Types.h" + +#ifndef USBWEBUSBSERIAL_INPUT_BUFFER_SIZE +#define USBWEBUSBSERIAL_INPUT_BUFFER_SIZE 128 +#endif + +#ifndef USBWEBUSBSERIAL_OUTPUT_BUFFER_SIZE +#define USBWEBUSBSERIAL_OUTPUT_BUFFER_SIZE 512 +#endif + +/** +* WebUSB/USBSerial composite device class +* Handles outputting to standard CDC or WebUSB endpoint depending on mode +* +*/ +class USBWebUSBSerial: public USBDevice +{ +public: + + /** + * Constructor + * + * @param vendor_id Your vendor_id + * @param product_id Your product_id + * @param product_release Your product_release (default: 0x0001) + * @param connect_blocking define if the connection must be blocked if USB not plugged in + * + */ + USBWebUSBSerial(uint16_t vendor_id, uint16_t product_id, uint16_t product_release = 0x0001, bool connect_blocking = true); + virtual ~USBWebUSBSerial(); + + const std::string& manufacturerName() const { return m_manufacturerName; } + void setManufacturerName(const std::string &manufacturerName); + + const std::string& productName() const { return m_productName; } + void setProductName(const std::string &productName); + + const std::string& serialNumber() const { return m_serialNumber; } + void setSerialNumber(const std::string &serialNumber); + + /** + * Read up to size bytes from input buffer + * + * @returns the number of bytes read + */ + + int read(uint8_t *buf, uint16_t size); + + /** + * Check the number of bytes available. + * + * @returns the number of bytes available + */ + uint8_t available(); + + /** Determine if there is a character available to read + * + * @returns + * 1 if there is a character available to read, + * 0 otherwise + */ + int readable() { return available() ? 1 : 0; } + + /** Determine if there is space available to write a character + * + * @returns + * 1 if there is space to write a character, + * 0 otherwise + */ + int writeable() { return 1; } // Always return 1 since we use a circular buffer + + /** + * Write data asynchronously using internal output buffer + * + * @param buf pointer to data + * @param size size of the buffer. The maximum size of data is limited by the size of the internal buffer + * + * @returns true if successfull + */ + bool writeBuffered(const uint8_t * buf, uint16_t size); + + /** + * Attach a member function to call when a packet is received. + * + * @param tptr pointer to the object to call the member function on + * @param mptr pointer to the member function to be called + */ + template<typename T> + void attach(T* tptr, void (T::*mptr)(void)) + { + if (mptr && tptr) + { + m_rx.attach(tptr, mptr); + } + } + + /** + * Attach a callback called when a packet is received + * + * @param fptr function pointer + */ + void attach(void (*fptr)(void)) + { + if (fptr) + { + m_rx.attach(fptr); + } + } + + /** + * Attach a callback to call when serial's settings are changed. + * + * @param fptr function pointer + */ + void attach(void (*fptr)(int baud, int bits, int parity, int stop)) + { + m_settingsChangedCallback = fptr; + } + +protected: + + /* + * Get device descriptor. Warning: this method has to store the length of the report descriptor in reportLength. + * + * @returns pointer to the device descriptor + */ + virtual uint8_t * deviceDesc(); + + /* + * Get string manufacturer descriptor + * + * @returns pointer to the string manufacturer descriptor + */ + virtual uint8_t * stringImanufacturerDesc(); + + /* + * Get string product descriptor + * + * @returns pointer to the string product descriptor + */ + virtual uint8_t * stringIproductDesc(); + + /* + * Get string serial descriptor + * + * @returns pointer to the string serial descriptor + */ + virtual uint8_t * stringIserialDesc(); + + /* + * Get configuration descriptor + * + * @returns pointer to the configuration descriptor + */ + virtual uint8_t * configurationDesc(); + + /* + * Get BOS descriptor + * + * @returns pointer to the BOS descriptor + */ + virtual uint8_t * bosDesc(); + + /* + * Write from internal buffer to active endpoint + */ + void writeToActiveEndpoint(); + + /* + * Read from the active endpoint into the internal buffer (non-blocking) + * + * @returns true if successful + */ + bool readActiveEP(); + + /* + * Called by USBCallback_requestCompleted when CDC line coding is changed + * Warning: Called in ISR + * + * @param baud The baud rate + * @param bits The number of bits in a word (5-8) + * @param parity The parity + * @param stop The number of stop bits (1 or 2) + */ + virtual void lineCodingChanged(int baud, int bits, int parity, int stop) + { + if (m_settingsChangedCallback) + { + m_settingsChangedCallback(baud, bits, parity, stop); + } + } + + virtual bool USBCallback_request(); + virtual void USBCallback_requestCompleted(uint8_t *buf, uint32_t length); + virtual bool USBCallback_setConfiguration(uint8_t configuration); + virtual void USBCallback_busReset(void); + + virtual bool EPCDC_OUT_callback(); + virtual bool EPWEBUSB_OUT_callback(); + virtual bool EPOUTCallbackHandler(uint8_t endpoint); + + virtual bool EPCDC_IN_callback(); + virtual bool EPWEBUSB_IN_callback(); + +private: + uint8_t activeOutEndpoint() const { return m_webUSBMode ? EPWEBUSB_OUT : EPCDC_OUT; } + uint8_t activeInEndpoint() const { return m_webUSBMode ? EPWEBUSB_IN : EPCDC_IN; } + void createDynamicDescriptors(); + uint8_t *createStringDescriptor(const std::string &string) const; + void setWebUSBMode(bool webUSBMode); + uint32_t timeSinceWrite() const; + + static uint8_t s_MSOS2Descriptor[]; + volatile bool m_terminalConnected; + FunctionPointer m_rx; + CircBuffer<uint8_t,USBWEBUSBSERIAL_INPUT_BUFFER_SIZE> m_inputBuffer; + CircBuffer<uint8_t,USBWEBUSBSERIAL_OUTPUT_BUFFER_SIZE> m_outputBuffer; + void (*m_settingsChangedCallback)(int baud, int bits, int parity, int stop) = nullptr; + + bool m_pendingWrite = false; + uint32_t m_lastWriteTime = 0; + std::string m_manufacturerName = "mbed.org"; + uint8_t *m_manufacturerStringDesc = nullptr; + std::string m_productName = "CDC/WebUSB Device"; + uint8_t *m_productStringDesc = nullptr; + std::string m_serialNumber = "0123456789"; + uint8_t *m_serialStringDesc = nullptr; + + bool m_webUSBMode = false; +}; + +#endif