diff --git a/cores/arduino/USB/SAMD21_USBDevice.h b/cores/arduino/USB/SAMD21_USBDevice.h index 8c5e8f80a16bd86e0306b48907043cc3c273af4f..a6259f90fd38b48c728a5fe5839f30e8eb735abd 100644 --- a/cores/arduino/USB/SAMD21_USBDevice.h +++ b/cores/arduino/USB/SAMD21_USBDevice.h @@ -195,6 +195,32 @@ void USBDevice_SAMD21G18x::calibrate() { usb.PADCAL.bit.TRIM = pad_trim; } +/* + * Synchronization primitives. + * TODO: Move into a separate header file and make an API out of it + */ + +class __Guard { +public: + __Guard() : primask(__get_PRIMASK()), loops(1) { + __disable_irq(); + } + ~__Guard() { + if (primask == 0) { + __enable_irq(); + // http://infocenter.arm.com/help/topic/com.arm.doc.dai0321a/BIHBFEIB.html + __ISB(); + } + } + uint32_t enter() { return loops--; } +private: + uint32_t primask; + uint32_t loops; +}; + +#define synchronized for (__Guard __guard; __guard.enter(); ) + + /* * USB EP generic handlers. */ @@ -222,39 +248,51 @@ public: usbd.epBank0SetSize(ep, 64); usbd.epBank0SetType(ep, 3); // BULK OUT - usbd.epBank0SetAddress(ep, data0); + usbd.epBank0SetAddress(ep, const_cast<uint8_t *>(data0)); release(); } // Read one byte from the buffer, if the buffer is empty -1 is returned int read() { + // R/W: current, first0/1, ready0/1, notify + // R : last0/1, data0/1 if (current == 0) { - if (!ready0) { - return -1; + synchronized { + if (!ready0) { + return -1; + } } + // when ready0==true the buffer is not being filled and last0 is constant if (first0 == last0) { first0 = 0; current = 1; - ready0 = false; - if (notify) { - notify = false; - release(); + synchronized { + ready0 = false; + if (notify) { + notify = false; + release(); + } } return -1; } return data0[first0++]; } else { - if (!ready1) { - return -1; + synchronized { + if (!ready1) { + return -1; + } } + // when ready1==true the buffer is not being filled and last1 is constant if (first1 == last1) { first1 = 0; current = 0; - ready1 = false; - if (notify) { - notify = false; - release(); + synchronized { + ready1 = false; + if (notify) { + notify = false; + release(); + } } return -1; } @@ -264,33 +302,39 @@ public: virtual void handleEndpoint() { + // R/W : incoming, ready0/1 + // W : last0/1, notify if (usbd.epBank0IsTransferComplete(ep)) { // Ack Transfer complete usbd.epBank0AckTransferComplete(ep); - //usbd.epBank0AckTransferFailed(ep); + //usbd.epBank0AckTransferFailed(ep); // XXX // Update counters and swap banks if (incoming == 0) { last0 = usbd.epBank0ByteCount(ep); incoming = 1; - usbd.epBank0SetAddress(ep, data1); + usbd.epBank0SetAddress(ep, const_cast<uint8_t *>(data1)); ready0 = true; - if (ready1) { - notify = true; - return; + synchronized { + if (ready1) { + notify = true; + return; + } + notify = false; } - notify = false; } else { last1 = usbd.epBank0ByteCount(ep); incoming = 0; - usbd.epBank0SetAddress(ep, data0); - ready1 = true; - if (ready0) { - notify = true; - return; + usbd.epBank0SetAddress(ep, const_cast<uint8_t *>(data0)); + synchronized { + ready1 = true; + if (ready0) { + notify = true; + return; + } + notify = false; } - notify = false; } release(); } @@ -298,6 +342,7 @@ public: virtual uint32_t recv(void *_data, uint32_t len) { + // TODO Write an optimized version of this one uint8_t *data = reinterpret_cast<uint8_t *>(_data); uint32_t i; for (i=0; i<len; i++) { @@ -328,14 +373,16 @@ private: const uint32_t size; uint32_t current, incoming; - uint8_t *data0; - uint32_t first0, last0; - bool ready0; + volatile uint8_t *data0; + uint32_t first0; + volatile uint32_t last0; + volatile bool ready0; - uint8_t *data1; - uint32_t first1, last1; - bool ready1; + volatile uint8_t *data1; + uint32_t first1; + volatile uint32_t last1; + volatile bool ready1; - bool notify; + volatile bool notify; };