diff --git a/cores/arduino/USB/CDC.cpp b/cores/arduino/USB/CDC.cpp index 5a111dce9..67cc7f70e 100644 --- a/cores/arduino/USB/CDC.cpp +++ b/cores/arduino/USB/CDC.cpp @@ -163,8 +163,15 @@ void Serial_::end(void) void Serial_::accept(void) { - uint8_t buffer[CDC_SERIAL_BUFFER_SIZE]; - uint32_t len = usb.recv(CDC_ENDPOINT_OUT, &buffer, CDC_SERIAL_BUFFER_SIZE); + uint32_t ringBufferSpace = availableForStore(); + if (ringBufferSpace < EPX_SIZE) { + // usb.recv will always try to receive up to EPX_SIZE bytes on the endpoint + // make sure there is enough space, so that data is not lost + return; + } + + uint8_t buffer[EPX_SIZE]; + uint32_t len = usb.recv(CDC_ENDPOINT_OUT, &buffer, sizeof(buffer)); uint8_t enableInterrupts = ((__get_PRIMASK() & 0x1) == 0); __disable_irq(); @@ -197,7 +204,8 @@ int Serial_::available(void) return CDC_SERIAL_BUFFER_SIZE; } if (buffer->head == buffer->tail) { - USB->DEVICE.DeviceEndpoint[CDC_ENDPOINT_OUT].EPINTENSET.reg = USB_DEVICE_EPINTENCLR_TRCPT(1); + if (usb.available(CDC_ENDPOINT_OUT)) + accept(); } return (uint32_t)(CDC_SERIAL_BUFFER_SIZE + buffer->head - buffer->tail) % CDC_SERIAL_BUFFER_SIZE; } @@ -236,8 +244,7 @@ int Serial_::read(void) unsigned char c = buffer->buffer[buffer->tail]; buffer->tail = (uint32_t)(buffer->tail + 1) % CDC_SERIAL_BUFFER_SIZE; buffer->full = false; -// if (usb.available(CDC_ENDPOINT_OUT)) -// accept(); + return c; } } @@ -345,6 +352,17 @@ bool Serial_::rts() { return _usbLineInfo.lineState & 0x2; } +int Serial_::availableForStore(void) { + ring_buffer *buffer = &cdc_rx_buffer; + + if (buffer->full) + return 0; + else if (buffer->head >= buffer->tail) + return CDC_SERIAL_BUFFER_SIZE - 1 - buffer->head + buffer->tail; + else + return buffer->tail - buffer->head - 1; +} + Serial_ SerialUSB(USBDevice); #endif diff --git a/cores/arduino/USB/USBAPI.h b/cores/arduino/USB/USBAPI.h index 1de826608..16adb6d09 100644 --- a/cores/arduino/USB/USBAPI.h +++ b/cores/arduino/USB/USBAPI.h @@ -167,6 +167,8 @@ class Serial_ : public Stream }; private: + int availableForStore(void); + USBDeviceClass &usb; RingBuffer *_cdc_rx_buffer; }; diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index cd356d578..bfd0a214c 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -245,12 +245,25 @@ void USBDeviceClass::handleEndpoint(uint8_t ep) #if defined(CDC_ENABLED) if (ep == CDC_ENDPOINT_OUT) { - // The RAM Buffer is empty: we can receive data - //usbd.epBank0ResetReady(CDC_ENDPOINT_OUT); - // Handle received bytes if (available(CDC_ENDPOINT_OUT)) + { + // always disable transfer complete, + // in case the CDC receive buffer is full + usbd.epBank0DisableTransferComplete(CDC_ENDPOINT_OUT); + SerialUSB.accept(); + } + else + { + // ZLP received + + // The RAM Buffer is empty: we can receive data + usbd.epBank0ResetReady(CDC_ENDPOINT_OUT); + + // Clear Transfer complete 0 flag + usbd.epBank0AckTransferComplete(CDC_ENDPOINT_OUT); + } } if (ep == CDC_ENDPOINT_IN) { @@ -434,10 +447,6 @@ void USBDeviceClass::initEP(uint32_t ep, uint32_t config) } else if (config == USB_ENDPOINT_TYPE_CONTROL) { - // XXX: Needed? -// usbd.epBank0DisableAutoZLP(ep); -// usbd.epBank1DisableAutoZLP(ep); - // Setup Control OUT usbd.epBank0SetSize(ep, 64); usbd.epBank0SetAddress(ep, &udd_ep_out_cache_buffer[ep]); @@ -535,6 +544,9 @@ uint32_t USBDeviceClass::recv(uint32_t ep, void *_data, uint32_t len) // Clear Transfer complete 0 flag usbd.epBank0AckTransferComplete(ep); + + // Enable Transfer complete 0 interrupt + usbd.epBank0EnableTransferComplete(ep); } return len;