Fork of https://developer.mbed.org/users/bscott/code/STM32_USBDevice/

Fork of STM32_USBDevice by Bradley Scott

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBWebUSBSerial.cpp Source File

USBWebUSBSerial.cpp

00001 #include "USBWebUSBSerial.h"
00002 #include "CriticalSectionLock.h"
00003 
00004 static uint8_t cdc_line_coding[7]= {0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x08};
00005 
00006 #define DEFAULT_CONFIGURATION (1)
00007 
00008 #define CDC_SET_LINE_CODING        0x20
00009 #define CDC_GET_LINE_CODING        0x21
00010 #define CDC_SET_CONTROL_LINE_STATE 0x22
00011 
00012 // USB standard values
00013 #define USB_CS_INTERFACE 0x24
00014 #define USB_HEADER_FUNCTION_DESCRIPTOR_TYPE 0x00
00015 #define USB_CALL_MANAGEMENT_FUNCTION_DESCRIPTOR_TYPE 0x01
00016 #define USB_ABSTRACT_CONTROL_MANAGEMENT_FUNCTION_DESCRIPTOR_TYPE 0x02
00017 #define USB_UNION_INTERFACE_FUNCTION_DESCRIPTOR_TYPE 0x06
00018 #define PLATFORM_DEVICE_CAPABILITY_TYPE 0x05
00019 
00020 #define USB_CDC_CLASS 0x02
00021 #define USB_ACM_SUBCLASS 0x02
00022 #define USB_CDC_DATA_CLASS 0x0A
00023 #define USB_CUSTOM_CLASS 0xFF
00024 
00025 // MS OS 2.0 descriptor types
00026 #define MS_OS_20_SET_HEADER_DESCRIPTOR 0x00
00027 #define MS_OS_20_SUBSET_HEADER_CONFIGURATION 0x01
00028 #define MS_OS_20_SUBSET_HEADER_FUNCTION 0x02
00029 #define MS_OS_20_FEATURE_COMPATIBLE_ID 0x03
00030 #define MS_OS_20_FEATURE_REG_PROPERTY 0x04
00031 #define MS_OS_20_FEATURE_MIN_RESUME_TIME 0x05
00032 #define MS_OS_20_FEATURE_MODEL_ID 0x06
00033 #define MS_OS_20_FEATURE_CCGP_DEVICE 0x07
00034 
00035 #define MS_OS_20_DESCRIPTOR_INDEX 0x07
00036 #define MS_OS_20_DESCRIPTOR_LENGTH 178
00037 
00038 // Vendor commands
00039 #define WINUSB_VENDOR_CODE 0x01
00040 #define SET_WEBUSB_ACTIVE_VENDOR_CODE 0xAA
00041 
00042 // Control Line State bits
00043 #define CLS_DTR   (1 << 0)
00044 #define CLS_RTS   (1 << 1)
00045 
00046 #ifdef USB_DEVICE_WRITE_BLOCKING_TIMEOUT_MS
00047 #define WEBUSB_WRITE_TIMEOUT (USB_DEVICE_WRITE_BLOCKING_TIMEOUT_MS)
00048 #else
00049 #define WEBUSB_WRITE_TIMEOUT 1000
00050 #endif
00051 
00052 
00053 uint8_t USBWebUSBSerial::s_MSOS2Descriptor[] =
00054 {
00055     // Microsoft OS 2.0 descriptor set header (table 10)
00056     0x0A, 0x00,  // Header size (always 10 bytes)
00057     LSB(MS_OS_20_SET_HEADER_DESCRIPTOR),
00058     MSB(MS_OS_20_SET_HEADER_DESCRIPTOR),
00059     0x00, 0x00, 0x03, 0x06,  // Windows version (8.1) (0x06030000)
00060     LSB(MS_OS_20_DESCRIPTOR_LENGTH),
00061     MSB(MS_OS_20_DESCRIPTOR_LENGTH),
00062 
00063     // Configuration subset header (table 11)
00064     0x08, 0x00, // wLength, always 8
00065     LSB(MS_OS_20_SUBSET_HEADER_CONFIGURATION),
00066     MSB(MS_OS_20_SUBSET_HEADER_CONFIGURATION),
00067     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
00068     0x00, // reserved
00069     LSB(MS_OS_20_DESCRIPTOR_LENGTH - 10), // wTotalLength (length of subset including this header)
00070     MSB(MS_OS_20_DESCRIPTOR_LENGTH - 10),
00071 
00072     // Function subset (table 12)
00073     0x08, 0x00, // wLength, always 8
00074     LSB(MS_OS_20_SUBSET_HEADER_FUNCTION),
00075     MSB(MS_OS_20_SUBSET_HEADER_FUNCTION),
00076     0x02, // bFirstInterface
00077     0x00, // reserved
00078     LSB(MS_OS_20_DESCRIPTOR_LENGTH - 18), // wSubSetLength (length of subset including this header)
00079     MSB(MS_OS_20_DESCRIPTOR_LENGTH - 18),
00080 
00081     // Microsoft OS 2.0 compatible ID descriptor (table 13)
00082     // Ties the winusb driver to the webusb interface
00083     0x14, 0x00,  // wLength, always 20
00084     LSB(MS_OS_20_FEATURE_COMPATIBLE_ID),
00085     MSB(MS_OS_20_FEATURE_COMPATIBLE_ID),
00086     'W',  'I',  'N',  'U',  'S',  'B',  0x00, 0x00, // CompatibleID (string)
00087     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SubCompatibleID (string)
00088 
00089     // Registry property descriptor (table 14)
00090     // Sets a registry key named DeviceInterfaceGUIDs with a GUID for the WebUSB interface (apparently required before libusb can enumerate it...)
00091     0x84, 0x00,   // wLength (132)
00092     LSB(MS_OS_20_FEATURE_REG_PROPERTY),
00093     MSB(MS_OS_20_FEATURE_REG_PROPERTY),
00094     0x07, 0x00,   // wPropertyDataType (REG_MULTI_SZ) - see table 15
00095     0x2A, 0x00,   // wPropertyNameLength (42)
00096     // Property name (wide string) : DeviceInterfaceGUIDs
00097     '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,
00098     0x50, 0x00,   // wPropertyDataLength (80)
00099     // Property data (wide string): {307A82E9-227E-48C3-8C4E-627BE96A7A78} (randomly generated for this device)
00100     '{', 0, '3', 0, '0', 0, '7', 0, 'A', 0, '8', 0, '2', 0, 'E', 0, '9', 0, '-', 0,
00101     '2', 0, '2', 0, '7', 0, 'E', 0, '-', 0,
00102     '4', 0, '8', 0, 'C', 0, '3', 0, '-', 0,
00103     '8', 0, 'C', 0, '4', 0, 'E', 0, '-', 0,
00104     '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
00105 };
00106 
00107 
00108 USBWebUSBSerial::USBWebUSBSerial(uint16_t vendor_id, uint16_t product_id, uint16_t product_release, bool connect_blocking)
00109     : USBDevice(vendor_id, product_id, product_release)
00110 {
00111     m_terminalConnected = false;
00112     USBDevice::connect(connect_blocking);
00113     createDynamicDescriptors();
00114 }
00115 
00116 USBWebUSBSerial::~USBWebUSBSerial()
00117 {
00118     delete[] m_manufacturerStringDesc;
00119     delete[] m_productStringDesc;
00120     delete[] m_serialStringDesc;
00121 }
00122 
00123 void USBWebUSBSerial::USBCallback_busReset()
00124 {
00125     m_terminalConnected = false;
00126     m_pendingWrite = false;
00127     setWebUSBMode(false);
00128 }
00129 
00130 bool USBWebUSBSerial::USBCallback_request()
00131 {
00132     /* Called in ISR context */
00133 
00134     bool success = false;
00135     CONTROL_TRANSFER * transfer = getTransferPtr();
00136 
00137     /* Process class-specific requests */
00138     if (transfer->setup.bmRequestType.Type == CLASS_TYPE)
00139     {
00140         switch (transfer->setup.bRequest)
00141         {
00142             case CDC_GET_LINE_CODING:
00143                 transfer->remaining = 7;
00144                 transfer->ptr = cdc_line_coding;
00145                 transfer->direction = DEVICE_TO_HOST;
00146                 success = true;
00147                 break;
00148             case CDC_SET_LINE_CODING:
00149                 transfer->remaining = 7;
00150                 transfer->notify = true;
00151                 success = true;
00152                 break;
00153             case CDC_SET_CONTROL_LINE_STATE:
00154                 if (transfer->setup.wValue & CLS_DTR) {
00155                     m_terminalConnected = true;
00156                 } else {
00157                     m_terminalConnected = false;
00158                     if (!m_webUSBMode)
00159                     {
00160                         m_pendingWrite = false;
00161                     }
00162                 }
00163                 success = true;
00164                 break;
00165             default:
00166                 break;
00167         }
00168     }
00169     else if (transfer->setup.bmRequestType.Type == VENDOR_TYPE && transfer->setup.bRequest == WINUSB_VENDOR_CODE && transfer->setup.wIndex == MS_OS_20_DESCRIPTOR_INDEX)
00170     {
00171         // Request for the MS OS 2.0 descriptor
00172         transfer->remaining = MS_OS_20_DESCRIPTOR_LENGTH;
00173         transfer->ptr = s_MSOS2Descriptor;
00174         transfer->direction = DEVICE_TO_HOST;
00175         success = true;
00176     }
00177     else if (transfer->setup.bmRequestType.Type == VENDOR_TYPE && transfer->setup.bRequest == SET_WEBUSB_ACTIVE_VENDOR_CODE)
00178     {
00179         if (transfer->setup.wValue == 0)
00180         {
00181             // Disable WebUSB mode
00182             setWebUSBMode(false);
00183         }
00184         else
00185         {
00186             // Enable WebUSB mode
00187             setWebUSBMode(true);
00188         }
00189         success = true;
00190     }
00191 
00192     return success;
00193 }
00194 
00195 void USBWebUSBSerial::USBCallback_requestCompleted(uint8_t *buf, uint32_t length)
00196 {
00197     // Request of setting line coding has 7 bytes
00198     if (length != 7)
00199     {
00200         return;
00201     }
00202 
00203     CONTROL_TRANSFER * transfer = getTransferPtr();
00204 
00205     /* Process class-specific requests */
00206     if (transfer->setup.bmRequestType.Type == CLASS_TYPE)
00207     {
00208         if (transfer->setup.bRequest == CDC_SET_LINE_CODING)
00209         {
00210             if (memcmp(cdc_line_coding, buf, 7))
00211             {
00212                 memcpy(cdc_line_coding, buf, 7);
00213 
00214                 int baud = buf[0] + (buf[1] << 8)
00215                          + (buf[2] << 16) + (buf[3] << 24);
00216                 int stop = buf[4];
00217                 int bits = buf[6];
00218                 int parity = buf[5];
00219 
00220                 lineCodingChanged(baud, bits, parity, stop);
00221             }
00222         }
00223     }
00224 }
00225 
00226 // Called in ISR context
00227 // Set configuration. Return false if the
00228 // configuration is not supported.
00229 bool USBWebUSBSerial::USBCallback_setConfiguration(uint8_t configuration)
00230 {
00231     if (configuration != DEFAULT_CONFIGURATION)
00232     {
00233         return false;
00234     }
00235 
00236     if (configured())
00237     {
00238         // Already configured, nothing to do
00239         return true;
00240     }
00241 
00242     // Configure endpoints > 0
00243     addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT);
00244     addEndpoint(EPCDC_IN, MAX_PACKET_SIZE_EPBULK);
00245     addEndpoint(EPCDC_OUT, MAX_PACKET_SIZE_EPBULK);
00246     addEndpoint(EPWEBUSB_IN, MAX_PACKET_SIZE_EPBULK);
00247     addEndpoint(EPWEBUSB_OUT, MAX_PACKET_SIZE_EPBULK);
00248 
00249     // We activate the endpoints to be able to receive data
00250     readStart(EPCDC_OUT, MAX_PACKET_SIZE_EPBULK);
00251     readStart(EPWEBUSB_OUT, MAX_PACKET_SIZE_EPBULK);
00252     return true;
00253 }
00254 
00255 void USBWebUSBSerial::writeToActiveEndpoint()
00256 {
00257     CriticalSectionLock lock;
00258     if(!configured() || m_outputBuffer.isEmpty())
00259     {
00260         m_pendingWrite = false;
00261         return;
00262     }
00263 
00264     uint8_t buffer[MAX_PACKET_SIZE_EPBULK];
00265     uint16_t size = m_outputBuffer.dequeue(buffer, MAX_PACKET_SIZE_EPBULK);
00266 
00267     EP_STATUS result = endpointWrite(activeInEndpoint(), buffer, size);
00268 
00269     if (result != EP_PENDING)
00270     {
00271         return;
00272     }
00273 
00274     m_lastWriteTime = osKernelGetTickCount();
00275     m_pendingWrite = true;
00276 }
00277 
00278 bool USBWebUSBSerial::readActiveEP()
00279 {
00280     CriticalSectionLock lock;
00281     uint8_t buffer[MAX_PACKET_SIZE_EPBULK];
00282     uint32_t size = 0;
00283     if (!USBDevice::readEP_NB(activeOutEndpoint(), buffer, &size, MAX_PACKET_SIZE_EPBULK))
00284     {
00285         return false;
00286     }
00287     if (!readStart(activeOutEndpoint(), MAX_PACKET_SIZE_EPBULK))
00288     {
00289         return false;
00290     }
00291 
00292     m_inputBuffer.queue(buffer, size);
00293 
00294     if (size != 0 && activeOutEndpoint() == EPCDC_OUT)
00295     {
00296         // terminal must be connected now since we received packets
00297         m_terminalConnected = true;
00298     }
00299 
00300     // call a potential handler
00301     if (m_rx)
00302     {
00303         m_rx.call();
00304     }
00305 
00306     return true;
00307 }
00308 
00309 uint8_t * USBWebUSBSerial::deviceDesc()
00310 {
00311     static uint8_t deviceDescriptor[] = {
00312         DEVICE_DESCRIPTOR_LENGTH, // bLength
00313         DEVICE_DESCRIPTOR,    // bDescriptorType
00314         0x10, 0x02,           // bcdUSB = 2.10
00315         0,                    // bDeviceClass: composite (unspecified on device level)
00316         0,                    // bDeviceSubClass
00317         0,                    // bDeviceProtocol
00318         MAX_PACKET_SIZE_EP0,  // bMaxPacketSize0
00319         (uint8_t)(LSB(VENDOR_ID)), (uint8_t)(MSB(VENDOR_ID)),  // idVendor
00320         (uint8_t)(LSB(PRODUCT_ID)), (uint8_t)(MSB(PRODUCT_ID)),// idProduct
00321         0x00, 0x01,           // bcdDevice
00322         STRING_OFFSET_IMANUFACTURER, // iManufacturer
00323         STRING_OFFSET_IPRODUCT, // iProduct
00324         STRING_OFFSET_ISERIAL, // iSerialNumber
00325         1                     // bNumConfigurations
00326     };
00327     return deviceDescriptor;
00328 }
00329 
00330 uint8_t * USBWebUSBSerial::stringImanufacturerDesc()
00331 {
00332     return m_manufacturerStringDesc;
00333 }
00334 
00335 uint8_t * USBWebUSBSerial::stringIproductDesc()
00336 {
00337     return m_productStringDesc;
00338 }
00339 
00340 uint8_t * USBWebUSBSerial::stringIserialDesc()
00341 {
00342     return m_serialStringDesc;
00343 }
00344 
00345 #define CONFIG1_DESC_SIZE (CONFIGURATION_DESCRIPTOR_LENGTH + \
00346                            INTERFACE_ASSOCIATION_DESCRIPTOR_LENGTH + \
00347                            INTERFACE_DESCRIPTOR_LENGTH + \
00348                            5+5+4+5 + \
00349                            ENDPOINT_DESCRIPTOR_LENGTH + \
00350                            INTERFACE_DESCRIPTOR_LENGTH + \
00351                            ENDPOINT_DESCRIPTOR_LENGTH + \
00352                            ENDPOINT_DESCRIPTOR_LENGTH + \
00353                            INTERFACE_DESCRIPTOR_LENGTH + \
00354                            ENDPOINT_DESCRIPTOR_LENGTH + \
00355                            ENDPOINT_DESCRIPTOR_LENGTH)
00356 
00357 uint8_t * USBWebUSBSerial::configurationDesc()
00358 {
00359     static uint8_t configDescriptor[] = {
00360         // configuration descriptor
00361         CONFIGURATION_DESCRIPTOR_LENGTH,  // bLength
00362         CONFIGURATION_DESCRIPTOR, // bDescriptorType
00363         LSB(CONFIG1_DESC_SIZE), // wTotalLength
00364         MSB(CONFIG1_DESC_SIZE),
00365         3,                      // bNumInterfaces
00366         1,                      // bConfigurationValue
00367         0,                      // iConfiguration
00368         0x80,                   // bmAttributes
00369         50,                     // bMaxPower
00370 
00371         // IAD to associate the two CDC interfaces
00372         INTERFACE_ASSOCIATION_DESCRIPTOR_LENGTH, // bLength
00373         INTERFACE_ASSOCIATION_DESCRIPTOR, // bDescriptorType
00374         0x00,                   // bFirstInterface
00375         0x02,                   // bInterfaceCount
00376         USB_CDC_CLASS,          // bFunctionClass
00377         USB_ACM_SUBCLASS,       // bFunctionSubClass
00378         0,                      // bFunctionProtocol
00379         0,                      // iFunction
00380 
00381         // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
00382         INTERFACE_DESCRIPTOR_LENGTH, // bLength
00383         INTERFACE_DESCRIPTOR,   // bDescriptorType
00384         0,                      // bInterfaceNumber
00385         0,                      // bAlternateSetting
00386         1,                      // bNumEndpoints
00387         USB_CDC_CLASS,          // bInterfaceClass
00388         USB_ACM_SUBCLASS,       // bInterfaceSubClass
00389         0x01,                   // bInterfaceProtocol
00390         0,                      // iInterface
00391 
00392         // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26
00393         5,                      // bFunctionLength
00394         USB_CS_INTERFACE,       // bDescriptorType
00395         USB_HEADER_FUNCTION_DESCRIPTOR_TYPE, // bDescriptorSubtype
00396         0x10, 0x01,             // bcdCDC
00397 
00398         // Call Management Functional Descriptor, CDC PSTN Spec 5.3.1, Table 3
00399         5,                      // bFunctionLength
00400         USB_CS_INTERFACE,       // bDescriptorType
00401         USB_CALL_MANAGEMENT_FUNCTION_DESCRIPTOR_TYPE, // bDescriptorSubtype
00402         0x03,                   // bmCapabilities
00403         1,                      // bDataInterface
00404 
00405         // Abstract Control Management Functional Descriptor, CDC PSTN Spec 5.3.2, Table 4
00406         4,                      // bFunctionLength
00407         USB_CS_INTERFACE,       // bDescriptorType
00408         USB_ABSTRACT_CONTROL_MANAGEMENT_FUNCTION_DESCRIPTOR_TYPE, // bDescriptorSubtype
00409         0x06,                   // bmCapabilities
00410 
00411         // Union Functional Descriptor, CDC Spec 5.2.3.2, Table 16
00412         5,                      // bFunctionLength
00413         USB_CS_INTERFACE,       // bDescriptorType
00414         USB_UNION_INTERFACE_FUNCTION_DESCRIPTOR_TYPE, // bDescriptorSubtype
00415         0,                      // bMasterInterface
00416         1,                      // bSlaveInterface0
00417 
00418         // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
00419         ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
00420         ENDPOINT_DESCRIPTOR,            // bDescriptorType
00421         PHY_TO_DESC(EPINT_IN),          // bEndpointAddress
00422         E_INTERRUPT,                    // bmAttributes (0x03=intr)
00423         LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
00424         MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
00425         16,                             // bInterval
00426 
00427         // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
00428         INTERFACE_DESCRIPTOR_LENGTH, // bLength
00429         INTERFACE_DESCRIPTOR,       // bDescriptorType
00430         1,                          // bInterfaceNumber
00431         0,                          // bAlternateSetting
00432         2,                          // bNumEndpoints
00433         USB_CDC_DATA_CLASS,         // bInterfaceClass
00434         0x00,                       // bInterfaceSubClass
00435         0x00,                       // bInterfaceProtocol
00436         0,                          // iInterface
00437 
00438         // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
00439         ENDPOINT_DESCRIPTOR_LENGTH, // bLength
00440         ENDPOINT_DESCRIPTOR,        // bDescriptorType
00441         PHY_TO_DESC(EPCDC_IN),     // bEndpointAddress
00442         E_BULK,                     // bmAttributes (0x02=bulk)
00443         LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
00444         MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
00445         0,                          // bInterval
00446 
00447         // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
00448         ENDPOINT_DESCRIPTOR_LENGTH, // bLength
00449         ENDPOINT_DESCRIPTOR,        // bDescriptorType
00450         PHY_TO_DESC(EPCDC_OUT),    // bEndpointAddress
00451         E_BULK,                     // bmAttributes (0x02=bulk)
00452         LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
00453         MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
00454         0,                          // bInterval
00455 
00456         // WebUSB interface
00457         INTERFACE_DESCRIPTOR_LENGTH, // bLength
00458         INTERFACE_DESCRIPTOR,       // bDescriptorType
00459         2,                          // bInterfaceNumber
00460         0,                          // bAlternateSetting
00461         2,                          // bNumEndpoints
00462         USB_CUSTOM_CLASS,         // bInterfaceClass
00463         0x00,                       // bInterfaceSubClass
00464         0x00,                       // bInterfaceProtocol
00465         0,                          // iInterface
00466 
00467         // WebUSB IN endpoint
00468         ENDPOINT_DESCRIPTOR_LENGTH, // bLength
00469         ENDPOINT_DESCRIPTOR,        // bDescriptorType
00470         PHY_TO_DESC(EPWEBUSB_IN),   // bEndpointAddress
00471         E_BULK,                     // bmAttributes (0x02=bulk)
00472         LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
00473         MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
00474         0,                          // bInterval
00475 
00476         // WebUSB OUT endpoint
00477         ENDPOINT_DESCRIPTOR_LENGTH, // bLength
00478         ENDPOINT_DESCRIPTOR,        // bDescriptorType
00479         PHY_TO_DESC(EPWEBUSB_OUT),  // bEndpointAddress
00480         E_BULK,                     // bmAttributes (0x02=bulk)
00481         LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
00482         MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
00483         0                           // bInterval
00484     };
00485     return configDescriptor;
00486 }
00487 
00488 #define BOS_MSOS2_PLATFORM_DESCRIPTOR_LENGTH 28
00489 #define BOS_TOTAL_LENGTH (BOS_DESCRIPTOR_LENGTH + BOS_MSOS2_PLATFORM_DESCRIPTOR_LENGTH)
00490 
00491 uint8_t * USBWebUSBSerial::bosDesc()
00492 {
00493     static uint8_t bosDescriptor[] = {
00494         BOS_DESCRIPTOR_LENGTH, // bLength
00495         BOS_DESCRIPTOR,        // bDescriptorType
00496         LSB(BOS_TOTAL_LENGTH), // wTotalLength (LSB)
00497         MSB(BOS_TOTAL_LENGTH), // wTotalLength (MSB)
00498         0x01,                  // bNumDeviceCaps
00499 
00500         // MS OS 2.0 descriptors information
00501         BOS_MSOS2_PLATFORM_DESCRIPTOR_LENGTH,
00502         DEVICE_CAPABILITY_DESCRIPTOR,
00503         PLATFORM_DEVICE_CAPABILITY_TYPE,
00504         0x00, // bReserved
00505         0xDF, 0x60, 0xDD, 0xD8,         // PlatformCapabilityUUID ({D8DD60DF-4589-4CC7-9CD2-659D9E648A9F})
00506         0x89, 0x45,
00507         0xC7, 0x4C,
00508         0x9C, 0xD2,
00509         0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F,
00510 
00511         0x00, 0x00, 0x03, 0x06,    // Windows version (8.1 = 0x06030000)
00512         LSB(MS_OS_20_DESCRIPTOR_LENGTH), // wMSOSDecriptorSetTotalLength (LSB)
00513         MSB(MS_OS_20_DESCRIPTOR_LENGTH), // wMSOSDecriptorSetTotalLength (MSB)
00514         WINUSB_VENDOR_CODE,         // bMS_VendorCode
00515         0x00 // bAltEnum
00516     };
00517     return bosDescriptor;
00518 }
00519 
00520 int USBWebUSBSerial::read(uint8_t *buf, uint16_t size)
00521 {
00522     CriticalSectionLock lock;
00523     return m_inputBuffer.dequeue(buf, size);
00524 }
00525 
00526 bool USBWebUSBSerial::writeBuffered(const uint8_t * buf, uint16_t size)
00527 {
00528     CriticalSectionLock lock;
00529     if(!m_terminalConnected && !m_webUSBMode)
00530     {
00531         return false;
00532     }
00533 
00534     m_outputBuffer.queue(buf, size);
00535     if (!m_pendingWrite)
00536     {
00537         writeToActiveEndpoint();
00538     }
00539     else if (m_webUSBMode)
00540     {
00541         // Check if the write has timed out
00542         if (timeSinceWrite() > WEBUSB_WRITE_TIMEOUT)
00543         {
00544             // Host is no longer reading WebUSB endpoint, assume the client is gone and go back to CDC mode
00545             setWebUSBMode(false);
00546         }
00547     }
00548 
00549     return true;
00550 }
00551 
00552 bool USBWebUSBSerial::EPCDC_OUT_callback()
00553 {
00554     EPOUTCallbackHandler(EPCDC_OUT);
00555     return true;
00556 }
00557 
00558 bool USBWebUSBSerial::EPWEBUSB_OUT_callback()
00559 {
00560     EPOUTCallbackHandler(EPWEBUSB_OUT);
00561     return true;    
00562 }
00563 
00564 bool USBWebUSBSerial::EPOUTCallbackHandler(uint8_t endpoint)
00565 {
00566     CriticalSectionLock lock;
00567     if (endpoint == activeOutEndpoint())
00568     {
00569         return readActiveEP();
00570     }
00571     else
00572     {
00573         // Read out the data but ignore it since it is on the inactive endpoint
00574         uint8_t buffer[MAX_PACKET_SIZE_EPBULK];
00575         uint32_t size = 0;
00576         if (!USBDevice::readEP_NB(endpoint, buffer, &size, MAX_PACKET_SIZE_EPBULK))
00577         {
00578             return false;
00579         }
00580         if (!readStart(endpoint, MAX_PACKET_SIZE_EPBULK))
00581         {
00582             return false;
00583         }
00584 
00585         if (size != 0 && endpoint == EPCDC_OUT)
00586         {
00587             // terminal must be connected now since we received packets
00588             m_terminalConnected = true;
00589         }
00590     }
00591     return true;
00592 }
00593 
00594 bool USBWebUSBSerial::EPCDC_IN_callback()
00595 {
00596     CriticalSectionLock lock;
00597     if (!m_webUSBMode)
00598     {
00599         writeToActiveEndpoint();
00600     }
00601 
00602     return true;
00603 }
00604 
00605 bool USBWebUSBSerial::EPWEBUSB_IN_callback()
00606 {
00607     CriticalSectionLock lock;
00608     if (m_webUSBMode)
00609     {
00610         writeToActiveEndpoint();
00611     }
00612 
00613     return true;
00614 }
00615 
00616 uint8_t USBWebUSBSerial::available()
00617 {
00618     CriticalSectionLock lock;
00619     return m_inputBuffer.available();
00620 }
00621 
00622 void USBWebUSBSerial::setManufacturerName(const std::string &manufacturerName)
00623 {
00624     m_manufacturerName = manufacturerName;
00625     delete[] m_manufacturerStringDesc;
00626     m_manufacturerStringDesc = nullptr;
00627     createDynamicDescriptors();
00628 }
00629 
00630 void USBWebUSBSerial::setProductName(const std::string &productName)
00631 {
00632     m_productName = productName;
00633     delete[] m_productStringDesc;
00634     m_productStringDesc = nullptr;
00635     createDynamicDescriptors();
00636 }
00637 
00638 void USBWebUSBSerial::setSerialNumber(const std::string &serialNumber)
00639 {
00640     m_serialNumber = serialNumber;
00641     delete[] m_serialStringDesc;
00642     m_serialStringDesc = nullptr;
00643     createDynamicDescriptors();
00644 }
00645 
00646 void USBWebUSBSerial::createDynamicDescriptors()
00647 {
00648     if (!m_manufacturerStringDesc)
00649     {
00650         m_manufacturerStringDesc = createStringDescriptor(m_manufacturerName);
00651     }
00652     if (!m_productStringDesc)
00653     {
00654         m_productStringDesc = createStringDescriptor(m_productName);
00655     }
00656     if (!m_serialStringDesc)
00657     {
00658         m_serialStringDesc = createStringDescriptor(m_serialNumber);
00659     }
00660 }
00661 
00662 uint8_t *USBWebUSBSerial::createStringDescriptor(const std::string &string) const
00663 {
00664     uint8_t stringSize = string.size()*2;
00665     uint8_t descriptorSize = 2 + stringSize;
00666     uint8_t *descriptor = new uint8_t[descriptorSize];
00667     descriptor[0] = descriptorSize; // bLength
00668     descriptor[1] = STRING_DESCRIPTOR; // bDescriptorType
00669     for (int i = 0; i < stringSize/2; i++)
00670     {
00671         descriptor[(i*2)+2] = string[i];
00672         descriptor[(i*2)+3] = 0;
00673     }
00674     return descriptor;
00675 }
00676 
00677 void USBWebUSBSerial::setWebUSBMode(bool webUSBMode)
00678 {
00679     CriticalSectionLock lock;
00680     if (webUSBMode != m_webUSBMode)
00681     {
00682         m_webUSBMode = webUSBMode;
00683         m_pendingWrite = false;
00684 
00685         // Clear buffers to clean out any left over data
00686         m_inputBuffer.flush();
00687         m_outputBuffer.flush();
00688     }
00689 }
00690 
00691 uint32_t USBWebUSBSerial::timeSinceWrite() const
00692 {
00693     uint32_t currentTime = osKernelGetTickCount();
00694     if (currentTime < m_lastWriteTime)
00695     {
00696         // Tick count has wrapped around and started from 0 again
00697         return currentTime + (0xFFFFFFFF - m_lastWriteTime);
00698     }
00699     else
00700     {
00701         return currentTime - m_lastWriteTime;
00702     }
00703 }