switch to setup for Arduino Boards Manager

This commit is contained in:
Erik Tylek Kettenburg
2015-06-23 12:42:35 -07:00
parent bc55c9bb45
commit 6ca6b114d5
3581 changed files with 93 additions and 51 deletions

View File

@@ -0,0 +1,301 @@
/* 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 "Arduino.h"
#include "USBAPI.h"
#include "Reset.h"
#ifdef CDC_ENABLED
#define CDC_SERIAL_BUFFER_SIZE 512
/* For information purpose only since RTS is not always handled by the terminal application */
#define CDC_LINESTATE_DTR 0x01 // Data Terminal Ready
#define CDC_LINESTATE_RTS 0x02 // Ready to Send
#define CDC_LINESTATE_READY (CDC_LINESTATE_RTS | CDC_LINESTATE_DTR)
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;
} LineInfo;
static volatile LineInfo _usbLineInfo = {
57600, // dWDTERate
0x00, // bCharFormat
0x00, // bParityType
0x08, // bDataBits
0x00 // lineState
};
_Pragma("pack(1)")
static const CDCDescriptor _cdcInterface =
{
D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1),
// CDC communication interface
D_INTERFACE(CDC_ACM_INTERFACE,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0),
D_CDCCS(CDC_HEADER,0x10,0x01), // Header (1.10 bcd)
D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not)
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_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,512,0),
D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,512,0)
};
static const CDCDescriptor _cdcOtherInterface =
{
D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1),
// CDC communication interface
D_INTERFACE(CDC_ACM_INTERFACE,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0),
D_CDCCS(CDC_HEADER,0x10,0x01), // Header (1.10 bcd)
D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not)
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_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,64,0),
D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,64,0)
};
_Pragma("pack()")
int WEAK CDC_GetInterface(uint8_t* interfaceNum)
{
interfaceNum[0] += 2; // uses 2
return USBD_SendControl(0,&_cdcInterface,sizeof(_cdcInterface));
}
int WEAK CDC_GetOtherInterface(uint8_t* interfaceNum)
{
interfaceNum[0] += 2; // uses 2
return USBD_SendControl(0,&_cdcOtherInterface,sizeof(_cdcOtherInterface));
}
bool WEAK CDC_Setup(Setup& setup)
{
uint8_t r = setup.bRequest;
uint8_t requestType = setup.bmRequestType;
if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType)
{
if (CDC_GET_LINE_CODING == r)
{
USBD_SendControl(0,(void*)&_usbLineInfo,7);
return true;
}
}
if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType)
{
if (CDC_SET_LINE_CODING == r)
{
USBD_RecvControl((void*)&_usbLineInfo,7);
return true;
}
if (CDC_SET_CONTROL_LINE_STATE == r)
{
_usbLineInfo.lineState = setup.wValueL;
// auto-reset into the bootloader is triggered when the port, already
// open at 1200 bps, is closed.
if (1200 == _usbLineInfo.dwDTERate)
{
// We check DTR state to determine if host port is open (bit 0 of lineState).
if ((_usbLineInfo.lineState & 0x01) == 0)
initiateReset(250);
else
cancelReset();
}
return true;
}
}
return false;
}
int _serialPeek = -1;
void Serial_::begin(uint32_t baud_count)
{
}
void Serial_::begin(uint32_t baud_count, uint8_t config)
{
}
void Serial_::end(void)
{
}
void Serial_::accept(void)
{
static uint32_t guard = 0;
// synchronized access to guard
do {
if (__LDREXW(&guard) != 0) {
__CLREX();
return; // busy
}
} while (__STREXW(1, &guard) != 0); // retry until write succeed
ring_buffer *buffer = &cdc_rx_buffer;
uint32_t i = (uint32_t)(buffer->head+1) % CDC_SERIAL_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) {
uint32_t c;
if (!USBD_Available(CDC_RX)) {
udd_ack_fifocon(CDC_RX);
break;
}
c = USBD_Recv(CDC_RX);
// c = UDD_Recv8(CDC_RX & 0xF);
buffer->buffer[buffer->head] = c;
buffer->head = i;
i = (i + 1) % CDC_SERIAL_BUFFER_SIZE;
}
// release the guard
guard = 0;
}
int Serial_::available(void)
{
ring_buffer *buffer = &cdc_rx_buffer;
return (unsigned int)(CDC_SERIAL_BUFFER_SIZE + buffer->head - buffer->tail) % CDC_SERIAL_BUFFER_SIZE;
}
int Serial_::peek(void)
{
ring_buffer *buffer = &cdc_rx_buffer;
if (buffer->head == buffer->tail)
{
return -1;
}
else
{
return buffer->buffer[buffer->tail];
}
}
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)
{
return -1;
}
else
{
unsigned char c = buffer->buffer[buffer->tail];
buffer->tail = (unsigned int)(buffer->tail + 1) % CDC_SERIAL_BUFFER_SIZE;
if (USBD_Available(CDC_RX))
accept();
return c;
}
}
void Serial_::flush(void)
{
USBD_Flush(CDC_TX);
}
size_t Serial_::write(const uint8_t *buffer, size_t size)
{
/* only try to send bytes if the high-level CDC 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)
if (_usbLineInfo.lineState > 0)
{
int r = USBD_Send(CDC_TX, buffer, size);
if (r > 0)
{
return r;
} else
{
setWriteError();
return 0;
}
}
setWriteError();
return 0;
}
size_t Serial_::write(uint8_t c) {
return write(&c, 1);
}
// This operator is a convenient way for a sketch to check whether the
// port has actually been configured and opened by the host (as opposed
// to just being connected to the host). It can be used, for example, in
// setup() before printing to ensure that an application on the host is
// actually ready to receive and display the data.
// We add a short delay before returning to fix a bug observed by Federico
// where the port is configured (lineState != 0) but not quite opened.
Serial_::operator bool()
{
// this is here to avoid spurious opening after upload
if (millis() < 500)
return false;
bool result = false;
if (_usbLineInfo.lineState > 0)
{
result = true;
}
delay(10);
return result;
}
Serial_ SerialUSB;
Serial_ Serial;
#endif

View File

@@ -0,0 +1,518 @@
/* 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 "Arduino.h"
#ifdef HID_ENABLED
//#define RAWHID_ENABLED
// Singletons for mouse and keyboard
Mouse_ Mouse;
Keyboard_ Keyboard;
//================================================================================
//================================================================================
// 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
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
};
_Pragma("pack(1)")
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;
#define WEAK __attribute__ ((weak))
int WEAK HID_GetInterface(uint8_t* interfaceNum)
{
interfaceNum[0] += 1; // uses 1
return USBD_SendControl(0,&_hidInterface,sizeof(_hidInterface));
}
int WEAK HID_GetDescriptor(int i)
{
return USBD_SendControl(0,_hidReportDescriptor,sizeof(_hidReportDescriptor));
}
void WEAK HID_SendReport(uint8_t id, const void* data, uint32_t len)
{
uint8_t p[64];
const uint8_t *d = reinterpret_cast<const uint8_t *>(data);
p[0] = id;
for (uint32_t i=0; i<len; i++)
p[i+1] = d[i];
USBD_Send(HID_TX, p, len+1);
}
bool WEAK HID_Setup(Setup& setup)
{
uint8_t r = setup.bRequest;
uint8_t requestType = setup.bmRequestType;
if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType)
{
if (HID_GET_REPORT == r)
{
//HID_GetReport();
return true;
}
if (HID_GET_PROTOCOL == r)
{
//Send8(_hid_protocol); // TODO
return true;
}
}
if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType)
{
if (HID_SET_PROTOCOL == r)
{
_hid_protocol = setup.wValueL;
return true;
}
if (HID_SET_IDLE == r)
{
_hid_idle = setup.wValueL;
return true;
}
}
return false;
}
//================================================================================
//================================================================================
// Mouse
Mouse_::Mouse_(void) : _buttons(0)
{
}
void Mouse_::begin(void)
{
}
void Mouse_::end(void)
{
}
void Mouse_::click(uint8_t b)
{
_buttons = b;
move(0,0,0);
_buttons = 0;
move(0,0,0);
}
void Mouse_::move(signed char x, signed char y, signed char wheel)
{
uint8_t m[4];
m[0] = _buttons;
m[1] = x;
m[2] = y;
m[3] = wheel;
HID_SendReport(1,m,4);
}
void Mouse_::buttons(uint8_t b)
{
if (b != _buttons)
{
_buttons = b;
move(0,0,0);
}
}
void Mouse_::press(uint8_t b)
{
buttons(_buttons | b);
}
void Mouse_::release(uint8_t b)
{
buttons(_buttons & ~b);
}
bool Mouse_::isPressed(uint8_t b)
{
if ((b & _buttons) > 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
};
uint8_t USBPutChar(uint8_t c);
// 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

View File

@@ -0,0 +1,222 @@
/*
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
*/
#ifndef __USBAPI__
#define __USBAPI__
#if defined __cplusplus
#include "RingBuffer.h"
//================================================================================
//================================================================================
// USB
class USBDevice_
{
public:
USBDevice_();
bool configured();
bool attach();
bool detach(); // Serial port goes down too...
void poll();
};
extern USBDevice_ USBDevice;
//================================================================================
//================================================================================
// Serial over CDC (Serial1 is the physical port)
class Serial_ : public Stream
{
private:
RingBuffer *_cdc_rx_buffer;
public:
void begin(uint32_t baud_count);
void begin(uint32_t baud_count, uint8_t config);
void end(void);
virtual int available(void);
virtual void accept(void);
virtual int peek(void);
virtual int read(void);
virtual void flush(void);
virtual size_t write(uint8_t);
virtual size_t write(const uint8_t *buffer, size_t size);
using Print::write; // pull in write(str) from Print
operator bool();
};
extern Serial_ SerialUSB;
extern Serial_ Serial;
//================================================================================
//================================================================================
// 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;
//================================================================================
//================================================================================
// 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'
int HID_GetInterface(uint8_t* interfaceNum);
int HID_GetDescriptor(int i);
bool HID_Setup(Setup& setup);
void HID_SendReport(uint8_t id, const void* data, uint32_t len);
//================================================================================
//================================================================================
// MSC 'Driver'
int MSC_GetInterface(uint8_t* interfaceNum);
int MSC_GetDescriptor(int i);
bool MSC_Setup(Setup& setup);
bool MSC_Data(uint8_t rx,uint8_t tx);
//================================================================================
//================================================================================
// CSC 'Driver'
int CDC_GetInterface(uint8_t* interfaceNum);
int CDC_GetOtherInterface(uint8_t* interfaceNum);
int CDC_GetDescriptor(int i);
bool CDC_Setup(Setup& setup);
//================================================================================
//================================================================================
#define TRANSFER_RELEASE 0x40
#define TRANSFER_ZERO 0x20
void USBD_InitControl(int end);
int USBD_SendControl(uint8_t flags, const void* d, uint32_t len);
int USBD_RecvControl(void* d, uint32_t len);
int 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
#endif

View File

@@ -0,0 +1,882 @@
// Copyright (c) 2010, 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 "Arduino.h"
#include "USBAPI.h"
#include "Reset.h"
#include <stdio.h>
//#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"
#elif USB_PID == USB_PID_DIGIX
#define USB_PRODUCT "Digistump DigiX"
#else
#define USB_PRODUCT "USB IO Board"
#endif
#endif
const uint8_t STRING_PRODUCT[] = USB_PRODUCT;
#define USB_MANUFACTURER "Digistump"
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_DIGIX,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1);
const DeviceDescriptor USB_DeviceDescriptorA =
D_DEVICE(DEVICE_CLASS,0x00,0x00,64,USB_VID_DIGIX,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
{
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)
{
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 || len < 0)
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 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)
{
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)
{
_cmark = 0;
_cend = end;
}
// Clipped by _cmark/_cend
int USBD_SendControl(uint8_t flags, const void* d, uint32_t len)
{
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)
{
UDD_WaitOUT();
UDD_Recv(EP0, (uint8_t*)d, len);
UDD_ClearOUT();
return len;
}
// Handle CLASS_INTERFACE requests
bool USBD_ClassInterfaceRequest(Setup& setup)
{
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)
{
int total = 0;
uint8_t interfaces = 0;
#ifdef CDC_ENABLED
total = CDC_GetInterface(&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;
}
int USBD_SendOtherInterfaces(void)
{
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)
{
// 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)
{
// 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 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
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 )
{
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 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; i<sizeof(test_packet_buffer); i++)
{
ptr_dest[i] = test_packet_buffer[i];;
}
// Tst PACKET
UOTGHS->UOTGHS_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
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
// 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;
#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);
}
// VBUS or counting frames
// Any frame counting?
uint32_t USBD_Connected(void)
{
uint8_t f = UDD_GetFrameNumber();
delay(3);
return f != UDD_GetFrameNumber();
}
//=======================================================================
//=======================================================================
USBDevice_ USBDevice;
USBDevice_::USBDevice_()
{
UDD_SetStack(&USB_ISR);
if (UDD_Init() == 0UL)
{
_usbInitialized=1UL;
}
}
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()
{
}

View File

@@ -0,0 +1,311 @@
// Copyright (c) 2010, 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.
*/
#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
_Pragma("pack(1)")
// 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
{
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 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
{
uint8_t len; // 5
uint8_t dtype; // 0x24
uint8_t subtype;
uint8_t d0;
uint8_t d1;
} CDCCSInterfaceDescriptor;
typedef struct
{
uint8_t len; // 4
uint8_t dtype; // 0x24
uint8_t subtype;
uint8_t d0;
} CDCCSInterfaceDescriptor4;
typedef struct
{
uint8_t len;
uint8_t dtype; // 0x24
uint8_t subtype; // 1
uint8_t bmCapabilities;
uint8_t bDataInterface;
} CMFunctionalDescriptor;
typedef struct
{
uint8_t len;
uint8_t dtype; // 0x24
uint8_t subtype; // 1
uint8_t bmCapabilities;
} ACMFunctionalDescriptor;
typedef struct
{
// 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
{
InterfaceDescriptor msc;
EndpointDescriptor in;
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) \
{ 18, 1, 0x200, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs }
#define D_CONFIG(_totalLength,_interfaces) \
{ 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_SELF_POWERED, USB_CONFIG_POWER_MA(500) }
#define D_OTHERCONFIG(_totalLength,_interfaces) \
{ 9, 7, _totalLength,_interfaces, 1, 0, USB_CONFIG_SELF_POWERED, USB_CONFIG_POWER_MA(500) }
#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 }
#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_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 }
#define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 }
#endif

View File

@@ -0,0 +1,64 @@
// Copyright (c) 2010, 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.
*/
#ifndef __USBDESC_H__
#define __USBDESC_H__
#define CDC_ENABLED
#define HID_ENABLED
#ifdef CDC_ENABLED
#define CDC_INTERFACE_COUNT 2
#define CDC_ENPOINT_COUNT 3
#else
#define CDC_INTERFACE_COUNT 0
#define CDC_ENPOINT_COUNT 0
#endif
#ifdef HID_ENABLED
#define HID_INTERFACE_COUNT 1
#define HID_ENPOINT_COUNT 1
#else
#define HID_INTERFACE_COUNT 0
#define HID_ENPOINT_COUNT 0
#endif
#define CDC_ACM_INTERFACE 0 // CDC ACM
#define CDC_DATA_INTERFACE 1 // CDC Data
#define CDC_FIRST_ENDPOINT 1
#define CDC_ENDPOINT_ACM (CDC_FIRST_ENDPOINT) // CDC First
#define CDC_ENDPOINT_OUT (CDC_FIRST_ENDPOINT+1)
#define CDC_ENDPOINT_IN (CDC_FIRST_ENDPOINT+2)
#define HID_INTERFACE (CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT) // HID Interface
#define HID_FIRST_ENDPOINT (CDC_FIRST_ENDPOINT + CDC_ENPOINT_COUNT)
#define HID_ENDPOINT_INT (HID_FIRST_ENDPOINT)
#define INTERFACE_COUNT (MSC_INTERFACE + MSC_INTERFACE_COUNT)
#ifdef CDC_ENABLED
#define CDC_RX CDC_ENDPOINT_OUT
#define CDC_TX CDC_ENDPOINT_IN
#endif
#ifdef HID_ENABLED
#define HID_TX HID_ENDPOINT_INT
#endif
#define IMANUFACTURER 1
#define IPRODUCT 2
#endif /* __USBDESC_H__ */