Fork of https://developer.mbed.org/users/bscott/code/STM32_USBDevice/
Fork of STM32_USBDevice by
Diff: USBSerial/USBWebUSBSerial.cpp
- Branch:
- feature_WebUSB
- Revision:
- 77:a98f786d05d4
- Parent:
- 76:eef92651f52f
- Child:
- 78:ba3f68a86e6d
--- a/USBSerial/USBWebUSBSerial.cpp Thu Jul 19 12:57:27 2018 +0200 +++ b/USBSerial/USBWebUSBSerial.cpp Tue Jul 24 13:08:29 2018 +0200 @@ -1,4 +1,5 @@ #include "USBWebUSBSerial.h" +#include "CriticalSectionLock.h" static uint8_t cdc_line_coding[7]= {0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x08}; @@ -115,7 +116,8 @@ void USBWebUSBSerial::USBCallback_busReset() { m_terminalConnected = false; - m_webUSBMode = false; + m_pendingWrite = false; + setWebUSBMode(false); } bool USBWebUSBSerial::USBCallback_request() @@ -146,6 +148,10 @@ m_terminalConnected = true; } else { m_terminalConnected = false; + if (!m_webUSBMode) + { + m_pendingWrite = false; + } } success = true; break; @@ -166,12 +172,12 @@ if (transfer->setup.wValue == 0) { // Disable WebUSB mode - m_webUSBMode = false; + setWebUSBMode(false); } else { // Enable WebUSB mode - m_webUSBMode = true; + setWebUSBMode(true); } success = true; } @@ -239,49 +245,32 @@ return true; } -bool USBWebUSBSerial::send(const uint8_t * buffer, uint32_t size) +void USBWebUSBSerial::writeToActiveEndpoint() { - if (!m_webUSBMode) - { - return USBDevice::write(EPCDC_IN, buffer, size, MAX_PACKET_SIZE_EPBULK); - } - else + CriticalSectionLock lock; + if(!configured() || m_outputBuffer.isEmpty()) { - EP_STATUS result; - if (size > MAX_PACKET_SIZE_EPBULK) - { - return false; - } - - if(!configured()) { - return false; - } - - result = endpointWrite(EPWEBUSB_IN, buffer, size); + m_pendingWrite = false; + return; + } - if (result != EP_PENDING) - { - return false; - } + uint8_t buffer[MAX_PACKET_SIZE_EPBULK]; + uint16_t size = m_outputBuffer.dequeue(buffer, MAX_PACKET_SIZE_EPBULK); - // Wait for completion (or until timeout is reached) - uint32_t tstart = osKernelGetTickCount(); - do { - result = endpointWriteResult(EPWEBUSB_IN); + EP_STATUS result = endpointWrite(activeInEndpoint(), buffer, size); - if ((osKernelGetTickCount()-tstart) > (WEBUSB_WRITE_TIMEOUT)) { - // Host is not reading from the endpoint, assume the WebUSB client is no longer active and switch back to CDC mode - m_webUSBMode = false; - break; - } - } while (result == EP_PENDING); + if (result != EP_PENDING) + { + return; + } - return (result == EP_COMPLETED); - } + 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)) @@ -293,10 +282,7 @@ return false; } - for (uint32_t i = 0; i < size; i++) - { - m_buffer.queue(buffer[i]); - } + m_inputBuffer.queue(buffer, size); if (size != 0 && activeOutEndpoint() == EPCDC_OUT) { @@ -527,36 +513,45 @@ int USBWebUSBSerial::_putc(int c) { - if (!m_terminalConnected && !m_webUSBMode) + if (!writeBuffered((uint8_t *)&c, 1)) { return 0; } - send((uint8_t *)&c, 1); return 1; } int USBWebUSBSerial::_getc() { uint8_t c = 0; - while (m_buffer.isEmpty()); - m_buffer.dequeue(&c); + while (!available()); + CriticalSectionLock lock; + m_inputBuffer.dequeue(&c); return c; } -bool USBWebUSBSerial::writeBlock(const uint8_t * buf, uint16_t size) +bool USBWebUSBSerial::writeBuffered(const uint8_t * buf, uint16_t size) { + CriticalSectionLock lock; if(!m_terminalConnected && !m_webUSBMode) { return false; } - if(size > MAX_PACKET_SIZE_EPBULK) + + m_outputBuffer.queue(buf, size); + if (!m_pendingWrite) { - return false; + writeToActiveEndpoint(); } - if(!send(buf, size)) + else if (m_webUSBMode) { - return false; + // 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; } @@ -574,6 +569,7 @@ bool USBWebUSBSerial::EPOUTCallbackHandler(uint8_t endpoint) { + CriticalSectionLock lock; if (endpoint == activeOutEndpoint()) { return readActiveEP(); @@ -601,9 +597,32 @@ 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() { - return m_buffer.available(); + CriticalSectionLock lock; + return m_inputBuffer.available(); } void USBWebUSBSerial::setManufacturerName(const std::string &manufacturerName) @@ -659,4 +678,32 @@ 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