From 44174a0ae621076694049b31086a8ee8a2085156 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 25 Jun 2015 19:13:16 +0200 Subject: [PATCH 01/17] USB device refactoring (WIP) --- cores/arduino/USB/CDC.cpp | 141 ++-- cores/arduino/USB/HID.cpp | 31 +- cores/arduino/USB/SAMD21_USBDevice.h | 197 +++++ cores/arduino/USB/USBAPI.h | 134 +-- cores/arduino/USB/USBCore.cpp | 1125 ++++++++++++++------------ cores/arduino/USB/USBCore.h | 12 +- cores/arduino/USB/USBDesc.h | 2 +- cores/arduino/USB/USB_device.h | 63 -- cores/arduino/USB/USB_host.h | 2 +- cores/arduino/USB/USB_interrupt.c | 23 - cores/arduino/USB/samd21_device.c | 349 -------- cores/arduino/USB/samd21_device.h | 108 --- cores/arduino/USB/samd21_host.c | 72 +- cores/arduino/USB/samd21_host.h | 24 +- 14 files changed, 1030 insertions(+), 1253 deletions(-) create mode 100644 cores/arduino/USB/SAMD21_USBDevice.h delete mode 100644 cores/arduino/USB/USB_device.h delete mode 100644 cores/arduino/USB/USB_interrupt.c delete mode 100644 cores/arduino/USB/samd21_device.c delete mode 100644 cores/arduino/USB/samd21_device.h diff --git a/cores/arduino/USB/CDC.cpp b/cores/arduino/USB/CDC.cpp index 33c7b7e86..c0e61a893 100644 --- a/cores/arduino/USB/CDC.cpp +++ b/cores/arduino/USB/CDC.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2015 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,22 +16,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include +#include // Needed for auto-reset with 1200bps port touch + #include #include #include -// Include Atmel headers -#include "Arduino.h" -#include "sam.h" -#include "wiring_constants.h" -#include "USBCore.h" -#include "USB/USB_device.h" -#include "USBDesc.h" -#include "USBAPI.h" - -#include "Reset.h" - - #ifdef CDC_ENABLED #define CDC_SERIAL_BUFFER_SIZE 64 @@ -42,96 +33,93 @@ #define CDC_LINESTATE_READY (CDC_LINESTATE_RTS | CDC_LINESTATE_DTR) -struct ring_buffer -{ +struct ring_buffer { uint8_t buffer[CDC_SERIAL_BUFFER_SIZE]; volatile uint32_t head; volatile uint32_t tail; }; - ring_buffer cdc_rx_buffer = { { 0 }, 0, 0}; -typedef struct -{ - uint32_t dwDTERate; - uint8_t bCharFormat; - uint8_t bParityType; - uint8_t bDataBits; - uint8_t lineState; +typedef struct { + uint32_t dwDTERate; + uint8_t bCharFormat; + uint8_t bParityType; + uint8_t bDataBits; + uint8_t lineState; } LineInfo; _Pragma("pack(1)") static volatile LineInfo _usbLineInfo = { - 115200, // dWDTERate - 0x00, // bCharFormat - 0x00, // bParityType - 0x08, // bDataBits - 0x00 // lineState + 115200, // dWDTERate + 0x00, // bCharFormat + 0x00, // bParityType + 0x08, // bDataBits + 0x00 // lineState }; -static const CDCDescriptor _cdcInterface = -{ -#if (defined CDC_ENABLED) && defined(HID_ENABLED) +static const CDCDescriptor _cdcInterface = { + #if (defined CDC_ENABLED) && defined(HID_ENABLED) D_IAD(0, 2, CDC_COMMUNICATION_INTERFACE_CLASS, CDC_ABSTRACT_CONTROL_MODEL, 0), -#endif - // CDC communication interface - D_INTERFACE(CDC_ACM_INTERFACE,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0), - D_CDCCS( CDC_HEADER, CDC_V1_10 & 0xFF, (CDC_V1_10>>8) & 0x0FF ), // Header (1.10 bcd) - - D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported - D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE,CDC_DATA_INTERFACE), // Communication interface is master, data interface is slave 0 - D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not) - D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM),USB_ENDPOINT_TYPE_INTERRUPT,0x10, 0x10), - - // CDC data interface - D_INTERFACE(CDC_DATA_INTERFACE,2,CDC_DATA_INTERFACE_CLASS,0,0), - D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,EPX_SIZE,0), - D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,EPX_SIZE,0) + #endif + + // CDC communication interface + D_INTERFACE(CDC_ACM_INTERFACE, 1, CDC_COMMUNICATION_INTERFACE_CLASS, CDC_ABSTRACT_CONTROL_MODEL, 0), + D_CDCCS(CDC_HEADER, CDC_V1_10 & 0xFF, (CDC_V1_10>>8) & 0x0FF), // Header (1.10 bcd) + + D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT, 6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported + D_CDCCS(CDC_UNION, CDC_ACM_INTERFACE, CDC_DATA_INTERFACE), // Communication interface is master, data interface is slave 0 + D_CDCCS(CDC_CALL_MANAGEMENT, 1, 1), // Device handles call management (not) + D_ENDPOINT(USB_ENDPOINT_IN(CDC_ENDPOINT_ACM), USB_ENDPOINT_TYPE_INTERRUPT, 0x10, 0x10), + + // CDC data interface + D_INTERFACE(CDC_DATA_INTERFACE, 2, CDC_DATA_INTERFACE_CLASS, 0, 0), + D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT), USB_ENDPOINT_TYPE_BULK, EPX_SIZE, 0), + D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ), USB_ENDPOINT_TYPE_BULK, EPX_SIZE, 0) }; _Pragma("pack()") -const void* WEAK CDC_GetInterface(void) +const void* CDC_GetInterface(void) { - return &_cdcInterface; + return &_cdcInterface; } -uint32_t WEAK CDC_GetInterfaceLength(void) +uint32_t CDC_GetInterfaceLength(void) { - return sizeof( _cdcInterface ); + return sizeof(_cdcInterface); } -bool WEAK CDC_Setup(Setup& setup) +bool CDC_Setup(Setup& setup) { - uint8_t r = setup.bRequest; uint8_t requestType = setup.bmRequestType; + uint8_t r = setup.bRequest; - if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) + if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) { - if (CDC_GET_LINE_CODING == r) + if (r == CDC_GET_LINE_CODING) { - USBD_SendControl(0,(void*)&_usbLineInfo,7); + USBDevice.sendControl((void*)&_usbLineInfo, 7); return true; } } - if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) + if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) { - if (CDC_SET_LINE_CODING == r) + if (r == CDC_SET_LINE_CODING) { - USBD_RecvControl((void*)&_usbLineInfo,7); + USBDevice.recvControl((void*)&_usbLineInfo, 7); } - if (CDC_SET_CONTROL_LINE_STATE == r) + if (r == CDC_SET_CONTROL_LINE_STATE) { _usbLineInfo.lineState = setup.wValueL; } - if (CDC_SET_LINE_CODING == r || CDC_SET_CONTROL_LINE_STATE == r) + if (r == CDC_SET_LINE_CODING || r == CDC_SET_CONTROL_LINE_STATE) { // auto-reset into the bootloader is triggered when the port, already // open at 1200 bps, is closed. We check DTR state to determine if host // port is open (bit 0 of lineState). - if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0) + if (_usbLineInfo.dwDTERate == 1200 && (_usbLineInfo.lineState & 0x01) == 0) { initiateReset(250); } @@ -161,7 +149,7 @@ void Serial_::end(void) void Serial_::accept(void) { uint8_t buffer[CDC_SERIAL_BUFFER_SIZE]; - uint32_t len = USBD_Recv(CDC_ENDPOINT_OUT, (void*)&buffer, CDC_SERIAL_BUFFER_SIZE); + uint32_t len = usb.recv(CDC_ENDPOINT_OUT, &buffer, CDC_SERIAL_BUFFER_SIZE); noInterrupts(); ring_buffer *ringBuffer = &cdc_rx_buffer; @@ -173,7 +161,7 @@ void Serial_::accept(void) // and so we don't write the character or advance the head. uint32_t k = 0; i = (i + 1) % CDC_SERIAL_BUFFER_SIZE; - while (i != ringBuffer->tail && len>0) { + while ((i != ringBuffer->tail) && (len > 0)) { len--; ringBuffer->buffer[ringBuffer->head] = buffer[k++]; ringBuffer->head = i; @@ -185,6 +173,9 @@ void Serial_::accept(void) int Serial_::available(void) { ring_buffer *buffer = &cdc_rx_buffer; + if (buffer->head == buffer->tail) { + USB->DEVICE.DeviceEndpoint[2].EPINTENSET.reg = USB_DEVICE_EPINTENCLR_TRCPT(1); + } return (uint32_t)(CDC_SERIAL_BUFFER_SIZE + buffer->head - buffer->tail) % CDC_SERIAL_BUFFER_SIZE; } @@ -202,12 +193,22 @@ int Serial_::peek(void) } } + +// if the ringBuffer is empty: try to fill it +// if it's still empty: return -1 +// else return the last char +// so the buffer is filled only when needed int Serial_::read(void) { ring_buffer *buffer = &cdc_rx_buffer; // if the head isn't ahead of the tail, we don't have any characters if (buffer->head == buffer->tail) + { + if (usb.available(CDC_ENDPOINT_OUT)) + accept(); + } + if (buffer->head == buffer->tail) { return -1; } @@ -215,15 +216,15 @@ int Serial_::read(void) { unsigned char c = buffer->buffer[buffer->tail]; buffer->tail = (uint32_t)(buffer->tail + 1) % CDC_SERIAL_BUFFER_SIZE; - if (USBD_Available(CDC_ENDPOINT_OUT)) - accept(); +// if (usb.available(CDC_ENDPOINT_OUT)) +// accept(); return c; } } void Serial_::flush(void) { - USBD_Flush(CDC_ENDPOINT_IN); + usb.flush(CDC_ENDPOINT_IN); } size_t Serial_::write(const uint8_t *buffer, size_t size) @@ -239,13 +240,11 @@ size_t Serial_::write(const uint8_t *buffer, size_t size) // or locks up, or host virtual serial port hangs) // if (_usbLineInfo.lineState > 0) // Problem with Windows(R) { - uint32_t r = USBD_Send(CDC_ENDPOINT_IN, buffer, size); + uint32_t r = usb.send(CDC_ENDPOINT_IN, buffer, size); - if (r > 0) - { + if (r > 0) { return r; - } else - { + } else { setWriteError(); return 0; } @@ -282,6 +281,6 @@ Serial_::operator bool() return result; } -Serial_ SerialUSB; +Serial_ SerialUSB(USBDevice); #endif diff --git a/cores/arduino/USB/HID.cpp b/cores/arduino/USB/HID.cpp index f5d561e0e..45208b2d8 100644 --- a/cores/arduino/USB/HID.cpp +++ b/cores/arduino/USB/HID.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2014 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,13 +16,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "USBAPI.h" -#include "Reset.h" -#include "USBCore.h" -#include "USBDesc.h" -#include "sam.h" -#include "USB/USB_device.h" - +#include #ifdef HID_ENABLED @@ -143,14 +137,12 @@ _Pragma("pack()") uint8_t _hid_protocol = 1; uint8_t _hid_idle = 1; -#define WEAK __attribute__ ((weak)) - -const void* WEAK HID_GetInterface(void) +const void* HID_GetInterface(void) { return &_hidInterface; } -uint32_t WEAK HID_GetInterfaceLength(void) +uint32_t HID_GetInterfaceLength(void) { return sizeof( _hidInterface ); } @@ -160,12 +152,12 @@ uint32_t HID_SizeReportDescriptor(void) return sizeof(_hidReportDescriptor); } -uint32_t WEAK HID_GetDescriptor(void) +uint32_t HID_GetDescriptor(void) { - return USBD_SendControl(0,_hidReportDescriptor,sizeof(_hidReportDescriptor)); + return USBDevice.sendControl(_hidReportDescriptor, sizeof(_hidReportDescriptor)); } -void WEAK HID_SendReport(uint8_t id, const void* data, uint32_t len) +void HID_SendReport(uint8_t id, const void* data, uint32_t len) { uint8_t p[8]; const uint8_t *d = reinterpret_cast(data); @@ -175,10 +167,10 @@ void WEAK HID_SendReport(uint8_t id, const void* data, uint32_t len) { p[i+1] = d[i]; } - USBD_Send(HID_ENDPOINT_INT, p, len+1); + USBDevice.send(HID_ENDPOINT_INT, p, len+1); } -bool WEAK HID_Setup(Setup& setup) +bool HID_Setup(Setup& setup) { uint8_t r = setup.bRequest; uint8_t requestType = setup.bmRequestType; @@ -197,8 +189,9 @@ bool WEAK HID_Setup(Setup& setup) } if (HID_GET_IDLE == r) { - UDD_Send(0, &_hid_idle, 1); - UDD_ClearIN(); + USBDevice.armSend(0, &_hid_idle, 1); + // RAM buffer is full, we can send data (IN) + USB->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.BK1RDY = 1; return true; } } diff --git a/cores/arduino/USB/SAMD21_USBDevice.h b/cores/arduino/USB/SAMD21_USBDevice.h new file mode 100644 index 000000000..203a1c787 --- /dev/null +++ b/cores/arduino/USB/SAMD21_USBDevice.h @@ -0,0 +1,197 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include + +#include +#include +#include + +typedef uint8_t ep_t; + +class USBDevice_SAMD21G18x { +public: + USBDevice_SAMD21G18x() : usb(USB->DEVICE) { + // Empty + } + + // USB Device function mapping + // --------------------------- + + // Reset USB Device + void reset(); + + // Enable + inline void enable() { usb.CTRLA.bit.ENABLE = 1; } + inline void disable() { usb.CTRLA.bit.ENABLE = 0; } + + // USB mode (device/host) + inline void setUSBDeviceMode() { usb.CTRLA.bit.MODE = USB_CTRLA_MODE_DEVICE_Val; } + inline void setUSBHostMode() { usb.CTRLA.bit.MODE = USB_CTRLA_MODE_HOST_Val; } + + inline void runInStandby() { usb.CTRLA.bit.RUNSTDBY = 1; } + inline void noRunInStandby() { usb.CTRLA.bit.RUNSTDBY = 0; } + + // USB speed + inline void setFullSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS_Val; } + inline void setLowSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_LS_Val; } + inline void setHiSpeed() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_HS_Val; } + inline void setHiSpeedTestMode() { usb.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_HSTM_Val; } + + // Authorize attach if Vbus is present + inline void attach() { usb.CTRLB.bit.DETACH = 0; } + inline void detach() { usb.CTRLB.bit.DETACH = 1; } + + // USB Interrupts + inline bool isEndOfResetInterrupt() { return usb.INTFLAG.bit.EORST; } + inline void ackEndOfResetInterrupt() { usb.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST; } + inline void enableEndOfResetInterrupt() { usb.INTENSET.bit.EORST = 1; } + inline void disableEndOfResetInterrupt() { usb.INTENCLR.bit.EORST = 1; } + + inline bool isStartOfFrameInterrupt() { return usb.INTFLAG.bit.SOF; } + inline void ackStartOfFrameInterrupt() { usb.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF; } + inline void enableStartOfFrameInterrupt() { usb.INTENSET.bit.SOF = 1; } + inline void disableStartOfFrameInterrupt() { usb.INTENCLR.bit.SOF = 1; } + + // USB Address + inline void setAddress(uint32_t addr) { usb.DADD.bit.DADD = addr; usb.DADD.bit.ADDEN = 1; } + inline void unsetAddress() { usb.DADD.bit.DADD = 0; usb.DADD.bit.ADDEN = 0; } + + // Frame number + inline uint16_t frameNumber() { return usb.FNUM.bit.FNUM; } + + // Load calibration values + void calibrate(); + + // USB Device Endpoints function mapping + // ------------------------------------- + + // Config + inline void epBank0SetType(ep_t ep, uint8_t type) { usb.DeviceEndpoint[ep].EPCFG.bit.EPTYPE0 = type; } + inline void epBank1SetType(ep_t ep, uint8_t type) { usb.DeviceEndpoint[ep].EPCFG.bit.EPTYPE1 = type; } + + // Interrupts + inline uint16_t epInterruptSummary() { return usb.EPINTSMRY.reg; } + + inline bool epBank0IsSetupReceived(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.RXSTP; } + inline bool epBank0IsStalled(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.STALL & 1; } + inline bool epBank1IsStalled(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.STALL & 2; } + inline bool epBank0IsTransferComplete(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.TRCPT & 1; } + inline bool epBank1IsTransferComplete(ep_t ep) { return usb.DeviceEndpoint[ep].EPINTFLAG.bit.TRCPT & 2; } + + inline void epBank0AckSetupReceived(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_RXSTP; } + inline void epBank0AckStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL(1); } + inline void epBank1AckStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL(2); } + inline void epBank0AckTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT(1); } + inline void epBank1AckTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT(2); } + + inline void epBank0EnableSetupReceived(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.RXSTP = 1; } + inline void epBank0EnableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.STALL = 1; } + inline void epBank1EnableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.STALL = 2; } + inline void epBank0EnableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.TRCPT = 1; } + inline void epBank1EnableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENSET.bit.TRCPT = 2; } + + inline void epBank0DisableSetupReceived(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.RXSTP = 1; } + inline void epBank0DisableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.STALL = 1; } + inline void epBank1DisableStalled(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.STALL = 2; } + inline void epBank0DisableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.TRCPT = 1; } + inline void epBank1DisableTransferComplete(ep_t ep) { usb.DeviceEndpoint[ep].EPINTENCLR.bit.TRCPT = 2; } + + // Status + inline bool epBank0IsReady(ep_t ep) { return usb.DeviceEndpoint[ep].EPSTATUS.bit.BK0RDY; } + inline bool epBank1IsReady(ep_t ep) { return usb.DeviceEndpoint[ep].EPSTATUS.bit.BK1RDY; } + inline void epBank0SetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.BK0RDY = 1; } + inline void epBank1SetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.BK1RDY = 1; } + inline void epBank0ResetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.BK0RDY = 1; } + inline void epBank1ResetReady(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.BK1RDY = 1; } + + inline void epBank0SetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.STALLRQ = 1; } + inline void epBank1SetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSSET.bit.STALLRQ = 2; } + inline void epBank0ResetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.STALLRQ = 1; } + inline void epBank1ResetStallReq(ep_t ep) { usb.DeviceEndpoint[ep].EPSTATUSCLR.bit.STALLRQ = 2; } + + // Packet + inline uint16_t epBank0ByteCount(ep_t ep) { return EP[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT; } + inline uint16_t epBank1ByteCount(ep_t ep) { return EP[ep].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT; } + inline void epBank0SetByteCount(ep_t ep, uint16_t bc) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = bc; } + inline void epBank1SetByteCount(ep_t ep, uint16_t bc) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = bc; } + inline void epBank0SetMultiPacketSize(ep_t ep, uint16_t s) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = s; } + inline void epBank1SetMultiPacketSize(ep_t ep, uint16_t s) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.MULTI_PACKET_SIZE = s; } + + inline void epBank0SetAddress(ep_t ep, void *addr) { EP[ep].DeviceDescBank[0].ADDR.reg = (uint32_t)addr; } + inline void epBank1SetAddress(ep_t ep, void *addr) { EP[ep].DeviceDescBank[1].ADDR.reg = (uint32_t)addr; } + inline void epBank0SetSize(ep_t ep, uint16_t size) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.SIZE = EP_PCKSIZE_SIZE(size); } + inline void epBank1SetSize(ep_t ep, uint16_t size) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.SIZE = EP_PCKSIZE_SIZE(size); } + inline uint8_t EP_PCKSIZE_SIZE(uint16_t size) { + switch (size) { + case 8: return 0; + case 16: return 1; + case 32: return 2; + case 64: return 3; + case 128: return 4; + case 256: return 5; + case 512: return 6; + case 1023: return 7; + default: return 0; + } + } + + inline void epBank0DisableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.AUTO_ZLP = 0; } + inline void epBank1DisableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = 0; } + inline void epBank0EnableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[0].PCKSIZE.bit.AUTO_ZLP = 1; } + inline void epBank1EnableAutoZLP(ep_t ep) { EP[ep].DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = 1; } + +private: + // USB Device registers + UsbDevice &usb; + + // Endpoints descriptors table + __attribute__((__aligned__(4))) UsbDeviceDescriptor EP[USB_EPT_NUM]; +}; + +void USBDevice_SAMD21G18x::reset() { + usb.CTRLA.bit.SWRST = 1; + memset(EP, 0, sizeof(EP)); + while (usb.SYNCBUSY.bit.SWRST) {} + usb.DESCADD.reg = (uint32_t)(&EP); +} + +void USBDevice_SAMD21G18x::calibrate() { + // Load Pad Calibration data from non-volatile memory + uint32_t *pad_transn_p = (uint32_t *) USB_FUSES_TRANSN_ADDR; + uint32_t *pad_transp_p = (uint32_t *) USB_FUSES_TRANSP_ADDR; + uint32_t *pad_trim_p = (uint32_t *) USB_FUSES_TRIM_ADDR; + + uint32_t pad_transn = (*pad_transn_p & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos; + uint32_t pad_transp = (*pad_transp_p & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos; + uint32_t pad_trim = (*pad_trim_p & USB_FUSES_TRIM_Msk ) >> USB_FUSES_TRIM_Pos; + + if (pad_transn == 0x1F) // maximum value (31) + pad_transn = 5; + if (pad_transp == 0x1F) // maximum value (31) + pad_transp = 29; + if (pad_trim == 0x7) // maximum value (7) + pad_trim = 3; + + usb.PADCAL.bit.TRANSN = pad_transn; + usb.PADCAL.bit.TRANSP = pad_transp; + usb.PADCAL.bit.TRIM = pad_trim; +} + diff --git a/cores/arduino/USB/USBAPI.h b/cores/arduino/USB/USBAPI.h index 1229c3b71..b2d9d510b 100644 --- a/cores/arduino/USB/USBAPI.h +++ b/cores/arduino/USB/USBAPI.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2015 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,8 +16,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __USBAPI__ -#define __USBAPI__ +#pragma once #define HSTPIPCFG_PTYPE_BLK 1 #define HSTPIPCFG_PTOKEN_IN 2 @@ -25,17 +24,8 @@ #define HSTPIPCFG_PBK_1_BANK 4 #define HSTPIPCFG_PTYPE_INTRPT 5 - - -/* Define attribute */ -#if defined ( __CC_ARM ) /* Keil uVision 4 */ - #define WEAK (__attribute__ ((weak))) -#elif defined ( __ICCARM__ ) /* IAR Ewarm 5.41+ */ - #define WEAK __weak -#elif defined ( __GNUC__ ) /* GCC CS */ - #define WEAK __attribute__ ((weak)) -#endif - +#define EP0 0 +#define EPX_SIZE 64 // 64 for Full Speed, EPT size max is 1024 #if defined __cplusplus @@ -43,31 +33,81 @@ #include "RingBuffer.h" //================================================================================ -//================================================================================ -// USB +// USB -class USBDevice_ -{ +// Low level API +typedef struct { + union { + uint8_t bmRequestType; + struct { + uint8_t direction : 5; + uint8_t type : 2; + uint8_t transferDirection : 1; + }; + }; + uint8_t bRequest; + uint8_t wValueL; + uint8_t wValueH; + uint16_t wIndex; + uint16_t wLength; +} Setup; + +class USBDeviceClass { public: - USBDevice_(); - bool configured(); + USBDeviceClass() {}; - bool attach(); - bool detach(); // Serial port goes down too... - void poll(); + // USB Device API void init(); + bool attach(); + bool detach(); + void setAddress(uint32_t addr); + + bool configured(); + bool connected(); + + // Setup API + bool handleClassInterfaceSetup(Setup &setup); + bool handleStandardSetup(Setup &setup); + bool sendDescriptor(Setup &setup); + + // Control EndPoint API + uint32_t sendControl(const void *data, uint32_t len); + uint32_t recvControl(void *data, uint32_t len); + bool sendConfiguration(uint32_t maxlen); + bool sendStringDescriptor(const uint8_t *string, uint8_t maxlen); + + // Generic EndPoint API + void initEP(uint32_t ep, uint32_t type); + void handleEndpoint(uint8_t ep); + + uint32_t send(uint32_t ep, const void *data, uint32_t len); + void sendZlp(uint32_t ep); + uint32_t recv(uint32_t ep, void *data, uint32_t len); + uint32_t recv(uint32_t ep); + uint32_t available(uint32_t ep); + void flush(uint32_t ep); + void stall(uint32_t ep); + + // private? + uint32_t armSend(uint32_t ep, const void *data, uint32_t len); + uint8_t armRecv(uint32_t ep, uint32_t len); + uint8_t armRecvCtrlOUT(uint32_t ep, uint32_t len); + + void ISRHandler(); + +private: + bool initialized; }; -extern USBDevice_ USBDevice; -//================================================================================ +extern USBDeviceClass USBDevice; + //================================================================================ // Serial over CDC (Serial1 is the physical port) class Serial_ : public Stream { -private: - RingBuffer *_cdc_rx_buffer; public: + Serial_(USBDeviceClass &_usb) : usb(_usb) { } void begin(uint32_t baud_count); void begin(unsigned long, uint8_t); void end(void); @@ -81,6 +121,9 @@ class Serial_ : public Stream virtual size_t write(const uint8_t *buffer, size_t size); using Print::write; // pull in write(str) from Print operator bool(); +private: + USBDeviceClass &usb; + RingBuffer *_cdc_rx_buffer; }; extern Serial_ SerialUSB; @@ -175,26 +218,12 @@ class Keyboard_ : public Print }; extern Keyboard_ Keyboard; -//================================================================================ -//================================================================================ -// Low level API - -typedef struct -{ - uint8_t bmRequestType; - uint8_t bRequest; - uint8_t wValueL; - uint8_t wValueH; - uint16_t wIndex; - uint16_t wLength; -} Setup; - //================================================================================ //================================================================================ // HID 'Driver' -const void* WEAK HID_GetInterface(void); -uint32_t WEAK HID_GetInterfaceLength(void); +const void* HID_GetInterface(void); +uint32_t HID_GetInterfaceLength(void); uint32_t HID_SizeReportDescriptor(void); uint32_t HID_GetDescriptor(void); @@ -215,26 +244,9 @@ bool MSC_Data(uint8_t rx,uint8_t tx); // CDC 'Driver' const void* CDC_GetInterface(/*uint8_t* interfaceNum*/); -uint32_t WEAK CDC_GetInterfaceLength(void); +uint32_t CDC_GetInterfaceLength(void); uint32_t CDC_GetOtherInterface(uint8_t* interfaceNum); uint32_t CDC_GetDescriptor(uint32_t i); bool CDC_Setup(Setup& setup); -//================================================================================ -//================================================================================ - -uint32_t USBD_SendControl(uint8_t flags, const void* d, uint32_t len); -uint32_t USBD_RecvControl(void* d, uint32_t len); -uint32_t USBD_SendInterfaces(void); -bool USBD_ClassInterfaceRequest(Setup& setup); - -uint32_t USBD_Available(uint32_t ep); -uint32_t USBD_SendSpace(uint32_t ep); -uint32_t USBD_Send(uint32_t ep, const void* d, uint32_t len); -uint32_t USBD_Recv(uint32_t ep, void* data, uint32_t len); // non-blocking -uint32_t USBD_Recv(uint32_t ep); // non-blocking -void USBD_Flush(uint32_t ep); -uint32_t USBD_Connected(void); - #endif // __cplusplus -#endif // __USBAPI__ diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index 31b8380af..cfcf101aa 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2015 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,14 +16,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "../Arduino.h" -#include "USBCore.h" -#include "USB/USB_device.h" // needed for USB PID define -#include "USBDesc.h" -#include "USBAPI.h" +#include -//#define TRACE_CORE(x) x -#define TRACE_CORE(x) +#include "SAMD21_USBDevice.h" + +#include +#include +#include + +USBDevice_SAMD21G18x usbd; static char isRemoteWakeUpEnabled = 0; static char isEndpointHalt = 0; @@ -50,184 +51,56 @@ const uint8_t STRING_PRODUCT[] = USB_PRODUCT; # define USB_MANUFACTURER "Unknown" #endif -const uint8_t STRING_MANUFACTURER[12] = USB_MANUFACTURER; +const uint8_t STRING_MANUFACTURER[] = USB_MANUFACTURER; // DEVICE DESCRIPTOR #if (defined CDC_ENABLED) && defined(HID_ENABLED) -const DeviceDescriptor USB_DeviceDescriptor = - D_DEVICE(0xEF,0x02,0x01,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); +const DeviceDescriptor USB_DeviceDescriptor = D_DEVICE(0xEF, 0x02, 0x01, 64, USB_VID, USB_PID, 0x100, IMANUFACTURER, IPRODUCT, 0, 1); #elif defined(CDC_ENABLED) // CDC only -const DeviceDescriptor USB_DeviceDescriptor = - D_DEVICE(0x02,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); +const DeviceDescriptor USB_DeviceDescriptor = D_DEVICE(0x02, 0x00, 0x00, 64, USB_VID, USB_PID, 0x100, IMANUFACTURER, IPRODUCT, 0, 1); #else // HID only -const DeviceDescriptor USB_DeviceDescriptor = - D_DEVICE(0,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); +const DeviceDescriptor USB_DeviceDescriptor = D_DEVICE(0x00, 0x00, 0x00, 64, USB_VID, USB_PID, 0x100, IMANUFACTURER, IPRODUCT, 0, 1); #endif //================================================================== volatile uint32_t _usbConfiguration = 0; -volatile uint32_t _usbInitialized = 0; volatile uint32_t _usbSetInterface = 0; -//================================================================== - - -// Number of bytes, assumes a rx endpoint -uint32_t USBD_Available(uint32_t ep) -{ - return UDD_FifoByteCount(ep); -} - -// Non Blocking receive -// Return number of bytes read -uint32_t USBD_Recv(uint32_t ep, void* d, uint32_t len) -{ - if (!_usbConfiguration) - return -1; - - uint8_t *buffer; - uint8_t *data = (uint8_t *)d; - - len = min(UDD_FifoByteCount(ep), len); - - UDD_Recv_data(ep, len); - UDD_Recv(ep, &buffer); - for (uint32_t i=0; i USBD_SendControl TOTAL len=%lu\r\n", len);) - - while (len > 0) - { - sent = UDD_Send(EP0, data + pos, len); - TRACE_CORE(printf("=> USBD_SendControl sent=%lu\r\n", sent);) - pos += sent; - len -= sent; - } - - return length; -} +//================================================================== // Send a USB descriptor string. The string is stored as a // plain ASCII string but is sent out as UTF-16 with the // correct 2-byte prefix -static bool USB_SendStringDescriptor(const uint8_t *string, int wLength) +bool USBDeviceClass::sendStringDescriptor(const uint8_t *string, uint8_t maxlen) { - uint16_t buff[64]; + if (maxlen < 2) + return false; + + uint16_t buff[maxlen/2]; int l = 1; - wLength -= 2; - while (*string && wLength>0) + maxlen -= 2; + while (*string && maxlen>0) { buff[l++] = (uint8_t)(*string++); - wLength -= 2; + maxlen -= 2; } buff[0] = (3<<8) | (l*2); - return USBD_SendControl(0, (uint8_t*)buff, l*2); + return USBDevice.sendControl((uint8_t*)buff, l*2); } -uint32_t USBD_RecvControl(void* d, uint32_t len) -{ - uint8_t *buffer; - uint8_t *data = (uint8_t *)d; - uint32_t read = UDD_Recv_data(EP0, len); - if (read > len) - read = len; - UDD_Recv(EP0, &buffer); - while (!udd_is_OUT_transf_cplt(EP0)); - for (uint32_t i=0; i USBD_ClassInterfaceRequest\r\n");) - -#ifdef CDC_ENABLED - if (CDC_ACM_INTERFACE == i) - { - if( CDC_Setup(setup) == false ) - { - send_zlp(); - } - return true; - } -#endif - -#ifdef HID_ENABLED - if (HID_INTERFACE == i) - { - if( HID_Setup(setup) == true ) - { - send_zlp(); - } - return true; - } -#endif - - return false; -} - -// Construct a dynamic configuration descriptor -// This really needs dynamic endpoint allocation etc -// TODO -static bool USBD_SendConfiguration(uint32_t maxlen) +// Construct a dynamic configuration descriptor +// This really needs dynamic endpoint allocation etc +bool USBDeviceClass::sendConfiguration(uint32_t maxlen) { uint8_t cache_buffer[128]; uint8_t i; @@ -238,494 +111,728 @@ static bool USBD_SendConfiguration(uint32_t maxlen) num_interfaces[0] = 0; -#if (defined CDC_ENABLED) && defined(HID_ENABLED) - num_interfaces[0] += 3; - interfaces = (const uint8_t*) CDC_GetInterface(); - interfaces_length = CDC_GetInterfaceLength() + HID_GetInterfaceLength(); - if( maxlen > CDC_GetInterfaceLength() + HID_GetInterfaceLength() + sizeof(ConfigDescriptor) ) - { - maxlen = CDC_GetInterfaceLength() + HID_GetInterfaceLength() + sizeof(ConfigDescriptor); - } - -#else -#ifdef CDC_ENABLED - num_interfaces[0] += 2; +#if defined(CDC_ENABLED) && defined(HID_ENABLED) + num_interfaces[0] += 3; + interfaces = (const uint8_t*) CDC_GetInterface(); + interfaces_length = CDC_GetInterfaceLength() + HID_GetInterfaceLength(); + if (maxlen > CDC_GetInterfaceLength() + HID_GetInterfaceLength() + sizeof(ConfigDescriptor)) + { + maxlen = CDC_GetInterfaceLength() + HID_GetInterfaceLength() + sizeof(ConfigDescriptor); + } +#elif defined(CDC_ENABLED) + num_interfaces[0] += 2; interfaces = (const uint8_t*) CDC_GetInterface(); interfaces_length += CDC_GetInterfaceLength(); - if( maxlen > CDC_GetInterfaceLength()+ sizeof(ConfigDescriptor) ) + if (maxlen > CDC_GetInterfaceLength() + sizeof(ConfigDescriptor)) { - maxlen = CDC_GetInterfaceLength()+ sizeof(ConfigDescriptor); + maxlen = CDC_GetInterfaceLength() + sizeof(ConfigDescriptor); } -#endif - -#ifdef HID_ENABLED - num_interfaces[0] += 1; +#elif defined(HID_ENABLED) + num_interfaces[0] += 1; interfaces = (const uint8_t*) HID_GetInterface(); interfaces_length += HID_GetInterfaceLength(); - if( maxlen > HID_GetInterfaceLength()+ sizeof(ConfigDescriptor) ) + if (maxlen > HID_GetInterfaceLength() + sizeof(ConfigDescriptor)) { - maxlen = HID_GetInterfaceLength()+ sizeof(ConfigDescriptor); + maxlen = HID_GetInterfaceLength() + sizeof(ConfigDescriptor); } #endif -#endif _Pragma("pack(1)") - ConfigDescriptor config = D_CONFIG((uint16_t)(interfaces_length + sizeof(ConfigDescriptor)),num_interfaces[0]); + ConfigDescriptor config = D_CONFIG((uint16_t)(interfaces_length + sizeof(ConfigDescriptor)), num_interfaces[0]); _Pragma("pack()") - memcpy( cache_buffer, &config, sizeof(ConfigDescriptor) ); + memcpy(cache_buffer, &config, sizeof(ConfigDescriptor)); -#if (defined CDC_ENABLED) && defined(HID_ENABLED) - for ( i=0; i sizeof(cache_buffer)) - { + if (maxlen > sizeof(cache_buffer)) { maxlen = sizeof(cache_buffer); } - USBD_SendControl(0,cache_buffer, maxlen ); - return true; + return sendControl(cache_buffer, maxlen); } -static bool USBD_SendDescriptor(Setup* pSetup) +bool USBDeviceClass::sendDescriptor(Setup &setup) { - uint8_t t = pSetup->wValueH; + uint8_t t = setup.wValueH; uint8_t desc_length = 0; - const uint8_t* desc_addr = 0; + const uint8_t *desc_addr = 0; - if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) + if (t == USB_CONFIGURATION_DESCRIPTOR_TYPE) { - TRACE_CORE(printf("=> USBD_SendDescriptor : USB_CONFIGURATION_DESCRIPTOR_TYPE length=%d\r\n", setup.wLength);) - return USBD_SendConfiguration(pSetup->wLength); + return USBDevice.sendConfiguration(setup.wLength); } -#ifdef HID_ENABLED - if (HID_REPORT_DESCRIPTOR_TYPE == t) +#if defined(HID_ENABLED) + if (t == HID_REPORT_DESCRIPTOR_TYPE) { - TRACE_CORE(puts("=> USBD_SendDescriptor : HID_REPORT_DESCRIPTOR_TYPE\r\n");) return HID_GetDescriptor(); } - if (HID_HID_DESCRIPTOR_TYPE == t) + + if (t == HID_HID_DESCRIPTOR_TYPE) { uint8_t tab[9] = D_HIDREPORT((uint8_t)HID_SizeReportDescriptor()); - - TRACE_CORE(puts("=> USBD_SendDescriptor : HID_HID_DESCRIPTOR_TYPE\r\n");) - - return USBD_SendControl(0, tab, sizeof(tab)); + return USBDevice.sendControl(tab, sizeof(tab)); } #endif - if (USB_DEVICE_DESCRIPTOR_TYPE == t) + if (t == USB_DEVICE_DESCRIPTOR_TYPE) { - TRACE_CORE(puts("=> USBD_SendDescriptor : USB_DEVICE_DESCRIPTOR_TYPE\r\n");) desc_addr = (const uint8_t*)&USB_DeviceDescriptor; - if( *desc_addr > pSetup->wLength ) { - desc_length = pSetup->wLength; - } + if (*desc_addr > setup.wLength) { + desc_length = setup.wLength; + } } else if (USB_STRING_DESCRIPTOR_TYPE == t) { - TRACE_CORE(puts("=> USBD_SendDescriptor : USB_STRING_DESCRIPTOR_TYPE\r\n");) - if (pSetup->wValueL == 0) { + if (setup.wValueL == 0) { desc_addr = (const uint8_t*)&STRING_LANGUAGE; } - else if (pSetup->wValueL == IPRODUCT) { - return USB_SendStringDescriptor(STRING_PRODUCT, pSetup->wLength); + else if (setup.wValueL == IPRODUCT) { + return sendStringDescriptor(STRING_PRODUCT, setup.wLength); } - else if (pSetup->wValueL == IMANUFACTURER) { - return USB_SendStringDescriptor(STRING_MANUFACTURER, pSetup->wLength); + else if (setup.wValueL == IMANUFACTURER) { + return sendStringDescriptor(STRING_MANUFACTURER, setup.wLength); } else { return false; } - if( *desc_addr > pSetup->wLength ) { - desc_length = pSetup->wLength; + if (*desc_addr > setup.wLength) { + desc_length = setup.wLength; } } - else - { - TRACE_CORE(printf("Device ERROR");) - } - - if (desc_addr == 0) + else { + } + + if (desc_addr == 0) { return false; } - if (desc_length == 0) - { + if (desc_length == 0) { desc_length = *desc_addr; } - TRACE_CORE(printf("=> USBD_SendDescriptor : desc_addr=%p desc_length=%d\r\n", desc_addr, desc_length);) - USBD_SendControl(0, desc_addr, desc_length); + sendControl(desc_addr, desc_length); return true; } -void EndpointHandler(uint8_t bEndpoint) +void USBDeviceClass::handleEndpoint(uint8_t ep) { -#ifdef CDC_ENABLED - if( bEndpoint == CDC_ENDPOINT_OUT ) +#if defined(CDC_ENABLED) + if (ep == CDC_ENDPOINT_OUT) { - udd_OUT_transfer_allowed(CDC_ENDPOINT_OUT); + // The RAM Buffer is empty: we can receive data + //usbd.epBank0ResetReady(CDC_ENDPOINT_OUT); // Handle received bytes - if (USBD_Available(CDC_ENDPOINT_OUT)) - { + if (available(CDC_ENDPOINT_OUT)) SerialUSB.accept(); - } } - if( bEndpoint == CDC_ENDPOINT_IN ) + if (ep == CDC_ENDPOINT_IN) { - udd_IN_stop_transfer(CDC_ENDPOINT_IN); - /* Clear the transfer complete flag */ - udd_clear_IN_transf_cplt(CDC_ENDPOINT_IN); - + // NAK on endpoint IN, the bank is not yet filled in. + usbd.epBank1ResetReady(CDC_ENDPOINT_IN); + usbd.epBank1AckTransferComplete(CDC_ENDPOINT_IN); } - if( bEndpoint == CDC_ENDPOINT_ACM ) + if (ep == CDC_ENDPOINT_ACM) { - udd_IN_stop_transfer(CDC_ENDPOINT_ACM); - /* Clear the transfer complete flag */ - udd_clear_IN_transf_cplt(CDC_ENDPOINT_ACM); + // NAK on endpoint IN, the bank is not yet filled in. + usbd.epBank1ResetReady(CDC_ENDPOINT_ACM); + usbd.epBank1AckTransferComplete(CDC_ENDPOINT_ACM); } #endif -#ifdef HID_ENABLED - /* Nothing to do in our example */ +#if defined(HID_ENABLED) + // Empty #endif } +void USBDeviceClass::init() +{ + // Enable USB clock + PM->APBBMASK.reg |= PM_APBBMASK_USB; + + // Set up the USB DP/DN pins + PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1; + PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u))); + PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u)); + PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1; + PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u))); + PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u)); + + // Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference) + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(6) | // Generic Clock Multiplexer 6 + GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source + GCLK_CLKCTRL_CLKEN; + while (GCLK->STATUS.bit.SYNCBUSY) + ; + + // Reset USB Device + usbd.reset(); + + usbd.calibrate(); + usbd.setUSBDeviceMode(); + usbd.runInStandby(); + usbd.setFullSpeed(); + + // Configure interrupts + NVIC_SetPriority((IRQn_Type) USB_IRQn, 0UL); + NVIC_EnableIRQ((IRQn_Type) USB_IRQn); + + usbd.enable(); + + initialized = true; +} -void USB_ISR(void) +bool USBDeviceClass::attach() { - uint16_t flags; - uint8_t i; - uint8_t ept_int; + if (!initialized) + return false; - ept_int = udd_endpoint_interrupt(); + usbd.attach(); + usbd.enableEndOfResetInterrupt(); + usbd.enableStartOfFrameInterrupt(); - /* Not endpoint interrupt */ - if (0 == ept_int) - { - udd_clear_wakeup_interrupt(); - udd_clear_eorsm_interrupt(); - udd_clear_suspend_interrupt(); + _usbConfiguration = 0; + return true; +} - // End of bus reset - if (Is_udd_reset()) - { - TRACE_CORE(printf(">>> End of Reset\r\n");) - // Reset USB address to 0 - udd_configure_address(0); - - // Configure EP 0 - UDD_InitEP(0, USB_ENDPOINT_TYPE_CONTROL); - udd_enable_setup_received_interrupt(0); - _usbConfiguration = 0; - udd_ack_reset(); +void USBDeviceClass::setAddress(uint32_t addr) +{ + usbd.epBank1SetByteCount(0, 0); + usbd.epBank1AckTransferComplete(0); + + // RAM buffer is full, we can send data (IN) + usbd.epBank1SetReady(0); + + // Wait for transfer to complete + while (!usbd.epBank1IsTransferComplete(0)) {} + + // Set USB address to addr + USB->DEVICE.DADD.bit.DADD = addr; // Address + USB->DEVICE.DADD.bit.ADDEN = 1; // Enable +} + +bool USBDeviceClass::detach() +{ + if (!initialized) + return false; + usbd.detach(); + return true; +} + +bool USBDeviceClass::configured() +{ + return _usbConfiguration != 0; +} + +bool USBDeviceClass::handleClassInterfaceSetup(Setup& setup) +{ + uint8_t i = setup.wIndex; + + #if defined(CDC_ENABLED) + if (CDC_ACM_INTERFACE == i) + { + if (CDC_Setup(setup) == false) { + sendZlp(0); } + return true; + } + #endif - if (Is_udd_sof()) - { - udd_ack_sof(); + #if defined(HID_ENABLED) + if (HID_INTERFACE == i) + { + if (HID_Setup(setup) == true) { + sendZlp(0); } + return true; + } + #endif + return false; +} + +void USBDeviceClass::initEP(uint32_t ep, uint32_t config) +{ + if (config == (USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0))) + { + usbd.epBank1SetSize(ep, 8); + usbd.epBank1SetAddress(ep, &udd_ep_in_cache_buffer[ep]); + usbd.epBank1SetType(ep, 4); // INTERRUPT IN } - else + else if (config == (USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0))) { - // Endpoint interrupt - flags = udd_read_endpoint_flag(0); + usbd.epBank0SetSize(ep, 64); + usbd.epBank0SetAddress(ep, &udd_ep_out_cache_buffer[ep]); + usbd.epBank0SetType(ep, 3); // BULK OUT + + // Release OUT EP + usbd.epBank0SetMultiPacketSize(ep, 64); + usbd.epBank0SetByteCount(ep, 0); + + // The RAM Buffer is empty: we can receive data + //usbd.epBank0ResetReady(ep); + } + else if (config == (USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0))) + { + usbd.epBank1SetSize(ep, 64); + usbd.epBank1SetAddress(ep, &udd_ep_in_cache_buffer[ep]); - // endpoint received setup interrupt - if (flags & USB_DEVICE_EPINTFLAG_RXSTP) - { - Setup *pSetupData; + // NAK on endpoint IN, the bank is not yet filled in. + usbd.epBank1ResetReady(ep); - /* Clear the Received Setup flag */ - udd_read_endpoint_flag(0) = USB_DEVICE_EPINTFLAG_RXSTP; + usbd.epBank1SetType(ep, 3); // BULK IN + } + 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[0]); + usbd.epBank0SetType(ep, 1); // CONTROL OUT / SETUP + + // Setup Control IN + usbd.epBank1SetSize(ep, 64); + usbd.epBank1SetAddress(ep, &udd_ep_in_cache_buffer[0]); + usbd.epBank1SetType(ep, 1); // CONTROL IN + + // Release OUT EP + usbd.epBank0SetMultiPacketSize(ep, 64); + usbd.epBank0SetByteCount(ep, 0); + + // NAK on endpoint OUT, the bank is full. + usbd.epBank0SetReady(ep); + // NAK on endpoint IN, the bank is not yet filled in. + //usbd.epBank1ResetReady(ep); + } +} - UDD_Recv(EP0, (uint8_t**)&pSetupData); +void USBDeviceClass::flush(uint32_t ep) +{ + if (available(ep)) { + // RAM buffer is full, we can send data (IN) + usbd.epBank1SetReady(ep); - /* Clear the Bank 0 ready flag on Control OUT */ - udd_OUT_transfer_allowed(0); + // Clear the transfer complete flag + usbd.epBank1AckTransferComplete(ep); + } +} - bool ok = true; - if (REQUEST_STANDARD == (pSetupData->bmRequestType & REQUEST_TYPE)) - { - unsigned char data_to_be_send[2]; - - // Standard Requests - uint8_t r = pSetupData->bRequest; - if (GET_STATUS == r) - { - if( pSetupData->bmRequestType == 0 ) // device - { - // Send the device status - TRACE_CORE(puts(">>> EP0 Int: GET_STATUS\r\n");) - // Check current configuration for power mode (if device is configured) - // TODO - // Check if remote wake-up is enabled - // TODO - data_to_be_send[0]=0; - data_to_be_send[1]=0; - UDD_Send(0, data_to_be_send, 2); - } - // if( pSetupData->bmRequestType == 2 ) // Endpoint: - else - { - // Send the endpoint status - // Check if the endpoint if currently halted - if( isEndpointHalt == 1 ) - data_to_be_send[0]=1; - else - data_to_be_send[0]=0; - data_to_be_send[1]=0; - UDD_Send(0, data_to_be_send, 2); - } - } - else if (CLEAR_FEATURE == r) - { - // Check which is the selected feature - if( pSetupData->wValueL == 1) // DEVICEREMOTEWAKEUP - { - // Enable remote wake-up and send a ZLP - if( isRemoteWakeUpEnabled == 1 ) - data_to_be_send[0]=1; - else - data_to_be_send[0]=0; - data_to_be_send[1]=0; - UDD_Send(0, data_to_be_send, 2); - } - else // if( pSetupData->wValueL == 0) // ENDPOINTHALT - { - isEndpointHalt = 0; - send_zlp(); - } - } - else if (SET_FEATURE == r) - { - // Check which is the selected feature - if( pSetupData->wValueL == 1) // DEVICEREMOTEWAKEUP - { - // Enable remote wake-up and send a ZLP - isRemoteWakeUpEnabled = 1; - data_to_be_send[0] = 0; - UDD_Send(0, data_to_be_send, 1); - } - if( pSetupData->wValueL == 0) // ENDPOINTHALT - { - // Halt endpoint - isEndpointHalt = 1; - send_zlp(); - } - } - else if (SET_ADDRESS == r) - { - TRACE_CORE(puts(">>> EP0 Int: SET_ADDRESS\r\n");) - UDD_SetAddress(pSetupData->wValueL); - } - else if (GET_DESCRIPTOR == r) - { - TRACE_CORE(puts(">>> EP0 Int: GET_DESCRIPTOR\r\n");) - ok = USBD_SendDescriptor(pSetupData); - } - else if (SET_DESCRIPTOR == r) - { - TRACE_CORE(puts(">>> EP0 Int: SET_DESCRIPTOR\r\n");) - ok = false; - } - else if (GET_CONFIGURATION == r) - { - TRACE_CORE(puts(">>> EP0 Int: GET_CONFIGURATION\r\n");) - UDD_Send(0, (void*)&_usbConfiguration, 1); - } - else if (SET_CONFIGURATION == r) - { - if (REQUEST_DEVICE == (pSetupData->bmRequestType & REQUEST_RECIPIENT)) - { - TRACE_CORE(printf(">>> EP0 Int: SET_CONFIGURATION REQUEST_DEVICE %d\r\n", pSetupData->wValueL);) -#ifdef HID_ENABLED - UDD_InitEP( HID_ENDPOINT_INT, USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0)); -#endif +void USBDeviceClass::stall(uint32_t ep) +{ + // TODO: test + // TODO: use .bit. notation -#ifdef CDC_ENABLED - UDD_InitEP( CDC_ENDPOINT_ACM, USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0)); - UDD_InitEP( CDC_ENDPOINT_OUT, USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0)); - UDD_InitEP( CDC_ENDPOINT_IN, USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0)); -#endif - _usbConfiguration = pSetupData->wValueL; + // Stall endpoint + USB->DEVICE.DeviceEndpoint[ep].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ(2); +} -#ifdef CDC_ENABLED - // Enable interrupt for CDC reception from host (OUT packet) - udd_ept_enable_it_IN_transf_cplt(CDC_ENDPOINT_ACM); - udd_ept_enable_it_OUT_transf_cplt(CDC_ENDPOINT_OUT); -#endif - send_zlp(); - } - else - { - TRACE_CORE(puts(">>> EP0 Int: SET_CONFIGURATION failed!\r\n");) - ok = false; - } - } - else if (GET_INTERFACE == r) - { - TRACE_CORE(puts(">>> EP0 Int: GET_INTERFACE\r\n");) - UDD_Send(0, (void*)&_usbSetInterface, 1); - } - else if (SET_INTERFACE == r) - { - _usbSetInterface = pSetupData->wValueL; - TRACE_CORE(puts(">>> EP0 Int: SET_INTERFACE\r\n");) - send_zlp(); - } - } - else - { - TRACE_CORE(puts(">>> EP0 Int: ClassInterfaceRequest\r\n");) - ok = USBD_ClassInterfaceRequest(*pSetupData); - } +bool USBDeviceClass::connected() +{ + // Count frame numbers + uint8_t f = USB->DEVICE.FNUM.bit.FNUM; + //delay(3); + return f != USB->DEVICE.FNUM.bit.FNUM; +} - if (ok) - { - TRACE_CORE(puts(">>> EP0 Int: Send packet\r\n");) - UDD_ClearIN(); - } - else - { - TRACE_CORE(puts(">>> EP0 Int: Stall\r\n");) - UDD_Stall(0); - } - if( flags & USB_DEVICE_EPINTFLAG_STALL(2) ) - { - /* Clear the stall flag */ - udd_clear_stall_request(0); +uint32_t USBDeviceClass::recvControl(void *_data, uint32_t len) +{ + uint8_t *data = reinterpret_cast(_data); +// NO RXOUT ??????? - // Remove stall request - udd_remove_stall_request(0); - } - } // end if USB_DEVICE_EPINTFLAG_RXSTP + // The RAM Buffer is empty: we can receive data + usbd.epBank0ResetReady(0); - i=0; - ept_int &= 0xFE; // Remove endpoint number 0 (setup) - while (ept_int != 0) - { - // Check if endpoint has a pending interrupt - if ((ept_int & (1 << i)) != 0) - { - if( (udd_read_endpoint_flag(i) & USB_DEVICE_EPINTFLAG_TRCPT_Msk ) != 0 ) + //usbd.epBank0AckSetupReceived(0); + uint32_t read = armRecvCtrlOUT(0, len); + if (read > len) + read = len; + //while (!usbd.epBank0AckTransferComplete(0)) {} + uint8_t *buffer = udd_ep_out_cache_buffer[0]; + for (uint32_t i=0; i USB_EPT_NUM) break; // fire exit - } + uint8_t *buffer = udd_ep_out_cache_buffer[ep]; + uint8_t *data = reinterpret_cast(_data); + for (uint32_t i=0; iDEVICE.DeviceEndpoint[ep].EPINTFLAG.bit.TRCPT == 0); + return usbd.epBank0ByteCount(ep); +} -void USBD_Flush(uint32_t ep) +uint8_t USBDeviceClass::armRecv(uint32_t ep, uint32_t len) { - if (UDD_FifoByteCount(ep)) - { - UDD_ReleaseTX(ep); + usbd.epBank0SetSize(ep, 64); + usbd.epBank0SetAddress(ep, &udd_ep_out_cache_buffer[ep]); + usbd.epBank0SetMultiPacketSize(ep, 64); // XXX: Should be "len"? + uint16_t count = usbd.epBank0ByteCount(ep); + if (count >= 64) { + usbd.epBank0SetByteCount(ep, count - 64); + } else { + usbd.epBank0SetByteCount(ep, 0); } + // The RAM Buffer is empty: we can receive data + //usbd.epBank0ResetReady(ep); + + // Wait for transfer to complete + //while (!usbd.epBank0IsTransferComplete(ep)) {} + //while (usbd.epBank0IsReady(ep)) {} + // NAK on endpoint OUT, the bank is full. + //usbd.epBank0ResetReady(ep); + + return usbd.epBank0ByteCount(ep); } -// Counting frames -uint32_t USBD_Connected(void) +// Blocking Send of data to an endpoint +uint32_t USBDeviceClass::send(uint32_t ep, const void *data, uint32_t len) { - uint8_t f = UDD_GetFrameNumber(); + if (!_usbConfiguration) + return -1; + + armSend(ep, data, len); + + // Clear the transfer complete flag + usbd.epBank1AckTransferComplete(ep); - //delay(3); + // RAM buffer is full, we can send data (IN) + usbd.epBank1SetReady(ep); - return f != UDD_GetFrameNumber(); + // Wait for transfer to complete + while (!usbd.epBank1IsTransferComplete(ep)) { + ; // need fire exit. + } + return len; } +uint32_t USBDeviceClass::armSend(uint32_t ep, const void* data, uint32_t len) +{ + memcpy(&udd_ep_in_cache_buffer[ep], data, len); -//======================================================================= -//======================================================================= + // Get endpoint configuration from setting register + usbd.epBank1SetAddress(ep, &udd_ep_in_cache_buffer[ep]); + usbd.epBank1SetMultiPacketSize(ep, 0); + usbd.epBank1SetByteCount(ep, len); -USBDevice_ USBDevice; + return len; +} -USBDevice_::USBDevice_() +uint32_t USBDeviceClass::sendControl(const void* _data, uint32_t len) { - UDD_SetStack(&USB_ISR); + const uint8_t *data = reinterpret_cast(_data); + uint32_t length = len; + uint32_t sent = 0; + uint32_t pos = 0; + + while (len > 0) + { + sent = armSend(EP0, data + pos, len); + pos += sent; + len -= sent; + } + + return length; } -bool USBDevice_::attach() +void USBDeviceClass::sendZlp(uint32_t ep) { - if (_usbInitialized != 0UL) - { - UDD_Attach(); - _usbConfiguration = 0; - return true; - } - else - { - return false; - } + // Set the byte count as zero + usbd.epBank1SetByteCount(ep, 0); } -bool USBDevice_::detach() +bool USBDeviceClass::handleStandardSetup(Setup &setup) { - if (_usbInitialized != 0UL) - { - UDD_Detach(); + switch (setup.bRequest) { + case GET_STATUS: + if (setup.bmRequestType == 0) // device + { + // Send the device status + // TODO: Check current configuration for power mode (if device is configured) + // TODO: Check if remote wake-up is enabled + uint8_t buff[] = { 0, 0 }; + armSend(0, buff, 2); + return true; + } + // if( setup.bmRequestType == 2 ) // Endpoint: + else + { + // Send the endpoint status + // Check if the endpoint if currently halted + uint8_t buff[] = { 0, 0 }; + if (isEndpointHalt == 1) + buff[0] = 1; + armSend(0, buff, 2); + return true; + } + + case CLEAR_FEATURE: + // Check which is the selected feature + if (setup.wValueL == 1) // DEVICEREMOTEWAKEUP + { + // Enable remote wake-up and send a ZLP + uint8_t buff[] = { 0, 0 }; + if (isRemoteWakeUpEnabled == 1) + buff[0] = 1; + armSend(0, buff, 2); + return true; + } + else // if( setup.wValueL == 0) // ENDPOINTHALT + { + isEndpointHalt = 0; + sendZlp(0); + return true; + } + + case SET_FEATURE: + // Check which is the selected feature + if (setup.wValueL == 1) // DEVICEREMOTEWAKEUP + { + // Enable remote wake-up and send a ZLP + isRemoteWakeUpEnabled = 1; + uint8_t buff[] = { 0 }; + armSend(0, buff, 1); + return true; + } + if (setup.wValueL == 0) // ENDPOINTHALT + { + // Halt endpoint + isEndpointHalt = 1; + sendZlp(0); + return true; + } + + case SET_ADDRESS: + setAddress(setup.wValueL); return true; - } - else - { + + case GET_DESCRIPTOR: + return sendDescriptor(setup); + + case SET_DESCRIPTOR: return false; + + case GET_CONFIGURATION: + armSend(0, (void*)&_usbConfiguration, 1); + return true; + + case SET_CONFIGURATION: + if (REQUEST_DEVICE == (setup.bmRequestType & REQUEST_RECIPIENT)) { + #if defined(HID_ENABLED) + initEP(HID_ENDPOINT_INT, USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0)); + #endif + + #if defined(CDC_ENABLED) + initEP(CDC_ENDPOINT_ACM, USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0)); + initEP(CDC_ENDPOINT_OUT, USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0)); + initEP(CDC_ENDPOINT_IN, USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0)); + #endif + _usbConfiguration = setup.wValueL; + + #if defined(CDC_ENABLED) + // Enable interrupt for CDC reception from host (OUT packet) + usbd.epBank1EnableTransferComplete(CDC_ENDPOINT_ACM); + usbd.epBank0EnableTransferComplete(CDC_ENDPOINT_OUT); + #endif + + sendZlp(0); + return true; + } else { + return false; + } + + case GET_INTERFACE: + armSend(0, (void*)&_usbSetInterface, 1); + return true; + + case SET_INTERFACE: + _usbSetInterface = setup.wValueL; + sendZlp(0); + return true; + + default: + return true; } } -bool USBDevice_::configured() +void USBDeviceClass::ISRHandler() { - return _usbConfiguration; -} + // End-Of-Reset + if (usbd.isEndOfResetInterrupt()) + { + // Configure EP 0 + initEP(0, USB_ENDPOINT_TYPE_CONTROL); -void USBDevice_::poll() -{ + // Enable Setup-Received interrupt + usbd.epBank0EnableSetupReceived(0); + + _usbConfiguration = 0; + + usbd.ackEndOfResetInterrupt(); + } + + // Start-Of-Frame + if (usbd.isStartOfFrameInterrupt()) + { + usbd.ackStartOfFrameInterrupt(); + } + + // Endpoint 0 Received Setup interrupt + if (usbd.epBank0IsSetupReceived(0)) + { + usbd.epBank0AckSetupReceived(0); + + Setup *setup = reinterpret_cast(udd_ep_out_cache_buffer[0]); + + /* Clear the Bank 0 ready flag on Control OUT */ + // The RAM Buffer is empty: we can receive data + usbd.epBank0ResetReady(0); + + bool ok; + if (REQUEST_STANDARD == (setup->bmRequestType & REQUEST_TYPE)) { + // Standard Requests + ok = handleStandardSetup(*setup); + } else { + // Class Interface Requests + ok = handleClassInterfaceSetup(*setup); + } + + if (ok) { + usbd.epBank1SetReady(0); + } else { + stall(0); + } + + // XXX: Should be really cleared? + if (usbd.epBank1IsStalled(0)) // XXX:(USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.STALL) + { + usbd.epBank1AckStalled(0); + + // Remove stall request + usbd.epBank1DisableStalled(0); + } + + } // end Received Setup handler + + uint8_t i=0; + uint8_t ept_int = usbd.epInterruptSummary() & 0xFE; // Remove endpoint number 0 (setup) + while (ept_int != 0) + { + // Check if endpoint has a pending interrupt + if ((ept_int & (1 << i)) != 0) + { + // Endpoint Transfer Complete (0/1) Interrupt + if (usbd.epBank0IsTransferComplete(i) || + usbd.epBank1IsTransferComplete(i)) + { + handleEndpoint(i); + } + ept_int &= ~(1 << i); + } + i++; + if (i > USB_EPT_NUM) + break; // fire exit + } } -void USBDevice_::init() -{ - UDD_Init(); - _usbInitialized=1UL; +/* + * USB Device instance + * ------------------- + */ + +// USBDevice class instance +USBDeviceClass USBDevice; + +// USB_Handler ISR +extern "C" void USB_Handler(void) { + USBDevice.ISRHandler(); } diff --git a/cores/arduino/USB/USBCore.h b/cores/arduino/USB/USBCore.h index 1441a6492..d584fdfc9 100644 --- a/cores/arduino/USB/USBCore.h +++ b/cores/arduino/USB/USBCore.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2014 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -31,6 +31,16 @@ #define GET_INTERFACE 10 #define SET_INTERFACE 11 +// bEndpointAddress in Endpoint Descriptor +#define USB_ENDPOINT_DIRECTION_MASK 0x80 +#define USB_ENDPOINT_OUT(addr) ((addr) | 0x00) +#define USB_ENDPOINT_IN(addr) ((addr) | 0x80) + +#define USB_ENDPOINT_TYPE_MASK 0x03 +#define USB_ENDPOINT_TYPE_CONTROL 0x00 +#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01 +#define USB_ENDPOINT_TYPE_BULK 0x02 +#define USB_ENDPOINT_TYPE_INTERRUPT 0x03 // bmRequestType #define REQUEST_HOSTTODEVICE 0x00 diff --git a/cores/arduino/USB/USBDesc.h b/cores/arduino/USB/USBDesc.h index 9b1cdf8c1..655fb6d01 100644 --- a/cores/arduino/USB/USBDesc.h +++ b/cores/arduino/USB/USBDesc.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2014 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/cores/arduino/USB/USB_device.h b/cores/arduino/USB/USB_device.h deleted file mode 100644 index 6353f9770..000000000 --- a/cores/arduino/USB/USB_device.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - Copyright (c) 2014 Arduino. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef USB_DEVICE_H_INCLUDED -#define USB_DEVICE_H_INCLUDED - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include "USB/samd21_device.h" - - -// bEndpointAddress in Endpoint Descriptor -#define USB_ENDPOINT_DIRECTION_MASK 0x80 -#define USB_ENDPOINT_OUT(addr) ((addr) | 0x00) -#define USB_ENDPOINT_IN(addr) ((addr) | 0x80) - -#define USB_ENDPOINT_TYPE_MASK 0x03 -#define USB_ENDPOINT_TYPE_CONTROL 0x00 -#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01 -#define USB_ENDPOINT_TYPE_BULK 0x02 -#define USB_ENDPOINT_TYPE_INTERRUPT 0x03 - - -extern void UDD_ClearIN(void); -extern uint32_t UDD_FifoByteCount(uint32_t ep); -extern void UDD_ReleaseRX(uint32_t ep); -extern void UDD_ReleaseTX(uint32_t ep); -extern uint32_t UDD_Send(uint32_t ep, const void* data, uint32_t len); -extern uint8_t UDD_Recv_data(uint32_t ep, uint32_t len); -extern void UDD_Recv(uint32_t ep, uint8_t** data); -extern void UDD_Init(void); -extern void UDD_InitEP( uint32_t ul_ep, uint32_t ul_ep_cfg ); -extern void send_zlp (void); -extern void UDD_Attach(void); -extern void UDD_Detach(void); -extern void UDD_SetAddress(uint32_t addr); -extern void UDD_Stall(uint32_t ep); -extern uint32_t UDD_GetFrameNumber(void); -extern void UDD_SetStack(void (*pf_isr)(void)); - -#ifdef __cplusplus -} -#endif - -#endif /* USB_DEVICE_H_INCLUDED */ diff --git a/cores/arduino/USB/USB_host.h b/cores/arduino/USB/USB_host.h index e20738e85..390e3dd1e 100644 --- a/cores/arduino/USB/USB_host.h +++ b/cores/arduino/USB/USB_host.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2014 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/cores/arduino/USB/USB_interrupt.c b/cores/arduino/USB/USB_interrupt.c deleted file mode 100644 index 3f1f05f6c..000000000 --- a/cores/arduino/USB/USB_interrupt.c +++ /dev/null @@ -1,23 +0,0 @@ -/* -** Permission to use, copy, modify, and/or distribute this software for -** any purpose with or without fee is hereby granted, provided that the -** above copyright notice and this permission notice appear in all copies. -** -** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL -** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR -** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES -** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -** SOFTWARE. -*/ - -void (*gpf_isr)(void) = (0UL); - -void USB_Handler( void ) -{ - if (gpf_isr) - gpf_isr(); -} - diff --git a/cores/arduino/USB/samd21_device.c b/cores/arduino/USB/samd21_device.c deleted file mode 100644 index cff711f47..000000000 --- a/cores/arduino/USB/samd21_device.c +++ /dev/null @@ -1,349 +0,0 @@ -/* - Copyright (c) 2014 Arduino. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include -#include - -#include "variant.h" -#include "USB/USB_device.h" -#include "USB/samd21_device.h" -#include "sam.h" - -#ifdef __cplusplus -extern "C"{ -#endif // __cplusplus - -#ifdef SAMD_SERIES - -//#define TRACE_DEVICE(x) x -#define TRACE_DEVICE(x) - -__attribute__((__aligned__(4))) /*__attribute__((__section__(".bss_hram0")))*/ uint8_t udd_ep_out_cache_buffer[4][64]; -__attribute__((__aligned__(4))) /*__attribute__((__section__(".bss_hram0")))*/ uint8_t udd_ep_in_cache_buffer[4][128]; - -/** - * USB SRAM data containing pipe descriptor table - * The content of the USB SRAM can be : - * - modified by USB hardware interface to update pipe status. - * Thereby, it is read by software. - * - modified by USB software to control pipe. - * Thereby, it is read by hardware. - * This data section is volatile. - */ - __attribute__((__aligned__(4))) UsbDeviceDescriptor usb_endpoint_table[USB_EPT_NUM]; - - -extern void (*gpf_isr)(void); - - -void UDD_SetStack(void (*pf_isr)(void)) -{ - gpf_isr = pf_isr; -} - -// NVM Software Calibration Area Mapping -// USB TRANSN calibration value. Should be written to the USB PADCAL register. -#define NVM_USB_PAD_TRANSN_POS 45 -#define NVM_USB_PAD_TRANSN_SIZE 5 -// USB TRANSP calibration value. Should be written to the USB PADCAL register. -#define NVM_USB_PAD_TRANSP_POS 50 -#define NVM_USB_PAD_TRANSP_SIZE 5 -// USB TRIM calibration value. Should be written to the USB PADCAL register. -#define NVM_USB_PAD_TRIM_POS 55 -#define NVM_USB_PAD_TRIM_SIZE 3 - -void UDD_Init(void) -{ - uint32_t pad_transn; - uint32_t pad_transp; - uint32_t pad_trim; - uint32_t i; - - /* Enable USB clock */ - PM->APBBMASK.reg |= PM_APBBMASK_USB; - - /* Set up the USB DP/DN pins */ - PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1; - PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u))); - PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u)); - PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1; - PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u))); - PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u)); - - /* ---------------------------------------------------------------------------------------------- - * Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference) - */ - GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( 6 ) | // Generic Clock Multiplexer 6 - GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source - GCLK_CLKCTRL_CLKEN ; - - while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) - { - /* Wait for synchronization */ - } - - /* Reset */ - USB->DEVICE.CTRLA.bit.SWRST = 1; - while (USB->DEVICE.SYNCBUSY.bit.SWRST) { - /* Sync wait */ - } - - udd_enable(); - - /* Load Pad Calibration */ - pad_transn =( *((uint32_t *)(NVMCTRL_OTP4) // Non-Volatile Memory Controller - + (NVM_USB_PAD_TRANSN_POS / 32)) - >> (NVM_USB_PAD_TRANSN_POS % 32)) - & ((1 << NVM_USB_PAD_TRANSN_SIZE) - 1); - - if (pad_transn == 0x1F) { // maximum value (31) - pad_transn = 5; - } - - USB->DEVICE.PADCAL.bit.TRANSN = pad_transn; - - pad_transp =( *((uint32_t *)(NVMCTRL_OTP4) - + (NVM_USB_PAD_TRANSP_POS / 32)) - >> (NVM_USB_PAD_TRANSP_POS % 32)) - & ((1 << NVM_USB_PAD_TRANSP_SIZE) - 1); - - if (pad_transp == 0x1F) { // maximum value (31) - pad_transp = 29; - } - - USB->DEVICE.PADCAL.bit.TRANSP = pad_transp; - - pad_trim =( *((uint32_t *)(NVMCTRL_OTP4) - + (NVM_USB_PAD_TRIM_POS / 32)) - >> (NVM_USB_PAD_TRIM_POS % 32)) - & ((1 << NVM_USB_PAD_TRIM_SIZE) - 1); - - if (pad_trim == 0x7) { // maximum value (7) - pad_trim = 3; - } - - USB->DEVICE.PADCAL.bit.TRIM = pad_trim; - - /* Set the configuration */ - udd_force_device_mode(); - udd_device_run_in_standby(); - // Set address of USB SRAM - USB->DEVICE.DESCADD.reg = (uint32_t)(&usb_endpoint_table[0]); - // For USB_SPEED_FULL - udd_force_full_speed(); - memset(&usb_endpoint_table[0], 0, sizeof(usb_endpoint_table)); - - // Configure interrupts - NVIC_SetPriority((IRQn_Type) USB_IRQn, 0UL); - NVIC_EnableIRQ((IRQn_Type) USB_IRQn); -} - -void UDD_Attach(void) -{ - TRACE_DEVICE(printf("=> UDD_Attach\r\n");) - - // Authorize attach if Vbus is present - udd_attach_device(); - - // Enable USB line events - udd_enable_reset_interrupt(); - - // usefull for debug - udd_enable_sof_interrupt(); -} - -void UDD_Detach(void) -{ - TRACE_DEVICE(printf("=> UDD_Detach\r\n");) - udd_detach_device(); -} - -void send_zlp(void) -{ - /* Set the byte count as zero */ - usb_endpoint_table[0].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = 0; -} - - -void UDD_InitEP( uint32_t ul_ep_nb, uint32_t ul_ep_cfg ) -{ - TRACE_DEVICE(printf("=> UDD_InitEP : init EP %lu\r\n", (unsigned long)ul_ep_nb);) - - if( ul_ep_cfg == (USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0)) ) - { - USB->DEVICE.DeviceEndpoint[ul_ep_nb].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(4); - /* Set maximum packet size as 8 bytes */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[1].PCKSIZE.bit.SIZE = 0; // 8 bytes - /* Configure the data buffer */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[1].ADDR.reg = (uint32_t)&udd_ep_in_cache_buffer[ul_ep_nb]; - } - else if( ul_ep_cfg == (USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0)) ) - { - /* Configure BULK OUT endpoint for CDC Data interface*/ - USB->DEVICE.DeviceEndpoint[ul_ep_nb].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(3); - /* Set maximum packet size as 64 bytes */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].PCKSIZE.bit.SIZE = 0x3; // for 64 bytes - /* Configure the data buffer */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[ul_ep_nb]; - - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 64; - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; - // NACK if not ready - udd_OUT_transfer_allowed(ul_ep_nb); - } - else if( ul_ep_cfg == (USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0)) ) - { - /* Configure BULK IN endpoint for CDC Data interface */ - USB->DEVICE.DeviceEndpoint[ul_ep_nb].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(3); - /* Set maximum packet size as 64 bytes */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[1].PCKSIZE.bit.SIZE = 0x3; // for 64 bytes - /* Configure the data buffer */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[1].ADDR.reg = (uint32_t)&udd_ep_in_cache_buffer[ul_ep_nb]; - // NACK if not ready - udd_IN_stop_transfer(ul_ep_nb); - } - else if( ul_ep_cfg == USB_ENDPOINT_TYPE_CONTROL ) - { - /* Configure CONTROL endpoint */ - USB->DEVICE.DeviceEndpoint[ul_ep_nb].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(1) | USB_DEVICE_EPCFG_EPTYPE1(1); - udd_OUT_stop_transfer(ul_ep_nb); - udd_IN_stop_transfer(ul_ep_nb); - - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].PCKSIZE.reg &= ~USB_DEVICE_PCKSIZE_AUTO_ZLP; - usb_endpoint_table[ul_ep_nb].DeviceDescBank[1].PCKSIZE.reg &= ~USB_DEVICE_PCKSIZE_AUTO_ZLP; - - /* Set maximum packet size as 64 bytes */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].PCKSIZE.bit.SIZE = 0x3; // for 64 bytes - usb_endpoint_table[ul_ep_nb].DeviceDescBank[1].PCKSIZE.bit.SIZE = 0x3; // for 64 bytes - - /* get endpoint configuration from setting register */ - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[0]; - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 8; - usb_endpoint_table[ul_ep_nb].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; - - // NACK if not ready - udd_OUT_stop_transfer(ul_ep_nb); - udd_IN_stop_transfer(ul_ep_nb); - } -} - - -// Send packet. -void UDD_ClearIN(void) -{ - udd_IN_transfer_allowed(EP0); -} - - - -uint32_t UDD_Send(uint32_t ep, const void* data, uint32_t len) -{ - memcpy(&udd_ep_in_cache_buffer[ep], data, len); - - /* Get endpoint configuration from setting register */ - usb_endpoint_table[ep].DeviceDescBank[1].ADDR.reg = (uint32_t)&udd_ep_in_cache_buffer[ep]; - usb_endpoint_table[ep].DeviceDescBank[1].PCKSIZE.bit.MULTI_PACKET_SIZE = 0; - usb_endpoint_table[ep].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = len; - - return len; -} - -uint8_t UDD_Recv_data(uint32_t ep, uint32_t len) -{ - TRACE_DEVICE(printf("=> UDD_Recvdata : ep=%d\r\n", (char)ep);) - - if (len>64) len=64; - usb_endpoint_table[ep].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[ep]; - usb_endpoint_table[ep].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = len; - usb_endpoint_table[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; - udd_OUT_transfer_allowed(ep); - TRACE_DEVICE(printf("=> UDD_Recv_data : data=%lu\r\n", (unsigned long)data);) - - /* Wait for transfer to complete */ - while (!udd_is_OUT_transf_cplt(ep)); - /* Clear Transfer complete 0 flag */ - udd_clear_OUT_transf_cplt(ep); - - return udd_ep_out_cache_buffer[ep][0]; -} - -void UDD_Recv(uint32_t ep, uint8_t** ppData) -{ - *ppData = udd_ep_out_cache_buffer[ep]; -} - -void UDD_Stall(uint32_t ep) -{ - uint8_t ep_num = ep; - - // Stall endpoint - USB->DEVICE.DeviceEndpoint[ep_num].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ(2); -} - -uint32_t UDD_FifoByteCount(uint32_t ep) -{ - return ((uint16_t)(usb_endpoint_table[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT)); -} - -void UDD_ReleaseRX(uint32_t ep) -{ - TRACE_DEVICE(puts("=> UDD_ReleaseRX\r\n");) - // The RAM Buffer is empty: we can receive data - udd_OUT_transfer_allowed(ep); - /* Clear Transfer complete 0 flag */ - udd_clear_OUT_transf_cplt(ep); -} - -void UDD_ReleaseTX(uint32_t ep) -{ - TRACE_DEVICE(printf("=> UDD_ReleaseTX ep=%lu\r\n", (unsigned long)ep);) - // The RAM Buffer is full: we can send data - udd_IN_transfer_allowed(ep); - /* Clear the transfer complete flag */ - udd_clear_IN_transf_cplt(ep); -} - -void UDD_SetAddress(uint32_t addr) -{ - TRACE_DEVICE(printf("=> UDD_SetAddress : setting address to %lu\r\n", (unsigned long)addr);) - - /* Set the byte count as zero */ - usb_endpoint_table[0].DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = 0; - /* Clear the transfer complete flag */ - udd_clear_IN_transf_cplt(0); - /* Set the bank as ready */ - udd_IN_transfer_allowed(0); - - /* Wait for transfer to complete */ - while (!udd_is_IN_transf_cplt(EP0)) {} - - udd_configure_address(addr); -} - -uint32_t UDD_GetFrameNumber(void) -{ - return udd_frame_number(); -} - -#ifdef __cplusplus -} -#endif - -#endif /* SAMD_SERIES */ - diff --git a/cores/arduino/USB/samd21_device.h b/cores/arduino/USB/samd21_device.h deleted file mode 100644 index deded25b4..000000000 --- a/cores/arduino/USB/samd21_device.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - Copyright (c) 2014 Arduino. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef SAMD21_DEVICE_H_INCLUDED -#define SAMD21_DEVICE_H_INCLUDED - -#ifdef __cplusplus -extern "C" { -#endif - -#define EP0 0 -#define EPX_SIZE 64// 64 for Full Speed, EPT size max is 1024 - -// Force device low speed mode -#define udd_force_low_speed() USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_SPDCONF_Msk; USB->DEVICE.CTRLB.reg |= USB_DEVICE_CTRLB_SPDCONF_1_Val -// Force full speed mode -#define udd_force_full_speed() USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_SPDCONF_Msk - -// Attaches to USB bus -#define udd_attach_device() USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_DETACH -#define udd_detach_device() USB->DEVICE.CTRLB.reg |= USB_DEVICE_CTRLB_DETACH - -// Manage reset event -// Set when a USB "End of Reset" has been detected -#define udd_enable_reset_interrupt() USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_EORST -#define udd_ack_reset() USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST -#define Is_udd_reset() (USB->DEVICE.INTFLAG.reg & USB_DEVICE_INTFLAG_EORST) - -// Manage start of frame (SOF) event -#define udd_enable_sof_interrupt() USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF -#define udd_ack_sof() USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF -#define Is_udd_sof() (USB->DEVICE.INTENSET.reg & USB_DEVICE_INTENSET_SOF) -#define udd_frame_number() ((USB->DEVICE.FNUM.reg & USB_DEVICE_FNUM_FNUM_Msk) >> USB_DEVICE_FNUM_FNUM_Pos) - -// configures the USB device address and enable it. -#define udd_configure_address(address) USB->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | address - -// Clear BK0RDY for know that the BANK0 ram buffer (udd_g_ep_table[ep].DeviceDescBank[0]) is empty and can receive data -#define udd_OUT_transfer_allowed(ep) USB->DEVICE.DeviceEndpoint[ep].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY -// Set BK1RDY for know that the BANK1 ram buffer (udd_g_ep_table[ep].DeviceDescBank[1]) is full and can send data -#define udd_IN_transfer_allowed(ep) USB->DEVICE.DeviceEndpoint[ep].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK1RDY - -// Stop OUT transfer -#define udd_OUT_stop_transfer(ep) USB->DEVICE.DeviceEndpoint[ep].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY -// Stop IN transfer -#define udd_IN_stop_transfer(ep) USB->DEVICE.DeviceEndpoint[ep].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY - -#define udd_read_endpoint_flag(ep) USB->DEVICE.DeviceEndpoint[ep].EPINTFLAG.reg -// Is transfer completed ? -#define udd_is_IN_transf_cplt(ep) (USB->DEVICE.DeviceEndpoint[ep].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_TRCPT(2)) -#define udd_is_OUT_transf_cplt(ep) (USB->DEVICE.DeviceEndpoint[ep].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_TRCPT(1)) -// Clear the transfer complete flag -#define udd_clear_IN_transf_cplt(ep) USB->DEVICE.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT(2) -#define udd_clear_OUT_transf_cplt(ep) USB->DEVICE.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT(1) -// Enable interrupt transfer complete -#define udd_ept_enable_it_IN_transf_cplt(ep) USB->DEVICE.DeviceEndpoint[ep].EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT(2) -#define udd_ept_enable_it_OUT_transf_cplt(ep) USB->DEVICE.DeviceEndpoint[ep].EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT(1) - -// Enables SETUP received interrupt -#define udd_enable_setup_received_interrupt(ep) USB->DEVICE.DeviceEndpoint[ep].EPINTENSET.reg = USB_DEVICE_EPINTFLAG_RXSTP -// Clear the stall flag -#define udd_clear_stall_request(ep) USB->DEVICE.DeviceEndpoint[ep].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_STALL(2) -// Remove stall -#define udd_remove_stall_request(ep) USB->DEVICE.DeviceEndpoint[ep].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ(2) - -// Endpoint Interrupt Summary -#define udd_endpoint_interrupt() USB->DEVICE.EPINTSMRY.reg - -#define udd_clear_wakeup_interrupt() USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTENCLR_WAKEUP -#define udd_clear_eorsm_interrupt() USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTENCLR_EORSM -#define udd_clear_suspend_interrupt() USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTENCLR_SUSPEND - - - -// Force device mode -#define udd_force_device_mode() USB->DEVICE.CTRLA.reg &= ~USB_CTRLA_MODE -// Run in Standby -#define udd_device_run_in_standby() USB->DEVICE.CTRLA.reg |= USB_CTRLA_RUNSTDBY -// Force host mode -#define udd_force_host_mode() USB->DEVICE.CTRLA.reg |= USB_CTRLA_MODE - - -// Enable USB macro -#define udd_enable() USB->DEVICE.CTRLA.reg |= USB_CTRLA_ENABLE -// Disable USB macro -#define udd_disable() USB->DEVICE.CTRLA.reg &= ~USB_CTRLA_ENABLE - -#ifdef __cplusplus -} -#endif - -#endif /* SAMD21_DEVICE_H_INCLUDED */ - diff --git a/cores/arduino/USB/samd21_host.c b/cores/arduino/USB/samd21_host.c index 0ad323134..687cdcb06 100644 --- a/cores/arduino/USB/samd21_host.c +++ b/cores/arduino/USB/samd21_host.c @@ -1,20 +1,20 @@ -/* - Copyright (c) 2014 Arduino. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ +/* + Copyright (c) 2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ #include @@ -22,9 +22,11 @@ #include #include "../Arduino.h" -#include "../wiring_private.h" +#include "variant.h" #include "USB_host.h" #include "samd21_host.h" +#include "sam.h" +#include "wiring_digital.h" #define HOST_DEFINED #ifdef HOST_DEFINED @@ -67,20 +69,20 @@ void UHD_Init(void) uint32_t pad_trim; uint32_t i; - UHD_SetStack(&UHD_Handler); + UHD_SetStack(&UHD_Handler); /* Enable USB clock */ PM->APBBMASK.reg |= PM_APBBMASK_USB; /* Set up the USB DP/DM pins */ - pinPeripheral( PIN_USB_DM, PIO_COM ); - pinPeripheral( PIN_USB_DP, PIO_COM ); -// PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1; -// PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u))); -// PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u)); -// PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1; -// PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u))); -// PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u)); + pinPeripheral( PIN_USB_DM, PIO_COM ); + pinPeripheral( PIN_USB_DP, PIO_COM ); +// PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1; +// PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u))); +// PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u)); +// PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1; +// PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u))); +// PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u)); /* ---------------------------------------------------------------------------------------------- * Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference) @@ -102,9 +104,9 @@ void UHD_Init(void) } // uhd_enable(); - USB->DEVICE.CTRLA.reg |= USB_CTRLA_ENABLE | USB_CTRLA_MODE; + USB->DEVICE.CTRLA.reg |= USB_CTRLA_ENABLE | USB_CTRLA_MODE; uhd_force_host_mode(); - while (USB->HOST.SYNCBUSY.reg == USB_SYNCBUSY_ENABLE); + while (USB->HOST.SYNCBUSY.reg == USB_SYNCBUSY_ENABLE); /* Load Pad Calibration */ pad_transn = (*((uint32_t *)(NVMCTRL_OTP4) // Non-Volatile Memory Controller @@ -183,8 +185,8 @@ void UHD_Handler(void) { uint16_t flags; - if (USB->HOST.CTRLA.bit.MODE) { - /*host mode ISR */ + if (USB->HOST.CTRLA.bit.MODE) { + /*host mode ISR */ /* get interrupt flags */ flags = USB->HOST.INTFLAG.reg; @@ -305,7 +307,7 @@ uhd_vbus_state_t UHD_GetVBUSState(void) */ uint32_t UHD_Pipe0_Alloc(uint32_t ul_add, uint32_t ul_ep_size) { - if( USB->HOST.STATUS.reg & USB_HOST_STATUS_SPEED(1) ) + if( USB->HOST.STATUS.reg & USB_HOST_STATUS_SPEED(1) ) ul_ep_size = USB_PCKSIZE_SIZE_8_BYTES; // Low Speed else ul_ep_size = USB_PCKSIZE_SIZE_64_BYTES; // Full Speed @@ -356,7 +358,7 @@ uint32_t UHD_Pipe_Alloc(uint32_t ul_dev_addr, uint32_t ul_dev_ep, uint32_t ul_ty USB->HOST.HostPipe[ul_dev_ep].PSTATUSCLR.reg = USB_HOST_PSTATUSCLR_BK0RDY; } - if( USB->HOST.STATUS.reg & USB_HOST_STATUS_SPEED(1) ) + if( USB->HOST.STATUS.reg & USB_HOST_STATUS_SPEED(1) ) ul_maxsize = USB_PCKSIZE_SIZE_8_BYTES; // Low Speed else ul_maxsize = USB_PCKSIZE_SIZE_64_BYTES; // Full Speed @@ -373,7 +375,7 @@ uint32_t UHD_Pipe_Alloc(uint32_t ul_dev_addr, uint32_t ul_dev_ep, uint32_t ul_ty void UHD_Pipe_CountZero(uint32_t ul_pipe) { - usb_pipe_table[ul_pipe].HostDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; + usb_pipe_table[ul_pipe].HostDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0; } /** @@ -448,7 +450,7 @@ void UHD_Pipe_Send(uint32_t ul_pipe, uint32_t ul_token_type) /* Start transfer */ if(ul_token_type == USB_HOST_PCFG_PTOKEN_SETUP ) { - USB->HOST.HostPipe[ul_pipe].PINTFLAG.reg = USB_HOST_PINTFLAG_TXSTP; + USB->HOST.HostPipe[ul_pipe].PINTFLAG.reg = USB_HOST_PINTFLAG_TXSTP; USB->HOST.HostPipe[ul_pipe].PSTATUSSET.reg = USB_HOST_PSTATUSSET_BK0RDY; } else if(ul_token_type == USB_HOST_PCFG_PTOKEN_IN ) diff --git a/cores/arduino/USB/samd21_host.h b/cores/arduino/USB/samd21_host.h index 5e2e2c897..d2d9c9e09 100644 --- a/cores/arduino/USB/samd21_host.h +++ b/cores/arduino/USB/samd21_host.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2014 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -28,18 +28,18 @@ extern __attribute__((__aligned__(4))) volatile UsbHostDescriptor usb_pipe_table #define USB_EP_DIR_IN 0x80 // USB_SETUP_DEVICE_TO_HOST #define USB_EP_DIR_OUT 0x00 // USB_SETUP_HOST_TO_DEVICE -#define USB_HOST_PTYPE_DIS USB_HOST_PCFG_PTYPE(0x0) // Pipe is disabled -#define USB_HOST_PTYPE_CTRL USB_HOST_PCFG_PTYPE(0x1) // Pipe is enabled and configured as CONTROL -#define USB_HOST_PTYPE_ISO USB_HOST_PCFG_PTYPE(0x2) // Pipe is enabled and configured as ISO -#define USB_HOST_PTYPE_BULK USB_HOST_PCFG_PTYPE(0x3) // Pipe is enabled and configured as BULK -#define USB_HOST_PTYPE_INT USB_HOST_PCFG_PTYPE(0x4) // Pipe is enabled and configured as INTERRUPT -#define USB_HOST_PTYPE_EXT USB_HOST_PCFG_PTYPE(0x5) // Pipe is enabled and configured as EXTENDED +#define USB_HOST_PTYPE_DIS USB_HOST_PCFG_PTYPE(0x0) // Pipe is disabled +#define USB_HOST_PTYPE_CTRL USB_HOST_PCFG_PTYPE(0x1) // Pipe is enabled and configured as CONTROL +#define USB_HOST_PTYPE_ISO USB_HOST_PCFG_PTYPE(0x2) // Pipe is enabled and configured as ISO +#define USB_HOST_PTYPE_BULK USB_HOST_PCFG_PTYPE(0x3) // Pipe is enabled and configured as BULK +#define USB_HOST_PTYPE_INT USB_HOST_PCFG_PTYPE(0x4) // Pipe is enabled and configured as INTERRUPT +#define USB_HOST_PTYPE_EXT USB_HOST_PCFG_PTYPE(0x5) // Pipe is enabled and configured as EXTENDED #define USB_HOST_NB_BK_1 1 -#define USB_HOST_PCFG_PTOKEN_SETUP USB_HOST_PCFG_PTOKEN(0x0) -#define USB_HOST_PCFG_PTOKEN_IN USB_HOST_PCFG_PTOKEN(0x1) -#define USB_HOST_PCFG_PTOKEN_OUT USB_HOST_PCFG_PTOKEN(0x2) +#define USB_HOST_PCFG_PTOKEN_SETUP USB_HOST_PCFG_PTOKEN(0x0) +#define USB_HOST_PCFG_PTOKEN_IN USB_HOST_PCFG_PTOKEN(0x1) +#define USB_HOST_PCFG_PTOKEN_OUT USB_HOST_PCFG_PTOKEN(0x2) #define USB_ERRORFLOW USB_HOST_STATUS_BK_ERRORFLOW #define USB_ERRORTIMEOUT USB_HOST_STATUS_PIPE_TOUTER @@ -84,7 +84,7 @@ extern __attribute__((__aligned__(4))) volatile UsbHostDescriptor usb_pipe_table #define Is_uhd_sof() (USB->HOST.INTFLAG.reg & USB_HOST_INTFLAG_HSOF) // USB address of pipes -#define uhd_configure_address(pipe_num, addr) usb_pipe_table[pipe_num].HostDescBank[0].CTRL_PIPE.bit.PDADDR = addr +#define uhd_configure_address(pipe_num, addr) usb_pipe_table[pipe_num].HostDescBank[0].CTRL_PIPE.bit.PDADDR = addr #define uhd_get_configured_address(pipe_num) usb_pipe_table[pipe_num].HostDescBank[0].CTRL_PIPE.bit.PDADDR // Pipes @@ -104,7 +104,7 @@ extern __attribute__((__aligned__(4))) volatile UsbHostDescriptor usb_pipe_table #define uhd_ack_out_ready(p) USB->HOST.HostPipe[p].PINTFLAG.reg = USB_HOST_PINTFLAG_TRCPT(1) #define Is_uhd_out_ready(p) ((USB->HOST.HostPipe[p].PINTFLAG.reg&USB_HOST_PINTFLAG_TRCPT(1)) == USB_HOST_PINTFLAG_TRCPT(1)) #define uhd_ack_nak_received(p) usb_pipe_table[p].HostDescBank[1].STATUS_BK.reg &= ~USB_HOST_STATUS_BK_ERRORFLOW -#define Is_uhd_nak_received(p) (usb_pipe_table[p].HostDescBank[1].STATUS_BK.reg & USB_HOST_STATUS_BK_ERRORFLOW) +#define Is_uhd_nak_received(p) (usb_pipe_table[p].HostDescBank[1].STATUS_BK.reg & USB_HOST_STATUS_BK_ERRORFLOW) // Endpoint Interrupt Summary #define uhd_endpoint_interrupt() USB->HOST.PINTSMRY.reg From 3ddf463e89249d10b33e093cf14fa88d83c44551 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 29 Jun 2015 16:52:49 +0200 Subject: [PATCH 02/17] USBDevice: added 'full' flag to USB buffer This way all the 64 bytes available can be filled up --- cores/arduino/USB/CDC.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/cores/arduino/USB/CDC.cpp b/cores/arduino/USB/CDC.cpp index c0e61a893..d68bd8c49 100644 --- a/cores/arduino/USB/CDC.cpp +++ b/cores/arduino/USB/CDC.cpp @@ -37,8 +37,9 @@ struct ring_buffer { uint8_t buffer[CDC_SERIAL_BUFFER_SIZE]; volatile uint32_t head; volatile uint32_t tail; + volatile bool full; }; -ring_buffer cdc_rx_buffer = { { 0 }, 0, 0}; +ring_buffer cdc_rx_buffer = {{0}, 0, 0, false}; typedef struct { uint32_t dwDTERate; @@ -160,19 +161,22 @@ void Serial_::accept(void) // current location of the tail), we're about to overflow the buffer // and so we don't write the character or advance the head. uint32_t k = 0; - i = (i + 1) % CDC_SERIAL_BUFFER_SIZE; - while ((i != ringBuffer->tail) && (len > 0)) { + while (len > 0 && !ringBuffer->full) { len--; - ringBuffer->buffer[ringBuffer->head] = buffer[k++]; - ringBuffer->head = i; - i = (i + 1) % CDC_SERIAL_BUFFER_SIZE; + ringBuffer->buffer[i++] = buffer[k++]; + i %= CDC_SERIAL_BUFFER_SIZE; + if (i == ringBuffer->tail) + ringBuffer->full = true; } + ringBuffer->head = i; interrupts(); } int Serial_::available(void) { ring_buffer *buffer = &cdc_rx_buffer; + if (buffer->full) + return CDC_SERIAL_BUFFER_SIZE; if (buffer->head == buffer->tail) { USB->DEVICE.DeviceEndpoint[2].EPINTENSET.reg = USB_DEVICE_EPINTENCLR_TRCPT(1); } @@ -182,13 +186,9 @@ int Serial_::available(void) int Serial_::peek(void) { ring_buffer *buffer = &cdc_rx_buffer; - - if (buffer->head == buffer->tail) - { + if (buffer->head == buffer->tail && !buffer->full) { return -1; - } - else - { + } else { return buffer->buffer[buffer->tail]; } } @@ -203,12 +203,12 @@ int Serial_::read(void) ring_buffer *buffer = &cdc_rx_buffer; // if the head isn't ahead of the tail, we don't have any characters - if (buffer->head == buffer->tail) + if (buffer->head == buffer->tail && !buffer->full) { if (usb.available(CDC_ENDPOINT_OUT)) accept(); } - if (buffer->head == buffer->tail) + if (buffer->head == buffer->tail && !buffer->full) { return -1; } @@ -216,6 +216,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; From 90d2f8032a671c8250044464fda1d52c97609fe2 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 30 Jun 2015 18:08:49 +0200 Subject: [PATCH 03/17] USB: fix CDC endpoints * fix in_endpoint buffer size (was too big) * use the same EP for CDC_ENDPOINT_OUT and CDC_ENDPOINT_IN (different buffers) * fix CDC_ENDPOINT_IN ep type --- cores/arduino/USB/USBCore.cpp | 20 +++++++++++++------- cores/arduino/USB/USBDesc.h | 4 ++-- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index cfcf101aa..472efc421 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -68,11 +68,11 @@ const DeviceDescriptor USB_DeviceDescriptor = D_DEVICE(0x00, 0x00, 0x00, 64, USB volatile uint32_t _usbConfiguration = 0; volatile uint32_t _usbSetInterface = 0; -static __attribute__((__aligned__(4))) /*__attribute__((__section__(".bss_hram0")))*/ +static __attribute__((__aligned__(8))) //__attribute__((__section__(".bss_hram0"))) uint8_t udd_ep_out_cache_buffer[4][64]; -static __attribute__((__aligned__(4))) /*__attribute__((__section__(".bss_hram0")))*/ -uint8_t udd_ep_in_cache_buffer[4][128]; +static __attribute__((__aligned__(8))) //__attribute__((__section__(".bss_hram0"))) +uint8_t udd_ep_in_cache_buffer[4][64]; //================================================================== @@ -375,7 +375,7 @@ void USBDeviceClass::initEP(uint32_t ep, uint32_t config) { if (config == (USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0))) { - usbd.epBank1SetSize(ep, 8); + usbd.epBank1SetSize(ep, 64); usbd.epBank1SetAddress(ep, &udd_ep_in_cache_buffer[ep]); usbd.epBank1SetType(ep, 4); // INTERRUPT IN } @@ -580,7 +580,13 @@ uint32_t USBDeviceClass::send(uint32_t ep, const void *data, uint32_t len) if (!_usbConfiguration) return -1; - armSend(ep, data, len); + //armSend(ep, data, len); + + /* memcopy could be safer in multithreaded environment */ + memcpy(&udd_ep_in_cache_buffer[ep], data, len); + + usbd.epBank1SetAddress(ep, &udd_ep_in_cache_buffer[ep]); + usbd.epBank1SetByteCount(ep, len); // Clear the transfer complete flag usbd.epBank1AckTransferComplete(ep); @@ -712,9 +718,9 @@ bool USBDeviceClass::handleStandardSetup(Setup &setup) #endif #if defined(CDC_ENABLED) - initEP(CDC_ENDPOINT_ACM, USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0)); + initEP(CDC_ENDPOINT_ACM, USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0)); initEP(CDC_ENDPOINT_OUT, USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0)); - initEP(CDC_ENDPOINT_IN, USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0)); + initEP(CDC_ENDPOINT_IN, USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0)); #endif _usbConfiguration = setup.wValueL; diff --git a/cores/arduino/USB/USBDesc.h b/cores/arduino/USB/USBDesc.h index 655fb6d01..4c3263893 100644 --- a/cores/arduino/USB/USBDesc.h +++ b/cores/arduino/USB/USBDesc.h @@ -28,11 +28,11 @@ #define CDC_DATA_INTERFACE 1 // CDC Data #define CDC_ENDPOINT_ACM 1 #define CDC_ENDPOINT_OUT 2 -#define CDC_ENDPOINT_IN 3 +#define CDC_ENDPOINT_IN 2 // HID #define HID_INTERFACE 2 // HID -#define HID_ENDPOINT_INT 4 +#define HID_ENDPOINT_INT 3 // Defined string description #define IMANUFACTURER 1 From 9d0d5d61586cd285fb838be1a6c17923fc75984e Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 2 Jul 2015 15:43:40 +0200 Subject: [PATCH 04/17] fix back-to-back SerialUSB test --- cores/arduino/USB/CDC.cpp | 7 +++++-- cores/arduino/USB/USBCore.cpp | 24 +++++++++++++----------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/cores/arduino/USB/CDC.cpp b/cores/arduino/USB/CDC.cpp index d68bd8c49..0ecee14a0 100644 --- a/cores/arduino/USB/CDC.cpp +++ b/cores/arduino/USB/CDC.cpp @@ -25,7 +25,7 @@ #ifdef CDC_ENABLED -#define CDC_SERIAL_BUFFER_SIZE 64 +#define CDC_SERIAL_BUFFER_SIZE 256 /* For information purpose only since RTS is not always handled by the terminal application */ #define CDC_LINESTATE_DTR 0x01 // Data Terminal Ready @@ -175,9 +175,12 @@ void Serial_::accept(void) int Serial_::available(void) { ring_buffer *buffer = &cdc_rx_buffer; - if (buffer->full) + if (buffer->full) { + USB->DEVICE.DeviceEndpoint[2].EPINTENSET.reg = ~USB_DEVICE_EPINTENCLR_RXSTP; return CDC_SERIAL_BUFFER_SIZE; + } if (buffer->head == buffer->tail) { + USB->DEVICE.DeviceEndpoint[2].EPINTENSET.reg = USB_DEVICE_EPINTENCLR_RXSTP; USB->DEVICE.DeviceEndpoint[2].EPINTENSET.reg = USB_DEVICE_EPINTENCLR_TRCPT(1); } return (uint32_t)(CDC_SERIAL_BUFFER_SIZE + buffer->head - buffer->tail) % CDC_SERIAL_BUFFER_SIZE; diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index 472efc421..3852e30fb 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -68,10 +68,10 @@ const DeviceDescriptor USB_DeviceDescriptor = D_DEVICE(0x00, 0x00, 0x00, 64, USB volatile uint32_t _usbConfiguration = 0; volatile uint32_t _usbSetInterface = 0; -static __attribute__((__aligned__(8))) //__attribute__((__section__(".bss_hram0"))) +static __attribute__((__aligned__(4))) //__attribute__((__section__(".bss_hram0"))) uint8_t udd_ep_out_cache_buffer[4][64]; -static __attribute__((__aligned__(8))) //__attribute__((__section__(".bss_hram0"))) +static __attribute__((__aligned__(4))) //__attribute__((__section__(".bss_hram0"))) uint8_t udd_ep_in_cache_buffer[4][64]; //================================================================== @@ -502,17 +502,19 @@ uint32_t USBDeviceClass::recv(uint32_t ep, void *_data, uint32_t len) // NAK on endpoint OUT, the bank is full. //usbd.epBank0SetReady(CDC_ENDPOINT_OUT); - uint8_t *buffer = udd_ep_out_cache_buffer[ep]; - uint8_t *data = reinterpret_cast(_data); - for (uint32_t i=0; i(_data); + // for (uint32_t i=0; i= 64) { usbd.epBank0SetByteCount(ep, count - 64); From ffd05f251a9c3b0c31661738a468bd994d328396 Mon Sep 17 00:00:00 2001 From: Jean-Christophe BUDA Date: Fri, 3 Jul 2015 12:12:46 +0200 Subject: [PATCH 05/17] Fix to USBDevice blocking-send --- cores/arduino/USB/CDC.cpp | 4 +-- cores/arduino/USB/USBCore.cpp | 61 ++++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/cores/arduino/USB/CDC.cpp b/cores/arduino/USB/CDC.cpp index 0ecee14a0..f3e4cd70b 100644 --- a/cores/arduino/USB/CDC.cpp +++ b/cores/arduino/USB/CDC.cpp @@ -242,11 +242,11 @@ size_t Serial_::write(const uint8_t *buffer, size_t size) // TODO - ZE - check behavior on different OSes and test what happens if an // open connection isn't broken cleanly (cable is yanked out, host dies // or locks up, or host virtual serial port hangs) -// if (_usbLineInfo.lineState > 0) // Problem with Windows(R) + if (_usbLineInfo.lineState > 0) // Problem with Windows(R) { uint32_t r = usb.send(CDC_ENDPOINT_IN, buffer, size); - if (r > 0) { + if (r == 0) { return r; } else { setWriteError(); diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index 3852e30fb..3792c85cd 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -579,27 +579,64 @@ uint8_t USBDeviceClass::armRecv(uint32_t ep, uint32_t len) // Blocking Send of data to an endpoint uint32_t USBDeviceClass::send(uint32_t ep, const void *data, uint32_t len) { + uint32_t length = 0; + if (!_usbConfiguration) return -1; + if (len > 16384) + return -1; - //armSend(ep, data, len); + if ((unsigned int)data > 0x20000000) + { + // Buffer in RAM + usbd.epBank1SetAddress(ep, (void *)data); + usbd.epBank1SetMultiPacketSize(ep, 0); - /* memcopy could be safer in multithreaded environment */ - memcpy(&udd_ep_in_cache_buffer[ep], data, len); + usbd.epBank1SetByteCount(ep, len); - usbd.epBank1SetAddress(ep, &udd_ep_in_cache_buffer[ep]); - usbd.epBank1SetByteCount(ep, len); + // Clear the transfer complete flag + usbd.epBank1AckTransferComplete(ep); - // Clear the transfer complete flag - usbd.epBank1AckTransferComplete(ep); + // RAM buffer is full, we can send data (IN) + usbd.epBank1SetReady(ep); - // RAM buffer is full, we can send data (IN) - usbd.epBank1SetReady(ep); + // Wait for transfer to complete + while (!usbd.epBank1IsTransferComplete(ep)) { + ; // need fire exit. + } + len = 0; + } + else + { + // Flash area + while (len != 0) + { + if (len >= 64) { + length = 64; + } else { + length = len; + } - // Wait for transfer to complete - while (!usbd.epBank1IsTransferComplete(ep)) { - ; // need fire exit. + /* memcopy could be safer in multi threaded environment */ + memcpy(&udd_ep_in_cache_buffer[ep], data, length); + + usbd.epBank1SetAddress(ep, &udd_ep_in_cache_buffer[ep]); + usbd.epBank1SetByteCount(ep, length); + + // Clear the transfer complete flag + usbd.epBank1AckTransferComplete(ep); + + // RAM buffer is full, we can send data (IN) + usbd.epBank1SetReady(ep); + + // Wait for transfer to complete + while (!usbd.epBank1IsTransferComplete(ep)) { + ; // need fire exit. + } + len -= length; + } } + return len; } From ff8bc8996a43f8c628d84671b36262e5cf054654 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Fri, 3 Jul 2015 15:54:26 +0200 Subject: [PATCH 06/17] use different EP for CDC IN and OUT --- cores/arduino/USB/CDC.cpp | 2 -- cores/arduino/USB/USBDesc.h | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cores/arduino/USB/CDC.cpp b/cores/arduino/USB/CDC.cpp index f3e4cd70b..944073336 100644 --- a/cores/arduino/USB/CDC.cpp +++ b/cores/arduino/USB/CDC.cpp @@ -176,11 +176,9 @@ int Serial_::available(void) { ring_buffer *buffer = &cdc_rx_buffer; if (buffer->full) { - USB->DEVICE.DeviceEndpoint[2].EPINTENSET.reg = ~USB_DEVICE_EPINTENCLR_RXSTP; return CDC_SERIAL_BUFFER_SIZE; } if (buffer->head == buffer->tail) { - USB->DEVICE.DeviceEndpoint[2].EPINTENSET.reg = USB_DEVICE_EPINTENCLR_RXSTP; USB->DEVICE.DeviceEndpoint[2].EPINTENSET.reg = USB_DEVICE_EPINTENCLR_TRCPT(1); } return (uint32_t)(CDC_SERIAL_BUFFER_SIZE + buffer->head - buffer->tail) % CDC_SERIAL_BUFFER_SIZE; diff --git a/cores/arduino/USB/USBDesc.h b/cores/arduino/USB/USBDesc.h index 4c3263893..655fb6d01 100644 --- a/cores/arduino/USB/USBDesc.h +++ b/cores/arduino/USB/USBDesc.h @@ -28,11 +28,11 @@ #define CDC_DATA_INTERFACE 1 // CDC Data #define CDC_ENDPOINT_ACM 1 #define CDC_ENDPOINT_OUT 2 -#define CDC_ENDPOINT_IN 2 +#define CDC_ENDPOINT_IN 3 // HID #define HID_INTERFACE 2 // HID -#define HID_ENDPOINT_INT 3 +#define HID_ENDPOINT_INT 4 // Defined string description #define IMANUFACTURER 1 From 660809176825fedbab60ffc0cbae13c3452898cd Mon Sep 17 00:00:00 2001 From: Jean-Christophe BUDA Date: Fri, 3 Jul 2015 16:29:56 +0200 Subject: [PATCH 07/17] HID class fixes --- cores/arduino/USB/HID.cpp | 4 +--- cores/arduino/USB/USBCore.cpp | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cores/arduino/USB/HID.cpp b/cores/arduino/USB/HID.cpp index 45208b2d8..edcc2167c 100644 --- a/cores/arduino/USB/HID.cpp +++ b/cores/arduino/USB/HID.cpp @@ -190,8 +190,6 @@ bool HID_Setup(Setup& setup) if (HID_GET_IDLE == r) { USBDevice.armSend(0, &_hid_idle, 1); - // RAM buffer is full, we can send data (IN) - USB->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.BK1RDY = 1; return true; } } @@ -207,7 +205,7 @@ bool HID_Setup(Setup& setup) if (HID_SET_IDLE == r) { _hid_idle = setup.wValueH; - return true; + return false; } } return false; diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index 3792c85cd..3baf7cc50 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -361,7 +361,7 @@ bool USBDeviceClass::handleClassInterfaceSetup(Setup& setup) #if defined(HID_ENABLED) if (HID_INTERFACE == i) { - if (HID_Setup(setup) == true) { + if (HID_Setup(setup) == false) { sendZlp(0); } return true; From fe4d51f851eb15701a41249da99eb020026bef64 Mon Sep 17 00:00:00 2001 From: Jean-Christophe BUDA Date: Wed, 8 Jul 2015 16:41:58 +0200 Subject: [PATCH 08/17] Update for host and Device USB --- cores/arduino/USB/USBCore.cpp | 60 ++++++++++--------------------- cores/arduino/USB/USB_interrupt.c | 30 ++++++++++++++++ cores/arduino/USB/samd21_host.c | 16 +++++---- libraries/USBHost/src/Usb.cpp | 4 +-- 4 files changed, 60 insertions(+), 50 deletions(-) create mode 100644 cores/arduino/USB/USB_interrupt.c diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index 3baf7cc50..b9ba77e4e 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -29,6 +29,15 @@ USBDevice_SAMD21G18x usbd; static char isRemoteWakeUpEnabled = 0; static char isEndpointHalt = 0; +extern void (*gpf_isr)(void); + +// USB_Handler ISR +extern "C" void UDD_Handler(void) { + USBDevice.ISRHandler(); +} + + + const uint16_t STRING_LANGUAGE[2] = { (3<<8) | (2+2), 0x0409 // English @@ -285,6 +294,8 @@ void USBDeviceClass::init() while (GCLK->STATUS.bit.SYNCBUSY) ; + UHD_SetStack(&UDD_Handler); + // Reset USB Device usbd.reset(); @@ -388,9 +399,6 @@ void USBDeviceClass::initEP(uint32_t ep, uint32_t config) // Release OUT EP usbd.epBank0SetMultiPacketSize(ep, 64); usbd.epBank0SetByteCount(ep, 0); - - // The RAM Buffer is empty: we can receive data - //usbd.epBank0ResetReady(ep); } else if (config == (USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0))) { @@ -405,12 +413,12 @@ void USBDeviceClass::initEP(uint32_t ep, uint32_t config) else if (config == USB_ENDPOINT_TYPE_CONTROL) { // XXX: Needed? - usbd.epBank0DisableAutoZLP(ep); - usbd.epBank1DisableAutoZLP(ep); +// usbd.epBank0DisableAutoZLP(ep); +// usbd.epBank1DisableAutoZLP(ep); // Setup Control OUT usbd.epBank0SetSize(ep, 64); - usbd.epBank0SetAddress(ep, &udd_ep_out_cache_buffer[0]); + usbd.epBank0SetAddress(ep, &udd_ep_out_cache_buffer[ep]); usbd.epBank0SetType(ep, 1); // CONTROL OUT / SETUP // Setup Control IN @@ -424,8 +432,6 @@ void USBDeviceClass::initEP(uint32_t ep, uint32_t config) // NAK on endpoint OUT, the bank is full. usbd.epBank0SetReady(ep); - // NAK on endpoint IN, the bank is not yet filled in. - //usbd.epBank1ResetReady(ep); } } @@ -461,7 +467,6 @@ bool USBDeviceClass::connected() uint32_t USBDeviceClass::recvControl(void *_data, uint32_t len) { uint8_t *data = reinterpret_cast(_data); -// NO RXOUT ??????? // The RAM Buffer is empty: we can receive data usbd.epBank0ResetReady(0); @@ -499,17 +504,8 @@ uint32_t USBDeviceClass::recv(uint32_t ep, void *_data, uint32_t len) usbd.epBank0DisableTransferComplete(ep); - // NAK on endpoint OUT, the bank is full. - //usbd.epBank0SetReady(CDC_ENDPOINT_OUT); - memcpy(_data, udd_ep_out_cache_buffer[ep], len); - // uint8_t *buffer = udd_ep_out_cache_buffer[ep]; - // uint8_t *data = reinterpret_cast(_data); - // for (uint32_t i=0; iDEVICE.DeviceEndpoint[ep].EPINTFLAG.bit.TRCPT == 0); + while (!usbd.epBank0IsTransferComplete(ep)) {} return usbd.epBank0ByteCount(ep); } uint8_t USBDeviceClass::armRecv(uint32_t ep, uint32_t len) { - //usbd.epBank0SetSize(ep, 64); - //usbd.epBank0SetAddress(ep, &udd_ep_out_cache_buffer[ep]); - //usbd.epBank0SetMultiPacketSize(ep, 64); // XXX: Should be "len"? uint16_t count = usbd.epBank0ByteCount(ep); if (count >= 64) { usbd.epBank0SetByteCount(ep, count - 64); } else { usbd.epBank0SetByteCount(ep, 0); } - // The RAM Buffer is empty: we can receive data - //usbd.epBank0ResetReady(ep); - - // Wait for transfer to complete - //while (!usbd.epBank0IsTransferComplete(ep)) {} - //while (usbd.epBank0IsReady(ep)) {} - // NAK on endpoint OUT, the bank is full. - //usbd.epBank0ResetReady(ep); - return usbd.epBank0ByteCount(ep); } @@ -837,8 +816,7 @@ void USBDeviceClass::ISRHandler() stall(0); } - // XXX: Should be really cleared? - if (usbd.epBank1IsStalled(0)) // XXX:(USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.STALL) + if (usbd.epBank1IsStalled(0)) { usbd.epBank1AckStalled(0); @@ -878,6 +856,6 @@ void USBDeviceClass::ISRHandler() USBDeviceClass USBDevice; // USB_Handler ISR -extern "C" void USB_Handler(void) { - USBDevice.ISRHandler(); -} +// extern "C" void USB_Handler(void) { +// USBDevice.ISRHandler(); +// } diff --git a/cores/arduino/USB/USB_interrupt.c b/cores/arduino/USB/USB_interrupt.c new file mode 100644 index 000000000..09f7a81a8 --- /dev/null +++ b/cores/arduino/USB/USB_interrupt.c @@ -0,0 +1,30 @@ +/* + Copyright (c) 2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +void (*gpf_isr)(void) = (0UL); + +void USB_Handler( void ) +{ + if (gpf_isr) + gpf_isr(); +} + +void UHD_SetStack(void (*pf_isr)(void)) +{ + gpf_isr = pf_isr; +} diff --git a/cores/arduino/USB/samd21_host.c b/cores/arduino/USB/samd21_host.c index 687cdcb06..350a38108 100644 --- a/cores/arduino/USB/samd21_host.c +++ b/cores/arduino/USB/samd21_host.c @@ -34,8 +34,6 @@ //#define TRACE_UOTGHS_HOST(x) x #define TRACE_UOTGHS_HOST(x) -//extern void (*gpf_isr)(void); - // Handle UOTGHS Host driver state static uhd_vbus_state_t uhd_state = UHD_STATE_NO_VBUS; @@ -43,10 +41,6 @@ __attribute__((__aligned__(4))) volatile UsbHostDescriptor usb_pipe_table[USB_EP extern void (*gpf_isr)(void); -void UHD_SetStack(void (*pf_isr)(void)) -{ - gpf_isr = pf_isr; -} // NVM Software Calibration Area Mapping // USB TRANSN calibration value. Should be written to the USB PADCAL register. @@ -180,7 +174,6 @@ void UHD_Init(void) /** * \brief Interrupt sub routine for USB Host state machine management. */ -//static void UHD_ISR(void) void UHD_Handler(void) { uint16_t flags; @@ -518,4 +511,13 @@ uint32_t UHD_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type) return 0; } + + + + +// USB_Handler ISR +// void USB_Handler(void) { +// UHD_Handler(); +// } + #endif // HOST_DEFINED diff --git a/libraries/USBHost/src/Usb.cpp b/libraries/USBHost/src/Usb.cpp index 6c1570b82..38b73805e 100644 --- a/libraries/USBHost/src/Usb.cpp +++ b/libraries/USBHost/src/Usb.cpp @@ -21,7 +21,7 @@ e-mail : support@circuitsathome.com #include "Usb.h" -#ifdef ARDUINO_SAMD_ZERO +//#ifdef ARDUINO_SAMD_ZERO static uint32_t usb_error = 0; static uint32_t usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; @@ -854,4 +854,4 @@ uint32_t USBHost::setConf(uint32_t addr, uint32_t ep, uint32_t conf_value) { return ( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL)); } -#endif //ARDUINO_SAMD_ZERO +//#endif //ARDUINO_SAMD_ZERO From e748f0985f3d56c6d82b391601bbea25b8f39ae9 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 8 Jul 2015 17:31:43 +0200 Subject: [PATCH 09/17] Moved USB ISR handler in startup.c --- cores/arduino/USB/USBCore.cpp | 2 +- cores/arduino/USB/USB_host.h | 2 +- cores/arduino/USB/USB_interrupt.c | 30 ------------------------------ cores/arduino/USB/samd21_host.c | 2 +- cores/arduino/cortex_handlers.c | 21 +++++++++++++++++---- cores/arduino/startup.c | 3 ++- 6 files changed, 22 insertions(+), 38 deletions(-) delete mode 100644 cores/arduino/USB/USB_interrupt.c diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index b9ba77e4e..557210c3e 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -294,7 +294,7 @@ void USBDeviceClass::init() while (GCLK->STATUS.bit.SYNCBUSY) ; - UHD_SetStack(&UDD_Handler); + USB_SetHandler(&UDD_Handler); // Reset USB Device usbd.reset(); diff --git a/cores/arduino/USB/USB_host.h b/cores/arduino/USB/USB_host.h index 390e3dd1e..319dffea5 100644 --- a/cores/arduino/USB/USB_host.h +++ b/cores/arduino/USB/USB_host.h @@ -48,7 +48,7 @@ typedef enum { extern void UHD_Init(void); extern void UHD_Handler(void); -extern void UHD_SetStack(void (*pf_isr)(void)); +extern void USB_SetHandler(void (*pf_isr)(void)); extern uhd_vbus_state_t UHD_GetVBUSState(void); extern uint32_t UHD_Pipe0_Alloc(uint32_t ul_add, uint32_t ul_ep_size); extern uint32_t UHD_Pipe_Alloc(uint32_t ul_dev_addr, uint32_t ul_dev_ep, uint32_t ul_type, uint32_t ul_dir, uint32_t ul_maxsize, uint32_t ul_interval, uint32_t ul_nb_bank); diff --git a/cores/arduino/USB/USB_interrupt.c b/cores/arduino/USB/USB_interrupt.c deleted file mode 100644 index 09f7a81a8..000000000 --- a/cores/arduino/USB/USB_interrupt.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - Copyright (c) 2014 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -void (*gpf_isr)(void) = (0UL); - -void USB_Handler( void ) -{ - if (gpf_isr) - gpf_isr(); -} - -void UHD_SetStack(void (*pf_isr)(void)) -{ - gpf_isr = pf_isr; -} diff --git a/cores/arduino/USB/samd21_host.c b/cores/arduino/USB/samd21_host.c index 350a38108..229f738df 100644 --- a/cores/arduino/USB/samd21_host.c +++ b/cores/arduino/USB/samd21_host.c @@ -63,7 +63,7 @@ void UHD_Init(void) uint32_t pad_trim; uint32_t i; - UHD_SetStack(&UHD_Handler); + USB_SetHandler(&UHD_Handler); /* Enable USB clock */ PM->APBBMASK.reg |= PM_APBBMASK_USB; diff --git a/cores/arduino/cortex_handlers.c b/cores/arduino/cortex_handlers.c index fed128c44..435736c59 100644 --- a/cores/arduino/cortex_handlers.c +++ b/cores/arduino/cortex_handlers.c @@ -16,8 +16,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "sam.h" -#include "variant.h" +#include +#include +#include /* RTOS Hooks */ extern void svcHook(void); @@ -25,7 +26,6 @@ extern void pendSVHook(void); extern int sysTickHook(void); /* Default empty handler */ - void Dummy_Handler(void) { #if defined DEBUG @@ -50,7 +50,7 @@ void RTC_Handler (void) __attribute__ ((weak, alias("Dummy_Handler"))); void EIC_Handler (void) __attribute__ ((weak, alias("Dummy_Handler"))); void NVMCTRL_Handler (void) __attribute__ ((weak, alias("Dummy_Handler"))); void DMAC_Handler (void) __attribute__ ((weak, alias("Dummy_Handler"))); -void USB_Handler (void) __attribute__ ((weak, alias("Dummy_Handler"))); +void USB_Handler (void) __attribute__ ((weak)); void EVSYS_Handler (void) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM0_Handler (void) __attribute__ ((weak, alias("Dummy_Handler"))); void SERCOM1_Handler (void) __attribute__ ((weak, alias("Dummy_Handler"))); @@ -176,3 +176,16 @@ void SysTick_Handler(void) return; SysTick_DefaultHandler(); } + +static void (*usb_isr)(void) = NULL; + +void USB_Handler(void) +{ + if (usb_isr) + usb_isr(); +} + +void USB_SetHandler(void (*new_usb_isr)(void)) +{ + usb_isr = new_usb_isr; +} diff --git a/cores/arduino/startup.c b/cores/arduino/startup.c index 9a43b4a8e..4ffdae28f 100644 --- a/cores/arduino/startup.c +++ b/cores/arduino/startup.c @@ -19,6 +19,8 @@ #include "sam.h" #include "variant.h" +#include + /** * \brief SystemInit() configures the needed clocks and according Flash Read Wait States. * At reset: @@ -222,4 +224,3 @@ void SystemInit( void ) ADC->CALIB.reg = ADC_CALIB_BIAS_CAL(bias) | ADC_CALIB_LINEARITY_CAL(linearity); } - From a6fa8329aacb80094b7d285112b8395701f743fa Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 17 Jul 2015 11:01:26 +0200 Subject: [PATCH 10/17] Fixed a lot of warnings in USBHost --- cores/arduino/USB/CDC.cpp | 6 ++- cores/arduino/USB/samd21_host.c | 5 ++- libraries/USBHost/src/MouseController.cpp | 42 ++++++++++---------- libraries/USBHost/src/Usb.cpp | 2 +- libraries/USBHost/src/Usb.h | 2 - libraries/USBHost/src/UsbCore.h | 10 ++--- libraries/USBHost/src/adk.cpp | 2 +- libraries/USBHost/src/confdescparser.h | 2 +- libraries/USBHost/src/hidboot.cpp | 4 +- libraries/USBHost/src/hidboot.h | 22 +++++----- libraries/USBHost/src/hidescriptorparser.cpp | 4 +- libraries/USBHost/src/hiduniversal.h | 2 +- libraries/USBHost/src/message.h | 14 +++++-- libraries/USBHost/src/printhex.h | 13 ++++-- libraries/USBHost/src/sink_parser.h | 2 +- libraries/USBHost/src/usbhub.cpp | 2 +- 16 files changed, 74 insertions(+), 60 deletions(-) diff --git a/cores/arduino/USB/CDC.cpp b/cores/arduino/USB/CDC.cpp index 944073336..daca74cc6 100644 --- a/cores/arduino/USB/CDC.cpp +++ b/cores/arduino/USB/CDC.cpp @@ -135,12 +135,14 @@ bool CDC_Setup(Setup& setup) } uint32_t _serialPeek = -1; -void Serial_::begin(uint32_t baud_count) +void Serial_::begin(uint32_t /* baud_count */) { + // uart config is ignored in USB-CDC } -void Serial_::begin(uint32_t baud_count, uint8_t config) +void Serial_::begin(uint32_t /* baud_count */, uint8_t /* config */) { + // uart config is ignored in USB-CDC } void Serial_::end(void) diff --git a/cores/arduino/USB/samd21_host.c b/cores/arduino/USB/samd21_host.c index 229f738df..895adced6 100644 --- a/cores/arduino/USB/samd21_host.c +++ b/cores/arduino/USB/samd21_host.c @@ -27,6 +27,7 @@ #include "samd21_host.h" #include "sam.h" #include "wiring_digital.h" +#include "wiring_private.h" #define HOST_DEFINED #ifdef HOST_DEFINED @@ -298,8 +299,10 @@ uhd_vbus_state_t UHD_GetVBUSState(void) * \retval 0 success. * \retval 1 error. */ -uint32_t UHD_Pipe0_Alloc(uint32_t ul_add, uint32_t ul_ep_size) +uint32_t UHD_Pipe0_Alloc(uint32_t ul_add , uint32_t ul_ep_size) { + (void)(ul_add); // Unused argument + if( USB->HOST.STATUS.reg & USB_HOST_STATUS_SPEED(1) ) ul_ep_size = USB_PCKSIZE_SIZE_8_BYTES; // Low Speed else diff --git a/libraries/USBHost/src/MouseController.cpp b/libraries/USBHost/src/MouseController.cpp index 3d528bc37..0912a0374 100644 --- a/libraries/USBHost/src/MouseController.cpp +++ b/libraries/USBHost/src/MouseController.cpp @@ -1,19 +1,19 @@ /* - Copyright (c) 2012 Arduino. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2015 Arduino LLC. All right reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include @@ -49,35 +49,35 @@ void MouseController::OnMouseMove(MOUSEINFO *mi) { mouseMoved(); } -void MouseController::OnLeftButtonUp(MOUSEINFO *mi) { +void MouseController::OnLeftButtonUp(MOUSEINFO * /* mi */) { buttons &= ~LEFT_BUTTON; mouseReleased(); mouseClicked(); } -void MouseController::OnLeftButtonDown(MOUSEINFO *mi) { +void MouseController::OnLeftButtonDown(MOUSEINFO * /* mi */) { buttons |= LEFT_BUTTON; mousePressed(); } -void MouseController::OnMiddleButtonUp(MOUSEINFO *mi) { +void MouseController::OnMiddleButtonUp(MOUSEINFO * /* mi */) { buttons &= ~MIDDLE_BUTTON; mouseReleased(); mouseClicked(); } -void MouseController::OnMiddleButtonDown(MOUSEINFO *mi) { +void MouseController::OnMiddleButtonDown(MOUSEINFO * /* mi */) { buttons |= MIDDLE_BUTTON; mousePressed(); } -void MouseController::OnRightButtonUp(MOUSEINFO *mi) { +void MouseController::OnRightButtonUp(MOUSEINFO * /* mi */) { buttons &= ~RIGHT_BUTTON; mouseReleased(); mouseClicked(); } -void MouseController::OnRightButtonDown(MOUSEINFO *mi) { +void MouseController::OnRightButtonDown(MOUSEINFO * /* mi */) { buttons |= RIGHT_BUTTON; mousePressed(); } diff --git a/libraries/USBHost/src/Usb.cpp b/libraries/USBHost/src/Usb.cpp index 38b73805e..cdde1a670 100644 --- a/libraries/USBHost/src/Usb.cpp +++ b/libraries/USBHost/src/Usb.cpp @@ -340,7 +340,7 @@ uint32_t USBHost::OutTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t nbytes, for( i=0; ibmSndToggle) diff --git a/libraries/USBHost/src/Usb.h b/libraries/USBHost/src/Usb.h index 40bed77ed..919b83523 100644 --- a/libraries/USBHost/src/Usb.h +++ b/libraries/USBHost/src/Usb.h @@ -22,8 +22,6 @@ e-mail : support@circuitsathome.com #include -#define ARDUINO 101 - //#include "Arduino.h" #include "macros.h" // None of these should ever be included by a driver, or a user's sketch. diff --git a/libraries/USBHost/src/UsbCore.h b/libraries/USBHost/src/UsbCore.h index fdb14c1c1..6382e8dc9 100644 --- a/libraries/USBHost/src/UsbCore.h +++ b/libraries/USBHost/src/UsbCore.h @@ -119,11 +119,11 @@ typedef MAX3421e MAX3421E; // Balanduino class USBDeviceConfig { public: - virtual uint32_t Init(uint32_t parent, uint32_t port, uint32_t lowspeed) { + virtual uint32_t Init(uint32_t /* parent */, uint32_t /* port */, uint32_t /* lowspeed */) { return 0; } - virtual uint32_t ConfigureDevice(uint32_t parent, uint32_t port, uint32_t lowspeed) { + virtual uint32_t ConfigureDevice(uint32_t /* parent */, uint32_t /* port */, uint32_t /* lowspeed */) { return 0; } @@ -139,15 +139,15 @@ class USBDeviceConfig { return 0; } - virtual void ResetHubPort(uint32_t port) { + virtual void ResetHubPort(uint32_t /* port */) { return; } // Note used for hubs only! - virtual uint32_t VIDPIDOK(uint32_t vid, uint32_t pid) { + virtual uint32_t VIDPIDOK(uint32_t /* vid */, uint32_t /* pid */) { return false; } - virtual uint32_t DEVCLASSOK(uint32_t klass) { + virtual uint32_t DEVCLASSOK(uint32_t /* klass */) { return false; } }; diff --git a/libraries/USBHost/src/adk.cpp b/libraries/USBHost/src/adk.cpp index e271cb4a4..165f50c3d 100644 --- a/libraries/USBHost/src/adk.cpp +++ b/libraries/USBHost/src/adk.cpp @@ -347,7 +347,7 @@ uint32_t ADK::Init(uint32_t parent, uint32_t port, uint32_t lowspeed) { } /* Extracts bulk-IN and bulk-OUT endpoint information from config descriptor */ -void ADK::EndpointXtract(uint32_t conf, uint32_t iface, uint32_t alt, uint32_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) { +void ADK::EndpointXtract(uint32_t conf, uint32_t /* iface */, uint32_t /* alt */, uint32_t /* proto */, const USB_ENDPOINT_DESCRIPTOR *pep) { //ErrorMessage(PSTR("Conf.Val"), conf); //ErrorMessage(PSTR("Iface Num"), iface); //ErrorMessage(PSTR("Alt.Set"), alt); diff --git a/libraries/USBHost/src/confdescparser.h b/libraries/USBHost/src/confdescparser.h index 6ee6a1eef..4b2b41b4f 100644 --- a/libraries/USBHost/src/confdescparser.h +++ b/libraries/USBHost/src/confdescparser.h @@ -85,7 +85,7 @@ UseOr(false) { }; template -void ConfigDescParser::Parse(const uint32_t len, const uint8_t *pbuf, const uint32_t &offset) { +void ConfigDescParser::Parse(const uint32_t len, const uint8_t *pbuf, const uint32_t & /* offset */) { uint32_t cntdn = len; uint8_t *p = (uint8_t*)pbuf; diff --git a/libraries/USBHost/src/hidboot.cpp b/libraries/USBHost/src/hidboot.cpp index 9f6b8743a..ea59f39fb 100644 --- a/libraries/USBHost/src/hidboot.cpp +++ b/libraries/USBHost/src/hidboot.cpp @@ -16,7 +16,7 @@ e-mail : support@circuitsathome.com */ #include "hidboot.h" -void MouseReportParser::Parse(HID *hid, uint32_t is_rpt_id, uint32_t len, uint8_t *buf) { +void MouseReportParser::Parse(HID * /* hid */, uint32_t /* is_rpt_id */, uint32_t /* len */, uint8_t *buf) { MOUSEINFO *pmi = (MOUSEINFO*)buf; // Future: // bool event; @@ -124,7 +124,7 @@ void MouseReportParser::Parse(HID *hid, uint32_t is_rpt_id, uint32_t len, uint8_ }; -void KeyboardReportParser::Parse(HID *hid, uint32_t is_rpt_id, uint32_t len, uint8_t *buf) { +void KeyboardReportParser::Parse(HID *hid, uint32_t /* is_rpt_id */, uint32_t /* len */, uint8_t *buf) { // On error - return if (buf[2] == 1) return; diff --git a/libraries/USBHost/src/hidboot.h b/libraries/USBHost/src/hidboot.h index 621ce57ac..1aa98e1af 100644 --- a/libraries/USBHost/src/hidboot.h +++ b/libraries/USBHost/src/hidboot.h @@ -64,25 +64,25 @@ class MouseReportParser : public HIDReportParser { protected: - virtual void OnMouseMove(MOUSEINFO *mi) { + virtual void OnMouseMove(MOUSEINFO *) { }; - virtual void OnLeftButtonUp(MOUSEINFO *mi) { + virtual void OnLeftButtonUp(MOUSEINFO *) { }; - virtual void OnLeftButtonDown(MOUSEINFO *mi) { + virtual void OnLeftButtonDown(MOUSEINFO *) { }; - virtual void OnRightButtonUp(MOUSEINFO *mi) { + virtual void OnRightButtonUp(MOUSEINFO *) { }; - virtual void OnRightButtonDown(MOUSEINFO *mi) { + virtual void OnRightButtonDown(MOUSEINFO *) { }; - virtual void OnMiddleButtonUp(MOUSEINFO *mi) { + virtual void OnMiddleButtonUp(MOUSEINFO *) { }; - virtual void OnMiddleButtonDown(MOUSEINFO *mi) { + virtual void OnMiddleButtonDown(MOUSEINFO *) { }; }; @@ -153,13 +153,13 @@ class KeyboardReportParser : public HIDReportParser { protected: virtual uint8_t HandleLockingKeys(HID* hid, uint8_t key); - virtual void OnControlKeysChanged(uint8_t before, uint8_t after) { + virtual void OnControlKeysChanged(uint8_t /* before */, uint8_t /* after */) { }; - virtual void OnKeyDown(uint8_t mod, uint8_t key) { + virtual void OnKeyDown(uint8_t /* mod */, uint8_t /* key */) { }; - virtual void OnKeyUp(uint8_t mod, uint8_t key) { + virtual void OnKeyUp(uint8_t /* mod */, uint8_t /* key */) { }; virtual const uint8_t *getNumKeys() { @@ -520,7 +520,7 @@ uint32_t HIDBoot::Init(uint32_t parent, uint32_t port, uint32_t l } template -void HIDBoot::EndpointXtract(uint32_t conf, uint32_t iface, uint32_t alt, uint32_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) { +void HIDBoot::EndpointXtract(uint32_t conf, uint32_t iface, uint32_t /* alt */, uint32_t /* proto */, const USB_ENDPOINT_DESCRIPTOR *pep) { // If the first configuration satisfies, the others are not considered. //if(bNumEP > 1 && conf != bConfNum) if(bNumEP == totalEndpoints(BOOT_PROTOCOL)) diff --git a/libraries/USBHost/src/hidescriptorparser.cpp b/libraries/USBHost/src/hidescriptorparser.cpp index 1e30d08eb..353874300 100644 --- a/libraries/USBHost/src/hidescriptorparser.cpp +++ b/libraries/USBHost/src/hidescriptorparser.cpp @@ -990,7 +990,7 @@ const char * const ReportDescParserBase::medInstrTitles4[] PROGMEM = { pstrUsageSoftControlAdjust }; -void ReportDescParserBase::Parse(const uint32_t len, const uint8_t *pbuf, const uint32_t &offset) { +void ReportDescParserBase::Parse(const uint32_t len, const uint8_t *pbuf, const uint32_t & /* offset */) { uint32_t cntdn = (uint32_t)len; uint8_t *p = (uint8_t*)pbuf; @@ -1589,7 +1589,7 @@ void ReportDescParser2::OnInputItem(uint8_t itm) { E_Notify(PSTR("\r\n"), 0x80); } -void UniversalReportParser::Parse(HID *hid, uint32_t is_rpt_id, uint32_t len, uint8_t *buf) { +void UniversalReportParser::Parse(HID *hid, uint32_t /* is_rpt_id */, uint32_t len, uint8_t *buf) { ReportDescParser2 prs(len, buf); uint8_t ret = hid->GetReportDescr(0, &prs); diff --git a/libraries/USBHost/src/hiduniversal.h b/libraries/USBHost/src/hiduniversal.h index b0e7958a6..3387619e9 100644 --- a/libraries/USBHost/src/hiduniversal.h +++ b/libraries/USBHost/src/hiduniversal.h @@ -75,7 +75,7 @@ class HIDUniversal : public HID { return 0; }; - virtual void ParseHIDData(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) { + virtual void ParseHIDData(HID * /* hid */, bool /* is_rpt_id */, uint8_t /* len */, uint8_t * /* buf */) { return; }; diff --git a/libraries/USBHost/src/message.h b/libraries/USBHost/src/message.h index 41f526de2..6144b56de 100644 --- a/libraries/USBHost/src/message.h +++ b/libraries/USBHost/src/message.h @@ -55,24 +55,30 @@ void NotifyFail(uint8_t rcode); #define NotifyFail(...) ((void)0) #endif +#ifdef DEBUG_USB_HOST template void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) { -#ifdef DEBUG_USB_HOST Notify(msg, level); Notify(PSTR(": "), level); D_PrintHex (rcode, level); Notify(PSTR("\r\n"), level); -#endif } template void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0) { -#ifdef DEBUG_USB_HOST Notify(msg, 0x80); Notify(PSTR(": "), 0x80); D_PrintHex (rcode, 0x80); Notify(PSTR("\r\n"), 0x80); -#endif } +#else +template +void ErrorMessage(uint8_t, char const *, ERROR_TYPE = 0) { +} + +template +void ErrorMessage(char const *, ERROR_TYPE = 0) { +} +#endif #endif // __MESSAGE_H__ diff --git a/libraries/USBHost/src/printhex.h b/libraries/USBHost/src/printhex.h index 369d7e1f7..98c1ae602 100644 --- a/libraries/USBHost/src/printhex.h +++ b/libraries/USBHost/src/printhex.h @@ -66,18 +66,23 @@ void PrintHex2(Print *prn, T val) { prn->print((T)val, HEX); } -template void D_PrintHex(T val, int lvl) { #ifdef DEBUG_USB_HOST +template void D_PrintHex(T val, int lvl) { PrintHex (val, lvl); -#endif } template void D_PrintBin(T val, int lvl) { -#ifdef DEBUG_USB_HOST PrintBin (val, lvl); -#endif } +#else +template void D_PrintHex(T, int) { +} + +template +void D_PrintBin(T, int) { +} +#endif diff --git a/libraries/USBHost/src/sink_parser.h b/libraries/USBHost/src/sink_parser.h index a23637d2b..f1c7386a3 100644 --- a/libraries/USBHost/src/sink_parser.h +++ b/libraries/USBHost/src/sink_parser.h @@ -33,7 +33,7 @@ class SinkParser : public BASE_CLASS { void Initialize() { }; - void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset) { + void Parse(const LEN_TYPE /* len */, const uint8_t * /* pbuf */, const OFFSET_TYPE & /* offset */) { }; }; diff --git a/libraries/USBHost/src/usbhub.cpp b/libraries/USBHost/src/usbhub.cpp index a6aebd973..1f6aa712b 100644 --- a/libraries/USBHost/src/usbhub.cpp +++ b/libraries/USBHost/src/usbhub.cpp @@ -374,7 +374,7 @@ uint32_t USBHub::PortStatusChange(uint32_t port, HubEvent &evt) { return 0; } -void PrintHubPortStatus(USBHub *hubptr, uint32_t addr, uint32_t port, uint32_t print_changes) { +void PrintHubPortStatus(USBHub *hubptr, uint32_t /* addr */, uint32_t port, uint32_t print_changes) { uint8_t rcode = 0; HubEvent evt; From 45d787ddb699a9fa5258a73b76f9a422de73a0bb Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 17 Jul 2015 11:26:46 +0200 Subject: [PATCH 11/17] Removed some unused warning in USB-Core --- cores/arduino/USB/USBAPI.h | 4 ++-- cores/arduino/USB/USBCore.cpp | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cores/arduino/USB/USBAPI.h b/cores/arduino/USB/USBAPI.h index b2d9d510b..bbb0a3e03 100644 --- a/cores/arduino/USB/USBAPI.h +++ b/cores/arduino/USB/USBAPI.h @@ -90,8 +90,8 @@ class USBDeviceClass { // private? uint32_t armSend(uint32_t ep, const void *data, uint32_t len); - uint8_t armRecv(uint32_t ep, uint32_t len); - uint8_t armRecvCtrlOUT(uint32_t ep, uint32_t len); + uint8_t armRecv(uint32_t ep); + uint8_t armRecvCtrlOUT(uint32_t ep); void ISRHandler(); diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index 557210c3e..99009e835 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -472,7 +472,7 @@ uint32_t USBDeviceClass::recvControl(void *_data, uint32_t len) usbd.epBank0ResetReady(0); //usbd.epBank0AckSetupReceived(0); - uint32_t read = armRecvCtrlOUT(0, len); + uint32_t read = armRecvCtrlOUT(0); if (read > len) read = len; //while (!usbd.epBank0AckTransferComplete(0)) {} @@ -500,7 +500,7 @@ uint32_t USBDeviceClass::recv(uint32_t ep, void *_data, uint32_t len) if (available(ep) < len) len = available(ep); - armRecv(ep, len); + armRecv(ep); usbd.epBank0DisableTransferComplete(ep); @@ -518,7 +518,7 @@ uint32_t USBDeviceClass::recv(uint32_t ep, void *_data, uint32_t len) return len; } -// Recv 1 byte if ready +// Recv 1 byte if ready uint32_t USBDeviceClass::recv(uint32_t ep) { uint8_t c; @@ -529,9 +529,9 @@ uint32_t USBDeviceClass::recv(uint32_t ep) } } -uint8_t USBDeviceClass::armRecvCtrlOUT(uint32_t ep, uint32_t len) +uint8_t USBDeviceClass::armRecvCtrlOUT(uint32_t ep) { - /* get endpoint configuration from setting register */ + // Get endpoint configuration from setting register usbd.epBank0SetAddress(ep, &udd_ep_out_cache_buffer[ep]); usbd.epBank0SetMultiPacketSize(ep, 8); usbd.epBank0SetByteCount(ep, 0); @@ -544,7 +544,7 @@ uint8_t USBDeviceClass::armRecvCtrlOUT(uint32_t ep, uint32_t len) return usbd.epBank0ByteCount(ep); } -uint8_t USBDeviceClass::armRecv(uint32_t ep, uint32_t len) +uint8_t USBDeviceClass::armRecv(uint32_t ep) { uint16_t count = usbd.epBank0ByteCount(ep); if (count >= 64) { @@ -555,7 +555,7 @@ uint8_t USBDeviceClass::armRecv(uint32_t ep, uint32_t len) return usbd.epBank0ByteCount(ep); } -// Blocking Send of data to an endpoint +// Blocking Send of data to an endpoint uint32_t USBDeviceClass::send(uint32_t ep, const void *data, uint32_t len) { uint32_t length = 0; From ac16594d2aa1d86b3216ddc40a3526f20152177b Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 10 Sep 2015 16:08:32 +0200 Subject: [PATCH 12/17] Disabled SRAM shortcut when in USBCore::send The shortcut has some issues: - sometimes it fails when sending an odd number of bytes (may be due to memory alignment?) - the data pointer should point to "stable" data (and this is not guaranteed by caller, it may be some sort of temporary buffer) - the SRAM is not guaranteed to start at 0x20000000 All the above problems must be properly fixed before reenabling this part --- cores/arduino/USB/USBCore.cpp | 57 ++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index 99009e835..d40662f08 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -565,6 +565,17 @@ uint32_t USBDeviceClass::send(uint32_t ep, const void *data, uint32_t len) if (len > 16384) return -1; +#if 0 +// This shortcut has some issues: +// - sometimes it fails when sending an odd number of bytes (may be +// due to memory alignment?) +// - the data pointer should point to "stable" data (and this is not +// guaranteed by caller, it may be some sort of temporary buffer) +// - the SRAM is not guaranteed to start at 0x20000000 + +// All the above problems must be properly fixed before reenabling +// this part + if ((unsigned int)data > 0x20000000) { // Buffer in RAM @@ -583,39 +594,37 @@ uint32_t USBDeviceClass::send(uint32_t ep, const void *data, uint32_t len) while (!usbd.epBank1IsTransferComplete(ep)) { ; // need fire exit. } - len = 0; + return 0; } - else +#endif + + // Flash area + while (len != 0) { - // Flash area - while (len != 0) - { - if (len >= 64) { - length = 64; - } else { - length = len; - } + if (len >= 64) { + length = 64; + } else { + length = len; + } - /* memcopy could be safer in multi threaded environment */ - memcpy(&udd_ep_in_cache_buffer[ep], data, length); + /* memcopy could be safer in multi threaded environment */ + memcpy(&udd_ep_in_cache_buffer[ep], data, length); - usbd.epBank1SetAddress(ep, &udd_ep_in_cache_buffer[ep]); - usbd.epBank1SetByteCount(ep, length); + usbd.epBank1SetAddress(ep, &udd_ep_in_cache_buffer[ep]); + usbd.epBank1SetByteCount(ep, length); - // Clear the transfer complete flag - usbd.epBank1AckTransferComplete(ep); + // Clear the transfer complete flag + usbd.epBank1AckTransferComplete(ep); - // RAM buffer is full, we can send data (IN) - usbd.epBank1SetReady(ep); + // RAM buffer is full, we can send data (IN) + usbd.epBank1SetReady(ep); - // Wait for transfer to complete - while (!usbd.epBank1IsTransferComplete(ep)) { - ; // need fire exit. - } - len -= length; + // Wait for transfer to complete + while (!usbd.epBank1IsTransferComplete(ep)) { + ; // need fire exit. } + len -= length; } - return len; } From 81cbda3aa64e9a4f6639cda7024cea542e169ed6 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 10 Sep 2015 18:46:28 +0200 Subject: [PATCH 13/17] Fixed bug in USBCore::send... (yikes!) --- cores/arduino/USB/USBCore.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index d40662f08..d32dd4cb2 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -624,6 +624,7 @@ uint32_t USBDeviceClass::send(uint32_t ep, const void *data, uint32_t len) ; // need fire exit. } len -= length; + data += length; } return len; } From 6d2f3db02aa21f403b13854e0be85aa2de5a6db8 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Fri, 17 Jul 2015 17:43:25 +0200 Subject: [PATCH 14/17] adapt USB core to PluggableUSB --- cores/arduino/USB/CDC.cpp | 18 +- cores/arduino/USB/HID.cpp | 530 ----------------------------- cores/arduino/USB/PluggableUSB.cpp | 98 ++++++ cores/arduino/USB/PluggableUSB.h | 63 ++++ cores/arduino/USB/USBAPI.h | 128 +------ cores/arduino/USB/USBCore.cpp | 207 ++++++----- cores/arduino/USB/USBCore.h | 37 -- cores/arduino/USB/USBDesc.h | 15 +- libraries/HID/HID.cpp | 176 ++++++++++ libraries/HID/HID.h | 93 +++++ libraries/HID/keywords.txt | 21 ++ libraries/HID/library.properties | 8 + 12 files changed, 610 insertions(+), 784 deletions(-) delete mode 100644 cores/arduino/USB/HID.cpp create mode 100644 cores/arduino/USB/PluggableUSB.cpp create mode 100644 cores/arduino/USB/PluggableUSB.h create mode 100644 libraries/HID/HID.cpp create mode 100644 libraries/HID/HID.h create mode 100644 libraries/HID/keywords.txt create mode 100644 libraries/HID/library.properties diff --git a/cores/arduino/USB/CDC.cpp b/cores/arduino/USB/CDC.cpp index daca74cc6..0f1016848 100644 --- a/cores/arduino/USB/CDC.cpp +++ b/cores/arduino/USB/CDC.cpp @@ -58,10 +58,8 @@ static volatile LineInfo _usbLineInfo = { 0x00 // lineState }; -static const CDCDescriptor _cdcInterface = { - #if (defined CDC_ENABLED) && defined(HID_ENABLED) +static CDCDescriptor _cdcInterface = { D_IAD(0, 2, CDC_COMMUNICATION_INTERFACE_CLASS, CDC_ABSTRACT_CONTROL_MODEL, 0), - #endif // CDC communication interface D_INTERFACE(CDC_ACM_INTERFACE, 1, CDC_COMMUNICATION_INTERFACE_CLASS, CDC_ABSTRACT_CONTROL_MODEL, 0), @@ -79,17 +77,23 @@ static const CDCDescriptor _cdcInterface = { }; _Pragma("pack()") -const void* CDC_GetInterface(void) +const void* _CDC_GetInterface(void) { return &_cdcInterface; } -uint32_t CDC_GetInterfaceLength(void) +uint32_t _CDC_GetInterfaceLength(void) { return sizeof(_cdcInterface); } -bool CDC_Setup(Setup& setup) +int CDC_GetInterface(uint8_t* interfaceNum) +{ + interfaceNum[0] += 2; // uses 2 + return USBDevice.sendControl(&_cdcInterface,sizeof(_cdcInterface)); +} + +bool CDC_Setup(USBSetup& setup) { uint8_t requestType = setup.bmRequestType; uint8_t r = setup.bRequest; @@ -181,7 +185,7 @@ int Serial_::available(void) return CDC_SERIAL_BUFFER_SIZE; } if (buffer->head == buffer->tail) { - USB->DEVICE.DeviceEndpoint[2].EPINTENSET.reg = USB_DEVICE_EPINTENCLR_TRCPT(1); + USB->DEVICE.DeviceEndpoint[CDC_ENDPOINT_OUT].EPINTENSET.reg = USB_DEVICE_EPINTENCLR_TRCPT(1); } return (uint32_t)(CDC_SERIAL_BUFFER_SIZE + buffer->head - buffer->tail) % CDC_SERIAL_BUFFER_SIZE; } diff --git a/cores/arduino/USB/HID.cpp b/cores/arduino/USB/HID.cpp deleted file mode 100644 index edcc2167c..000000000 --- a/cores/arduino/USB/HID.cpp +++ /dev/null @@ -1,530 +0,0 @@ -/* - Copyright (c) 2014 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include - -#ifdef HID_ENABLED - -//#define RAWHID_ENABLED - -// Singletons for mouse and keyboard -Mouse_ Mouse; -Keyboard_ Keyboard; - -//================================================================================ -//================================================================================ - -#define LSB(_x) ((_x) & 0xFF) -#define MSB(_x) ((_x) >> 8) - -#define RAWHID_USAGE_PAGE 0xFFC0 -#define RAWHID_USAGE 0x0C00 -#define RAWHID_TX_SIZE 64 -#define RAWHID_RX_SIZE 64 - -// HID report descriptor -_Pragma("pack(1)") -extern const uint8_t _hidReportDescriptor[] = { - // Mouse - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 54 - 0x09, 0x02, // USAGE (Mouse) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x01, // USAGE (Pointer) - 0xa1, 0x00, // COLLECTION (Physical) - 0x85, 0x01, // REPORT_ID (1) - 0x05, 0x09, // USAGE_PAGE (Button) - 0x19, 0x01, // USAGE_MINIMUM (Button 1) - 0x29, 0x03, // USAGE_MAXIMUM (Button 3) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x95, 0x03, // REPORT_COUNT (3) - 0x75, 0x01, // REPORT_SIZE (1) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x95, 0x01, // REPORT_COUNT (1) - 0x75, 0x05, // REPORT_SIZE (5) - 0x81, 0x03, // INPUT (Cnst,Var,Abs) - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) - 0x09, 0x30, // USAGE (X) - 0x09, 0x31, // USAGE (Y) - 0x09, 0x38, // USAGE (Wheel) - 0x15, 0x81, // LOGICAL_MINIMUM (-127) - 0x25, 0x7f, // LOGICAL_MAXIMUM (127) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x03, // REPORT_COUNT (3) - 0x81, 0x06, // INPUT (Data,Var,Rel) - 0xc0, // END_COLLECTION - 0xc0, // END_COLLECTION - - // Keyboard - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47 - 0x09, 0x06, // USAGE (Keyboard) - 0xa1, 0x01, // COLLECTION (Application) - 0x85, 0x02, // REPORT_ID (2) - 0x05, 0x07, // USAGE_PAGE (Keyboard) - - 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) - 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x75, 0x01, // REPORT_SIZE (1) - - 0x95, 0x08, // REPORT_COUNT (8) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x95, 0x01, // REPORT_COUNT (1) - 0x75, 0x08, // REPORT_SIZE (8) - 0x81, 0x03, // INPUT (Cnst,Var,Abs) - - 0x95, 0x06, // REPORT_COUNT (6) - 0x75, 0x08, // REPORT_SIZE (8) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x65, // LOGICAL_MAXIMUM (101) - 0x05, 0x07, // USAGE_PAGE (Keyboard) - - 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) - 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) - 0x81, 0x00, // INPUT (Data,Ary,Abs) - 0xc0, // END_COLLECTION - -#ifdef RAWHID_ENABLED - // RAW HID - 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), // 30 - 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), - - 0xA1, 0x01, // Collection 0x01 - 0x85, 0x03, // REPORT_ID (3) - 0x75, 0x08, // report size = 8 bits - 0x15, 0x00, // logical minimum = 0 - 0x26, 0xFF, 0x00, // logical maximum = 255 - - 0x95, 64, // report count TX - 0x09, 0x01, // usage - 0x81, 0x02, // Input (array) - - 0x95, 64, // report count RX - 0x09, 0x02, // usage - 0x91, 0x02, // Output (array) - 0xC0 // end collection -#endif -}; - -extern const HIDDescriptor _hidInterface = -{ - D_INTERFACE(HID_INTERFACE,1,3,0,0), - D_HIDREPORT(sizeof(_hidReportDescriptor)), - D_ENDPOINT(USB_ENDPOINT_IN(HID_ENDPOINT_INT),USB_ENDPOINT_TYPE_INTERRUPT,0x40,0x01) -}; -_Pragma("pack()") - -//================================================================================ -//================================================================================ -// Driver - -uint8_t _hid_protocol = 1; -uint8_t _hid_idle = 1; - -const void* HID_GetInterface(void) -{ - return &_hidInterface; -} - -uint32_t HID_GetInterfaceLength(void) -{ - return sizeof( _hidInterface ); -} - -uint32_t HID_SizeReportDescriptor(void) -{ - return sizeof(_hidReportDescriptor); -} - -uint32_t HID_GetDescriptor(void) -{ - return USBDevice.sendControl(_hidReportDescriptor, sizeof(_hidReportDescriptor)); -} - -void HID_SendReport(uint8_t id, const void* data, uint32_t len) -{ - uint8_t p[8]; - const uint8_t *d = reinterpret_cast(data); - - p[0] = id; - for (uint32_t i=0; i 0) - return true; - return false; -} - -//================================================================================ -//================================================================================ -// Keyboard - -Keyboard_::Keyboard_(void) -{ -} - -void Keyboard_::begin(void) -{ -} - -void Keyboard_::end(void) -{ -} - -void Keyboard_::sendReport(KeyReport* keys) -{ - HID_SendReport(2,keys,sizeof(KeyReport)); -} - -#define SHIFT 0x80 -extern const uint8_t _asciimap[128] = -{ - 0x00, // NUL - 0x00, // SOH - 0x00, // STX - 0x00, // ETX - 0x00, // EOT - 0x00, // ENQ - 0x00, // ACK - 0x00, // BEL - 0x2a, // BS Backspace - 0x2b, // TAB Tab - 0x28, // LF Enter - 0x00, // VT - 0x00, // FF - 0x00, // CR - 0x00, // SO - 0x00, // SI - 0x00, // DEL - 0x00, // DC1 - 0x00, // DC2 - 0x00, // DC3 - 0x00, // DC4 - 0x00, // NAK - 0x00, // SYN - 0x00, // ETB - 0x00, // CAN - 0x00, // EM - 0x00, // SUB - 0x00, // ESC - 0x00, // FS - 0x00, // GS - 0x00, // RS - 0x00, // US - - 0x2c, // ' ' - 0x1e|SHIFT, // ! - 0x34|SHIFT, // " - 0x20|SHIFT, // # - 0x21|SHIFT, // $ - 0x22|SHIFT, // % - 0x24|SHIFT, // & - 0x34, // ' - 0x26|SHIFT, // ( - 0x27|SHIFT, // ) - 0x25|SHIFT, // * - 0x2e|SHIFT, // + - 0x36, // , - 0x2d, // - - 0x37, // . - 0x38, // / - 0x27, // 0 - 0x1e, // 1 - 0x1f, // 2 - 0x20, // 3 - 0x21, // 4 - 0x22, // 5 - 0x23, // 6 - 0x24, // 7 - 0x25, // 8 - 0x26, // 9 - 0x33|SHIFT, // : - 0x33, // ; - 0x36|SHIFT, // < - 0x2e, // = - 0x37|SHIFT, // > - 0x38|SHIFT, // ? - 0x1f|SHIFT, // @ - 0x04|SHIFT, // A - 0x05|SHIFT, // B - 0x06|SHIFT, // C - 0x07|SHIFT, // D - 0x08|SHIFT, // E - 0x09|SHIFT, // F - 0x0a|SHIFT, // G - 0x0b|SHIFT, // H - 0x0c|SHIFT, // I - 0x0d|SHIFT, // J - 0x0e|SHIFT, // K - 0x0f|SHIFT, // L - 0x10|SHIFT, // M - 0x11|SHIFT, // N - 0x12|SHIFT, // O - 0x13|SHIFT, // P - 0x14|SHIFT, // Q - 0x15|SHIFT, // R - 0x16|SHIFT, // S - 0x17|SHIFT, // T - 0x18|SHIFT, // U - 0x19|SHIFT, // V - 0x1a|SHIFT, // W - 0x1b|SHIFT, // X - 0x1c|SHIFT, // Y - 0x1d|SHIFT, // Z - 0x2f, // [ - 0x31, // bslash - 0x30, // ] - 0x23|SHIFT, // ^ - 0x2d|SHIFT, // _ - 0x35, // ` - 0x04, // a - 0x05, // b - 0x06, // c - 0x07, // d - 0x08, // e - 0x09, // f - 0x0a, // g - 0x0b, // h - 0x0c, // i - 0x0d, // j - 0x0e, // k - 0x0f, // l - 0x10, // m - 0x11, // n - 0x12, // o - 0x13, // p - 0x14, // q - 0x15, // r - 0x16, // s - 0x17, // t - 0x18, // u - 0x19, // v - 0x1a, // w - 0x1b, // x - 0x1c, // y - 0x1d, // z - 0x2f|SHIFT, // - 0x31|SHIFT, // | - 0x30|SHIFT, // } - 0x35|SHIFT, // ~ - 0 // DEL -}; - -// press() adds the specified key (printing, non-printing, or modifier) -// to the persistent key report and sends the report. Because of the way -// USB HID works, the host acts like the key remains pressed until we -// call release(), releaseAll(), or otherwise clear the report and resend. -size_t Keyboard_::press(uint8_t k) -{ - uint8_t i; - if (k >= 136) { // it's a non-printing key (not a modifier) - k = k - 136; - } else if (k >= 128) { // it's a modifier key - _keyReport.modifiers |= (1<<(k-128)); - k = 0; - } else { // it's a printing key - k = _asciimap[k]; - if (!k) { - setWriteError(); - return 0; - } - if (k & 0x80) { // it's a capital letter or other character reached with shift - _keyReport.modifiers |= 0x02; // the left shift modifier - k &= 0x7F; - } - } - - // Add k to the key report only if it's not already present - // and if there is an empty slot. - if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && - _keyReport.keys[2] != k && _keyReport.keys[3] != k && - _keyReport.keys[4] != k && _keyReport.keys[5] != k) { - - for (i=0; i<6; i++) { - if (_keyReport.keys[i] == 0x00) { - _keyReport.keys[i] = k; - break; - } - } - if (i == 6) { - setWriteError(); - return 0; - } - } - sendReport(&_keyReport); - return 1; -} - -// release() takes the specified key out of the persistent key report and -// sends the report. This tells the OS the key is no longer pressed and that -// it shouldn't be repeated any more. -size_t Keyboard_::release(uint8_t k) -{ - uint8_t i; - if (k >= 136) { // it's a non-printing key (not a modifier) - k = k - 136; - } else if (k >= 128) { // it's a modifier key - _keyReport.modifiers &= ~(1<<(k-128)); - k = 0; - } else { // it's a printing key - k = _asciimap[k]; - if (!k) { - return 0; - } - if (k & 0x80) { // it's a capital letter or other character reached with shift - _keyReport.modifiers &= ~(0x02); // the left shift modifier - k &= 0x7F; - } - } - - // Test the key report to see if k is present. Clear it if it exists. - // Check all positions in case the key is present more than once (which it shouldn't be) - for (i=0; i<6; i++) { - if (0 != k && _keyReport.keys[i] == k) { - _keyReport.keys[i] = 0x00; - } - } - - sendReport(&_keyReport); - return 1; -} - -void Keyboard_::releaseAll(void) -{ - _keyReport.keys[0] = 0; - _keyReport.keys[1] = 0; - _keyReport.keys[2] = 0; - _keyReport.keys[3] = 0; - _keyReport.keys[4] = 0; - _keyReport.keys[5] = 0; - _keyReport.modifiers = 0; - sendReport(&_keyReport); -} - -size_t Keyboard_::write(uint8_t c) -{ - uint8_t p = 0; - - p = press(c); // Keydown - release(c); // Keyup - - return (p); // Just return the result of press() since release() almost always returns 1 -} - -#endif diff --git a/cores/arduino/USB/PluggableUSB.cpp b/cores/arduino/USB/PluggableUSB.cpp new file mode 100644 index 000000000..84d781d81 --- /dev/null +++ b/cores/arduino/USB/PluggableUSB.cpp @@ -0,0 +1,98 @@ +/* + PluggableUSB.cpp + Copyright (c) 2015 Arduino LLC + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "USBAPI.h" +#include "USBDesc.h" +#include "PluggableUSB.h" + +#ifdef PLUGGABLE_USB_ENABLED + +#define MAX_MODULES 6 + +static uint8_t lastIf = CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT; +static uint8_t lastEp = CDC_FIRST_ENDPOINT + CDC_ENPOINT_COUNT; + +extern uint32_t EndPoints[]; + +//PUSBCallbacks cbs[MAX_MODULES]; +static uint8_t modules_count = 0; + +static PUSBListNode* rootNode = NULL; + +int PUSB_GetInterface(uint8_t* interfaceNum) +{ + int ret = 0; + PUSBListNode* node = rootNode; + for (uint8_t i=0; icb->getInterface(interfaceNum); + node = node->next; + } + return ret; +} + +int PUSB_GetDescriptor(int8_t t) +{ + int ret = 0; + PUSBListNode* node = rootNode; + for (uint8_t i=0; icb->getDescriptor(t); + node = node->next; + } + return ret; +} + +bool PUSB_Setup(USBSetup& setup, uint8_t j) +{ + bool ret = false; + PUSBListNode* node = rootNode; + for (uint8_t i=0; icb->setup(setup, j); + node = node->next; + } + return ret; +} + +int8_t PUSB_AddFunction(PUSBListNode *node, uint8_t* interface) +{ + if (modules_count >= MAX_MODULES) { + return 0; + } + + if (modules_count == 0) { + rootNode = node; + } else { + PUSBListNode *current = rootNode; + while(current->next != NULL) { + current = current->next; + } + current->next = node; + } + + *interface = lastIf; + lastIf += node->cb->numInterfaces; + for ( uint8_t i = 0; i< node->cb->numEndpoints; i++) { + EndPoints[lastEp] = node->cb->endpointType[i]; + lastEp++; + } + modules_count++; + return lastEp - node->cb->numEndpoints; + // restart USB layer??? +} + +#endif \ No newline at end of file diff --git a/cores/arduino/USB/PluggableUSB.h b/cores/arduino/USB/PluggableUSB.h new file mode 100644 index 000000000..205900550 --- /dev/null +++ b/cores/arduino/USB/PluggableUSB.h @@ -0,0 +1,63 @@ +/* + PluggableUSB.h + Copyright (c) 2015 Arduino LLC + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef PUSB_h +#define PUSB_h + +#include "USBAPI.h" +#include + +#if defined(USBCON) + +typedef struct __attribute__((packed)) +{ + bool (*setup)(USBSetup& setup, uint8_t i); + int (*getInterface)(uint8_t* interfaceNum); + int (*getDescriptor)(int8_t t); + int8_t numEndpoints; + int8_t numInterfaces; + uint8_t *endpointType; +} PUSBCallbacks; + +typedef struct +{ + uint8_t interface; + uint8_t firstEndpoint; +} PUSBReturn; + +class PUSBListNode { +public: + PUSBListNode *next = NULL; + PUSBCallbacks *cb; + PUSBListNode(PUSBCallbacks *ncb) {cb = ncb;} +}; + +int8_t PUSB_AddFunction(PUSBListNode *node, uint8_t *interface); + +int PUSB_GetInterface(uint8_t* interfaceNum); + +int PUSB_GetDescriptor(int8_t t); + +bool PUSB_Setup(USBSetup& setup, uint8_t i); + +void PUSB_Begin(); + +#endif + +#endif diff --git a/cores/arduino/USB/USBAPI.h b/cores/arduino/USB/USBAPI.h index bbb0a3e03..23d0ae242 100644 --- a/cores/arduino/USB/USBAPI.h +++ b/cores/arduino/USB/USBAPI.h @@ -50,7 +50,7 @@ typedef struct { uint8_t wValueH; uint16_t wIndex; uint16_t wLength; -} Setup; +} USBSetup; class USBDeviceClass { public: @@ -66,17 +66,21 @@ class USBDeviceClass { bool connected(); // Setup API - bool handleClassInterfaceSetup(Setup &setup); - bool handleStandardSetup(Setup &setup); - bool sendDescriptor(Setup &setup); + bool handleClassInterfaceSetup(USBSetup &setup); + bool handleStandardSetup(USBSetup &setup); + bool sendDescriptor(USBSetup &setup); // Control EndPoint API uint32_t sendControl(const void *data, uint32_t len); + uint32_t sendControl(int /* ep */, const void *data, uint32_t len) { return sendControl(data, len); } uint32_t recvControl(void *data, uint32_t len); - bool sendConfiguration(uint32_t maxlen); + uint32_t sendConfiguration(uint32_t maxlen); bool sendStringDescriptor(const uint8_t *string, uint8_t maxlen); + void initControl(int end); + uint8_t SendInterfaces(uint32_t* total); // Generic EndPoint API + void initEndpoints(void); void initEP(uint32_t ep, uint32_t type); void handleEndpoint(uint8_t ep); @@ -96,6 +100,8 @@ class USBDeviceClass { void ISRHandler(); private: + void packMessages(bool val); + bool initialized; }; @@ -127,126 +133,24 @@ class Serial_ : public Stream }; extern Serial_ SerialUSB; -//================================================================================ -//================================================================================ -// Mouse - -#define MOUSE_LEFT 1 -#define MOUSE_RIGHT 2 -#define MOUSE_MIDDLE 4 -#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE) - -class Mouse_ -{ -private: - uint8_t _buttons; - void buttons(uint8_t b); -public: - Mouse_(void); - void begin(void); - void end(void); - void click(uint8_t b = MOUSE_LEFT); - void move(signed char x, signed char y, signed char wheel = 0); - void press(uint8_t b = MOUSE_LEFT); // press LEFT by default - void release(uint8_t b = MOUSE_LEFT); // release LEFT by default - bool isPressed(uint8_t b = MOUSE_ALL); // check all buttons by default -}; -extern Mouse_ Mouse; - -//================================================================================ -//================================================================================ -// Keyboard - -#define KEY_LEFT_CTRL 0x80 -#define KEY_LEFT_SHIFT 0x81 -#define KEY_LEFT_ALT 0x82 -#define KEY_LEFT_GUI 0x83 -#define KEY_RIGHT_CTRL 0x84 -#define KEY_RIGHT_SHIFT 0x85 -#define KEY_RIGHT_ALT 0x86 -#define KEY_RIGHT_GUI 0x87 - -#define KEY_UP_ARROW 0xDA -#define KEY_DOWN_ARROW 0xD9 -#define KEY_LEFT_ARROW 0xD8 -#define KEY_RIGHT_ARROW 0xD7 -#define KEY_BACKSPACE 0xB2 -#define KEY_TAB 0xB3 -#define KEY_RETURN 0xB0 -#define KEY_ESC 0xB1 -#define KEY_INSERT 0xD1 -#define KEY_DELETE 0xD4 -#define KEY_PAGE_UP 0xD3 -#define KEY_PAGE_DOWN 0xD6 -#define KEY_HOME 0xD2 -#define KEY_END 0xD5 -#define KEY_CAPS_LOCK 0xC1 -#define KEY_F1 0xC2 -#define KEY_F2 0xC3 -#define KEY_F3 0xC4 -#define KEY_F4 0xC5 -#define KEY_F5 0xC6 -#define KEY_F6 0xC7 -#define KEY_F7 0xC8 -#define KEY_F8 0xC9 -#define KEY_F9 0xCA -#define KEY_F10 0xCB -#define KEY_F11 0xCC -#define KEY_F12 0xCD - -// Low level key report: up to 6 keys and shift, ctrl etc at once -typedef struct -{ - uint8_t modifiers; - uint8_t reserved; - uint8_t keys[6]; -} KeyReport; - -class Keyboard_ : public Print -{ -private: - KeyReport _keyReport; - void sendReport(KeyReport* keys); -public: - Keyboard_(void); - void begin(void); - void end(void); - virtual size_t write(uint8_t k); - virtual size_t press(uint8_t k); - virtual size_t release(uint8_t k); - virtual void releaseAll(void); -}; -extern Keyboard_ Keyboard; - -//================================================================================ -//================================================================================ -// HID 'Driver' - -const void* HID_GetInterface(void); -uint32_t HID_GetInterfaceLength(void); -uint32_t HID_SizeReportDescriptor(void); - -uint32_t HID_GetDescriptor(void); -bool HID_Setup(Setup& setup); -void HID_SendReport(uint8_t id, const void* data, uint32_t len); - //================================================================================ //================================================================================ // MSC 'Driver' uint32_t MSC_GetInterface(uint8_t* interfaceNum); uint32_t MSC_GetDescriptor(uint32_t i); -bool MSC_Setup(Setup& setup); +bool MSC_Setup(USBSetup& setup); bool MSC_Data(uint8_t rx,uint8_t tx); //================================================================================ //================================================================================ // CDC 'Driver' -const void* CDC_GetInterface(/*uint8_t* interfaceNum*/); -uint32_t CDC_GetInterfaceLength(void); +int CDC_GetInterface(uint8_t* interfaceNum); +const void* _CDC_GetInterface(void); +uint32_t _CDC_GetInterfaceLength(void); uint32_t CDC_GetOtherInterface(uint8_t* interfaceNum); uint32_t CDC_GetDescriptor(uint32_t i); -bool CDC_Setup(Setup& setup); +bool CDC_Setup(USBSetup& setup); #endif // __cplusplus diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index d32dd4cb2..26f3ced61 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -19,10 +19,12 @@ #include #include "SAMD21_USBDevice.h" +#include "PluggableUSB.h" #include #include #include +#include USBDevice_SAMD21G18x usbd; @@ -64,13 +66,8 @@ const uint8_t STRING_MANUFACTURER[] = USB_MANUFACTURER; // DEVICE DESCRIPTOR -#if (defined CDC_ENABLED) && defined(HID_ENABLED) -const DeviceDescriptor USB_DeviceDescriptor = D_DEVICE(0xEF, 0x02, 0x01, 64, USB_VID, USB_PID, 0x100, IMANUFACTURER, IPRODUCT, 0, 1); -#elif defined(CDC_ENABLED) // CDC only -const DeviceDescriptor USB_DeviceDescriptor = D_DEVICE(0x02, 0x00, 0x00, 64, USB_VID, USB_PID, 0x100, IMANUFACTURER, IPRODUCT, 0, 1); -#else // HID only +const DeviceDescriptor USB_DeviceDescriptorB = D_DEVICE(0xEF, 0x02, 0x01, 64, USB_VID, USB_PID, 0x100, IMANUFACTURER, IPRODUCT, 0, 1); const DeviceDescriptor USB_DeviceDescriptor = D_DEVICE(0x00, 0x00, 0x00, 64, USB_VID, USB_PID, 0x100, IMANUFACTURER, IPRODUCT, 0, 1); -#endif //================================================================== @@ -107,79 +104,72 @@ bool USBDeviceClass::sendStringDescriptor(const uint8_t *string, uint8_t maxlen) return USBDevice.sendControl((uint8_t*)buff, l*2); } -// Construct a dynamic configuration descriptor -// This really needs dynamic endpoint allocation etc -bool USBDeviceClass::sendConfiguration(uint32_t maxlen) +bool _dry_run = false; +bool _pack_message = false; +uint16_t _pack_size = 0; +uint8_t _pack_buffer[256]; + +void USBDeviceClass::packMessages(bool val) { - uint8_t cache_buffer[128]; - uint8_t i; + if (val) { + _pack_message = true; + _pack_size = 0; + } else { + _pack_message = false; + sendControl(_pack_buffer, _pack_size); + } +} - const uint8_t* interfaces; - uint32_t interfaces_length = 0; - uint8_t num_interfaces[1]; +uint8_t USBDeviceClass::SendInterfaces(uint32_t* total) +{ + uint8_t interfaces = 0; - num_interfaces[0] = 0; +#if defined(CDC_ENABLED) + total[0] += CDC_GetInterface(&interfaces); +#endif -#if defined(CDC_ENABLED) && defined(HID_ENABLED) - num_interfaces[0] += 3; - interfaces = (const uint8_t*) CDC_GetInterface(); - interfaces_length = CDC_GetInterfaceLength() + HID_GetInterfaceLength(); - if (maxlen > CDC_GetInterfaceLength() + HID_GetInterfaceLength() + sizeof(ConfigDescriptor)) - { - maxlen = CDC_GetInterfaceLength() + HID_GetInterfaceLength() + sizeof(ConfigDescriptor); - } -#elif defined(CDC_ENABLED) - num_interfaces[0] += 2; - interfaces = (const uint8_t*) CDC_GetInterface(); - interfaces_length += CDC_GetInterfaceLength(); - if (maxlen > CDC_GetInterfaceLength() + sizeof(ConfigDescriptor)) - { - maxlen = CDC_GetInterfaceLength() + sizeof(ConfigDescriptor); - } -#elif defined(HID_ENABLED) - num_interfaces[0] += 1; - interfaces = (const uint8_t*) HID_GetInterface(); - interfaces_length += HID_GetInterfaceLength(); - if (maxlen > HID_GetInterfaceLength() + sizeof(ConfigDescriptor)) - { - maxlen = HID_GetInterfaceLength() + sizeof(ConfigDescriptor); - } +#ifdef PLUGGABLE_USB_ENABLED + total[0] += PUSB_GetInterface(&interfaces); #endif -_Pragma("pack(1)") - ConfigDescriptor config = D_CONFIG((uint16_t)(interfaces_length + sizeof(ConfigDescriptor)), num_interfaces[0]); -_Pragma("pack()") + return interfaces; +} - memcpy(cache_buffer, &config, sizeof(ConfigDescriptor)); +// Construct a dynamic configuration descriptor +// This really needs dynamic endpoint allocation etc +uint32_t USBDeviceClass::sendConfiguration(uint32_t maxlen) +{ + uint32_t total = 0; + // Count and measure interfaces + _dry_run = true; + uint8_t interfaces = SendInterfaces(&total); -#if defined(CDC_ENABLED) && defined(HID_ENABLED) - for (i=0; i sizeof(cache_buffer)) { - maxlen = sizeof(cache_buffer); + // Now send them + _dry_run = false; + + if (maxlen == sizeof(ConfigDescriptor)) { + sendControl(&config, sizeof(ConfigDescriptor)); + return true; } - return sendControl(cache_buffer, maxlen); + + packMessages(true); + sendControl(&config, sizeof(ConfigDescriptor)); + SendInterfaces(&total); + packMessages(false); + + return true; } -bool USBDeviceClass::sendDescriptor(Setup &setup) +bool USBDeviceClass::sendDescriptor(USBSetup &setup) { uint8_t t = setup.wValueH; uint8_t desc_length = 0; + bool _cdcComposite; + int ret; const uint8_t *desc_addr = 0; if (t == USB_CONFIGURATION_DESCRIPTOR_TYPE) @@ -187,22 +177,20 @@ bool USBDeviceClass::sendDescriptor(Setup &setup) return USBDevice.sendConfiguration(setup.wLength); } -#if defined(HID_ENABLED) - if (t == HID_REPORT_DESCRIPTOR_TYPE) - { - return HID_GetDescriptor(); - } - - if (t == HID_HID_DESCRIPTOR_TYPE) - { - uint8_t tab[9] = D_HIDREPORT((uint8_t)HID_SizeReportDescriptor()); - return USBDevice.sendControl(tab, sizeof(tab)); +#ifdef PLUGGABLE_USB_ENABLED + ret = PUSB_GetDescriptor(t); + if (ret != 0) { + return (ret > 0 ? true : false); } #endif if (t == USB_DEVICE_DESCRIPTOR_TYPE) { - desc_addr = (const uint8_t*)&USB_DeviceDescriptor; + if (setup.wLength == 8) + _cdcComposite = 1; + + desc_addr = _cdcComposite ? (const uint8_t*)&USB_DeviceDescriptorB : (const uint8_t*)&USB_DeviceDescriptor; + if (*desc_addr > setup.wLength) { desc_length = setup.wLength; } @@ -269,7 +257,7 @@ void USBDeviceClass::handleEndpoint(uint8_t ep) } #endif -#if defined(HID_ENABLED) +#if defined(PLUGGABLE_USB_ENABLED) // Empty #endif } @@ -355,7 +343,7 @@ bool USBDeviceClass::configured() return _usbConfiguration != 0; } -bool USBDeviceClass::handleClassInterfaceSetup(Setup& setup) +bool USBDeviceClass::handleClassInterfaceSetup(USBSetup& setup) { uint8_t i = setup.wIndex; @@ -369,19 +357,44 @@ bool USBDeviceClass::handleClassInterfaceSetup(Setup& setup) } #endif - #if defined(HID_ENABLED) - if (HID_INTERFACE == i) - { - if (HID_Setup(setup) == false) { - sendZlp(0); - } - return true; + #if defined(PLUGGABLE_USB_ENABLED) + bool ret = PUSB_Setup(setup, i); + if ( ret == false) { + sendZlp(0); } + return ret; #endif return false; } +uint32_t EndPoints[] = +{ + USB_ENDPOINT_TYPE_CONTROL, + +#ifdef CDC_ENABLED + USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0), // CDC_ENDPOINT_ACM + USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0), // CDC_ENDPOINT_OUT + USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0), // CDC_ENDPOINT_IN +#endif + +#ifdef PLUGGABLE_USB_ENABLED + //allocate 6 endpoints and remove const so they can be changed by the user + 0, + 0, + 0, + 0, + 0, + 0, +#endif +}; + +void USBDeviceClass::initEndpoints() { + for (uint8_t i = 1; i < sizeof(EndPoints) && EndPoints[i] != 0; i++) { + initEP(i, EndPoints[i]); + } +} + void USBDeviceClass::initEP(uint32_t ep, uint32_t config) { if (config == (USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0))) @@ -648,6 +661,15 @@ uint32_t USBDeviceClass::sendControl(const void* _data, uint32_t len) uint32_t sent = 0; uint32_t pos = 0; + if (_dry_run == true) + return length; + + if (_pack_message == true) { + memcpy(&_pack_buffer[_pack_size], data, len); + _pack_size += len; + return length; + } + while (len > 0) { sent = armSend(EP0, data + pos, len); @@ -664,7 +686,7 @@ void USBDeviceClass::sendZlp(uint32_t ep) usbd.epBank1SetByteCount(ep, 0); } -bool USBDeviceClass::handleStandardSetup(Setup &setup) +bool USBDeviceClass::handleStandardSetup(USBSetup &setup) { switch (setup.bRequest) { case GET_STATUS: @@ -741,15 +763,8 @@ bool USBDeviceClass::handleStandardSetup(Setup &setup) case SET_CONFIGURATION: if (REQUEST_DEVICE == (setup.bmRequestType & REQUEST_RECIPIENT)) { - #if defined(HID_ENABLED) - initEP(HID_ENDPOINT_INT, USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0)); - #endif - #if defined(CDC_ENABLED) - initEP(CDC_ENDPOINT_ACM, USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN(0)); - initEP(CDC_ENDPOINT_OUT, USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0)); - initEP(CDC_ENDPOINT_IN, USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0)); - #endif + initEndpoints(); _usbConfiguration = setup.wValueL; #if defined(CDC_ENABLED) @@ -780,6 +795,10 @@ bool USBDeviceClass::handleStandardSetup(Setup &setup) void USBDeviceClass::ISRHandler() { + + if (_pack_message == true) { + return; + } // End-Of-Reset if (usbd.isEndOfResetInterrupt()) { @@ -805,7 +824,7 @@ void USBDeviceClass::ISRHandler() { usbd.epBank0AckSetupReceived(0); - Setup *setup = reinterpret_cast(udd_ep_out_cache_buffer[0]); + USBSetup *setup = reinterpret_cast(udd_ep_out_cache_buffer[0]); /* Clear the Bank 0 ready flag on Control OUT */ // The RAM Buffer is empty: we can receive data diff --git a/cores/arduino/USB/USBCore.h b/cores/arduino/USB/USBCore.h index d584fdfc9..0d2dc7854 100644 --- a/cores/arduino/USB/USBCore.h +++ b/cores/arduino/USB/USBCore.h @@ -70,13 +70,6 @@ #define MSC_RESET 0xFF #define MSC_GET_MAX_LUN 0xFE -#define HID_GET_REPORT 0x01 -#define HID_GET_IDLE 0x02 -#define HID_GET_PROTOCOL 0x03 -#define HID_SET_REPORT 0x09 -#define HID_SET_IDLE 0x0A -#define HID_SET_PROTOCOL 0x0B - // Descriptors // #define USB_DEVICE_DESC_SIZE 18 @@ -120,10 +113,6 @@ #define MSC_SUBCLASS_SCSI 0x06 #define MSC_PROTOCOL_BULK_ONLY 0x50 -#define HID_HID_DESCRIPTOR_TYPE 0x21 -#define HID_REPORT_DESCRIPTOR_TYPE 0x22 -#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23 - _Pragma("pack(1)") // Device @@ -234,10 +223,8 @@ typedef struct typedef struct { -#if (defined CDC_ENABLED) && defined(HID_ENABLED) // IAD IADDescriptor iad; // Only needed on compound device -#endif // Control InterfaceDescriptor cif; CDCCSInterfaceDescriptor header; @@ -259,26 +246,6 @@ typedef struct EndpointDescriptor out; } MSCDescriptor; -typedef struct -{ - uint8_t len; // 9 - uint8_t dtype; // 0x21 - uint8_t addr; - uint8_t versionL; // 0x101 - uint8_t versionH; // 0x101 - uint8_t country; - uint8_t desctype; // 0x22 report - uint8_t descLenL; - uint8_t descLenH; -} HIDDescDescriptor; - -typedef struct -{ - InterfaceDescriptor hid; - HIDDescDescriptor desc; - EndpointDescriptor in; -} HIDDescriptor; - _Pragma("pack()") #define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \ @@ -308,10 +275,6 @@ _Pragma("pack()") { 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 } /* iadclasscode_r10.pdf, Table 9�Z. Standard Interface Association Descriptor * bLength, bDescriptorType, bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass, bFunctionProtocol, iFunction */ -#define D_HIDREPORT(_descriptorLength) \ - { 9, 0x21, 0x1, 0x1, 0, 1, 0x22, _descriptorLength, 0 } -/* HID1_11.pdf E.8 HID Descriptor (Mouse) - * bLength, bDescriptorType, bcdHID, bCountryCode, bNumDescriptors, bDescriptorType, wItemLength */ // Functional Descriptor General Format #define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 } diff --git a/cores/arduino/USB/USBDesc.h b/cores/arduino/USB/USBDesc.h index 655fb6d01..2282a7182 100644 --- a/cores/arduino/USB/USBDesc.h +++ b/cores/arduino/USB/USBDesc.h @@ -21,18 +21,25 @@ // CDC or HID can be enabled together. #define CDC_ENABLED -#define HID_ENABLED +#define PLUGGABLE_USB_ENABLED + +#ifdef CDC_ENABLED +#define CDC_INTERFACE_COUNT 2 +#define CDC_ENPOINT_COUNT 3 +#endif // CDC #define CDC_ACM_INTERFACE 0 // CDC ACM #define CDC_DATA_INTERFACE 1 // CDC Data +#define CDC_FIRST_ENDPOINT 1 #define CDC_ENDPOINT_ACM 1 #define CDC_ENDPOINT_OUT 2 #define CDC_ENDPOINT_IN 3 -// HID -#define HID_INTERFACE 2 // HID -#define HID_ENDPOINT_INT 4 +#ifdef CDC_ENABLED +#define CDC_RX CDC_ENDPOINT_OUT +#define CDC_TX CDC_ENDPOINT_IN +#endif // Defined string description #define IMANUFACTURER 1 diff --git a/libraries/HID/HID.cpp b/libraries/HID/HID.cpp new file mode 100644 index 000000000..2679faa54 --- /dev/null +++ b/libraries/HID/HID.cpp @@ -0,0 +1,176 @@ +/* Copyright (c) 2015, Arduino LLC +** +** Original code (pre-library): Copyright (c) 2011, Peter Barrett +** +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +#include "USB/PluggableUSB.h" +#include "HID.h" + +HID_ HID; + +static uint8_t HID_ENDPOINT_INT; + +//================================================================================ +//================================================================================ + +// HID report descriptor + +#define LSB(_x) ((_x) & 0xFF) +#define MSB(_x) ((_x) >> 8) + +#define RAWHID_USAGE_PAGE 0xFFC0 +#define RAWHID_USAGE 0x0C00 +#define RAWHID_TX_SIZE 64 +#define RAWHID_RX_SIZE 64 + +static uint8_t HID_INTERFACE; + +HIDDescriptor _hidInterface; + +static HIDDescriptorListNode* rootNode = NULL; +static uint8_t sizeof_hidReportDescriptor = 0; +static uint8_t modules_count = 0; +//================================================================================ +//================================================================================ +// Driver + +uint8_t _hid_protocol = 1; +uint8_t _hid_idle = 1; + +int HID_GetInterface(uint8_t* interfaceNum) +{ + interfaceNum[0] += 1; // uses 1 + _hidInterface = + { + D_INTERFACE(HID_INTERFACE,1,3,0,0), + D_HIDREPORT(sizeof_hidReportDescriptor), + D_ENDPOINT(USB_ENDPOINT_IN (HID_ENDPOINT_INT),USB_ENDPOINT_TYPE_INTERRUPT,0x40,0x01) + }; + return USBDevice.sendControl(&_hidInterface,sizeof(_hidInterface)); +} + +int HID_GetDescriptor(int8_t t) +{ + if (HID_REPORT_DESCRIPTOR_TYPE == t) { + HIDDescriptorListNode* current = rootNode; + int total = 0; + while(current != NULL) { + total += USBDevice.sendControl(current->cb->descriptor,current->cb->length); + current = current->next; + } + return total; + } else { + return 0; + } +} + +void HID_::AppendDescriptor(HIDDescriptorListNode *node) +{ + if (modules_count == 0) { + rootNode = node; + } else { + HIDDescriptorListNode *current = rootNode; + while(current->next != NULL) { + current = current->next; + } + current->next = node; + } + modules_count++; + sizeof_hidReportDescriptor += node->cb->length; +} + +void HID_::SendReport(uint8_t id, const void* data, int len) +{ + uint8_t p[8]; + const uint8_t *d = reinterpret_cast(data); + + p[0] = id; + for (uint32_t i=0; i +#include + +#define _USING_HID + +//================================================================================ +//================================================================================ +// HID 'Driver' + +#define HID_GET_REPORT 0x01 +#define HID_GET_IDLE 0x02 +#define HID_GET_PROTOCOL 0x03 +#define HID_SET_REPORT 0x09 +#define HID_SET_IDLE 0x0A +#define HID_SET_PROTOCOL 0x0B + +#define HID_HID_DESCRIPTOR_TYPE 0x21 +#define HID_REPORT_DESCRIPTOR_TYPE 0x22 +#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23 + +typedef struct __attribute__((packed)) { + uint8_t length; + const void* descriptor; +} HID_Descriptor; + +class HIDDescriptorListNode { +public: + HIDDescriptorListNode *next = NULL; + const HID_Descriptor * cb; + HIDDescriptorListNode(const HID_Descriptor *ncb) {cb = ncb;} +}; + +class HID_ +{ +public: + HID_(void); + int begin(void); + void SendReport(uint8_t id, const void* data, int len); + void AppendDescriptor(HIDDescriptorListNode* node); +}; + +typedef struct +{ + uint8_t len; // 9 + uint8_t dtype; // 0x21 + uint8_t addr; + uint8_t versionL; // 0x101 + uint8_t versionH; // 0x101 + uint8_t country; + uint8_t desctype; // 0x22 report + uint8_t descLenL; + uint8_t descLenH; +} HIDDescDescriptor; + +typedef struct +{ + InterfaceDescriptor hid; + HIDDescDescriptor desc; + EndpointDescriptor in; +} HIDDescriptor; + +#define HID_TX HID_ENDPOINT_INT + +#define D_HIDREPORT(_descriptorLength) \ + { 9, 0x21, 0x1, 0x1, 0, 1, 0x22, _descriptorLength, 0 } + +#define WEAK __attribute__ ((weak)) + +#endif \ No newline at end of file diff --git a/libraries/HID/keywords.txt b/libraries/HID/keywords.txt new file mode 100644 index 000000000..32a9ba5f2 --- /dev/null +++ b/libraries/HID/keywords.txt @@ -0,0 +1,21 @@ +####################################### +# Syntax Coloring Map HID +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +HID KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +SendReport KEYWORD2 +AppendDescriptor KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### +HID_TX LITERAL1 \ No newline at end of file diff --git a/libraries/HID/library.properties b/libraries/HID/library.properties new file mode 100644 index 000000000..b175b1ede --- /dev/null +++ b/libraries/HID/library.properties @@ -0,0 +1,8 @@ +name=HID +version=1.0 +author=Arduino +maintainer=Arduino +sentence=Module for PluggableUSB infrastructure. Exposes an API for devices like Keyboards, Mice and Gamepads +paragraph= +url=http://www.arduino.cc/en/Reference/HID +architectures=samd \ No newline at end of file From 81475510fa80bc00cddf87f70644f5a483acc5dd Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Mon, 7 Sep 2015 15:29:11 +0200 Subject: [PATCH 15/17] fix pluggableUSB OUT packets --- cores/arduino/USB/PluggableUSB.h | 2 +- cores/arduino/USB/USBCore.cpp | 4 ++-- libraries/HID/HID.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cores/arduino/USB/PluggableUSB.h b/cores/arduino/USB/PluggableUSB.h index 205900550..502da9ebc 100644 --- a/cores/arduino/USB/PluggableUSB.h +++ b/cores/arduino/USB/PluggableUSB.h @@ -32,7 +32,7 @@ typedef struct __attribute__((packed)) int (*getDescriptor)(int8_t t); int8_t numEndpoints; int8_t numInterfaces; - uint8_t *endpointType; + uint32_t *endpointType; } PUSBCallbacks; typedef struct diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index 26f3ced61..171fe389f 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -75,10 +75,10 @@ volatile uint32_t _usbConfiguration = 0; volatile uint32_t _usbSetInterface = 0; static __attribute__((__aligned__(4))) //__attribute__((__section__(".bss_hram0"))) -uint8_t udd_ep_out_cache_buffer[4][64]; +uint8_t udd_ep_out_cache_buffer[6][64]; static __attribute__((__aligned__(4))) //__attribute__((__section__(".bss_hram0"))) -uint8_t udd_ep_in_cache_buffer[4][64]; +uint8_t udd_ep_in_cache_buffer[6][64]; //================================================================== diff --git a/libraries/HID/HID.cpp b/libraries/HID/HID.cpp index 2679faa54..c4bbd5cd8 100644 --- a/libraries/HID/HID.cpp +++ b/libraries/HID/HID.cpp @@ -152,7 +152,7 @@ bool HID_Setup(USBSetup& setup, uint8_t i) HID_::HID_(void) { - static uint8_t endpointType[1]; + static uint32_t endpointType[1]; endpointType[0] = USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0); From 87bbaaa43d885349bd18dd0324c98a13ed2dff22 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 16 Sep 2015 14:56:21 +0200 Subject: [PATCH 16/17] fix PUSB_getInterface return value --- cores/arduino/USB/PluggableUSB.cpp | 2 +- cores/arduino/USB/USBCore.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cores/arduino/USB/PluggableUSB.cpp b/cores/arduino/USB/PluggableUSB.cpp index 84d781d81..1a15dfa46 100644 --- a/cores/arduino/USB/PluggableUSB.cpp +++ b/cores/arduino/USB/PluggableUSB.cpp @@ -40,7 +40,7 @@ int PUSB_GetInterface(uint8_t* interfaceNum) int ret = 0; PUSBListNode* node = rootNode; for (uint8_t i=0; icb->getInterface(interfaceNum); + ret += node->cb->getInterface(interfaceNum); node = node->next; } return ret; diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index 171fe389f..ddc20146b 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -156,6 +156,8 @@ uint32_t USBDeviceClass::sendConfiguration(uint32_t maxlen) return true; } + total = 0; + packMessages(true); sendControl(&config, sizeof(ConfigDescriptor)); SendInterfaces(&total); From 02945cc78eaa5fb073290df3af70bc74fcaaac8e Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Mon, 5 Oct 2015 18:27:43 +0200 Subject: [PATCH 17/17] [PluggableUSB] port to stable API --- cores/arduino/USB/PluggableUSB.cpp | 95 ++++++++------ cores/arduino/USB/PluggableUSB.h | 61 +++++---- cores/arduino/USB/USBAPI.h | 3 +- cores/arduino/USB/USBCore.cpp | 10 +- cores/arduino/USB/USBCore.h | 8 +- libraries/HID/HID.cpp | 204 +++++++++++++---------------- libraries/HID/HID.h | 132 +++++++++++-------- 7 files changed, 266 insertions(+), 247 deletions(-) diff --git a/cores/arduino/USB/PluggableUSB.cpp b/cores/arduino/USB/PluggableUSB.cpp index 1a15dfa46..0f2d08c0d 100644 --- a/cores/arduino/USB/PluggableUSB.cpp +++ b/cores/arduino/USB/PluggableUSB.cpp @@ -19,80 +19,89 @@ #include "USBAPI.h" #include "USBDesc.h" +#include "USBCore.h" #include "PluggableUSB.h" +#if defined(USBCON) #ifdef PLUGGABLE_USB_ENABLED -#define MAX_MODULES 6 - -static uint8_t lastIf = CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT; -static uint8_t lastEp = CDC_FIRST_ENDPOINT + CDC_ENPOINT_COUNT; - extern uint32_t EndPoints[]; -//PUSBCallbacks cbs[MAX_MODULES]; -static uint8_t modules_count = 0; - -static PUSBListNode* rootNode = NULL; - -int PUSB_GetInterface(uint8_t* interfaceNum) +int PluggableUSB_::getInterface(uint8_t* interfaceCount) { - int ret = 0; - PUSBListNode* node = rootNode; - for (uint8_t i=0; icb->getInterface(interfaceNum); - node = node->next; + int sent = 0; + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + int res = node->getInterface(interfaceCount); + if (res < 0) + return -1; + sent += res; } - return ret; + return sent; } -int PUSB_GetDescriptor(int8_t t) +int PluggableUSB_::getDescriptor(USBSetup& setup) { - int ret = 0; - PUSBListNode* node = rootNode; - for (uint8_t i=0; icb->getDescriptor(t); - node = node->next; + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + int ret = node->getDescriptor(setup); + // ret!=0 -> request has been processed + if (ret) + return ret; } - return ret; + return 0; } -bool PUSB_Setup(USBSetup& setup, uint8_t j) +bool PluggableUSB_::setup(USBSetup& setup) { - bool ret = false; - PUSBListNode* node = rootNode; - for (uint8_t i=0; icb->setup(setup, j); - node = node->next; + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + if (node->setup(setup)) { + return true; + } } - return ret; + return false; } -int8_t PUSB_AddFunction(PUSBListNode *node, uint8_t* interface) +bool PluggableUSB_::plug(PluggableUSBModule *node) { - if (modules_count >= MAX_MODULES) { - return 0; + if ((lastEp + node->numEndpoints) > USB_ENDPOINTS) { + return false; } - if (modules_count == 0) { + if (!rootNode) { rootNode = node; } else { - PUSBListNode *current = rootNode; - while(current->next != NULL) { + PluggableUSBModule *current = rootNode; + while (current->next) { current = current->next; } current->next = node; } - *interface = lastIf; - lastIf += node->cb->numInterfaces; - for ( uint8_t i = 0; i< node->cb->numEndpoints; i++) { - EndPoints[lastEp] = node->cb->endpointType[i]; + node->pluggedInterface = lastIf; + node->pluggedEndpoint = lastEp; + lastIf += node->numInterfaces; + for (uint8_t i = 0; i < node->numEndpoints; i++) { + EndPoints[lastEp] = node->endpointType[i]; lastEp++; } - modules_count++; - return lastEp - node->cb->numEndpoints; + return true; // restart USB layer??? } +PluggableUSB_& PluggableUSB() +{ + static PluggableUSB_ obj; + return obj; +} + +PluggableUSB_::PluggableUSB_() : lastIf(CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT), + lastEp(CDC_FIRST_ENDPOINT + CDC_ENPOINT_COUNT), + rootNode(NULL) +{ + // Empty +} + +#endif #endif \ No newline at end of file diff --git a/cores/arduino/USB/PluggableUSB.h b/cores/arduino/USB/PluggableUSB.h index 502da9ebc..eb18ca253 100644 --- a/cores/arduino/USB/PluggableUSB.h +++ b/cores/arduino/USB/PluggableUSB.h @@ -25,38 +25,47 @@ #if defined(USBCON) -typedef struct __attribute__((packed)) -{ - bool (*setup)(USBSetup& setup, uint8_t i); - int (*getInterface)(uint8_t* interfaceNum); - int (*getDescriptor)(int8_t t); - int8_t numEndpoints; - int8_t numInterfaces; - uint32_t *endpointType; -} PUSBCallbacks; - -typedef struct -{ - uint8_t interface; - uint8_t firstEndpoint; -} PUSBReturn; - -class PUSBListNode { +class PluggableUSBModule { public: - PUSBListNode *next = NULL; - PUSBCallbacks *cb; - PUSBListNode(PUSBCallbacks *ncb) {cb = ncb;} -}; + PluggableUSBModule(uint8_t numEps, uint8_t numIfs, uint32_t *epType) : + numEndpoints(numEps), numInterfaces(numIfs), endpointType(epType) + { } + +protected: + virtual bool setup(USBSetup& setup) = 0; + virtual int getInterface(uint8_t* interfaceCount) = 0; + virtual int getDescriptor(USBSetup& setup) = 0; + + uint8_t pluggedInterface; + uint8_t pluggedEndpoint; -int8_t PUSB_AddFunction(PUSBListNode *node, uint8_t *interface); + const uint8_t numEndpoints; + const uint8_t numInterfaces; + const uint32_t *endpointType; -int PUSB_GetInterface(uint8_t* interfaceNum); + PluggableUSBModule *next = NULL; -int PUSB_GetDescriptor(int8_t t); + friend class PluggableUSB_; +}; -bool PUSB_Setup(USBSetup& setup, uint8_t i); +class PluggableUSB_ { +public: + PluggableUSB_(); + bool plug(PluggableUSBModule *node); + int getInterface(uint8_t* interfaceCount); + int getDescriptor(USBSetup& setup); + bool setup(USBSetup& setup); + +private: + uint8_t lastIf; + uint8_t lastEp; + PluggableUSBModule* rootNode; +}; -void PUSB_Begin(); +// Replacement for global singleton. +// This function prevents static-initialization-order-fiasco +// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use +PluggableUSB_& PluggableUSB(); #endif diff --git a/cores/arduino/USB/USBAPI.h b/cores/arduino/USB/USBAPI.h index 23d0ae242..f4a0babf8 100644 --- a/cores/arduino/USB/USBAPI.h +++ b/cores/arduino/USB/USBAPI.h @@ -78,6 +78,7 @@ class USBDeviceClass { bool sendStringDescriptor(const uint8_t *string, uint8_t maxlen); void initControl(int end); uint8_t SendInterfaces(uint32_t* total); + void packMessages(bool val); // Generic EndPoint API void initEndpoints(void); @@ -100,8 +101,6 @@ class USBDeviceClass { void ISRHandler(); private: - void packMessages(bool val); - bool initialized; }; diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp index ddc20146b..a584a638e 100644 --- a/cores/arduino/USB/USBCore.cpp +++ b/cores/arduino/USB/USBCore.cpp @@ -75,10 +75,10 @@ volatile uint32_t _usbConfiguration = 0; volatile uint32_t _usbSetInterface = 0; static __attribute__((__aligned__(4))) //__attribute__((__section__(".bss_hram0"))) -uint8_t udd_ep_out_cache_buffer[6][64]; +uint8_t udd_ep_out_cache_buffer[7][64]; static __attribute__((__aligned__(4))) //__attribute__((__section__(".bss_hram0"))) -uint8_t udd_ep_in_cache_buffer[6][64]; +uint8_t udd_ep_in_cache_buffer[7][64]; //================================================================== @@ -129,7 +129,7 @@ uint8_t USBDeviceClass::SendInterfaces(uint32_t* total) #endif #ifdef PLUGGABLE_USB_ENABLED - total[0] += PUSB_GetInterface(&interfaces); + total[0] += PluggableUSB().getInterface(&interfaces); #endif return interfaces; @@ -180,7 +180,7 @@ bool USBDeviceClass::sendDescriptor(USBSetup &setup) } #ifdef PLUGGABLE_USB_ENABLED - ret = PUSB_GetDescriptor(t); + ret = PluggableUSB().getDescriptor(setup); if (ret != 0) { return (ret > 0 ? true : false); } @@ -360,7 +360,7 @@ bool USBDeviceClass::handleClassInterfaceSetup(USBSetup& setup) #endif #if defined(PLUGGABLE_USB_ENABLED) - bool ret = PUSB_Setup(setup, i); + bool ret = PluggableUSB().setup(setup); if ( ret == false) { sendZlp(0); } diff --git a/cores/arduino/USB/USBCore.h b/cores/arduino/USB/USBCore.h index 0d2dc7854..853f305ae 100644 --- a/cores/arduino/USB/USBCore.h +++ b/cores/arduino/USB/USBCore.h @@ -36,6 +36,8 @@ #define USB_ENDPOINT_OUT(addr) ((addr) | 0x00) #define USB_ENDPOINT_IN(addr) ((addr) | 0x80) +#define USB_ENDPOINTS 7 + #define USB_ENDPOINT_TYPE_MASK 0x03 #define USB_ENDPOINT_TYPE_CONTROL 0x00 #define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01 @@ -58,9 +60,9 @@ #define REQUEST_OTHER 0x03 #define REQUEST_RECIPIENT 0x1F -#define REQUEST_DEVICETOHOST_CLASS_INTERFACE (REQUEST_DEVICETOHOST + REQUEST_CLASS + REQUEST_INTERFACE) -#define REQUEST_HOSTTODEVICE_CLASS_INTERFACE (REQUEST_HOSTTODEVICE + REQUEST_CLASS + REQUEST_INTERFACE) - +#define REQUEST_DEVICETOHOST_CLASS_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_CLASS | REQUEST_INTERFACE) +#define REQUEST_HOSTTODEVICE_CLASS_INTERFACE (REQUEST_HOSTTODEVICE | REQUEST_CLASS | REQUEST_INTERFACE) +#define REQUEST_DEVICETOHOST_STANDARD_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_INTERFACE) // Class requests #define CDC_SET_LINE_CODING 0x20 diff --git a/libraries/HID/HID.cpp b/libraries/HID/HID.cpp index c4bbd5cd8..94bf9f598 100644 --- a/libraries/HID/HID.cpp +++ b/libraries/HID/HID.cpp @@ -19,158 +19,132 @@ #include "USB/PluggableUSB.h" #include "HID.h" -HID_ HID; +#if defined(USBCON) -static uint8_t HID_ENDPOINT_INT; - -//================================================================================ -//================================================================================ - -// HID report descriptor - -#define LSB(_x) ((_x) & 0xFF) -#define MSB(_x) ((_x) >> 8) - -#define RAWHID_USAGE_PAGE 0xFFC0 -#define RAWHID_USAGE 0x0C00 -#define RAWHID_TX_SIZE 64 -#define RAWHID_RX_SIZE 64 - -static uint8_t HID_INTERFACE; - -HIDDescriptor _hidInterface; - -static HIDDescriptorListNode* rootNode = NULL; -static uint8_t sizeof_hidReportDescriptor = 0; -static uint8_t modules_count = 0; -//================================================================================ -//================================================================================ -// Driver - -uint8_t _hid_protocol = 1; -uint8_t _hid_idle = 1; +HID_& HID() +{ + static HID_ obj; + return obj; +} -int HID_GetInterface(uint8_t* interfaceNum) +int HID_::getInterface(uint8_t* interfaceCount) { - interfaceNum[0] += 1; // uses 1 - _hidInterface = - { - D_INTERFACE(HID_INTERFACE,1,3,0,0), - D_HIDREPORT(sizeof_hidReportDescriptor), - D_ENDPOINT(USB_ENDPOINT_IN (HID_ENDPOINT_INT),USB_ENDPOINT_TYPE_INTERRUPT,0x40,0x01) + *interfaceCount += 1; // uses 1 + HIDDescriptor hidInterface = { + D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE), + D_HIDREPORT(descriptorSize), + D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, 0x40, 0x01) }; - return USBDevice.sendControl(&_hidInterface,sizeof(_hidInterface)); + return USBDevice.sendControl(&hidInterface, sizeof(hidInterface)); } -int HID_GetDescriptor(int8_t t) +int HID_::getDescriptor(USBSetup& setup) { - if (HID_REPORT_DESCRIPTOR_TYPE == t) { - HIDDescriptorListNode* current = rootNode; - int total = 0; - while(current != NULL) { - total += USBDevice.sendControl(current->cb->descriptor,current->cb->length); - current = current->next; - } - return total; - } else { - return 0; + // Check if this is a HID Class Descriptor request + if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; } + if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; } + + // In a HID Class Descriptor wIndex cointains the interface number + if (setup.wIndex != pluggedInterface) { return 0; } + + int total = 0; + HIDSubDescriptor* node; + USBDevice.packMessages(true); + for (node = rootNode; node; node = node->next) { + int res = USBDevice.sendControl(node->data, node->length); + if (res == -1) + return -1; + total += res; } + USBDevice.packMessages(false); + return total; } -void HID_::AppendDescriptor(HIDDescriptorListNode *node) +void HID_::AppendDescriptor(HIDSubDescriptor *node) { - if (modules_count == 0) { + if (!rootNode) { rootNode = node; } else { - HIDDescriptorListNode *current = rootNode; - while(current->next != NULL) { + HIDSubDescriptor *current = rootNode; + while (current->next) { current = current->next; } current->next = node; } - modules_count++; - sizeof_hidReportDescriptor += node->cb->length; + descriptorSize += node->length; } void HID_::SendReport(uint8_t id, const void* data, int len) { - uint8_t p[8]; - const uint8_t *d = reinterpret_cast(data); - + uint8_t p[64]; p[0] = id; - for (uint32_t i=0; i #include +#include "USB/PluggableUSB.h" -#define _USING_HID +#if defined(USBCON) -//================================================================================ -//================================================================================ -// HID 'Driver' +#define _USING_HID +// HID 'Driver' +// ------------ #define HID_GET_REPORT 0x01 #define HID_GET_IDLE 0x02 #define HID_GET_PROTOCOL 0x03 @@ -42,52 +40,80 @@ #define HID_REPORT_DESCRIPTOR_TYPE 0x22 #define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23 -typedef struct __attribute__((packed)) { - uint8_t length; - const void* descriptor; -} HID_Descriptor; +// HID subclass HID1.11 Page 8 4.2 Subclass +#define HID_SUBCLASS_NONE 0 +#define HID_SUBCLASS_BOOT_INTERFACE 1 + +// HID Keyboard/Mouse bios compatible protocols HID1.11 Page 9 4.3 Protocols +#define HID_PROTOCOL_NONE 0 +#define HID_PROTOCOL_KEYBOARD 1 +#define HID_PROTOCOL_MOUSE 2 + +// Normal or bios protocol (Keyboard/Mouse) HID1.11 Page 54 7.2.5 Get_Protocol Request +// "protocol" variable is used for this purpose. +#define HID_BOOT_PROTOCOL 0 +#define HID_REPORT_PROTOCOL 1 + +typedef struct +{ + uint8_t len; // 9 + uint8_t dtype; // 0x21 + uint8_t addr; + uint8_t versionL; // 0x101 + uint8_t versionH; // 0x101 + uint8_t country; + uint8_t desctype; // 0x22 report + uint8_t descLenL; + uint8_t descLenH; +} HIDDescDescriptor; + +typedef struct +{ + InterfaceDescriptor hid; + HIDDescDescriptor desc; + EndpointDescriptor in; +} HIDDescriptor; -class HIDDescriptorListNode { +class HIDSubDescriptor { public: - HIDDescriptorListNode *next = NULL; - const HID_Descriptor * cb; - HIDDescriptorListNode(const HID_Descriptor *ncb) {cb = ncb;} + HIDSubDescriptor *next = NULL; + HIDSubDescriptor(const void *d, const uint16_t l) : data(d), length(l) { } + + const void* data; + const uint16_t length; }; -class HID_ +class HID_ : public PluggableUSBModule { public: HID_(void); int begin(void); void SendReport(uint8_t id, const void* data, int len); - void AppendDescriptor(HIDDescriptorListNode* node); -}; + void AppendDescriptor(HIDSubDescriptor* node); -typedef struct -{ - uint8_t len; // 9 - uint8_t dtype; // 0x21 - uint8_t addr; - uint8_t versionL; // 0x101 - uint8_t versionH; // 0x101 - uint8_t country; - uint8_t desctype; // 0x22 report - uint8_t descLenL; - uint8_t descLenH; -} HIDDescDescriptor; +protected: + // Implementation of the PluggableUSBModule + int getInterface(uint8_t* interfaceCount); + int getDescriptor(USBSetup& setup); + bool setup(USBSetup& setup); -typedef struct -{ - InterfaceDescriptor hid; - HIDDescDescriptor desc; - EndpointDescriptor in; -} HIDDescriptor; +private: + uint32_t epType[1]; + + HIDSubDescriptor* rootNode; + uint16_t descriptorSize; + + uint8_t protocol; + uint8_t idle; +}; -#define HID_TX HID_ENDPOINT_INT +// Replacement for global singleton. +// This function prevents static-initialization-order-fiasco +// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use +HID_& HID(); -#define D_HIDREPORT(_descriptorLength) \ - { 9, 0x21, 0x1, 0x1, 0, 1, 0x22, _descriptorLength, 0 } +#define D_HIDREPORT(length) { 9, 0x21, 0x01, 0x01, 0, 1, 0x22, lowByte(length), highByte(length) } -#define WEAK __attribute__ ((weak)) +#endif -#endif \ No newline at end of file +#endif