From 4cb88ec89cb2fe12a74f5080f408cba342dd0697 Mon Sep 17 00:00:00 2001 From: Gurbrinder Date: Wed, 8 Apr 2015 15:51:28 -0700 Subject: [PATCH 1/7] Create Midi.cpp --- .../arduino/sam/cores/arduino/USB/Midi.cpp | 183 ++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 hardware/arduino/sam/cores/arduino/USB/Midi.cpp diff --git a/hardware/arduino/sam/cores/arduino/USB/Midi.cpp b/hardware/arduino/sam/cores/arduino/USB/Midi.cpp new file mode 100644 index 00000000000..a95b1cb943c --- /dev/null +++ b/hardware/arduino/sam/cores/arduino/USB/Midi.cpp @@ -0,0 +1,183 @@ +// Copyright (c) 2015, Gary Grewal +/* +** 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 "Arduino.h" +#include "USBAPI.h" +#include "Reset.h" + +#ifdef MIDI_ENABLED + +#define MIDI_BUFFER_SIZE 128 + +struct ring_bufferMIDI +{ + midiEventPacket_t midiEvent[MIDI_BUFFER_SIZE]; + volatile uint32_t head; + volatile uint32_t tail; +}; + +ring_bufferMIDI midi_rx_buffer = {{0,0,0,0 }, 0, 0}; + +_Pragma("pack(1)") +static const MIDIDescriptor _midiInterface = +{ +#ifdef CDC_ENABLED + D_IAD(MIDI_AC_INTERFACE,MIDI_INTERFACE_COUNT, MIDI_AUDIO, MIDI_AUDIO_CONTROL, 0), +#endif + D_INTERFACE(MIDI_AC_INTERFACE,0,MIDI_AUDIO,MIDI_AUDIO_CONTROL,0), + D_AC_INTERFACE(0x1, MIDI_INTERFACE), + D_INTERFACE(MIDI_INTERFACE,2, MIDI_AUDIO,MIDI_STREAMING,0), + D_AS_INTERFACE, + D_MIDI_INJACK(MIDI_JACK_EMD, 0x1), + D_MIDI_INJACK(MIDI_JACK_EXT, 0x2), + D_MIDI_OUTJACK(MIDI_JACK_EMD, 0x3, 1, 2, 1), + D_MIDI_OUTJACK(MIDI_JACK_EXT, 0x4, 1, 1, 1), + D_MIDI_JACK_EP(USB_ENDPOINT_OUT(MIDI_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,0x0040), + D_MIDI_AC_JACK_EP(1, 1), + D_MIDI_JACK_EP(USB_ENDPOINT_IN(MIDI_ENDPOINT_IN),USB_ENDPOINT_TYPE_BULK,0x0040), + D_MIDI_AC_JACK_EP (1, 3) +}; +_Pragma("pack()") + +int WEAK MIDI_GetInterface(uint8_t* interfaceNum) +{ + interfaceNum[0] += 2; // uses 2 + return USBD_SendControl(0,&_midiInterface,sizeof(_midiInterface)); +} +bool WEAK MIDI_Setup(Setup& setup) +{ + //Support requests here if needed. Typically these are optional + return false; +} + +void MIDI_::begin() +{ + //Nothing to do +} + +void MIDI_::accept(void) +{ + static uint32_t mguard = 0; + + // synchronized access to guard + do { + if (__LDREXW(&mguard) != 0) { + __CLREX(); + return; // busy + } + } while (__STREXW(1, &mguard) != 0); // retry until write succeed + + ring_bufferMIDI *buffer = &midi_rx_buffer; + uint32_t i = (uint32_t)(buffer->head+1) % MIDI_BUFFER_SIZE; + + // if we should be storing the received character into the location + // just before the tail (meaning that the head would advance to the + // current location of the tail), we're about to overflow the buffer + // and so we don't write the character or advance the head. + while (i != buffer->tail) { + int c; + midiEventPacket_t event; + if (!USBD_Available(MIDI_RX)) { + udd_ack_fifocon(MIDI_RX); + break; + } + c = USBD_Recv(MIDI_RX, &event, sizeof(event) ); + + //MIDI paacket has to be 4 bytes + if(c < 4) + return; + buffer->midiEvent[buffer->head] = event; + buffer->head = i; + + i = (i + 1) % MIDI_BUFFER_SIZE; + } + + // release the guard + mguard = 0; +} + +uint32_t MIDI_::available(void) +{ + + ring_bufferMIDI *buffer = &midi_rx_buffer; + return (uint32_t)(MIDI_BUFFER_SIZE + buffer->head - buffer->tail) % MIDI_BUFFER_SIZE; +} + + +midiEventPacket_t MIDI_::read(void) +{ + ring_bufferMIDI *buffer = &midi_rx_buffer; + midiEventPacket_t c = buffer->midiEvent[buffer->tail]; + c.header = 0; + c.byte1 = 0; + c.byte2 = 0; + c.byte3 = 0; + + // if the head isn't ahead of the tail, we don't have any characters + if (buffer->head == buffer->tail) + { + return c; + } + else + { + midiEventPacket_t c = buffer->midiEvent[buffer->tail]; + buffer->tail = (uint32_t)(buffer->tail + 1) % MIDI_BUFFER_SIZE; + if (USBD_Available(MIDI_RX)) + accept(); + return c; + } +} + +void MIDI_::flush(void) +{ + USBD_Flush(MIDI_TX); +} + +size_t MIDI_::write(const uint8_t *buffer, size_t size) +{ + /* only try to send bytes if the high-level MIDI connection itself + is open (not just the pipe) - the OS should set lineState when the port + is opened and clear lineState when the port is closed. + bytes sent before the user opens the connection or after + the connection is closed are lost - just like with a UART. */ + + // 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) + + int r = USBD_Send(MIDI_TX, buffer, size); + + if (r > 0) + { + return r; + } else + { + return 0; + } + return 0; +} + +void MIDI_::sendMIDI(midiEventPacket_t event) +{ + uint8_t data[4]; + data[0] = event.header; + data[1] = event.byte1; + data[2] = event.byte2; + data[3] = event.byte3; + write(data, 4); +} + +MIDI_ MidiUSB; +#endif From 7a6b16084d9635485c0a0366733571b00096ca75 Mon Sep 17 00:00:00 2001 From: Gurbrinder Date: Wed, 8 Apr 2015 15:52:24 -0700 Subject: [PATCH 2/7] USB MIDI --- .../arduino/sam/cores/arduino/USB/USBAPI.h | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/hardware/arduino/sam/cores/arduino/USB/USBAPI.h b/hardware/arduino/sam/cores/arduino/USB/USBAPI.h index 3cf601e9e87..5b570112b40 100644 --- a/hardware/arduino/sam/cores/arduino/USB/USBAPI.h +++ b/hardware/arduino/sam/cores/arduino/USB/USBAPI.h @@ -64,6 +64,37 @@ class Serial_ : public Stream }; extern Serial_ SerialUSB; + +//Gurbrinder: Midi Interface +//================================================================================ +//================================================================================ +// MIDI USB class + +typedef struct +{ + uint8_t header; + uint8_t byte1; + uint8_t byte2; + uint8_t byte3; +}midiEventPacket_t; + +class MIDI_ +{ +private: + RingBuffer *_midi_rx_buffer; +public: + void begin(); + + virtual uint32_t available(void); + virtual void accept(void); + virtual midiEventPacket_t read(void); + virtual void flush(void); + virtual void sendMIDI(midiEventPacket_t event); + virtual size_t write(const uint8_t *buffer, size_t size); + operator bool(); +}; +extern MIDI_ MidiUSB; + //================================================================================ //================================================================================ // Mouse @@ -196,6 +227,15 @@ int CDC_GetOtherInterface(uint8_t* interfaceNum); int CDC_GetDescriptor(int i); bool CDC_Setup(Setup& setup); +//================================================================================ +//================================================================================ +// MIDI 'Driver' + +int MIDI_GetInterface(uint8_t* interfaceNum); +int MIDI_GetOtherInterface(uint8_t* interfaceNum); +int MIDI_GetDescriptor(int i); +bool MIDI_Setup(Setup& setup); + //================================================================================ //================================================================================ From ed21dbd5df50b00182ac8efda3d637bf9d5e03af Mon Sep 17 00:00:00 2001 From: Gurbrinder Date: Wed, 8 Apr 2015 15:53:21 -0700 Subject: [PATCH 3/7] Update USBCore.cpp --- .../arduino/sam/cores/arduino/USB/USBCore.cpp | 1200 +++++------------ 1 file changed, 369 insertions(+), 831 deletions(-) diff --git a/hardware/arduino/sam/cores/arduino/USB/USBCore.cpp b/hardware/arduino/sam/cores/arduino/USB/USBCore.cpp index c21fda7f4c9..6a19cf85042 100644 --- a/hardware/arduino/sam/cores/arduino/USB/USBCore.cpp +++ b/hardware/arduino/sam/cores/arduino/USB/USBCore.cpp @@ -14,873 +14,411 @@ ** SOFTWARE. */ -#include "Arduino.h" -#include "USBAPI.h" -#include "Reset.h" -#include +#ifndef __USBCORE_H__ +#define __USBCORE_H__ + +// Standard requests +#define GET_STATUS 0 +#define CLEAR_FEATURE 1 +#define SET_FEATURE 3 +#define SET_ADDRESS 5 +#define GET_DESCRIPTOR 6 +#define SET_DESCRIPTOR 7 +#define GET_CONFIGURATION 8 +#define SET_CONFIGURATION 9 +#define GET_INTERFACE 10 +#define SET_INTERFACE 11 + + +// bmRequestType +#define REQUEST_HOSTTODEVICE 0x00 +#define REQUEST_DEVICETOHOST 0x80 +#define REQUEST_DIRECTION 0x80 + +#define REQUEST_STANDARD 0x00 +#define REQUEST_CLASS 0x20 +#define REQUEST_VENDOR 0x40 +#define REQUEST_TYPE 0x60 + +#define REQUEST_DEVICE 0x00 +#define REQUEST_INTERFACE 0x01 +#define REQUEST_ENDPOINT 0x02 +#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) + +// Class requests + +#define CDC_SET_LINE_CODING 0x20 +#define CDC_GET_LINE_CODING 0x21 +#define CDC_SET_CONTROL_LINE_STATE 0x22 + +#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 +#define USB_CONFIGUARTION_DESC_SIZE 9 +#define USB_INTERFACE_DESC_SIZE 9 +#define USB_ENDPOINT_DESC_SIZE 7 + +#define USB_DEVICE_DESCRIPTOR_TYPE 1 +#define USB_CONFIGURATION_DESCRIPTOR_TYPE 2 +#define USB_STRING_DESCRIPTOR_TYPE 3 +#define USB_INTERFACE_DESCRIPTOR_TYPE 4 +#define USB_ENDPOINT_DESCRIPTOR_TYPE 5 +#define USB_DEVICE_QUALIFIER 6 +#define USB_OTHER_SPEED_CONFIGURATION 7 + +#define USB_DEVICE_CLASS_COMMUNICATIONS 0x02 +#define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03 +#define USB_DEVICE_CLASS_STORAGE 0x08 +#define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF + +#define USB_CONFIG_POWERED_MASK 0x40 +#define USB_CONFIG_BUS_POWERED 0x80 +#define USB_CONFIG_SELF_POWERED 0xC0 +#define USB_CONFIG_REMOTE_WAKEUP 0x20 + +// bMaxPower in Configuration Descriptor +#define USB_CONFIG_POWER_MA(mA) ((mA)/2) + +// 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 + +#define TOBYTES(x) ((x) & 0xFF),(((x) >> 8) & 0xFF) + +#define CDC_V1_10 0x0110 +#define CDC_COMMUNICATION_INTERFACE_CLASS 0x02 + +#define CDC_CALL_MANAGEMENT 0x01 +#define CDC_ABSTRACT_CONTROL_MODEL 0x02 +#define CDC_HEADER 0x00 +#define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02 +#define CDC_UNION 0x06 +#define CDC_CS_INTERFACE 0x24 +#define CDC_CS_ENDPOINT 0x25 +#define CDC_DATA_INTERFACE_CLASS 0x0A + +#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 + +#define MIDI_AUDIO 0x01 +#define MIDI_AUDIO_CONTROL 0x01 +#define MIDI_CS_INTERFACE 0x24 +#define MIDI_CS_ENDPOINT 0x25 +#define MIDI_STREAMING 0x3 +#define MIDI_JACK_EMD 0x01 +#define MIDI_JACK_EXT 0X02 -//#define TRACE_CORE(x) x -#define TRACE_CORE(x) -static const uint32_t EndPoints[] = -{ - EP_TYPE_CONTROL, - -#ifdef CDC_ENABLED - EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM - EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT - EP_TYPE_BULK_IN, // CDC_ENDPOINT_IN -#endif - -#ifdef HID_ENABLED - EP_TYPE_INTERRUPT_IN_HID // HID_ENDPOINT_INT -#endif -}; - -/** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */ -#define TX_RX_LED_PULSE_MS 100 -volatile uint8_t TxLEDPulse; /**< Milliseconds remaining for data Tx LED pulse */ -volatile uint8_t RxLEDPulse; /**< Milliseconds remaining for data Rx LED pulse */ -static char isRemoteWakeUpEnabled = 0; -static char isEndpointHalt = 0; -//================================================================== -//================================================================== - -extern const uint16_t STRING_LANGUAGE[]; -extern const uint8_t STRING_PRODUCT[]; -extern const uint8_t STRING_MANUFACTURER[]; -extern const DeviceDescriptor USB_DeviceDescriptor; -extern const DeviceDescriptor USB_DeviceDescriptorA; - -const uint16_t STRING_LANGUAGE[2] = { - (3<<8) | (2+2), - 0x0409 // English -}; - -#ifndef USB_PRODUCT -// Use a hardcoded product name if none is provided -#if USB_PID == USB_PID_DUE -#define USB_PRODUCT "Arduino Due" -#else -#define USB_PRODUCT "USB IO Board" -#endif -#endif - -const uint8_t STRING_PRODUCT[] = USB_PRODUCT; - -#if USB_VID == 0x2341 -# if defined(USB_MANUFACTURER) -# undef USB_MANUFACTURER -# endif -# define USB_MANUFACTURER "Arduino LLC" -#elif !defined(USB_MANUFACTURER) -// Fall through to unknown if no manufacturer name was provided in a macro -# define USB_MANUFACTURER "Unknown" -#endif - -const uint8_t STRING_MANUFACTURER[12] = USB_MANUFACTURER; - -#ifdef CDC_ENABLED -#define DEVICE_CLASS 0x02 -#else -#define DEVICE_CLASS 0x00 -#endif - -// DEVICE DESCRIPTOR -const DeviceDescriptor USB_DeviceDescriptor = - D_DEVICE(0x00,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); - -const DeviceDescriptor USB_DeviceDescriptorA = - D_DEVICE(DEVICE_CLASS,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); - -const DeviceDescriptor USB_DeviceQualifier = - D_QUALIFIER(0x00,0x00,0x00,64,1); - -//! 7.1.20 Test Mode Support -static const unsigned char test_packet_buffer[] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // JKJKJKJK * 9 - 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA, // JJKKJJKK * 8 - 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE, // JJJJKKKK * 8 - 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // JJJJJJJKKKKKKK * 8 - 0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD, // JJJJJJJK * 8 - 0xFC,0x7E,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0x7E // {JKKKKKKK * 10}, JK -}; - -//================================================================== -//================================================================== - -volatile uint32_t _usbConfiguration = 0; -volatile uint32_t _usbInitialized = 0; -uint32_t _usbSetInterface = 0; -uint32_t _cdcComposite = 0; - -//================================================================== -//================================================================== +_Pragma("pack(1)") -#define USB_RECV_TIMEOUT -class LockEP +// Device +typedef struct { + uint8_t len; // 18 + uint8_t dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE + uint16_t usbVersion; // 0x200 + uint8_t deviceClass; + uint8_t deviceSubClass; + uint8_t deviceProtocol; + uint8_t packetSize0; // Packet 0 + uint16_t idVendor; + uint16_t idProduct; + uint16_t deviceVersion; // 0x100 + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} DeviceDescriptor; + +// Config +typedef struct { + uint8_t len; // 9 + uint8_t dtype; // 2 + uint16_t clen; // total length + uint8_t numInterfaces; + uint8_t config; + uint8_t iconfig; + uint8_t attributes; + uint8_t maxPower; +} ConfigDescriptor; + +// String + +// Interface +typedef struct { - irqflags_t flags; -public: - LockEP(uint32_t ep) : flags(cpu_irq_save()) - { - } - ~LockEP() - { - cpu_irq_restore(flags); - } -}; - -// Number of bytes, assumes a rx endpoint -uint32_t USBD_Available(uint32_t ep) + uint8_t len; // 9 + uint8_t dtype; // 4 + uint8_t number; + uint8_t alternate; + uint8_t numEndpoints; + uint8_t interfaceClass; + uint8_t interfaceSubClass; + uint8_t protocol; + uint8_t iInterface; +} InterfaceDescriptor; + +// Endpoint +typedef struct { - LockEP lock(ep); - return UDD_FifoByteCount(ep & 0xF); -} - -// Non Blocking receive -// Return number of bytes read -uint32_t USBD_Recv(uint32_t ep, void* d, uint32_t len) -{ - if (!_usbConfiguration) - return -1; - - LockEP lock(ep); - uint32_t n = UDD_FifoByteCount(ep & 0xF); - len = min(n,len); - n = len; - uint8_t* dst = (uint8_t*)d; - while (n--) - *dst++ = UDD_Recv8(ep & 0xF); - if (len && !UDD_FifoByteCount(ep & 0xF)) // release empty buffer - UDD_ReleaseRX(ep & 0xF); - - return len; -} - -// Recv 1 byte if ready -uint32_t USBD_Recv(uint32_t ep) + uint8_t len; // 7 + uint8_t dtype; // 5 + uint8_t addr; + uint8_t attr; + uint16_t packetSize; + uint8_t interval; +} EndpointDescriptor; + +// Interface Association Descriptor +// Used to bind 2 interfaces together in CDC compostite device +typedef struct { - uint8_t c; - if (USBD_Recv(ep & 0xF, &c, 1) != 1) - return -1; - else - return c; -} - -// Space in send EP -//uint32_t USBD_SendSpace(uint32_t ep) -//{ - //LockEP lock(ep); -//// if (!UDD_ReadWriteAllowed(ep & 0xF)) - ////{ - ////printf("pb "); // UOTGHS->UOTGHS_DEVEPTISR[%d]=0x%X\n\r", ep, UOTGHS->UOTGHS_DEVEPTISR[ep]); - ////return 0; - ////} - - //if(ep==0) return 64 - UDD_FifoByteCount(ep & 0xF); // EP0_SIZE jcb - //else return 512 - UDD_FifoByteCount(ep & 0xF); // EPX_SIZE jcb -//} - -// Blocking Send of data to an endpoint -uint32_t USBD_Send(uint32_t ep, const void* d, uint32_t len) + uint8_t len; // 8 + uint8_t dtype; // 11 + uint8_t firstInterface; + uint8_t interfaceCount; + uint8_t functionClass; + uint8_t funtionSubClass; + uint8_t functionProtocol; + uint8_t iInterface; +} IADDescriptor; + +// CDC CS interface descriptor +typedef struct { - uint32_t n; - int r = len; - const uint8_t* data = (const uint8_t*)d; - - if (!_usbConfiguration) - { - TRACE_CORE(printf("pb conf\n\r");) - return -1; - } - - while (len) - { - if(ep==0) n = EP0_SIZE; - else n = EPX_SIZE; - if (n > len) - n = len; - len -= n; - - UDD_Send(ep & 0xF, data, n); - data += n; - } - //TXLED1; // light the TX LED - //TxLEDPulse = TX_RX_LED_PULSE_MS; - return r; -} - -int _cmark; -int _cend; - -void USBD_InitControl(int end) + uint8_t len; // 5 + uint8_t dtype; // 0x24 + uint8_t subtype; + uint8_t d0; + uint8_t d1; +} CDCCSInterfaceDescriptor; + +typedef struct { - _cmark = 0; - _cend = end; -} + uint8_t len; // 4 + uint8_t dtype; // 0x24 + uint8_t subtype; + uint8_t d0; +} CDCCSInterfaceDescriptor4; -// Clipped by _cmark/_cend -int USBD_SendControl(uint8_t flags, const void* d, uint32_t len) +typedef struct { - const uint8_t* data = (const uint8_t*)d; - uint32_t length = len; - uint32_t sent = 0; - uint32_t pos = 0; - - TRACE_CORE(printf("=> USBD_SendControl TOTAL len=%lu\r\n", len);) - - if (_cmark < _cend) - { - while (len > 0) - { - sent = UDD_Send(EP0, data + pos, len); - TRACE_CORE(printf("=> USBD_SendControl sent=%lu\r\n", sent);) - pos += sent; - len -= sent; - } - } - - _cmark += length; - - 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) { - uint16_t buff[64]; - int l = 1; - wLength-=2; - while (*string && wLength>0) { - buff[l++] = (uint8_t)(*string++); - wLength-=2; - } - buff[0] = (3<<8) | (l*2); - return USBD_SendControl(0, (uint8_t*)buff, l*2); -} - -// Does not timeout or cross fifo boundaries -// Will only work for transfers <= 64 bytes -// TODO -int USBD_RecvControl(void* d, uint32_t len) + uint8_t len; + uint8_t dtype; // 0x24 + uint8_t subtype; // 1 + uint8_t bmCapabilities; + uint8_t bDataInterface; +} CMFunctionalDescriptor; + +typedef struct { - UDD_WaitOUT(); - UDD_Recv(EP0, (uint8_t*)d, len); - UDD_ClearOUT(); + uint8_t len; + uint8_t dtype; // 0x24 + uint8_t subtype; // 1 + uint8_t bmCapabilities; +} ACMFunctionalDescriptor; - return len; -} - -// Handle CLASS_INTERFACE requests -bool USBD_ClassInterfaceRequest(Setup& setup) +typedef struct { - uint8_t i = setup.wIndex; - - TRACE_CORE(printf("=> USBD_ClassInterfaceRequest\r\n");) - -#ifdef CDC_ENABLED - if (CDC_ACM_INTERFACE == i) - { - return CDC_Setup(setup); - } -#endif - -#ifdef HID_ENABLED - if (HID_INTERFACE == i) - { - return HID_Setup(setup); - } -#endif - - return false; -} - -int USBD_SendInterfaces(void) + // IAD + IADDescriptor iad; // Only needed on compound device + + // Control + InterfaceDescriptor cif; + CDCCSInterfaceDescriptor header; + CMFunctionalDescriptor callManagement; // Call Management + ACMFunctionalDescriptor controlManagement; // ACM + CDCCSInterfaceDescriptor functionalDescriptor; // CDC_UNION + EndpointDescriptor cifin; + + // Data + InterfaceDescriptor dif; + EndpointDescriptor in; + EndpointDescriptor out; +} CDCDescriptor; + +typedef struct { - int total = 0; - uint8_t interfaces = 0; - -#ifdef CDC_ENABLED - total = CDC_GetInterface(&interfaces); -#endif - -#ifdef HID_ENABLED - total += HID_GetInterface(&interfaces); -#endif + InterfaceDescriptor msc; + EndpointDescriptor in; + EndpointDescriptor out; +} MSCDescriptor; - total = total; // Get rid of compiler warning - TRACE_CORE(printf("=> USBD_SendInterfaces, total=%d interfaces=%d\r\n", total, interfaces);) - return interfaces; -} - -int USBD_SendOtherInterfaces(void) +typedef struct { - int total = 0; - uint8_t interfaces = 0; - -#ifdef CDC_ENABLED - total = CDC_GetOtherInterface(&interfaces); -#endif - -#ifdef HID_ENABLED - total += HID_GetInterface(&interfaces); -#endif - - total = total; // Get rid of compiler warning - TRACE_CORE(printf("=> USBD_SendInterfaces, total=%d interfaces=%d\r\n", total, interfaces);) - return interfaces; -} - -// Construct a dynamic configuration descriptor -// This really needs dynamic endpoint allocation etc -// TODO -static bool USBD_SendConfiguration(int maxlen) + 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 { - // Count and measure interfaces - USBD_InitControl(0); - //TRACE_CORE(printf("=> USBD_SendConfiguration _cmark1=%d\r\n", _cmark);) - int interfaces = USBD_SendInterfaces(); - //TRACE_CORE(printf("=> USBD_SendConfiguration _cmark2=%d\r\n", _cmark);) - //TRACE_CORE(printf("=> USBD_SendConfiguration sizeof=%d\r\n", sizeof(ConfigDescriptor));) - -_Pragma("pack(1)") - ConfigDescriptor config = D_CONFIG(_cmark + sizeof(ConfigDescriptor),interfaces); -_Pragma("pack()") - //TRACE_CORE(printf("=> USBD_SendConfiguration clen=%d\r\n", config.clen);) + InterfaceDescriptor hid; + HIDDescDescriptor desc; + EndpointDescriptor in; +} HIDDescriptor; - //TRACE_CORE(printf("=> USBD_SendConfiguration maxlen=%d\r\n", maxlen);) - // Now send them - USBD_InitControl(maxlen); - USBD_SendControl(0,&config,sizeof(ConfigDescriptor)); - USBD_SendInterfaces(); - return true; -} - -static bool USBD_SendOtherConfiguration(int maxlen) +typedef struct { - // Count and measure interfaces - USBD_InitControl(0); - //TRACE_CORE(printf("=> USBD_SendConfiguration _cmark1=%d\r\n", _cmark);) - int interfaces = USBD_SendOtherInterfaces(); - //TRACE_CORE(printf("=> USBD_SendConfiguration _cmark2=%d\r\n", _cmark);) - //TRACE_CORE(printf("=> USBD_SendConfiguration sizeof=%d\r\n", sizeof(ConfigDescriptor));) - -_Pragma("pack(1)") - ConfigDescriptor config = D_OTHERCONFIG(_cmark + sizeof(ConfigDescriptor),interfaces); -_Pragma("pack()") - //TRACE_CORE(printf("=> USBD_SendConfiguration clen=%d\r\n", config.clen);) - - //TRACE_CORE(printf("=> USBD_SendConfiguration maxlen=%d\r\n", maxlen);) - - // Now send them - USBD_InitControl(maxlen); - USBD_SendControl(0,&config,sizeof(ConfigDescriptor)); - USBD_SendOtherInterfaces(); - return true; -} - -static bool USBD_SendDescriptor(Setup& setup) + uint8_t len; // 9 + uint8_t dtype; // 4 + uint8_t dsubType; + uint16_t bcdADc; + uint16_t wTotalLength; + uint8_t bInCollection; + uint8_t interfaceNumbers; +} MIDI_ACInterfaceDescriptor; + +typedef struct { - uint8_t t = setup.wValueH; - uint8_t desc_length = 0; - const uint8_t* desc_addr = 0; - - if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) - { - TRACE_CORE(printf("=> USBD_SendDescriptor : USB_CONFIGURATION_DESCRIPTOR_TYPE length=%d\r\n", setup.wLength);) - return USBD_SendConfiguration(setup.wLength); - } - - USBD_InitControl(setup.wLength); -#ifdef HID_ENABLED - if (HID_REPORT_DESCRIPTOR_TYPE == t) - { - TRACE_CORE(puts("=> USBD_SendDescriptor : HID_REPORT_DESCRIPTOR_TYPE\r\n");) - return HID_GetDescriptor(t); - } -#endif + uint8_t len; // 9 + uint8_t dtype; // 4 + uint8_t dsubType; + uint8_t jackType; + uint8_t jackID; + uint8_t jackStrIndex; +} MIDIJackinDescriptor; + +typedef struct +{ + uint8_t len; // 9 + uint8_t dtype; // 4 + uint8_t dsubType; + uint8_t jackType; + uint8_t jackID; + uint8_t nPins; + uint8_t srcJackID; + uint8_t srcPinID; + uint8_t jackStrIndex; +} MIDIJackOutDescriptor; + +typedef struct +{ + EndpointDescriptor len; // 9 + uint8_t refresh; // 4 + uint8_t sync; +} MIDI_EPDescriptor; - if (USB_DEVICE_DESCRIPTOR_TYPE == t) - { - TRACE_CORE(puts("=> USBD_SendDescriptor : USB_DEVICE_DESCRIPTOR_TYPE\r\n");) - if (setup.wLength == 8) - { - _cdcComposite = 1; - } - desc_addr = _cdcComposite ? (const uint8_t*)&USB_DeviceDescriptorA : (const uint8_t*)&USB_DeviceDescriptor; - 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 (setup.wValueL == 0) { - desc_addr = (const uint8_t*)&STRING_LANGUAGE; - } - else if (setup.wValueL == IPRODUCT) { - return USB_SendStringDescriptor(STRING_PRODUCT, setup.wLength); - } - else if (setup.wValueL == IMANUFACTURER) { - return USB_SendStringDescriptor(STRING_MANUFACTURER, setup.wLength); - } - else { - return false; - } - if( *desc_addr > setup.wLength ) { - desc_length = setup.wLength; - } - } - else if (USB_DEVICE_QUALIFIER == t) - { - // Device qualifier descriptor requested - desc_addr = (const uint8_t*)&USB_DeviceQualifier; - if( *desc_addr > setup.wLength ) { - desc_length = setup.wLength; - } - } - else if (USB_OTHER_SPEED_CONFIGURATION == t) - { - // Other configuration descriptor requested - return USBD_SendOtherConfiguration(setup.wLength); - } - else - { - //printf("Device ERROR"); - } - - if (desc_addr == 0) - { - return false; - } - - 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); - - return true; -} - - -static void USB_SendZlp( void ) +typedef struct { - while( UOTGHS_DEVEPTISR_TXINI != (UOTGHS->UOTGHS_DEVEPTISR[0] & UOTGHS_DEVEPTISR_TXINI ) ) - { - if((UOTGHS->UOTGHS_DEVISR & UOTGHS_DEVISR_SUSP) == UOTGHS_DEVISR_SUSP) - { - return; - } - } - UOTGHS->UOTGHS_DEVEPTICR[0] = UOTGHS_DEVEPTICR_TXINIC; -} - - -static void Test_Mode_Support( uint8_t wIndex ) + uint8_t len; // 5 + uint8_t dtype; // 0x24 + uint8_t subtype; + uint8_t embJacks; + uint8_t jackID; +} MIDI_EP_ACDescriptor; + +typedef struct { - uint8_t i; - uint8_t *ptr_dest = (uint8_t *) &udd_get_endpoint_fifo_access8(2); - - switch( wIndex ) - { - case 4: - //Test mode Test_Packet: - //Upon command, a port must repetitively transmit the following test packet until - //the exit action is taken. This enables the testing of rise and fall times, eye - //patterns, jitter, and any other dynamic waveform specifications. - //The test packet is made up by concatenating the following strings. - //(Note: For J/K NRZI data, and for NRZ data, the bit on the left is the first one - //transmitted. "S" indicates that a bit stuff occurs, which inserts an "extra" NRZI data bit. - //"* N" is used to indicate N occurrences of a string of bits or symbols.) - //A port in Test_Packet mode must send this packet repetitively. The inter-packet timing - //must be no less than the minimum allowable inter-packet gap as defined in Section 7.1.18 and - //no greater than 125 us. - - // Send ZLP - USB_SendZlp(); - - UOTGHS->UOTGHS_DEVDMA[0].UOTGHS_DEVDMACONTROL = 0; // raz - UOTGHS->UOTGHS_DEVDMA[1].UOTGHS_DEVDMACONTROL = 0; // raz - - // Configure endpoint 2, 64 bytes, direction IN, type BULK, 1 bank - UOTGHS->UOTGHS_DEVEPTCFG[2] = UOTGHS_DEVEPTCFG_EPSIZE_64_BYTE - | UOTGHS_DEVEPTCFG_EPDIR_IN - | UOTGHS_DEVEPTCFG_EPTYPE_BLK - | UOTGHS_DEVEPTCFG_EPBK_1_BANK; - // Check if the configuration is ok - UOTGHS->UOTGHS_DEVEPTCFG[2] |= UOTGHS_DEVEPTCFG_ALLOC; - while((UOTGHS->UOTGHS_DEVEPTISR[2]&UOTGHS_DEVEPTISR_CFGOK)==0) {} - UOTGHS->UOTGHS_DEVEPT |= UOTGHS_DEVEPT_EPEN2; - // Write FIFO - for( i=0; iUOTGHS_DEVCTRL |= UOTGHS_DEVCTRL_TSTPCKT; - // Send packet - UOTGHS->UOTGHS_DEVEPTICR[2] = UOTGHS_DEVEPTICR_TXINIC; - UOTGHS->UOTGHS_DEVEPTIDR[2] = UOTGHS_DEVEPTIDR_FIFOCONC; - for(;;); -// break; - - case 1: - //Test mode Test_J: - //Upon command, a port's transceiver must enter the high-speed J state and remain in that - //state until the exit action is taken. This enables the testing of the high output drive - //level on the D+ line. - // Send a ZLP - USB_SendZlp(); - UOTGHS->UOTGHS_DEVCTRL |= UOTGHS_DEVCTRL_TSTJ; - for(;;); -// break; - - case 2: - //Test mode Test_K: - //Upon command, a port's transceiver must enter the high-speed K state and remain in - //that state until the exit action is taken. This enables the testing of the high output drive - //level on the D- line. - // Send a ZLP - USB_SendZlp(); - UOTGHS->UOTGHS_DEVCTRL |= UOTGHS_DEVCTRL_TSTK; - for(;;); -// break; - - case 3: - //Test mode Test_SE0_NAK: - //Upon command, a port's transceiver must enter the high-speed receive mode - //and remain in that mode until the exit action is taken. This enables the testing - //of output impedance, low level output voltage, and loading characteristics. - //In addition, while in this mode, upstream facing ports (and only upstream facing ports) - //must respond to any IN token packet with a NAK handshake (only if the packet CRC is - //determined to be correct) within the normal allowed device response time. This enables testing of - //the device squelch level circuitry and, additionally, provides a general purpose stimulus/response - //test for basic functional testing. - - // Send a ZLP - USB_SendZlp(); - UOTGHS->UOTGHS_DEVIDR = UOTGHS_DEVIDR_SUSPEC - | UOTGHS_DEVIDR_MSOFEC - | UOTGHS_DEVIDR_SOFEC - | UOTGHS_DEVIDR_EORSTEC - | UOTGHS_DEVIDR_WAKEUPEC - | UOTGHS_DEVIDR_EORSMEC - | UOTGHS_DEVIDR_UPRSMEC - | UOTGHS_DEVIDR_PEP_0 - | UOTGHS_DEVIDR_PEP_1 - | UOTGHS_DEVIDR_PEP_2 - | UOTGHS_DEVIDR_PEP_3 - | UOTGHS_DEVIDR_PEP_4 - | UOTGHS_DEVIDR_PEP_5 - | UOTGHS_DEVIDR_PEP_6 - | UOTGHS_DEVIDR_DMA_1 - | UOTGHS_DEVIDR_DMA_2 - | UOTGHS_DEVIDR_DMA_3 - | UOTGHS_DEVIDR_DMA_4 - | UOTGHS_DEVIDR_DMA_5 - | UOTGHS_DEVIDR_DMA_6; - for(;;); -// break; - } -} - - -//unsigned int iii=0; -// Endpoint 0 interrupt -static void USB_ISR(void) + uint8_t len; // 9 + uint8_t dtype; // 4 + uint8_t dsubType; + uint16_t bcdADc; + uint16_t wTotalLength; +} MIDI_ASInterfaceDescriptor; + +typedef struct { -// printf("ISR=0x%X\n\r", UOTGHS->UOTGHS_DEVISR); // jcb -// if( iii++ > 1500 ) while(1); // jcb - // 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); - udd_enable_address(); - - // Configure EP 0 - UDD_InitEP(0, EP_TYPE_CONTROL); - udd_enable_setup_received_interrupt(0); - udd_enable_endpoint_interrupt(0); - - _usbConfiguration = 0; - udd_ack_reset(); - } - #ifdef CDC_ENABLED - if (Is_udd_endpoint_interrupt(CDC_RX)) - { - udd_ack_out_received(CDC_RX); - - // Handle received bytes - if (USBD_Available(CDC_RX)) - SerialUSB.accept(); - } - - if (Is_udd_sof()) - { - udd_ack_sof(); - // USBD_Flush(CDC_TX); // jcb - } + // IAD + IADDescriptor iad; #endif + // MIDI Audio Control Interface + InterfaceDescriptor Audio_ControlInterface; + MIDI_ACInterfaceDescriptor Audio_ControlInterface_SPC; + + // MIDI Audio Streaming Interface + InterfaceDescriptor Audio_StreamInterface; + MIDI_ASInterfaceDescriptor Audio_StreamInterface_SPC; + + MIDIJackinDescriptor MIDI_In_Jack_Emb; + MIDIJackinDescriptor MIDI_In_Jack_Ext; + MIDIJackOutDescriptor MIDI_Out_Jack_Emb; + MIDIJackOutDescriptor MIDI_Out_Jack_Ext; + + MIDI_EPDescriptor MIDI_In_Jack_Endpoint; + MIDI_EP_ACDescriptor MIDI_In_Jack_Endpoint_SPC; + MIDI_EPDescriptor MIDI_Out_Jack_Endpoint; + MIDI_EP_ACDescriptor MIDI_Out_Jack_Endpoint_SPC; +} MIDIDescriptor; - // EP 0 Interrupt - if (Is_udd_endpoint_interrupt(0) ) - { - if (!UDD_ReceivedSetupInt()) - { - return; - } - - Setup setup; - UDD_Recv(EP0, (uint8_t*)&setup, 8); - UDD_ClearSetupInt(); - - uint8_t requestType = setup.bmRequestType; - if (requestType & REQUEST_DEVICETOHOST) - { - TRACE_CORE(puts(">>> EP0 Int: IN Request\r\n");) - UDD_WaitIN(); - } - else - { - TRACE_CORE(puts(">>> EP0 Int: OUT Request\r\n");) - UDD_ClearIN(); - } - - bool ok = true; - if (REQUEST_STANDARD == (requestType & REQUEST_TYPE)) - { - // Standard Requests - uint8_t r = setup.bRequest; - if (GET_STATUS == r) - { - if( setup.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 - UDD_Send8(EP0, 0); // TODO - UDD_Send8(EP0, 0); - } - // if( setup.bmRequestType == 2 ) // Endpoint: - else - { - // Send the endpoint status - // Check if the endpoint if currently halted - if( isEndpointHalt == 1 ) - UDD_Send8(EP0, 1); // TODO - else - UDD_Send8(EP0, 0); // TODO - UDD_Send8(EP0, 0); - } - } - else if (CLEAR_FEATURE == r) - { - // Check which is the selected feature - if( setup.wValueL == 1) // DEVICEREMOTEWAKEUP - { - // Enable remote wake-up and send a ZLP - if( isRemoteWakeUpEnabled == 1 ) - UDD_Send8(EP0, 1); - else - UDD_Send8(EP0, 0); - UDD_Send8(EP0, 0); - } - else // if( setup.wValueL == 0) // ENDPOINTHALT - { - isEndpointHalt = 0; // TODO - UDD_Send8(EP0, 0); - UDD_Send8(EP0, 0); - } - - } - else if (SET_FEATURE == r) - { - // Check which is the selected feature - if( setup.wValueL == 1) // DEVICEREMOTEWAKEUP - { - // Enable remote wake-up and send a ZLP - isRemoteWakeUpEnabled = 1; - UDD_Send8(EP0, 0); - } - if( setup.wValueL == 0) // ENDPOINTHALT - { - // Halt endpoint - isEndpointHalt = 1; - //USBD_Halt(USBGenericRequest_GetEndpointNumber(pRequest)); - UDD_Send8(EP0, 0); - } - if( setup.wValueL == 2) // TEST_MODE - { - // 7.1.20 Test Mode Support, 9.4.9 SetFeature - if( (setup.bmRequestType == 0 /*USBGenericRequest_DEVICE*/) && - ((setup.wIndex & 0x000F) == 0) ) - { - // the lower byte of wIndex must be zero - // the most significant byte of wIndex is used to specify the specific test mode - - UOTGHS->UOTGHS_DEVIDR &= ~UOTGHS_DEVIDR_SUSPEC; - UOTGHS->UOTGHS_DEVCTRL |= UOTGHS_DEVCTRL_SPDCONF_HIGH_SPEED; // remove suspend ? - - Test_Mode_Support( (setup.wIndex & 0xFF00)>>8 ); - } - } - } - else if (SET_ADDRESS == r) - { - TRACE_CORE(puts(">>> EP0 Int: SET_ADDRESS\r\n");) - UDD_WaitIN(); - UDD_SetAddress(setup.wValueL); - } - else if (GET_DESCRIPTOR == r) - { - TRACE_CORE(puts(">>> EP0 Int: GET_DESCRIPTOR\r\n");) - ok = USBD_SendDescriptor(setup); - } - 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_Send8(EP0, _usbConfiguration); - } - else if (SET_CONFIGURATION == r) - { - if (REQUEST_DEVICE == (requestType & REQUEST_RECIPIENT)) - { - TRACE_CORE(printf(">>> EP0 Int: SET_CONFIGURATION REQUEST_DEVICE %d\r\n", setup.wValueL);) - - UDD_InitEndpoints(EndPoints, (sizeof(EndPoints) / sizeof(EndPoints[0]))); - _usbConfiguration = setup.wValueL; +_Pragma("pack()") -#ifdef CDC_ENABLED - // Enable interrupt for CDC reception from host (OUT packet) - udd_enable_out_received_interrupt(CDC_RX); - udd_enable_endpoint_interrupt(CDC_RX); -#endif - } - 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_Send8(EP0, _usbSetInterface); - } - else if (SET_INTERFACE == r) - { - _usbSetInterface = setup.wValueL; - TRACE_CORE(puts(">>> EP0 Int: SET_INTERFACE\r\n");) - } - } - else - { - TRACE_CORE(puts(">>> EP0 Int: ClassInterfaceRequest\r\n");) - - UDD_WaitIN(); // Workaround: need tempo here, else CDC serial won't open correctly - - USBD_InitControl(setup.wLength); // Max length of transfer - ok = USBD_ClassInterfaceRequest(setup); - } - - if (ok) - { - TRACE_CORE(puts(">>> EP0 Int: Send packet\r\n");) - UDD_ClearIN(); - } - else - { - TRACE_CORE(puts(">>> EP0 Int: Stall\r\n");) - UDD_Stall(); - } - } -} - -void USBD_Flush(uint32_t ep) -{ - if (UDD_FifoByteCount(ep)) - UDD_ReleaseTX(ep); -} +#define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \ + { 18, 1, 0x200, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs } -// VBUS or counting frames -// Any frame counting? -uint32_t USBD_Connected(void) -{ - uint8_t f = UDD_GetFrameNumber(); +#define D_CONFIG(_totalLength,_interfaces) \ + { 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_SELF_POWERED, USB_CONFIG_POWER_MA(500) } - delay(3); +#define D_OTHERCONFIG(_totalLength,_interfaces) \ + { 9, 7, _totalLength,_interfaces, 1, 0, USB_CONFIG_SELF_POWERED, USB_CONFIG_POWER_MA(500) } - return f != UDD_GetFrameNumber(); -} +#define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \ + { 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 } +#define D_ENDPOINT(_addr,_attr,_packetSize, _interval) \ + { 7, 5, _addr,_attr,_packetSize, _interval } -//======================================================================= -//======================================================================= +#define D_QUALIFIER(_class,_subClass,_proto,_packetSize0,_configs) \ + { 10, 6, 0x200, _class,_subClass,_proto,_packetSize0,_configs } -USBDevice_ USBDevice; +#define D_IAD(_firstInterface, _count, _class, _subClass, _protocol) \ + { 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 } -USBDevice_::USBDevice_() -{ - UDD_SetStack(&USB_ISR); +#define D_HIDREPORT(_descriptorLength) \ + { 9, 0x21, 0x1, 0x1, 0, 1, 0x22, _descriptorLength, 0 } + +#define D_AC_INTERFACE(_streamingInterfaces, _MIDIInterface) \ + { 9, MIDI_CS_INTERFACE, 0x1, 0x0100, 0x0009, _streamingInterfaces, _MIDIInterface } + +#define D_AS_INTERFACE \ + { 0x7, MIDI_CS_INTERFACE, 0x01,0x0100, 0x0041} + +#define D_MIDI_INJACK(jackProp, _jackID) \ + { 0x06, MIDI_CS_INTERFACE, 0x02, jackProp, _jackID, 0 } + +#define D_MIDI_OUTJACK(jackProp, _jackID, _nPins, _srcID, _srcPin) \ + { 0x09, MIDI_CS_INTERFACE, 0x3, jackProp, _jackID, _nPins, _srcID, _srcPin, 0 } + +#define D_MIDI_JACK_EP(_addr,_attr,_packetSize) \ + { 9, 5, _addr,_attr,_packetSize, 0, 0, 0} - if (UDD_Init() == 0UL) - { - _usbInitialized=1UL; - } -} +#define D_MIDI_AC_JACK_EP(_nMIDI, _iDMIDI) \ + { 5, MIDI_CS_ENDPOINT, 0x1, _nMIDI, _iDMIDI} + +#define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 } +#define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 } -bool USBDevice_::attach(void) -{ - if (_usbInitialized != 0UL) - { - UDD_Attach(); - _usbConfiguration = 0; - return true; - } - else - { - return false; - } -} - -bool USBDevice_::detach(void) -{ - if (_usbInitialized != 0UL) - { - UDD_Detach(); - return true; - } - else - { - return false; - } -} - -// Check for interrupts -// TODO: VBUS detection -bool USBDevice_::configured() -{ - return _usbConfiguration; -} -void USBDevice_::poll() -{ -} +#endif From b50c9b6703c5c700aa314f33f6d5a371b070097a Mon Sep 17 00:00:00 2001 From: Gurbrinder Date: Wed, 8 Apr 2015 15:53:54 -0700 Subject: [PATCH 4/7] Update USBCore.h --- .../arduino/sam/cores/arduino/USB/USBCore.h | 115 +++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/hardware/arduino/sam/cores/arduino/USB/USBCore.h b/hardware/arduino/sam/cores/arduino/USB/USBCore.h index b01d7576a1e..6a19cf85042 100644 --- a/hardware/arduino/sam/cores/arduino/USB/USBCore.h +++ b/hardware/arduino/sam/cores/arduino/USB/USBCore.h @@ -125,6 +125,15 @@ #define HID_REPORT_DESCRIPTOR_TYPE 0x22 #define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23 +#define MIDI_AUDIO 0x01 +#define MIDI_AUDIO_CONTROL 0x01 +#define MIDI_CS_INTERFACE 0x24 +#define MIDI_CS_ENDPOINT 0x25 +#define MIDI_STREAMING 0x3 +#define MIDI_JACK_EMD 0x01 +#define MIDI_JACK_EXT 0X02 + + _Pragma("pack(1)") // Device @@ -279,6 +288,91 @@ typedef struct EndpointDescriptor in; } HIDDescriptor; + +typedef struct +{ + uint8_t len; // 9 + uint8_t dtype; // 4 + uint8_t dsubType; + uint16_t bcdADc; + uint16_t wTotalLength; + uint8_t bInCollection; + uint8_t interfaceNumbers; +} MIDI_ACInterfaceDescriptor; + +typedef struct +{ + uint8_t len; // 9 + uint8_t dtype; // 4 + uint8_t dsubType; + uint8_t jackType; + uint8_t jackID; + uint8_t jackStrIndex; +} MIDIJackinDescriptor; + +typedef struct +{ + uint8_t len; // 9 + uint8_t dtype; // 4 + uint8_t dsubType; + uint8_t jackType; + uint8_t jackID; + uint8_t nPins; + uint8_t srcJackID; + uint8_t srcPinID; + uint8_t jackStrIndex; +} MIDIJackOutDescriptor; + +typedef struct +{ + EndpointDescriptor len; // 9 + uint8_t refresh; // 4 + uint8_t sync; +} MIDI_EPDescriptor; + +typedef struct +{ + uint8_t len; // 5 + uint8_t dtype; // 0x24 + uint8_t subtype; + uint8_t embJacks; + uint8_t jackID; +} MIDI_EP_ACDescriptor; + +typedef struct +{ + uint8_t len; // 9 + uint8_t dtype; // 4 + uint8_t dsubType; + uint16_t bcdADc; + uint16_t wTotalLength; +} MIDI_ASInterfaceDescriptor; + +typedef struct +{ +#ifdef CDC_ENABLED + // IAD + IADDescriptor iad; +#endif + // MIDI Audio Control Interface + InterfaceDescriptor Audio_ControlInterface; + MIDI_ACInterfaceDescriptor Audio_ControlInterface_SPC; + + // MIDI Audio Streaming Interface + InterfaceDescriptor Audio_StreamInterface; + MIDI_ASInterfaceDescriptor Audio_StreamInterface_SPC; + + MIDIJackinDescriptor MIDI_In_Jack_Emb; + MIDIJackinDescriptor MIDI_In_Jack_Ext; + MIDIJackOutDescriptor MIDI_Out_Jack_Emb; + MIDIJackOutDescriptor MIDI_Out_Jack_Ext; + + MIDI_EPDescriptor MIDI_In_Jack_Endpoint; + MIDI_EP_ACDescriptor MIDI_In_Jack_Endpoint_SPC; + MIDI_EPDescriptor MIDI_Out_Jack_Endpoint; + MIDI_EP_ACDescriptor MIDI_Out_Jack_Endpoint_SPC; +} MIDIDescriptor; + _Pragma("pack()") #define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \ @@ -304,8 +398,27 @@ _Pragma("pack()") #define D_HIDREPORT(_descriptorLength) \ { 9, 0x21, 0x1, 0x1, 0, 1, 0x22, _descriptorLength, 0 } - + +#define D_AC_INTERFACE(_streamingInterfaces, _MIDIInterface) \ + { 9, MIDI_CS_INTERFACE, 0x1, 0x0100, 0x0009, _streamingInterfaces, _MIDIInterface } + +#define D_AS_INTERFACE \ + { 0x7, MIDI_CS_INTERFACE, 0x01,0x0100, 0x0041} + +#define D_MIDI_INJACK(jackProp, _jackID) \ + { 0x06, MIDI_CS_INTERFACE, 0x02, jackProp, _jackID, 0 } + +#define D_MIDI_OUTJACK(jackProp, _jackID, _nPins, _srcID, _srcPin) \ + { 0x09, MIDI_CS_INTERFACE, 0x3, jackProp, _jackID, _nPins, _srcID, _srcPin, 0 } + +#define D_MIDI_JACK_EP(_addr,_attr,_packetSize) \ + { 9, 5, _addr,_attr,_packetSize, 0, 0, 0} + +#define D_MIDI_AC_JACK_EP(_nMIDI, _iDMIDI) \ + { 5, MIDI_CS_ENDPOINT, 0x1, _nMIDI, _iDMIDI} + #define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 } #define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 } + #endif From 4d14f998b7a9aedae13716cabbc1c43f745987c9 Mon Sep 17 00:00:00 2001 From: Gurbrinder Date: Wed, 8 Apr 2015 15:54:19 -0700 Subject: [PATCH 5/7] Update USBDesc.h --- .../arduino/sam/cores/arduino/USB/USBDesc.h | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/hardware/arduino/sam/cores/arduino/USB/USBDesc.h b/hardware/arduino/sam/cores/arduino/USB/USBDesc.h index 878095e2450..9ecf852bf30 100644 --- a/hardware/arduino/sam/cores/arduino/USB/USBDesc.h +++ b/hardware/arduino/sam/cores/arduino/USB/USBDesc.h @@ -19,6 +19,7 @@ #define CDC_ENABLED #define HID_ENABLED +#define MIDI_ENABLED #ifdef CDC_ENABLED #define CDC_INTERFACE_COUNT 2 @@ -36,6 +37,14 @@ #define HID_ENPOINT_COUNT 0 #endif +#ifdef MIDI_ENABLED +#define MIDI_INTERFACE_COUNT 2 +#define MIDI_ENPOINT_COUNT 2 +#else +#define MIDI_INTERFACE_COUNT 0 +#define MIDI_ENPOINT_COUNT 0 +#endif + #define CDC_ACM_INTERFACE 0 // CDC ACM #define CDC_DATA_INTERFACE 1 // CDC Data #define CDC_FIRST_ENDPOINT 1 @@ -47,6 +56,12 @@ #define HID_FIRST_ENDPOINT (CDC_FIRST_ENDPOINT + CDC_ENPOINT_COUNT) #define HID_ENDPOINT_INT (HID_FIRST_ENDPOINT) +#define MIDI_AC_INTERFACE (HID_INTERFACE + HID_INTERFACE_COUNT) // MIDI AC Interface +#define MIDI_INTERFACE MIDI_AC_INTERFACE+1 +#define MIDI_FIRST_ENDPOINT (HID_FIRST_ENDPOINT + HID_ENPOINT_COUNT) +#define MIDI_ENDPOINT_OUT (MIDI_FIRST_ENDPOINT) +#define MIDI_ENDPOINT_IN (MIDI_FIRST_ENDPOINT+1) + #define INTERFACE_COUNT (MSC_INTERFACE + MSC_INTERFACE_COUNT) #ifdef CDC_ENABLED @@ -58,6 +73,11 @@ #define HID_TX HID_ENDPOINT_INT #endif +#ifdef MIDI_ENABLED +#define MIDI_RX MIDI_ENDPOINT_OUT +#define MIDI_TX MIDI_ENDPOINT_IN +#endif + #define IMANUFACTURER 1 #define IPRODUCT 2 From 1c6791885d779bc2a02e07801e442e9ce41a01c1 Mon Sep 17 00:00:00 2001 From: Gurbrinder Date: Wed, 8 Apr 2015 15:57:18 -0700 Subject: [PATCH 6/7] Create USBMIDI.ino --- .../examples/SimpleAudioPlayer/USBMIDI.ino | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 libraries/Audio/examples/SimpleAudioPlayer/USBMIDI.ino diff --git a/libraries/Audio/examples/SimpleAudioPlayer/USBMIDI.ino b/libraries/Audio/examples/SimpleAudioPlayer/USBMIDI.ino new file mode 100644 index 00000000000..aa497b0ca26 --- /dev/null +++ b/libraries/Audio/examples/SimpleAudioPlayer/USBMIDI.ino @@ -0,0 +1,55 @@ +/* + * MidiTest.cpp + * + * Created: 4/6/2015 10:47:08 AM + * Author: gurbrinder grewal + */ + + +#include "Arduino.h" + + + +// First parameter is the event type (0x09 = note on, 0x08 = note off). +// Second parameter is note-on/note-off, combined with the channel. +// Channel can be anything between 0-15. Typically reported to the user as 1-16. +// Third parameter is the note number (48 = middle C). +// Fourth parameter is the velocity (64 = normal, 127 = fastest). + +void noteOn(byte channel, byte pitch, byte velocity) { + midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity}; + MidiUSB.sendMIDI(noteOn); +} + +void noteOff(byte channel, byte pitch, byte velocity) { + midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity}; + MidiUSB.sendMIDI(noteOff); +} + +// First parameter is the event type (0x0B = control change). +// Second parameter is the event type, combined with the channel. +// Third parameter is the control number number (0-119). +// Fourth parameter is the control value (0-127). + +void controlChange(byte channel, byte control, byte value) { + midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value}; + MidiUSB.sendMIDI(event); +} + +void loop() { + SerialUSB.print("Hello world1"); + noteOn(0, 48, 64); // Channel 0, middle C, normal velocity + MidiUSB.flush(); + delay(500); + SerialUSB.print("Hello world2"); + noteOff(0, 48, 64); // Channel 0, middle C, normal velocity + MidiUSB.flush(); + delay(1500); + + // controlChange(0, 10, 65); // Set the value of controller 10 on channel 0 to 65 +} + +void setup() { + +} + From d396869a34173309e534e66637a95281b7f1d857 Mon Sep 17 00:00:00 2001 From: Gurbrinder Date: Thu, 16 Apr 2015 17:36:51 -0700 Subject: [PATCH 7/7] Fixed the horrible overwritten header --- .../arduino/sam/cores/arduino/USB/USBCore.cpp | 1275 ++++++++++++----- 1 file changed, 906 insertions(+), 369 deletions(-) diff --git a/hardware/arduino/sam/cores/arduino/USB/USBCore.cpp b/hardware/arduino/sam/cores/arduino/USB/USBCore.cpp index 6a19cf85042..7a5bbc047b1 100644 --- a/hardware/arduino/sam/cores/arduino/USB/USBCore.cpp +++ b/hardware/arduino/sam/cores/arduino/USB/USBCore.cpp @@ -14,411 +14,948 @@ ** SOFTWARE. */ -#ifndef __USBCORE_H__ -#define __USBCORE_H__ - -// Standard requests -#define GET_STATUS 0 -#define CLEAR_FEATURE 1 -#define SET_FEATURE 3 -#define SET_ADDRESS 5 -#define GET_DESCRIPTOR 6 -#define SET_DESCRIPTOR 7 -#define GET_CONFIGURATION 8 -#define SET_CONFIGURATION 9 -#define GET_INTERFACE 10 -#define SET_INTERFACE 11 - - -// bmRequestType -#define REQUEST_HOSTTODEVICE 0x00 -#define REQUEST_DEVICETOHOST 0x80 -#define REQUEST_DIRECTION 0x80 - -#define REQUEST_STANDARD 0x00 -#define REQUEST_CLASS 0x20 -#define REQUEST_VENDOR 0x40 -#define REQUEST_TYPE 0x60 - -#define REQUEST_DEVICE 0x00 -#define REQUEST_INTERFACE 0x01 -#define REQUEST_ENDPOINT 0x02 -#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) - -// Class requests - -#define CDC_SET_LINE_CODING 0x20 -#define CDC_GET_LINE_CODING 0x21 -#define CDC_SET_CONTROL_LINE_STATE 0x22 - -#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 -#define USB_CONFIGUARTION_DESC_SIZE 9 -#define USB_INTERFACE_DESC_SIZE 9 -#define USB_ENDPOINT_DESC_SIZE 7 - -#define USB_DEVICE_DESCRIPTOR_TYPE 1 -#define USB_CONFIGURATION_DESCRIPTOR_TYPE 2 -#define USB_STRING_DESCRIPTOR_TYPE 3 -#define USB_INTERFACE_DESCRIPTOR_TYPE 4 -#define USB_ENDPOINT_DESCRIPTOR_TYPE 5 -#define USB_DEVICE_QUALIFIER 6 -#define USB_OTHER_SPEED_CONFIGURATION 7 - -#define USB_DEVICE_CLASS_COMMUNICATIONS 0x02 -#define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03 -#define USB_DEVICE_CLASS_STORAGE 0x08 -#define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF - -#define USB_CONFIG_POWERED_MASK 0x40 -#define USB_CONFIG_BUS_POWERED 0x80 -#define USB_CONFIG_SELF_POWERED 0xC0 -#define USB_CONFIG_REMOTE_WAKEUP 0x20 - -// bMaxPower in Configuration Descriptor -#define USB_CONFIG_POWER_MA(mA) ((mA)/2) - -// 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 - -#define TOBYTES(x) ((x) & 0xFF),(((x) >> 8) & 0xFF) - -#define CDC_V1_10 0x0110 -#define CDC_COMMUNICATION_INTERFACE_CLASS 0x02 - -#define CDC_CALL_MANAGEMENT 0x01 -#define CDC_ABSTRACT_CONTROL_MODEL 0x02 -#define CDC_HEADER 0x00 -#define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02 -#define CDC_UNION 0x06 -#define CDC_CS_INTERFACE 0x24 -#define CDC_CS_ENDPOINT 0x25 -#define CDC_DATA_INTERFACE_CLASS 0x0A - -#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 - -#define MIDI_AUDIO 0x01 -#define MIDI_AUDIO_CONTROL 0x01 -#define MIDI_CS_INTERFACE 0x24 -#define MIDI_CS_ENDPOINT 0x25 -#define MIDI_STREAMING 0x3 -#define MIDI_JACK_EMD 0x01 -#define MIDI_JACK_EXT 0X02 +#include "Arduino.h" +#include "USBAPI.h" +#include "Reset.h" +#include + +// CDC Endpoints +#define EP_TYPE_BULK_IN_MIDI (UOTGHS_DEVEPTCFG_EPSIZE_64_BYTE | \ + UOTGHS_DEVEPTCFG_EPDIR_IN | \ + UOTGHS_DEVEPTCFG_EPTYPE_BLK | \ + UOTGHS_DEVEPTCFG_EPBK_1_BANK | \ + UOTGHS_DEVEPTCFG_NBTRANS_1_TRANS | \ + UOTGHS_DEVEPTCFG_ALLOC) + +#define EP_TYPE_BULK_OUT_MIDI (UOTGHS_DEVEPTCFG_EPSIZE_64_BYTE | \ + UOTGHS_DEVEPTCFG_EPTYPE_BLK | \ + UOTGHS_DEVEPTCFG_EPBK_1_BANK | \ + UOTGHS_DEVEPTCFG_NBTRANS_1_TRANS | \ + UOTGHS_DEVEPTCFG_ALLOC) + +//#define TRACE_CORE(x) x +#define TRACE_CORE(x) + +static const uint32_t EndPoints[] = +{ + EP_TYPE_CONTROL, +#ifdef CDC_ENABLED + EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM + EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT + EP_TYPE_BULK_IN, // CDC_ENDPOINT_IN +#endif -_Pragma("pack(1)") +#ifdef HID_ENABLED + EP_TYPE_INTERRUPT_IN_HID, // HID_ENDPOINT_INT +#endif -// Device -typedef struct { - uint8_t len; // 18 - uint8_t dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE - uint16_t usbVersion; // 0x200 - uint8_t deviceClass; - uint8_t deviceSubClass; - uint8_t deviceProtocol; - uint8_t packetSize0; // Packet 0 - uint16_t idVendor; - uint16_t idProduct; - uint16_t deviceVersion; // 0x100 - uint8_t iManufacturer; - uint8_t iProduct; - uint8_t iSerialNumber; - uint8_t bNumConfigurations; -} DeviceDescriptor; - -// Config -typedef struct { - uint8_t len; // 9 - uint8_t dtype; // 2 - uint16_t clen; // total length - uint8_t numInterfaces; - uint8_t config; - uint8_t iconfig; - uint8_t attributes; - uint8_t maxPower; -} ConfigDescriptor; - -// String - -// Interface -typedef struct -{ - uint8_t len; // 9 - uint8_t dtype; // 4 - uint8_t number; - uint8_t alternate; - uint8_t numEndpoints; - uint8_t interfaceClass; - uint8_t interfaceSubClass; - uint8_t protocol; - uint8_t iInterface; -} InterfaceDescriptor; - -// Endpoint -typedef struct +#ifdef MIDI_ENABLED + EP_TYPE_BULK_OUT_MIDI, // MIDI_ENDPOINT_OUT + EP_TYPE_BULK_IN_MIDI // MIDI_ENDPOINT_IN +#endif +}; + +/** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */ +#define TX_RX_LED_PULSE_MS 100 +volatile uint8_t TxLEDPulse; /**< Milliseconds remaining for data Tx LED pulse */ +volatile uint8_t RxLEDPulse; /**< Milliseconds remaining for data Rx LED pulse */ +static char isRemoteWakeUpEnabled = 0; +static char isEndpointHalt = 0; +//================================================================== +//================================================================== + +extern const uint16_t STRING_LANGUAGE[]; +extern const uint8_t STRING_PRODUCT[]; +extern const uint8_t STRING_MANUFACTURER[]; +extern const DeviceDescriptor USB_DeviceDescriptor; +extern const DeviceDescriptor USB_DeviceDescriptorA; +extern const DeviceDescriptor USB_DeviceDescriptorB; + +const uint16_t STRING_LANGUAGE[2] = { + (3<<8) | (2+2), + 0x0409 // English +}; + +#ifndef USB_PRODUCT +// Use a hardcoded product name if none is provided +#if USB_PID == USB_PID_DUE +#define USB_PRODUCT "Arduino Due" +#else +#define USB_PRODUCT "USB IO Board" +#endif +#endif + +const uint8_t STRING_PRODUCT[] = USB_PRODUCT; + +#if USB_VID == 0x2341 +# if defined(USB_MANUFACTURER) +# undef USB_MANUFACTURER +# endif +# define USB_MANUFACTURER "Arduino LLC" +#elif !defined(USB_MANUFACTURER) +// Fall through to unknown if no manufacturer name was provided in a macro +# define USB_MANUFACTURER "Unknown" +#endif + +const uint8_t STRING_MANUFACTURER[12] = USB_MANUFACTURER; + +#ifdef CDC_ENABLED +#define DEVICE_CLASS 0x02 +#else +#define DEVICE_CLASS 0x00 +#endif + +// DEVICE DESCRIPTOR +const DeviceDescriptor USB_DeviceDescriptor = + D_DEVICE(0x00,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); + +const DeviceDescriptor USB_DeviceDescriptorA = + D_DEVICE(DEVICE_CLASS,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); + +const DeviceDescriptor USB_DeviceDescriptorB = + D_DEVICE(0xEF,0x02,0x01,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1); + + +const DeviceDescriptor USB_DeviceQualifier = + D_QUALIFIER(0x00,0x00,0x00,64,1); + +//! 7.1.20 Test Mode Support +static const unsigned char test_packet_buffer[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // JKJKJKJK * 9 + 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA, // JJKKJJKK * 8 + 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE, // JJJJKKKK * 8 + 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // JJJJJJJKKKKKKK * 8 + 0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD, // JJJJJJJK * 8 + 0xFC,0x7E,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0x7E // {JKKKKKKK * 10}, JK +}; + +//================================================================== +//================================================================== + +volatile uint32_t _usbConfiguration = 0; +volatile uint32_t _usbInitialized = 0; +uint32_t _usbSetInterface = 0; +uint32_t _cdcComposite = 0; + +//================================================================== +//================================================================== + +#define USB_RECV_TIMEOUT +class LockEP { - uint8_t len; // 7 - uint8_t dtype; // 5 - uint8_t addr; - uint8_t attr; - uint16_t packetSize; - uint8_t interval; -} EndpointDescriptor; - -// Interface Association Descriptor -// Used to bind 2 interfaces together in CDC compostite device -typedef struct + irqflags_t flags; +public: + LockEP(uint32_t ep) : flags(cpu_irq_save()) + { + } + ~LockEP() + { + cpu_irq_restore(flags); + } +}; + +// Number of bytes, assumes a rx endpoint +uint32_t USBD_Available(uint32_t ep) { - uint8_t len; // 8 - uint8_t dtype; // 11 - uint8_t firstInterface; - uint8_t interfaceCount; - uint8_t functionClass; - uint8_t funtionSubClass; - uint8_t functionProtocol; - uint8_t iInterface; -} IADDescriptor; - -// CDC CS interface descriptor -typedef struct + LockEP lock(ep); + return UDD_FifoByteCount(ep & 0xF); +} + +// Non Blocking receive +// Return number of bytes read +uint32_t USBD_Recv(uint32_t ep, void* d, uint32_t len) { - uint8_t len; // 5 - uint8_t dtype; // 0x24 - uint8_t subtype; - uint8_t d0; - uint8_t d1; -} CDCCSInterfaceDescriptor; - -typedef struct + if (!_usbConfiguration) + return -1; + + LockEP lock(ep); + uint32_t n = UDD_FifoByteCount(ep & 0xF); + len = min(n,len); + n = len; + uint8_t* dst = (uint8_t*)d; + while (n--) + *dst++ = UDD_Recv8(ep & 0xF); + if (len && !UDD_FifoByteCount(ep & 0xF)) // release empty buffer + UDD_ReleaseRX(ep & 0xF); + + return len; +} + +// Recv 1 byte if ready +uint32_t USBD_Recv(uint32_t ep) { - uint8_t len; // 4 - uint8_t dtype; // 0x24 - uint8_t subtype; - uint8_t d0; -} CDCCSInterfaceDescriptor4; - -typedef struct + uint8_t c; + if (USBD_Recv(ep & 0xF, &c, 1) != 1) + return -1; + else + return c; +} + +// Space in send EP +//uint32_t USBD_SendSpace(uint32_t ep) +//{ + //LockEP lock(ep); +//// if (!UDD_ReadWriteAllowed(ep & 0xF)) + ////{ + ////printf("pb "); // UOTGHS->UOTGHS_DEVEPTISR[%d]=0x%X\n\r", ep, UOTGHS->UOTGHS_DEVEPTISR[ep]); + ////return 0; + ////} + + //if(ep==0) return 64 - UDD_FifoByteCount(ep & 0xF); // EP0_SIZE jcb + //else return 512 - UDD_FifoByteCount(ep & 0xF); // EPX_SIZE jcb +//} + +// Blocking Send of data to an endpoint +uint32_t USBD_Send(uint32_t ep, const void* d, uint32_t len) { - uint8_t len; - uint8_t dtype; // 0x24 - uint8_t subtype; // 1 - uint8_t bmCapabilities; - uint8_t bDataInterface; -} CMFunctionalDescriptor; - -typedef struct + uint32_t n; + int r = len; + const uint8_t* data = (const uint8_t*)d; + + if (!_usbConfiguration) + { + TRACE_CORE(printf("pb conf\n\r");) + return -1; + } + + while (len) + { + if(ep==0) n = EP0_SIZE; + else n = EPX_SIZE; + if (n > len) + n = len; + len -= n; + + UDD_Send(ep & 0xF, data, n); + data += n; + } + //TXLED1; // light the TX LED + //TxLEDPulse = TX_RX_LED_PULSE_MS; + return r; +} + +int _cmark; +int _cend; + +void USBD_InitControl(int end) { - uint8_t len; - uint8_t dtype; // 0x24 - uint8_t subtype; // 1 - uint8_t bmCapabilities; -} ACMFunctionalDescriptor; + _cmark = 0; + _cend = end; +} -typedef struct +// Clipped by _cmark/_cend +int USBD_SendControl(uint8_t flags, const void* d, uint32_t len) { - // IAD - IADDescriptor iad; // Only needed on compound device - - // Control - InterfaceDescriptor cif; - CDCCSInterfaceDescriptor header; - CMFunctionalDescriptor callManagement; // Call Management - ACMFunctionalDescriptor controlManagement; // ACM - CDCCSInterfaceDescriptor functionalDescriptor; // CDC_UNION - EndpointDescriptor cifin; - - // Data - InterfaceDescriptor dif; - EndpointDescriptor in; - EndpointDescriptor out; -} CDCDescriptor; - -typedef struct + const uint8_t* data = (const uint8_t*)d; + uint32_t length = len; + uint32_t sent = 0; + uint32_t pos = 0; + + TRACE_CORE(printf("=> USBD_SendControl TOTAL len=%lu\r\n", len);) + + if (_cmark < _cend) + { + while (len > 0) + { + sent = UDD_Send(EP0, data + pos, len); + TRACE_CORE(printf("=> USBD_SendControl sent=%lu\r\n", sent);) + pos += sent; + len -= sent; + } + } + + _cmark += length; + + return length; +} +//Bug +// 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) { +// uint16_t buff[64]; +// int l = 1; +// wLength-=2; +// while (*string && wLength>0) { +// buff[l++] = (uint8_t)(*string++); +// wLength-=2; +// } +// buff[0] = (3<<8) | (l*2); +// return USBD_SendControl(0, (uint8_t*)buff, l*2); +// } +static bool USB_SendStringDescriptor(const uint8_t *string, int wLength) { + uint16_t buff[64]; + int l = 1; + while (*string) { + buff[l++] = (uint8_t)(*string++); + } + buff[0] = (3<<8) | (l*2); + return USBD_SendControl(0, (uint8_t*)buff, wLength); +} + + +// Does not timeout or cross fifo boundaries +// Will only work for transfers <= 64 bytes +// TODO +int USBD_RecvControl(void* d, uint32_t len) { - InterfaceDescriptor msc; - EndpointDescriptor in; - EndpointDescriptor out; -} MSCDescriptor; + UDD_WaitOUT(); + UDD_Recv(EP0, (uint8_t*)d, len); + UDD_ClearOUT(); + + return len; +} -typedef struct +// Handle CLASS_INTERFACE requests +bool USBD_ClassInterfaceRequest(Setup& setup) { - 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 + uint8_t i = setup.wIndex; + + TRACE_CORE(printf("=> USBD_ClassInterfaceRequest\r\n");) + +#ifdef CDC_ENABLED + if (CDC_ACM_INTERFACE == i) + { + return CDC_Setup(setup); + } +#endif + +#ifdef HID_ENABLED + if (HID_INTERFACE == i) + { + return HID_Setup(setup); + } +#endif +#ifdef MIDI_ENABLED + if (MIDI_AC_INTERFACE == i) + { + return MIDI_Setup(setup); + } +#endif + + return false; +} + +int USBD_SendInterfaces(void) { - InterfaceDescriptor hid; - HIDDescDescriptor desc; - EndpointDescriptor in; -} HIDDescriptor; + int total = 0; + uint8_t interfaces = 0; + +#ifdef CDC_ENABLED + total = CDC_GetInterface(&interfaces); +#endif + +#ifdef HID_ENABLED + total += HID_GetInterface(&interfaces); +#endif + +#ifdef MIDI_ENABLED + total += MIDI_GetInterface(&interfaces); +#endif + total = total; // Get rid of compiler warning + TRACE_CORE(printf("=> USBD_SendInterfaces, total=%d interfaces=%d\r\n", total, interfaces);) + return interfaces; +} -typedef struct +int USBD_SendOtherInterfaces(void) { - uint8_t len; // 9 - uint8_t dtype; // 4 - uint8_t dsubType; - uint16_t bcdADc; - uint16_t wTotalLength; - uint8_t bInCollection; - uint8_t interfaceNumbers; -} MIDI_ACInterfaceDescriptor; - -typedef struct + int total = 0; + uint8_t interfaces = 0; + +#ifdef CDC_ENABLED + total = CDC_GetOtherInterface(&interfaces); +#endif + +#ifdef HID_ENABLED + total += HID_GetInterface(&interfaces); +#endif + +#ifdef MIDI_ENABLED + total += MIDI_GetInterface(&interfaces); +#endif + + total = total; // Get rid of compiler warning + TRACE_CORE(printf("=> USBD_SendInterfaces, total=%d interfaces=%d\r\n", total, interfaces);) + return interfaces; +} + +// Construct a dynamic configuration descriptor +// This really needs dynamic endpoint allocation etc +// TODO +static bool USBD_SendConfiguration(int maxlen) { - uint8_t len; // 9 - uint8_t dtype; // 4 - uint8_t dsubType; - uint8_t jackType; - uint8_t jackID; - uint8_t jackStrIndex; -} MIDIJackinDescriptor; - -typedef struct + // Count and measure interfaces + USBD_InitControl(0); + //TRACE_CORE(printf("=> USBD_SendConfiguration _cmark1=%d\r\n", _cmark);) + int interfaces = USBD_SendInterfaces(); + //TRACE_CORE(printf("=> USBD_SendConfiguration _cmark2=%d\r\n", _cmark);) + //TRACE_CORE(printf("=> USBD_SendConfiguration sizeof=%d\r\n", sizeof(ConfigDescriptor));) + +_Pragma("pack(1)") + ConfigDescriptor config = D_CONFIG(_cmark + sizeof(ConfigDescriptor),interfaces); +_Pragma("pack()") + //TRACE_CORE(printf("=> USBD_SendConfiguration clen=%d\r\n", config.clen);) + + //TRACE_CORE(printf("=> USBD_SendConfiguration maxlen=%d\r\n", maxlen);) + + // Now send them + USBD_InitControl(maxlen); + USBD_SendControl(0,&config,sizeof(ConfigDescriptor)); + USBD_SendInterfaces(); + return true; +} + +static bool USBD_SendOtherConfiguration(int maxlen) { - uint8_t len; // 9 - uint8_t dtype; // 4 - uint8_t dsubType; - uint8_t jackType; - uint8_t jackID; - uint8_t nPins; - uint8_t srcJackID; - uint8_t srcPinID; - uint8_t jackStrIndex; -} MIDIJackOutDescriptor; - -typedef struct + // Count and measure interfaces + USBD_InitControl(0); + //TRACE_CORE(printf("=> USBD_SendConfiguration _cmark1=%d\r\n", _cmark);) + int interfaces = USBD_SendOtherInterfaces(); + //TRACE_CORE(printf("=> USBD_SendConfiguration _cmark2=%d\r\n", _cmark);) + //TRACE_CORE(printf("=> USBD_SendConfiguration sizeof=%d\r\n", sizeof(ConfigDescriptor));) + +_Pragma("pack(1)") + ConfigDescriptor config = D_OTHERCONFIG(_cmark + sizeof(ConfigDescriptor),interfaces); +_Pragma("pack()") + //TRACE_CORE(printf("=> USBD_SendConfiguration clen=%d\r\n", config.clen);) + + //TRACE_CORE(printf("=> USBD_SendConfiguration maxlen=%d\r\n", maxlen);) + + // Now send them + USBD_InitControl(maxlen); + USBD_SendControl(0,&config,sizeof(ConfigDescriptor)); + USBD_SendOtherInterfaces(); + return true; +} + +static bool USBD_SendDescriptor(Setup& setup) { - EndpointDescriptor len; // 9 - uint8_t refresh; // 4 - uint8_t sync; -} MIDI_EPDescriptor; + uint8_t t = setup.wValueH; + uint8_t desc_length = 0; + const uint8_t* desc_addr = 0; + + if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) + { + TRACE_CORE(printf("=> USBD_SendDescriptor : USB_CONFIGURATION_DESCRIPTOR_TYPE length=%d\r\n", setup.wLength);) + return USBD_SendConfiguration(setup.wLength); + } + + USBD_InitControl(setup.wLength); +#ifdef HID_ENABLED + if (HID_REPORT_DESCRIPTOR_TYPE == t) + { + TRACE_CORE(puts("=> USBD_SendDescriptor : HID_REPORT_DESCRIPTOR_TYPE\r\n");) + return HID_GetDescriptor(t); + } +#endif -typedef struct + if (USB_DEVICE_DESCRIPTOR_TYPE == t) + { + TRACE_CORE(puts("=> USBD_SendDescriptor : USB_DEVICE_DESCRIPTOR_TYPE\r\n");) + if (setup.wLength == 8) + { + _cdcComposite = 1; + } + +#if 1 + desc_addr = (const uint8_t*)&USB_DeviceDescriptorB; +#else + desc_addr = _cdcComposite ? (const uint8_t*)&USB_DeviceDescriptorA : (const uint8_t*)&USB_DeviceDescriptor; +#endif + 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 (setup.wValueL == 0) { + desc_addr = (const uint8_t*)&STRING_LANGUAGE; + } + else if (setup.wValueL == IPRODUCT) { + return USB_SendStringDescriptor(STRING_PRODUCT, setup.wLength); + } + else if (setup.wValueL == IMANUFACTURER) { + return USB_SendStringDescriptor(STRING_MANUFACTURER, setup.wLength); + } + else { + return false; + } + if( *desc_addr > setup.wLength ) { + desc_length = setup.wLength; + } + } + else if (USB_DEVICE_QUALIFIER == t) + { + // Device qualifier descriptor requested + desc_addr = (const uint8_t*)&USB_DeviceQualifier; + if( *desc_addr > setup.wLength ) { + desc_length = setup.wLength; + } + } + else if (USB_OTHER_SPEED_CONFIGURATION == t) + { + // Other configuration descriptor requested + return USBD_SendOtherConfiguration(setup.wLength); + } + else + { + //printf("Device ERROR"); + } + + if (desc_addr == 0) + { + return false; + } + + 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); + + return true; +} + + +static void USB_SendZlp( void ) { - uint8_t len; // 5 - uint8_t dtype; // 0x24 - uint8_t subtype; - uint8_t embJacks; - uint8_t jackID; -} MIDI_EP_ACDescriptor; - -typedef struct + while( UOTGHS_DEVEPTISR_TXINI != (UOTGHS->UOTGHS_DEVEPTISR[0] & UOTGHS_DEVEPTISR_TXINI ) ) + { + if((UOTGHS->UOTGHS_DEVISR & UOTGHS_DEVISR_SUSP) == UOTGHS_DEVISR_SUSP) + { + return; + } + } + UOTGHS->UOTGHS_DEVEPTICR[0] = UOTGHS_DEVEPTICR_TXINIC; +} + + +static void Test_Mode_Support( uint8_t wIndex ) { - uint8_t len; // 9 - uint8_t dtype; // 4 - uint8_t dsubType; - uint16_t bcdADc; - uint16_t wTotalLength; -} MIDI_ASInterfaceDescriptor; - -typedef struct + uint8_t i; + uint8_t *ptr_dest = (uint8_t *) &udd_get_endpoint_fifo_access8(2); + + switch( wIndex ) + { + case 4: + //Test mode Test_Packet: + //Upon command, a port must repetitively transmit the following test packet until + //the exit action is taken. This enables the testing of rise and fall times, eye + //patterns, jitter, and any other dynamic waveform specifications. + //The test packet is made up by concatenating the following strings. + //(Note: For J/K NRZI data, and for NRZ data, the bit on the left is the first one + //transmitted. "S" indicates that a bit stuff occurs, which inserts an "extra" NRZI data bit. + //"* N" is used to indicate N occurrences of a string of bits or symbols.) + //A port in Test_Packet mode must send this packet repetitively. The inter-packet timing + //must be no less than the minimum allowable inter-packet gap as defined in Section 7.1.18 and + //no greater than 125 us. + + // Send ZLP + USB_SendZlp(); + + UOTGHS->UOTGHS_DEVDMA[0].UOTGHS_DEVDMACONTROL = 0; // raz + UOTGHS->UOTGHS_DEVDMA[1].UOTGHS_DEVDMACONTROL = 0; // raz + + // Configure endpoint 2, 64 bytes, direction IN, type BULK, 1 bank + UOTGHS->UOTGHS_DEVEPTCFG[2] = UOTGHS_DEVEPTCFG_EPSIZE_64_BYTE + | UOTGHS_DEVEPTCFG_EPDIR_IN + | UOTGHS_DEVEPTCFG_EPTYPE_BLK + | UOTGHS_DEVEPTCFG_EPBK_1_BANK; + // Check if the configuration is ok + UOTGHS->UOTGHS_DEVEPTCFG[2] |= UOTGHS_DEVEPTCFG_ALLOC; + while((UOTGHS->UOTGHS_DEVEPTISR[2]&UOTGHS_DEVEPTISR_CFGOK)==0) {} + UOTGHS->UOTGHS_DEVEPT |= UOTGHS_DEVEPT_EPEN2; + // Write FIFO + for( i=0; iUOTGHS_DEVCTRL |= UOTGHS_DEVCTRL_TSTPCKT; + // Send packet + UOTGHS->UOTGHS_DEVEPTICR[2] = UOTGHS_DEVEPTICR_TXINIC; + UOTGHS->UOTGHS_DEVEPTIDR[2] = UOTGHS_DEVEPTIDR_FIFOCONC; + for(;;); +// break; + + case 1: + //Test mode Test_J: + //Upon command, a port's transceiver must enter the high-speed J state and remain in that + //state until the exit action is taken. This enables the testing of the high output drive + //level on the D+ line. + // Send a ZLP + USB_SendZlp(); + UOTGHS->UOTGHS_DEVCTRL |= UOTGHS_DEVCTRL_TSTJ; + for(;;); +// break; + + case 2: + //Test mode Test_K: + //Upon command, a port's transceiver must enter the high-speed K state and remain in + //that state until the exit action is taken. This enables the testing of the high output drive + //level on the D- line. + // Send a ZLP + USB_SendZlp(); + UOTGHS->UOTGHS_DEVCTRL |= UOTGHS_DEVCTRL_TSTK; + for(;;); +// break; + + case 3: + //Test mode Test_SE0_NAK: + //Upon command, a port's transceiver must enter the high-speed receive mode + //and remain in that mode until the exit action is taken. This enables the testing + //of output impedance, low level output voltage, and loading characteristics. + //In addition, while in this mode, upstream facing ports (and only upstream facing ports) + //must respond to any IN token packet with a NAK handshake (only if the packet CRC is + //determined to be correct) within the normal allowed device response time. This enables testing of + //the device squelch level circuitry and, additionally, provides a general purpose stimulus/response + //test for basic functional testing. + + // Send a ZLP + USB_SendZlp(); + UOTGHS->UOTGHS_DEVIDR = UOTGHS_DEVIDR_SUSPEC + | UOTGHS_DEVIDR_MSOFEC + | UOTGHS_DEVIDR_SOFEC + | UOTGHS_DEVIDR_EORSTEC + | UOTGHS_DEVIDR_WAKEUPEC + | UOTGHS_DEVIDR_EORSMEC + | UOTGHS_DEVIDR_UPRSMEC + | UOTGHS_DEVIDR_PEP_0 + | UOTGHS_DEVIDR_PEP_1 + | UOTGHS_DEVIDR_PEP_2 + | UOTGHS_DEVIDR_PEP_3 + | UOTGHS_DEVIDR_PEP_4 + | UOTGHS_DEVIDR_PEP_5 + | UOTGHS_DEVIDR_PEP_6 + | UOTGHS_DEVIDR_DMA_1 + | UOTGHS_DEVIDR_DMA_2 + | UOTGHS_DEVIDR_DMA_3 + | UOTGHS_DEVIDR_DMA_4 + | UOTGHS_DEVIDR_DMA_5 + | UOTGHS_DEVIDR_DMA_6; + for(;;); +// break; + } +} + + +//unsigned int iii=0; +// Endpoint 0 interrupt +static void USB_ISR(void) { +// printf("ISR=0x%X\n\r", UOTGHS->UOTGHS_DEVISR); // jcb +// if( iii++ > 1500 ) while(1); // jcb + // 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); + udd_enable_address(); + + // Configure EP 0 + UDD_InitEP(0, EP_TYPE_CONTROL); + udd_enable_setup_received_interrupt(0); + udd_enable_endpoint_interrupt(0); + + _usbConfiguration = 0; + udd_ack_reset(); + } + #ifdef CDC_ENABLED - // IAD - IADDescriptor iad; + if (Is_udd_endpoint_interrupt(CDC_RX)) + { + udd_ack_out_received(CDC_RX); + + // Handle received bytes + if (USBD_Available(CDC_RX)) + SerialUSB.accept(); + } + + if (Is_udd_sof()) + { + udd_ack_sof(); + // USBD_Flush(CDC_TX); // jcb + } #endif - // MIDI Audio Control Interface - InterfaceDescriptor Audio_ControlInterface; - MIDI_ACInterfaceDescriptor Audio_ControlInterface_SPC; - - // MIDI Audio Streaming Interface - InterfaceDescriptor Audio_StreamInterface; - MIDI_ASInterfaceDescriptor Audio_StreamInterface_SPC; - - MIDIJackinDescriptor MIDI_In_Jack_Emb; - MIDIJackinDescriptor MIDI_In_Jack_Ext; - MIDIJackOutDescriptor MIDI_Out_Jack_Emb; - MIDIJackOutDescriptor MIDI_Out_Jack_Ext; - - MIDI_EPDescriptor MIDI_In_Jack_Endpoint; - MIDI_EP_ACDescriptor MIDI_In_Jack_Endpoint_SPC; - MIDI_EPDescriptor MIDI_Out_Jack_Endpoint; - MIDI_EP_ACDescriptor MIDI_Out_Jack_Endpoint_SPC; -} MIDIDescriptor; -_Pragma("pack()") +#ifdef MIDI_ENABLED + if (Is_udd_endpoint_interrupt(MIDI_RX)) + { + udd_ack_out_received(MIDI_RX); + + // Handle received bytes + if (USBD_Available(MIDI_RX)) + MidiUSB.accept(); + } + + if (Is_udd_sof()) + { + udd_ack_sof(); + // USBD_Flush(CDC_TX); // jcb + } +#endif -#define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \ - { 18, 1, 0x200, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs } + // EP 0 Interrupt + if (Is_udd_endpoint_interrupt(0) ) + { + if (!UDD_ReceivedSetupInt()) + { + return; + } + + Setup setup; + UDD_Recv(EP0, (uint8_t*)&setup, 8); + UDD_ClearSetupInt(); + + uint8_t requestType = setup.bmRequestType; + if (requestType & REQUEST_DEVICETOHOST) + { + TRACE_CORE(puts(">>> EP0 Int: IN Request\r\n");) + UDD_WaitIN(); + } + else + { + TRACE_CORE(puts(">>> EP0 Int: OUT Request\r\n");) + UDD_ClearIN(); + } + + bool ok = true; + if (REQUEST_STANDARD == (requestType & REQUEST_TYPE)) + { + // Standard Requests + uint8_t r = setup.bRequest; + if (GET_STATUS == r) + { + if( setup.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 + UDD_Send8(EP0, 0); // TODO + UDD_Send8(EP0, 0); + } + // if( setup.bmRequestType == 2 ) // Endpoint: + else + { + // Send the endpoint status + // Check if the endpoint if currently halted + if( isEndpointHalt == 1 ) + UDD_Send8(EP0, 1); // TODO + else + UDD_Send8(EP0, 0); // TODO + UDD_Send8(EP0, 0); + } + } + else if (CLEAR_FEATURE == r) + { + // Check which is the selected feature + if( setup.wValueL == 1) // DEVICEREMOTEWAKEUP + { + // Enable remote wake-up and send a ZLP + if( isRemoteWakeUpEnabled == 1 ) + UDD_Send8(EP0, 1); + else + UDD_Send8(EP0, 0); + UDD_Send8(EP0, 0); + } + else // if( setup.wValueL == 0) // ENDPOINTHALT + { + isEndpointHalt = 0; // TODO + UDD_Send8(EP0, 0); + UDD_Send8(EP0, 0); + } + + } + else if (SET_FEATURE == r) + { + // Check which is the selected feature + if( setup.wValueL == 1) // DEVICEREMOTEWAKEUP + { + // Enable remote wake-up and send a ZLP + isRemoteWakeUpEnabled = 1; + UDD_Send8(EP0, 0); + } + if( setup.wValueL == 0) // ENDPOINTHALT + { + // Halt endpoint + isEndpointHalt = 1; + //USBD_Halt(USBGenericRequest_GetEndpointNumber(pRequest)); + UDD_Send8(EP0, 0); + } + if( setup.wValueL == 2) // TEST_MODE + { + // 7.1.20 Test Mode Support, 9.4.9 SetFeature + if( (setup.bmRequestType == 0 /*USBGenericRequest_DEVICE*/) && + ((setup.wIndex & 0x000F) == 0) ) + { + // the lower byte of wIndex must be zero + // the most significant byte of wIndex is used to specify the specific test mode + + UOTGHS->UOTGHS_DEVIDR &= ~UOTGHS_DEVIDR_SUSPEC; + UOTGHS->UOTGHS_DEVCTRL |= UOTGHS_DEVCTRL_SPDCONF_HIGH_SPEED; // remove suspend ? + + Test_Mode_Support( (setup.wIndex & 0xFF00)>>8 ); + } + } + } + else if (SET_ADDRESS == r) + { + TRACE_CORE(puts(">>> EP0 Int: SET_ADDRESS\r\n");) + UDD_WaitIN(); + UDD_SetAddress(setup.wValueL); + } + else if (GET_DESCRIPTOR == r) + { + TRACE_CORE(puts(">>> EP0 Int: GET_DESCRIPTOR\r\n");) + ok = USBD_SendDescriptor(setup); + } + 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_Send8(EP0, _usbConfiguration); + } + else if (SET_CONFIGURATION == r) + { + if (REQUEST_DEVICE == (requestType & REQUEST_RECIPIENT)) + { + TRACE_CORE(printf(">>> EP0 Int: SET_CONFIGURATION REQUEST_DEVICE %d\r\n", setup.wValueL);) + + UDD_InitEndpoints(EndPoints, (sizeof(EndPoints) / sizeof(EndPoints[0]))); + _usbConfiguration = setup.wValueL; -#define D_CONFIG(_totalLength,_interfaces) \ - { 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_SELF_POWERED, USB_CONFIG_POWER_MA(500) } +#ifdef CDC_ENABLED + // Enable interrupt for CDC reception from host (OUT packet) + udd_enable_out_received_interrupt(CDC_RX); + udd_enable_endpoint_interrupt(CDC_RX); +#endif +#ifdef MIDI_ENABLED + // Enable interrupt for CDC reception from host (OUT packet) + udd_enable_out_received_interrupt(MIDI_RX); + udd_enable_endpoint_interrupt(MIDI_RX); +#endif + } + 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_Send8(EP0, _usbSetInterface); + } + else if (SET_INTERFACE == r) + { + _usbSetInterface = setup.wValueL; + TRACE_CORE(puts(">>> EP0 Int: SET_INTERFACE\r\n");) + } + } + else + { + TRACE_CORE(puts(">>> EP0 Int: ClassInterfaceRequest\r\n");) + + UDD_WaitIN(); // Workaround: need tempo here, else CDC serial won't open correctly + + USBD_InitControl(setup.wLength); // Max length of transfer + ok = USBD_ClassInterfaceRequest(setup); + } + + if (ok) + { + TRACE_CORE(puts(">>> EP0 Int: Send packet\r\n");) + UDD_ClearIN(); + } + else + { + TRACE_CORE(puts(">>> EP0 Int: Stall\r\n");) + UDD_Stall(); + } + } +} + +void USBD_Flush(uint32_t ep) +{ + if (UDD_FifoByteCount(ep)) + UDD_ReleaseTX(ep); +} -#define D_OTHERCONFIG(_totalLength,_interfaces) \ - { 9, 7, _totalLength,_interfaces, 1, 0, USB_CONFIG_SELF_POWERED, USB_CONFIG_POWER_MA(500) } +// VBUS or counting frames +// Any frame counting? +uint32_t USBD_Connected(void) +{ + uint8_t f = UDD_GetFrameNumber(); -#define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \ - { 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 } + delay(3); -#define D_ENDPOINT(_addr,_attr,_packetSize, _interval) \ - { 7, 5, _addr,_attr,_packetSize, _interval } + return f != UDD_GetFrameNumber(); +} -#define D_QUALIFIER(_class,_subClass,_proto,_packetSize0,_configs) \ - { 10, 6, 0x200, _class,_subClass,_proto,_packetSize0,_configs } -#define D_IAD(_firstInterface, _count, _class, _subClass, _protocol) \ - { 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 } +//======================================================================= +//======================================================================= -#define D_HIDREPORT(_descriptorLength) \ - { 9, 0x21, 0x1, 0x1, 0, 1, 0x22, _descriptorLength, 0 } - -#define D_AC_INTERFACE(_streamingInterfaces, _MIDIInterface) \ - { 9, MIDI_CS_INTERFACE, 0x1, 0x0100, 0x0009, _streamingInterfaces, _MIDIInterface } - -#define D_AS_INTERFACE \ - { 0x7, MIDI_CS_INTERFACE, 0x01,0x0100, 0x0041} - -#define D_MIDI_INJACK(jackProp, _jackID) \ - { 0x06, MIDI_CS_INTERFACE, 0x02, jackProp, _jackID, 0 } - -#define D_MIDI_OUTJACK(jackProp, _jackID, _nPins, _srcID, _srcPin) \ - { 0x09, MIDI_CS_INTERFACE, 0x3, jackProp, _jackID, _nPins, _srcID, _srcPin, 0 } - -#define D_MIDI_JACK_EP(_addr,_attr,_packetSize) \ - { 9, 5, _addr,_attr,_packetSize, 0, 0, 0} +USBDevice_ USBDevice; -#define D_MIDI_AC_JACK_EP(_nMIDI, _iDMIDI) \ - { 5, MIDI_CS_ENDPOINT, 0x1, _nMIDI, _iDMIDI} - -#define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 } -#define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 } +USBDevice_::USBDevice_() +{ + UDD_SetStack(&USB_ISR); + if (UDD_Init() == 0UL) + { + _usbInitialized=1UL; + } +} -#endif +bool USBDevice_::attach(void) +{ + if (_usbInitialized != 0UL) + { + UDD_Attach(); + _usbConfiguration = 0; + return true; + } + else + { + return false; + } +} + +bool USBDevice_::detach(void) +{ + if (_usbInitialized != 0UL) + { + UDD_Detach(); + return true; + } + else + { + return false; + } +} + +// Check for interrupts +// TODO: VBUS detection +bool USBDevice_::configured() +{ + return _usbConfiguration; +} + +void USBDevice_::poll() +{ +}