Fork of https://developer.mbed.org/users/bscott/code/STM32_USBDevice/
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