diff options
Diffstat (limited to 'cores')
-rw-r--r-- | cores/arduino/CDC.cpp | 84 | ||||
-rw-r--r-- | cores/arduino/HID.cpp | 518 | ||||
-rw-r--r-- | cores/arduino/HardwareSerial.cpp | 3 | ||||
-rw-r--r-- | cores/arduino/HardwareSerial.h | 4 | ||||
-rw-r--r-- | cores/arduino/IPAddress.cpp | 42 | ||||
-rw-r--r-- | cores/arduino/IPAddress.h | 7 | ||||
-rw-r--r-- | cores/arduino/PluggableUSB.cpp | 115 | ||||
-rw-r--r-- | cores/arduino/PluggableUSB.h | 74 | ||||
-rw-r--r-- | cores/arduino/Print.cpp | 7 | ||||
-rw-r--r-- | cores/arduino/Stream.cpp | 66 | ||||
-rw-r--r-- | cores/arduino/Stream.h | 42 | ||||
-rw-r--r-- | cores/arduino/Tone.cpp | 3 | ||||
-rw-r--r-- | cores/arduino/USBAPI.h | 168 | ||||
-rw-r--r-- | cores/arduino/USBCore.cpp | 321 | ||||
-rw-r--r-- | cores/arduino/USBCore.h | 60 | ||||
-rw-r--r-- | cores/arduino/USBDesc.h | 75 | ||||
-rw-r--r-- | cores/arduino/WInterrupts.c | 62 | ||||
-rw-r--r-- | cores/arduino/WString.cpp | 6 | ||||
-rw-r--r-- | cores/arduino/WString.h | 6 | ||||
-rw-r--r-- | cores/arduino/main.cpp | 3 | ||||
-rw-r--r-- | cores/arduino/wiring.c | 14 | ||||
-rw-r--r-- | cores/arduino/wiring_digital.c | 2 | ||||
-rw-r--r-- | cores/arduino/wiring_private.h | 3 | ||||
-rw-r--r-- | cores/arduino/wiring_pulse.c | 17 |
24 files changed, 794 insertions, 908 deletions
diff --git a/cores/arduino/CDC.cpp b/cores/arduino/CDC.cpp index 5d4f2a0..f19b44c 100644 --- a/cores/arduino/CDC.cpp +++ b/cores/arduino/CDC.cpp @@ -18,9 +18,9 @@ #include "USBAPI.h" #include <avr/wdt.h> +#include <util/atomic.h> #if defined(USBCON) -#ifdef CDC_ENABLED typedef struct { @@ -32,6 +32,7 @@ typedef struct } LineInfo; static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 }; +static volatile int32_t breakValue = -1; #define WEAK __attribute__ ((weak)) @@ -50,17 +51,17 @@ const CDCDescriptor _cdcInterface = // 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,0x40,0), - D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,0x40,0) + D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0), + D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0) }; -int WEAK CDC_GetInterface(u8* interfaceNum) +int CDC_GetInterface(u8* interfaceNum) { interfaceNum[0] += 2; // uses 2 return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface)); } -bool WEAK CDC_Setup(Setup& setup) +bool CDC_Setup(USBSetup& setup) { u8 r = setup.bRequest; u8 requestType = setup.bmRequestType; @@ -76,6 +77,11 @@ bool WEAK CDC_Setup(Setup& setup) if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) { + if (CDC_SEND_BREAK == r) + { + breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL; + } + if (CDC_SET_LINE_CODING == r) { USB_RecvControl((void*)&_usbLineInfo,7); @@ -93,10 +99,24 @@ bool WEAK CDC_Setup(Setup& setup) // with a relatively long period so it can finish housekeeping tasks // like servicing endpoints before the sketch ends +#ifndef MAGIC_KEY +#define MAGIC_KEY 0x7777 +#endif +#ifndef MAGIC_KEY_POS +#define MAGIC_KEY_POS 0x0800 +#endif + // We check DTR state to determine if host port is open (bit 0 of lineState). if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0) { - *(uint16_t *)0x0800 = 0x7777; +#if MAGIC_KEY_POS != (RAMEND-1) + *(uint16_t *)(RAMEND-1) = *(uint16_t *)MAGIC_KEY_POS; + *(uint16_t *)MAGIC_KEY_POS = MAGIC_KEY; +#else + // for future boards save the key in the inproblematic RAMEND + // which is reserved for the main() return value (which will never return) + *(uint16_t *)MAGIC_KEY_POS = MAGIC_KEY; +#endif wdt_enable(WDTO_120MS); } else @@ -108,7 +128,11 @@ bool WEAK CDC_Setup(Setup& setup) wdt_disable(); wdt_reset(); - *(uint16_t *)0x0800 = 0x0; +#if MAGIC_KEY_POS != (RAMEND-1) + *(uint16_t *)MAGIC_KEY_POS = *(uint16_t *)(RAMEND-1); +#else + *(uint16_t *)MAGIC_KEY_POS = 0x0000; +#endif } } return true; @@ -156,6 +180,11 @@ int Serial_::read(void) return USB_Recv(CDC_RX); } +int Serial_::availableForWrite(void) +{ + return USB_SendSpace(CDC_TX); +} + void Serial_::flush(void) { USB_Flush(CDC_TX); @@ -205,7 +234,46 @@ Serial_::operator bool() { return result; } +unsigned long Serial_::baud() { + // Disable interrupts while reading a multi-byte value + uint32_t baudrate; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + baudrate = _usbLineInfo.dwDTERate; + } + return baudrate; +} + +uint8_t Serial_::stopbits() { + return _usbLineInfo.bCharFormat; +} + +uint8_t Serial_::paritytype() { + return _usbLineInfo.bParityType; +} + +uint8_t Serial_::numbits() { + return _usbLineInfo.bDataBits; +} + +bool Serial_::dtr() { + return _usbLineInfo.lineState & 0x1; +} + +bool Serial_::rts() { + return _usbLineInfo.lineState & 0x2; +} + +int32_t Serial_::readBreak() { + int32_t ret; + // Disable IRQs while reading and clearing breakValue to make + // sure we don't overwrite a value just set by the ISR. + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + ret = breakValue; + breakValue = -1; + } + return ret; +} + Serial_ Serial; -#endif #endif /* if defined(USBCON) */ diff --git a/cores/arduino/HID.cpp b/cores/arduino/HID.cpp deleted file mode 100644 index 75c37b2..0000000 --- a/cores/arduino/HID.cpp +++ /dev/null @@ -1,518 +0,0 @@ - - -/* 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 "USBAPI.h" - -#if defined(USBCON) -#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 u8 _hidReportDescriptor[] PROGMEM; -const u8 _hidReportDescriptor[] = { - - // Mouse - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 54 - 0x09, 0x02, // USAGE (Mouse) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x01, // USAGE (Pointer) - 0xa1, 0x00, // COLLECTION (Physical) - 0x85, 0x01, // REPORT_ID (1) - 0x05, 0x09, // USAGE_PAGE (Button) - 0x19, 0x01, // USAGE_MINIMUM (Button 1) - 0x29, 0x03, // USAGE_MAXIMUM (Button 3) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x95, 0x03, // REPORT_COUNT (3) - 0x75, 0x01, // REPORT_SIZE (1) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x95, 0x01, // REPORT_COUNT (1) - 0x75, 0x05, // REPORT_SIZE (5) - 0x81, 0x03, // INPUT (Cnst,Var,Abs) - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) - 0x09, 0x30, // USAGE (X) - 0x09, 0x31, // USAGE (Y) - 0x09, 0x38, // USAGE (Wheel) - 0x15, 0x81, // LOGICAL_MINIMUM (-127) - 0x25, 0x7f, // LOGICAL_MAXIMUM (127) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x03, // REPORT_COUNT (3) - 0x81, 0x06, // INPUT (Data,Var,Rel) - 0xc0, // END_COLLECTION - 0xc0, // END_COLLECTION - - // Keyboard - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47 - 0x09, 0x06, // USAGE (Keyboard) - 0xa1, 0x01, // COLLECTION (Application) - 0x85, 0x02, // REPORT_ID (2) - 0x05, 0x07, // USAGE_PAGE (Keyboard) - - 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) - 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x75, 0x01, // REPORT_SIZE (1) - - 0x95, 0x08, // REPORT_COUNT (8) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x95, 0x01, // REPORT_COUNT (1) - 0x75, 0x08, // REPORT_SIZE (8) - 0x81, 0x03, // INPUT (Cnst,Var,Abs) - - 0x95, 0x06, // REPORT_COUNT (6) - 0x75, 0x08, // REPORT_SIZE (8) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x65, // LOGICAL_MAXIMUM (101) - 0x05, 0x07, // USAGE_PAGE (Keyboard) - - 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) - 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) - 0x81, 0x00, // INPUT (Data,Ary,Abs) - 0xc0, // END_COLLECTION - -#ifdef RAWHID_ENABLED - // RAW HID - 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), // 30 - 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), - - 0xA1, 0x01, // Collection 0x01 - 0x85, 0x03, // REPORT_ID (3) - 0x75, 0x08, // report size = 8 bits - 0x15, 0x00, // logical minimum = 0 - 0x26, 0xFF, 0x00, // logical maximum = 255 - - 0x95, 64, // report count TX - 0x09, 0x01, // usage - 0x81, 0x02, // Input (array) - - 0x95, 64, // report count RX - 0x09, 0x02, // usage - 0x91, 0x02, // Output (array) - 0xC0 // end collection -#endif -}; - -extern const HIDDescriptor _hidInterface PROGMEM; -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) -}; - -//================================================================================ -//================================================================================ -// Driver - -u8 _hid_protocol = 1; -u8 _hid_idle = 1; - -#define WEAK __attribute__ ((weak)) - -int WEAK HID_GetInterface(u8* interfaceNum) -{ - interfaceNum[0] += 1; // uses 1 - return USB_SendControl(TRANSFER_PGM,&_hidInterface,sizeof(_hidInterface)); -} - -int WEAK HID_GetDescriptor(int /* i */) -{ - return USB_SendControl(TRANSFER_PGM,_hidReportDescriptor,sizeof(_hidReportDescriptor)); -} - -void WEAK HID_SendReport(u8 id, const void* data, int len) -{ - USB_Send(HID_TX, &id, 1); - USB_Send(HID_TX | TRANSFER_RELEASE,data,len); -} - -bool WEAK HID_Setup(Setup& setup) -{ - u8 r = setup.bRequest; - u8 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) -{ - u8 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)); -} - -extern -const uint8_t _asciimap[128] PROGMEM; - -#define SHIFT 0x80 -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 = pgm_read_byte(_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 = pgm_read_byte(_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 = press(c); // Keydown - release(c); // Keyup - return p; // just return the result of press() since release() almost always returns 1 -} - -#endif - -#endif /* if defined(USBCON) */ diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index a2029a8..5cd89e5 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -138,8 +138,7 @@ void HardwareSerial::begin(unsigned long baud, byte config) void HardwareSerial::end() { // wait for transmission of outgoing data - while (_tx_buffer_head != _tx_buffer_tail) - ; + flush(); cbi(*_ucsrb, RXEN0); cbi(*_ucsrb, TXEN0); diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h index 1beafc5..8a5bf95 100644 --- a/cores/arduino/HardwareSerial.h +++ b/cores/arduino/HardwareSerial.h @@ -40,14 +40,14 @@ // often work, but occasionally a race condition can occur that makes // Serial behave erratically. See https://github.com/arduino/Arduino/issues/2405 #if !defined(SERIAL_TX_BUFFER_SIZE) -#if (RAMEND < 1000) +#if ((RAMEND - RAMSTART) < 1023) #define SERIAL_TX_BUFFER_SIZE 16 #else #define SERIAL_TX_BUFFER_SIZE 64 #endif #endif #if !defined(SERIAL_RX_BUFFER_SIZE) -#if (RAMEND < 1000) +#if ((RAMEND - RAMSTART) < 1023) #define SERIAL_RX_BUFFER_SIZE 16 #else #define SERIAL_RX_BUFFER_SIZE 64 diff --git a/cores/arduino/IPAddress.cpp b/cores/arduino/IPAddress.cpp index 899cbd4..76aefa8 100644 --- a/cores/arduino/IPAddress.cpp +++ b/cores/arduino/IPAddress.cpp @@ -43,6 +43,48 @@ IPAddress::IPAddress(const uint8_t *address) memcpy(_address.bytes, address, sizeof(_address.bytes)); } +bool IPAddress::fromString(const char *address) +{ + // TODO: add support for "a", "a.b", "a.b.c" formats + + uint16_t acc = 0; // Accumulator + uint8_t dots = 0; + + while (*address) + { + char c = *address++; + if (c >= '0' && c <= '9') + { + acc = acc * 10 + (c - '0'); + if (acc > 255) { + // Value out of [0..255] range + return false; + } + } + else if (c == '.') + { + if (dots == 3) { + // Too much dots (there must be 3 dots) + return false; + } + _address.bytes[dots++] = acc; + acc = 0; + } + else + { + // Invalid char + return false; + } + } + + if (dots != 3) { + // Too few dots (there must be 3 dots) + return false; + } + _address.bytes[3] = acc; + return true; +} + IPAddress& IPAddress::operator=(const uint8_t *address) { memcpy(_address.bytes, address, sizeof(_address.bytes)); diff --git a/cores/arduino/IPAddress.h b/cores/arduino/IPAddress.h index 94acdc4..d762f2c 100644 --- a/cores/arduino/IPAddress.h +++ b/cores/arduino/IPAddress.h @@ -21,7 +21,8 @@ #define IPAddress_h #include <stdint.h> -#include <Printable.h> +#include "Printable.h" +#include "WString.h" // A class to make it easier to handle and pass around IP addresses @@ -45,6 +46,9 @@ public: IPAddress(uint32_t address); IPAddress(const uint8_t *address); + bool fromString(const char *address); + bool fromString(const String &address) { return fromString(address.c_str()); } + // Overloaded cast operator to allow IPAddress objects to be used where a pointer // to a four-byte uint8_t array is expected operator uint32_t() const { return _address.dword; }; @@ -71,5 +75,4 @@ public: const IPAddress INADDR_NONE(0,0,0,0); - #endif diff --git a/cores/arduino/PluggableUSB.cpp b/cores/arduino/PluggableUSB.cpp new file mode 100644 index 0000000..c489d9f --- /dev/null +++ b/cores/arduino/PluggableUSB.cpp @@ -0,0 +1,115 @@ +/* + PluggableUSB.cpp + Copyright (c) 2015 Arduino LLC + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "USBAPI.h" +#include "PluggableUSB.h" + +#if defined(USBCON) +#ifdef PLUGGABLE_USB_ENABLED + +extern uint8_t _initEndpoints[]; + +int PluggableUSB_::getInterface(uint8_t* interfaceCount) +{ + int sent = 0; + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + int res = node->getInterface(interfaceCount); + if (res < 0) + return -1; + sent += res; + } + return sent; +} + +int PluggableUSB_::getDescriptor(USBSetup& setup) +{ + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + int ret = node->getDescriptor(setup); + // ret!=0 -> request has been processed + if (ret) + return ret; + } + return 0; +} + +void PluggableUSB_::getShortName(char *iSerialNum) +{ + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + iSerialNum += node->getShortName(iSerialNum); + } + *iSerialNum = 0; +} + +bool PluggableUSB_::setup(USBSetup& setup) +{ + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + if (node->setup(setup)) { + return true; + } + } + return false; +} + +bool PluggableUSB_::plug(PluggableUSBModule *node) +{ + if ((lastEp + node->numEndpoints) > USB_ENDPOINTS) { + return false; + } + + if (!rootNode) { + rootNode = node; + } else { + PluggableUSBModule *current = rootNode; + while (current->next) { + current = current->next; + } + current->next = node; + } + + node->pluggedInterface = lastIf; + node->pluggedEndpoint = lastEp; + lastIf += node->numInterfaces; + for (uint8_t i = 0; i < node->numEndpoints; i++) { + _initEndpoints[lastEp] = node->endpointType[i]; + lastEp++; + } + return true; + // restart USB layer??? +} + +PluggableUSB_& PluggableUSB() +{ + static PluggableUSB_ obj; + return obj; +} + +PluggableUSB_::PluggableUSB_() : lastIf(CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT), + lastEp(CDC_FIRST_ENDPOINT + CDC_ENPOINT_COUNT), + rootNode(NULL) +{ + // Empty +} + +#endif + +#endif /* if defined(USBCON) */ diff --git a/cores/arduino/PluggableUSB.h b/cores/arduino/PluggableUSB.h new file mode 100644 index 0000000..507f0df --- /dev/null +++ b/cores/arduino/PluggableUSB.h @@ -0,0 +1,74 @@ +/* + PluggableUSB.h + Copyright (c) 2015 Arduino LLC + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef PUSB_h +#define PUSB_h + +#include "USBAPI.h" +#include <stdint.h> + +#if defined(USBCON) + +class PluggableUSBModule { +public: + PluggableUSBModule(uint8_t numEps, uint8_t numIfs, uint8_t *epType) : + numEndpoints(numEps), numInterfaces(numIfs), endpointType(epType) + { } + +protected: + virtual bool setup(USBSetup& setup) = 0; + virtual int getInterface(uint8_t* interfaceCount) = 0; + virtual int getDescriptor(USBSetup& setup) = 0; + virtual uint8_t getShortName(char *name) { name[0] = 'A'+pluggedInterface; return 1; } + + uint8_t pluggedInterface; + uint8_t pluggedEndpoint; + + const uint8_t numEndpoints; + const uint8_t numInterfaces; + const uint8_t *endpointType; + + PluggableUSBModule *next = NULL; + + friend class PluggableUSB_; +}; + +class PluggableUSB_ { +public: + PluggableUSB_(); + bool plug(PluggableUSBModule *node); + int getInterface(uint8_t* interfaceCount); + int getDescriptor(USBSetup& setup); + bool setup(USBSetup& setup); + void getShortName(char *iSerialNum); + +private: + uint8_t lastIf; + uint8_t lastEp; + PluggableUSBModule* rootNode; +}; + +// Replacement for global singleton. +// This function prevents static-initialization-order-fiasco +// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use +PluggableUSB_& PluggableUSB(); + +#endif + +#endif diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 782d50b..bc97c85 100644 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -17,6 +17,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Modified 23 November 2006 by David A. Mellis + Modified 03 August 2015 by Chuck Todd */ #include <stdlib.h> @@ -34,7 +35,8 @@ size_t Print::write(const uint8_t *buffer, size_t size) { size_t n = 0; while (size--) { - n += write(*buffer++); + if (write(*buffer++)) n++; + else break; } return n; } @@ -46,7 +48,8 @@ size_t Print::print(const __FlashStringHelper *ifsh) while (1) { unsigned char c = pgm_read_byte(p++); if (c == 0) break; - n += write(c); + if (write(c)) n++; + else break; } return n; } diff --git a/cores/arduino/Stream.cpp b/cores/arduino/Stream.cpp index b31942f..f665465 100644 --- a/cores/arduino/Stream.cpp +++ b/cores/arduino/Stream.cpp @@ -26,7 +26,6 @@ #include "Stream.h" #define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait -#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field // private method to read stream with timeout int Stream::timedRead() @@ -54,14 +53,30 @@ int Stream::timedPeek() // returns peek of the next digit in the stream or -1 if timeout // discards non-numeric characters -int Stream::peekNextDigit() +int Stream::peekNextDigit(LookaheadMode lookahead, bool detectDecimal) { int c; while (1) { c = timedPeek(); - if (c < 0) return c; // timeout - if (c == '-') return c; - if (c >= '0' && c <= '9') return c; + + if( c < 0 || + c == '-' || + (c >= '0' && c <= '9') || + (detectDecimal && c == '.')) return c; + + switch( lookahead ){ + case SKIP_NONE: return -1; // Fail code. + case SKIP_WHITESPACE: + switch( c ){ + case ' ': + case '\t': + case '\r': + case '\n': break; + default: return -1; // Fail code. + } + case SKIP_ALL: + break; + } read(); // discard non-numeric } } @@ -107,31 +122,25 @@ bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t } } - // returns the first valid (long) integer value from the current position. -// initial characters that are not digits (or the minus sign) are skipped -// function is terminated by the first character that is not a digit. -long Stream::parseInt() -{ - return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout) -} - -// as above but a given skipChar is ignored -// this allows format characters (typically commas) in values to be ignored -long Stream::parseInt(char skipChar) +// lookahead determines how parseInt looks ahead in the stream. +// See LookaheadMode enumeration at the top of the file. +// Lookahead is terminated by the first character that is not a valid part of an integer. +// Once parsing commences, 'ignore' will be skipped in the stream. +long Stream::parseInt(LookaheadMode lookahead, char ignore) { bool isNegative = false; long value = 0; int c; - c = peekNextDigit(); + c = peekNextDigit(lookahead, false); // ignore non numeric leading characters if(c < 0) return 0; // zero returned if timeout do{ - if(c == skipChar) - ; // ignore this charactor + if(c == ignore) + ; // ignore this character else if(c == '-') isNegative = true; else if(c >= '0' && c <= '9') // is c a digit? @@ -139,36 +148,29 @@ long Stream::parseInt(char skipChar) read(); // consume the character we got with peek c = timedPeek(); } - while( (c >= '0' && c <= '9') || c == skipChar ); + while( (c >= '0' && c <= '9') || c == ignore ); if(isNegative) value = -value; return value; } - // as parseInt but returns a floating point value -float Stream::parseFloat() +float Stream::parseFloat(LookaheadMode lookahead, char ignore) { - return parseFloat(NO_SKIP_CHAR); -} - -// as above but the given skipChar is ignored -// this allows format characters (typically commas) in values to be ignored -float Stream::parseFloat(char skipChar){ bool isNegative = false; bool isFraction = false; long value = 0; - char c; + int c; float fraction = 1.0; - c = peekNextDigit(); + c = peekNextDigit(lookahead, true); // ignore non numeric leading characters if(c < 0) return 0; // zero returned if timeout do{ - if(c == skipChar) + if(c == ignore) ; // ignore else if(c == '-') isNegative = true; @@ -182,7 +184,7 @@ float Stream::parseFloat(char skipChar){ read(); // consume the character we got with peek c = timedPeek(); } - while( (c >= '0' && c <= '9') || c == '.' || c == skipChar ); + while( (c >= '0' && c <= '9') || (c == '.' && !isFraction) || c == ignore ); if(isNegative) value = -value; diff --git a/cores/arduino/Stream.h b/cores/arduino/Stream.h index 15f6761..db71bb6 100644 --- a/cores/arduino/Stream.h +++ b/cores/arduino/Stream.h @@ -28,13 +28,24 @@ // compatability macros for testing /* #define getInt() parseInt() -#define getInt(skipChar) parseInt(skipchar) +#define getInt(ignore) parseInt(ignore) #define getFloat() parseFloat() -#define getFloat(skipChar) parseFloat(skipChar) +#define getFloat(ignore) parseFloat(ignore) #define getString( pre_string, post_string, buffer, length) readBytesBetween( pre_string, terminator, buffer, length) */ +// This enumeration provides the lookahead options for parseInt(), parseFloat() +// The rules set out here are used until either the first valid character is found +// or a time out occurs due to lack of input. +enum LookaheadMode{ + SKIP_ALL, // All invalid characters are ignored. + SKIP_NONE, // Nothing is skipped, and the stream is not touched unless the first waiting character is valid. + SKIP_WHITESPACE // Only tabs, spaces, line feeds & carriage returns are skipped. +}; + +#define NO_IGNORE_CHAR '\x01' // a char not found in a valid ASCII numeric field + class Stream : public Print { protected: @@ -42,7 +53,7 @@ class Stream : public Print unsigned long _startMillis; // used for timeout measurement int timedRead(); // private method to read stream with timeout int timedPeek(); // private method to peek stream with timeout - int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout + int peekNextDigit(LookaheadMode lookahead, bool detectDecimal); // returns the next numeric digit in the stream or -1 if timeout public: virtual int available() = 0; @@ -72,12 +83,15 @@ class Stream : public Print bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); // as above but search ends if the terminate string is found bool findUntil(uint8_t *target, size_t targetLen, char *terminate, size_t termLen) {return findUntil((char *)target, targetLen, terminate, termLen); } + long parseInt(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR); + // returns the first valid (long) integer value from the current position. + // lookahead determines how parseInt looks ahead in the stream. + // See LookaheadMode enumeration at the top of the file. + // Lookahead is terminated by the first character that is not a valid part of an integer. + // Once parsing commences, 'ignore' will be skipped in the stream. - long parseInt(); // returns the first valid (long) integer value from the current position. - // initial characters that are not digits (or the minus sign) are skipped - // integer is terminated by the first character that is not a digit. - - float parseFloat(); // float version of parseInt + float parseFloat(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR); + // float version of parseInt size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); } @@ -94,11 +108,11 @@ class Stream : public Print String readStringUntil(char terminator); protected: - long parseInt(char skipChar); // as above but the given skipChar is ignored - // as above but the given skipChar is ignored - // this allows format characters (typically commas) in values to be ignored - - float parseFloat(char skipChar); // as above but the given skipChar is ignored + long parseInt(char ignore) { return parseInt(SKIP_ALL, ignore); } + float parseFloat(char ignore) { return parseFloat(SKIP_ALL, ignore); } + // These overload exists for compatibility with any class that has derived + // Stream and used parseFloat/Int with a custom ignore character. To keep + // the public API simple, these overload remains protected. struct MultiTarget { const char *str; // string you're searching for @@ -111,5 +125,5 @@ class Stream : public Print int findMulti(struct MultiTarget *targets, int tCount); }; - +#undef NO_IGNORE_CHAR #endif diff --git a/cores/arduino/Tone.cpp b/cores/arduino/Tone.cpp index 7216219..1bfb3e3 100644 --- a/cores/arduino/Tone.cpp +++ b/cores/arduino/Tone.cpp @@ -209,7 +209,7 @@ static int8_t toneBegin(uint8_t _pin) #if defined(WGM42) bitWrite(TCCR4B, WGM42, 1); #elif defined(CS43) - #warning this may not be correct + // TODO this may not be correct // atmega32u4 bitWrite(TCCR4B, CS43, 1); #endif @@ -485,6 +485,7 @@ void noTone(uint8_t _pin) if (tone_pins[i] == _pin) { _timer = pgm_read_byte(tone_pin_to_timer_PGM + i); tone_pins[i] = 255; + break; } } diff --git a/cores/arduino/USBAPI.h b/cores/arduino/USBAPI.h index 5837b3e..358444e 100644 --- a/cores/arduino/USBAPI.h +++ b/cores/arduino/USBAPI.h @@ -32,6 +32,12 @@ typedef unsigned long u32; #include "Arduino.h" +// This definitions is usefull if you want to reduce the EP_SIZE to 16 +// at the moment only 64 and 16 as EP_SIZE for all EPs are supported except the control endpoint +#ifndef USB_EP_SIZE +#define USB_EP_SIZE 64 +#endif + #if defined(USBCON) #include "USBDesc.h" @@ -41,6 +47,14 @@ typedef unsigned long u32; //================================================================================ // USB +#define EP_TYPE_CONTROL (0x00) +#define EP_TYPE_BULK_IN ((1<<EPTYPE1) | (1<<EPDIR)) +#define EP_TYPE_BULK_OUT (1<<EPTYPE1) +#define EP_TYPE_INTERRUPT_IN ((1<<EPTYPE1) | (1<<EPTYPE0) | (1<<EPDIR)) +#define EP_TYPE_INTERRUPT_OUT ((1<<EPTYPE1) | (1<<EPTYPE0)) +#define EP_TYPE_ISOCHRONOUS_IN ((1<<EPTYPE0) | (1<<EPDIR)) +#define EP_TYPE_ISOCHRONOUS_OUT (1<<EPTYPE0) + class USBDevice_ { public: @@ -50,6 +64,7 @@ public: void attach(); void detach(); // Serial port goes down too... void poll(); + bool wakeupHost(); // returns false, when wakeup cannot be processed }; extern USBDevice_ USBDevice; @@ -60,7 +75,7 @@ extern USBDevice_ USBDevice; struct ring_buffer; #ifndef SERIAL_BUFFER_SIZE -#if (RAMEND < 1000) +#if ((RAMEND - RAMSTART) < 1023) #define SERIAL_BUFFER_SIZE 16 #else #define SERIAL_BUFFER_SIZE 64 @@ -83,6 +98,7 @@ public: virtual int available(void); virtual int peek(void); virtual int read(void); + int availableForWrite(void); virtual void flush(void); virtual size_t write(uint8_t); virtual size_t write(const uint8_t*, size_t); @@ -92,105 +108,54 @@ public: volatile uint8_t _rx_buffer_head; volatile uint8_t _rx_buffer_tail; unsigned char _rx_buffer[SERIAL_BUFFER_SIZE]; -}; -extern Serial_ Serial; -#define HAVE_CDCSERIAL + // This method allows processing "SEND_BREAK" requests sent by + // the USB host. Those requests indicate that the host wants to + // send a BREAK signal and are accompanied by a single uint16_t + // value, specifying the duration of the break. The value 0 + // means to end any current break, while the value 0xffff means + // to start an indefinite break. + // readBreak() will return the value of the most recent break + // request, but will return it at most once, returning -1 when + // readBreak() is called again (until another break request is + // received, which is again returned once). + // This also mean that if two break requests are received + // without readBreak() being called in between, the value of the + // first request is lost. + // Note that the value returned is a long, so it can return + // 0-0xffff as well as -1. + int32_t readBreak(); + + // These return the settings specified by the USB host for the + // serial port. These aren't really used, but are offered here + // in case a sketch wants to act on these settings. + uint32_t baud(); + uint8_t stopbits(); + uint8_t paritytype(); + uint8_t numbits(); + bool dtr(); + bool rts(); + enum { + ONE_STOP_BIT = 0, + ONE_AND_HALF_STOP_BIT = 1, + TWO_STOP_BITS = 2, + }; + enum { + NO_PARITY = 0, + ODD_PARITY = 1, + EVEN_PARITY = 2, + MARK_PARITY = 3, + SPACE_PARITY = 4, + }; -//================================================================================ -//================================================================================ -// 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_LEFT); // check LEFT 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; +extern Serial_ Serial; -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; +#define HAVE_CDCSERIAL //================================================================================ //================================================================================ -// Low level API +// Low level API typedef struct { @@ -200,16 +165,7 @@ typedef struct 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, int len); +} USBSetup; //================================================================================ //================================================================================ @@ -217,7 +173,7 @@ void HID_SendReport(uint8_t id, const void* data, int len); int MSC_GetInterface(uint8_t* interfaceNum); int MSC_GetDescriptor(int i); -bool MSC_Setup(Setup& setup); +bool MSC_Setup(USBSetup& setup); bool MSC_Data(uint8_t rx,uint8_t tx); //================================================================================ @@ -226,7 +182,7 @@ bool MSC_Data(uint8_t rx,uint8_t tx); int CDC_GetInterface(uint8_t* interfaceNum); int CDC_GetDescriptor(int i); -bool CDC_Setup(Setup& setup); +bool CDC_Setup(USBSetup& setup); //================================================================================ //================================================================================ @@ -237,8 +193,10 @@ bool CDC_Setup(Setup& setup); int USB_SendControl(uint8_t flags, const void* d, int len); int USB_RecvControl(void* d, int len); +int USB_RecvControlLong(void* d, int len); uint8_t USB_Available(uint8_t ep); +uint8_t USB_SendSpace(uint8_t ep); int USB_Send(uint8_t ep, const void* data, int len); // blocking int USB_Recv(uint8_t ep, void* data, int len); // non-blocking int USB_Recv(uint8_t ep); // non-blocking diff --git a/cores/arduino/USBCore.cpp b/cores/arduino/USBCore.cpp index b4f7bed..62b90ed 100644 --- a/cores/arduino/USBCore.cpp +++ b/cores/arduino/USBCore.cpp @@ -17,17 +17,11 @@ */ #include "USBAPI.h" +#include "PluggableUSB.h" +#include <stdlib.h> #if defined(USBCON) -#define EP_TYPE_CONTROL 0x00 -#define EP_TYPE_BULK_IN 0x81 -#define EP_TYPE_BULK_OUT 0x80 -#define EP_TYPE_INTERRUPT_IN 0xC1 -#define EP_TYPE_INTERRUPT_OUT 0xC0 -#define EP_TYPE_ISOCHRONOUS_IN 0x41 -#define EP_TYPE_ISOCHRONOUS_OUT 0x40 - /** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */ #define TX_RX_LED_PULSE_MS 100 volatile u8 TxLEDPulse; /**< Milliseconds remaining for data Tx LED pulse */ @@ -40,7 +34,7 @@ extern const u16 STRING_LANGUAGE[] PROGMEM; extern const u8 STRING_PRODUCT[] PROGMEM; extern const u8 STRING_MANUFACTURER[] PROGMEM; extern const DeviceDescriptor USB_DeviceDescriptor PROGMEM; -extern const DeviceDescriptor USB_DeviceDescriptorA PROGMEM; +extern const DeviceDescriptor USB_DeviceDescriptorB PROGMEM; const u16 STRING_LANGUAGE[2] = { (3<<8) | (2+2), @@ -72,23 +66,21 @@ const u8 STRING_PRODUCT[] PROGMEM = USB_PRODUCT; const u8 STRING_MANUFACTURER[] PROGMEM = 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); + D_DEVICE(0x00,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,ISERIAL,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,ISERIAL,1); //================================================================== //================================================================== volatile u8 _usbConfiguration = 0; +volatile u8 _usbCurrentStatus = 0; // meaning of bits see usb_20.pdf, Figure 9-4. Information Returned by a GetStatus() Request to a Device +volatile u8 _usbSuspendState = 0; // copy of UDINT to check SUSPI and WAKEUPI bits static inline void WaitIN(void) { @@ -119,7 +111,7 @@ static inline void ClearOUT(void) UEINTX = ~(1<<RXOUTI); } -void Recv(volatile u8* data, u8 count) +static inline void Recv(volatile u8* data, u8 count) { while (count--) *data++ = UEDATX; @@ -262,7 +254,7 @@ u8 USB_SendSpace(u8 ep) LockEP lock(ep); if (!ReadWriteAllowed()) return 0; - return 64 - FifoByteCount(); + return USB_EP_SIZE - FifoByteCount(); } // Blocking Send of data to an endpoint @@ -317,30 +309,26 @@ int USB_Send(u8 ep, const void* d, int len) return r; } -extern const u8 _initEndpoints[] PROGMEM; -const u8 _initEndpoints[] = +u8 _initEndpoints[USB_ENDPOINTS] = { - 0, + 0, // Control Endpoint -#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 + EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM + EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT + EP_TYPE_BULK_IN, // CDC_ENDPOINT_IN -#ifdef HID_ENABLED - EP_TYPE_INTERRUPT_IN // HID_ENDPOINT_INT -#endif + // Following endpoints are automatically initialized to 0 }; #define EP_SINGLE_64 0x32 // EP0 #define EP_DOUBLE_64 0x36 // Other endpoints +#define EP_SINGLE_16 0x12 static void InitEP(u8 index, u8 type, u8 size) { UENUM = index; - UECONX = 1; + UECONX = (1<<EPEN); UECFG0X = type; UECFG1X = size; } @@ -348,12 +336,18 @@ void InitEP(u8 index, u8 type, u8 size) static void InitEndpoints() { - for (u8 i = 1; i < sizeof(_initEndpoints); i++) + for (u8 i = 1; i < sizeof(_initEndpoints) && _initEndpoints[i] != 0; i++) { UENUM = i; - UECONX = 1; - UECFG0X = pgm_read_byte(_initEndpoints+i); + UECONX = (1<<EPEN); + UECFG0X = _initEndpoints[i]; +#if USB_EP_SIZE == 16 + UECFG1X = EP_SINGLE_16; +#elif USB_EP_SIZE == 64 UECFG1X = EP_DOUBLE_64; +#else +#error Unsupported value for USB_EP_SIZE +#endif } UERST = 0x7E; // And reset them UERST = 0; @@ -361,24 +355,21 @@ void InitEndpoints() // Handle CLASS_INTERFACE requests static -bool ClassInterfaceRequest(Setup& setup) +bool ClassInterfaceRequest(USBSetup& setup) { u8 i = setup.wIndex; -#ifdef CDC_ENABLED if (CDC_ACM_INTERFACE == i) return CDC_Setup(setup); -#endif -#ifdef HID_ENABLED - if (HID_INTERFACE == i) - return HID_Setup(setup); +#ifdef PLUGGABLE_USB_ENABLED + return PluggableUSB().setup(setup); #endif return false; } -int _cmark; -int _cend; +static int _cmark; +static int _cend; void InitControl(int end) { SetEP(0); @@ -419,11 +410,12 @@ int USB_SendControl(u8 flags, const void* d, int len) // Send a USB descriptor string. The string is stored in PROGMEM as a // plain ASCII string but is sent out as UTF-16 with the correct 2-byte // prefix -static bool USB_SendStringDescriptor(const u8*string_P, u8 string_len) { +static bool USB_SendStringDescriptor(const u8*string_P, u8 string_len, uint8_t flags) { SendControl(2 + string_len * 2); SendControl(3); + bool pgm = flags & TRANSFER_PGM; for(u8 i = 0; i < string_len; i++) { - bool r = SendControl(pgm_read_byte(&string_P[i])); + bool r = SendControl(pgm ? pgm_read_byte(&string_P[i]) : string_P[i]); r &= SendControl(0); // high byte if(!r) { return false; @@ -433,27 +425,35 @@ static bool USB_SendStringDescriptor(const u8*string_P, u8 string_len) { } // Does not timeout or cross fifo boundaries -// Will only work for transfers <= 64 bytes -// TODO int USB_RecvControl(void* d, int len) { - WaitOUT(); - Recv((u8*)d,len); - ClearOUT(); + auto length = len; + while(length) + { + // Dont receive more than the USB Control EP has to offer + // Use fixed 64 because control EP always have 64 bytes even on 16u2. + auto recvLength = length; + if(recvLength > 64){ + recvLength = 64; + } + + // Write data to fit to the end (not the beginning) of the array + WaitOUT(); + Recv((u8*)d + len - length, recvLength); + ClearOUT(); + length -= recvLength; + } return len; } -int SendInterfaces() +static u8 SendInterfaces() { - int total = 0; u8 interfaces = 0; -#ifdef CDC_ENABLED - total = CDC_GetInterface(&interfaces); -#endif + CDC_GetInterface(&interfaces); -#ifdef HID_ENABLED - total += HID_GetInterface(&interfaces); +#ifdef PLUGGABLE_USB_ENABLED + PluggableUSB().getInterface(&interfaces); #endif return interfaces; @@ -467,7 +467,7 @@ bool SendConfiguration(int maxlen) { // Count and measure interfaces InitControl(0); - int interfaces = SendInterfaces(); + u8 interfaces = SendInterfaces(); ConfigDescriptor config = D_CONFIG(_cmark + sizeof(ConfigDescriptor),interfaces); // Now send them @@ -477,19 +477,22 @@ bool SendConfiguration(int maxlen) return true; } -u8 _cdcComposite = 0; +static u8 _cdcComposite = 0; static -bool SendDescriptor(Setup& setup) +bool SendDescriptor(USBSetup& setup) { + int ret; u8 t = setup.wValueH; if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) return SendConfiguration(setup.wLength); InitControl(setup.wLength); -#ifdef HID_ENABLED - if (HID_REPORT_DESCRIPTOR_TYPE == t) - return HID_GetDescriptor(t); +#ifdef PLUGGABLE_USB_ENABLED + ret = PluggableUSB().getDescriptor(setup); + if (ret != 0) { + return (ret > 0 ? true : false); + } #endif const u8* desc_addr = 0; @@ -497,7 +500,7 @@ bool SendDescriptor(Setup& setup) { if (setup.wLength == 8) _cdcComposite = 1; - desc_addr = _cdcComposite ? (const u8*)&USB_DeviceDescriptorA : (const u8*)&USB_DeviceDescriptor; + desc_addr = _cdcComposite ? (const u8*)&USB_DeviceDescriptorB : (const u8*)&USB_DeviceDescriptor; } else if (USB_STRING_DESCRIPTOR_TYPE == t) { @@ -505,10 +508,17 @@ bool SendDescriptor(Setup& setup) desc_addr = (const u8*)&STRING_LANGUAGE; } else if (setup.wValueL == IPRODUCT) { - return USB_SendStringDescriptor(STRING_PRODUCT, strlen(USB_PRODUCT)); + return USB_SendStringDescriptor(STRING_PRODUCT, strlen(USB_PRODUCT), TRANSFER_PGM); } else if (setup.wValueL == IMANUFACTURER) { - return USB_SendStringDescriptor(STRING_MANUFACTURER, strlen(USB_MANUFACTURER)); + return USB_SendStringDescriptor(STRING_MANUFACTURER, strlen(USB_MANUFACTURER), TRANSFER_PGM); + } + else if (setup.wValueL == ISERIAL) { +#ifdef PLUGGABLE_USB_ENABLED + char name[ISERIAL_MAX_LEN]; + PluggableUSB().getShortName(name); + return USB_SendStringDescriptor((uint8_t*)name, strlen(name), 0); +#endif } else return false; @@ -529,7 +539,7 @@ ISR(USB_COM_vect) if (!ReceivedSetupInt()) return; - Setup setup; + USBSetup setup; Recv((u8*)&setup,8); ClearSetupInt(); @@ -544,16 +554,37 @@ ISR(USB_COM_vect) { // Standard Requests u8 r = setup.bRequest; + u16 wValue = setup.wValueL | (setup.wValueH << 8); if (GET_STATUS == r) { - Send8(0); // TODO - Send8(0); + if (requestType == (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_DEVICE)) + { + Send8(_usbCurrentStatus); + Send8(0); + } + else + { + // TODO: handle the HALT state of an endpoint here + // see "Figure 9-6. Information Returned by a GetStatus() Request to an Endpoint" in usb_20.pdf for more information + Send8(0); + Send8(0); + } } else if (CLEAR_FEATURE == r) { + if((requestType == (REQUEST_HOSTTODEVICE | REQUEST_STANDARD | REQUEST_DEVICE)) + && (wValue == DEVICE_REMOTE_WAKEUP)) + { + _usbCurrentStatus &= ~FEATURE_REMOTE_WAKEUP_ENABLED; + } } else if (SET_FEATURE == r) { + if((requestType == (REQUEST_HOSTTODEVICE | REQUEST_STANDARD | REQUEST_DEVICE)) + && (wValue == DEVICE_REMOTE_WAKEUP)) + { + _usbCurrentStatus |= FEATURE_REMOTE_WAKEUP_ENABLED; + } } else if (SET_ADDRESS == r) { @@ -609,11 +640,97 @@ void USB_Flush(u8 ep) ReleaseTX(); } +static inline void USB_ClockDisable() +{ +#if defined(OTGPADE) + USBCON = (USBCON & ~(1<<OTGPADE)) | (1<<FRZCLK); // freeze clock and disable VBUS Pad +#else // u2 Series + USBCON = (1 << FRZCLK); // freeze clock +#endif + PLLCSR &= ~(1<<PLLE); // stop PLL +} + +static inline void USB_ClockEnable() +{ +#if defined(UHWCON) + UHWCON |= (1<<UVREGE); // power internal reg +#endif + USBCON = (1<<USBE) | (1<<FRZCLK); // clock frozen, usb enabled + +// ATmega32U4 +#if defined(PINDIV) +#if F_CPU == 16000000UL + PLLCSR |= (1<<PINDIV); // Need 16 MHz xtal +#elif F_CPU == 8000000UL + PLLCSR &= ~(1<<PINDIV); // Need 8 MHz xtal +#else +#error "Clock rate of F_CPU not supported" +#endif + +#elif defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__) + // for the u2 Series the datasheet is confusing. On page 40 its called PINDIV and on page 290 its called PLLP0 +#if F_CPU == 16000000UL + // Need 16 MHz xtal + PLLCSR |= (1 << PLLP0); +#elif F_CPU == 8000000UL + // Need 8 MHz xtal + PLLCSR &= ~(1 << PLLP0); +#endif + +// AT90USB646, AT90USB647, AT90USB1286, AT90USB1287 +#elif defined(PLLP2) +#if F_CPU == 16000000UL +#if defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) + // For Atmel AT90USB128x only. Do not use with Atmel AT90USB64x. + PLLCSR = (PLLCSR & ~(1<<PLLP1)) | ((1<<PLLP2) | (1<<PLLP0)); // Need 16 MHz xtal +#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) + // For AT90USB64x only. Do not use with AT90USB128x. + PLLCSR = (PLLCSR & ~(1<<PLLP0)) | ((1<<PLLP2) | (1<<PLLP1)); // Need 16 MHz xtal +#else +#error "USB Chip not supported, please defined method of USB PLL initialization" +#endif +#elif F_CPU == 8000000UL + // for Atmel AT90USB128x and AT90USB64x + PLLCSR = (PLLCSR & ~(1<<PLLP2)) | ((1<<PLLP1) | (1<<PLLP0)); // Need 8 MHz xtal +#else +#error "Clock rate of F_CPU not supported" +#endif +#else +#error "USB Chip not supported, please defined method of USB PLL initialization" +#endif + + PLLCSR |= (1<<PLLE); + while (!(PLLCSR & (1<<PLOCK))) // wait for lock pll + { + } + + // Some tests on specific versions of macosx (10.7.3), reported some + // strange behaviors when the board is reset using the serial + // port touch at 1200 bps. This delay fixes this behavior. + delay(1); +#if defined(OTGPADE) + USBCON = (USBCON & ~(1<<FRZCLK)) | (1<<OTGPADE); // start USB clock, enable VBUS Pad +#else + USBCON &= ~(1 << FRZCLK); // start USB clock +#endif + +#if defined(RSTCPU) +#if defined(LSM) + UDCON &= ~((1<<RSTCPU) | (1<<LSM) | (1<<RMWKUP) | (1<<DETACH)); // enable attach resistor, set full speed mode +#else // u2 Series + UDCON &= ~((1 << RSTCPU) | (1 << RMWKUP) | (1 << DETACH)); // enable attach resistor, set full speed mode +#endif +#else + // AT90USB64x and AT90USB128x don't have RSTCPU + UDCON &= ~((1<<LSM) | (1<<RMWKUP) | (1<<DETACH)); // enable attach resistor, set full speed mode +#endif +} + // General interrupt ISR(USB_GEN_vect) { u8 udint = UDINT; - UDINT = 0; + UDINT = UDINT &= ~((1<<EORSTI) | (1<<SOFI)); // clear the IRQ flags for the IRQs which are handled here, except WAKEUPI and SUSPI (see below) // End of Reset if (udint & (1<<EORSTI)) @@ -626,9 +743,7 @@ ISR(USB_GEN_vect) // Start of Frame - happens every millisecond so we use it for TX and RX LED one-shot timing, too if (udint & (1<<SOFI)) { -#ifdef CDC_ENABLED USB_Flush(CDC_TX); // Send a tx frame if found -#endif // check whether the one-shot period has elapsed. if so, turn off the LED if (TxLEDPulse && !(--TxLEDPulse)) @@ -636,6 +751,30 @@ ISR(USB_GEN_vect) if (RxLEDPulse && !(--RxLEDPulse)) RXLED0; } + + // the WAKEUPI interrupt is triggered as soon as there are non-idle patterns on the data + // lines. Thus, the WAKEUPI interrupt can occur even if the controller is not in the "suspend" mode. + // Therefore the we enable it only when USB is suspended + if (udint & (1<<WAKEUPI)) + { + UDIEN = (UDIEN & ~(1<<WAKEUPE)) | (1<<SUSPE); // Disable interrupts for WAKEUP and enable interrupts for SUSPEND + + //TODO + // WAKEUPI shall be cleared by software (USB clock inputs must be enabled before). + //USB_ClockEnable(); + UDINT &= ~(1<<WAKEUPI); + _usbSuspendState = (_usbSuspendState & ~(1<<SUSPI)) | (1<<WAKEUPI); + } + else if (udint & (1<<SUSPI)) // only one of the WAKEUPI / SUSPI bits can be active at time + { + UDIEN = (UDIEN & ~(1<<SUSPE)) | (1<<WAKEUPE); // Disable interrupts for SUSPEND and enable interrupts for WAKEUP + + //TODO + //USB_ClockDisable(); + + UDINT &= ~((1<<WAKEUPI) | (1<<SUSPI)); // clear any already pending WAKEUP IRQs and the SUSPI request + _usbSuspendState = (_usbSuspendState & ~(1<<WAKEUPI)) | (1<<SUSPI); + } } // VBUS or counting frames @@ -659,24 +798,12 @@ USBDevice_::USBDevice_() void USBDevice_::attach() { _usbConfiguration = 0; - UHWCON = 0x01; // power internal reg - USBCON = (1<<USBE)|(1<<FRZCLK); // clock frozen, usb enabled -#if F_CPU == 16000000UL - PLLCSR = 0x12; // Need 16 MHz xtal -#elif F_CPU == 8000000UL - PLLCSR = 0x02; // Need 8 MHz xtal -#endif - while (!(PLLCSR & (1<<PLOCK))) // wait for lock pll - ; + _usbCurrentStatus = 0; + _usbSuspendState = 0; + USB_ClockEnable(); - // Some tests on specific versions of macosx (10.7.3), reported some - // strange behaviuors when the board is reset using the serial - // port touch at 1200 bps. This delay fixes this behaviour. - delay(1); - - USBCON = ((1<<USBE)|(1<<OTGPADE)); // start USB clock - UDIEN = (1<<EORSTE)|(1<<SOFE); // Enable interrupts for EOR (End of Reset) and SOF (start of frame) - UDCON = 0; // enable attach resistor + UDINT &= ~((1<<WAKEUPI) | (1<<SUSPI)); // clear already pending WAKEUP / SUSPEND requests + UDIEN = (1<<EORSTE) | (1<<SOFE) | (1<<SUSPE); // Enable interrupts for EOR (End of Reset), SOF (start of frame) and SUSPEND TX_RX_LED_INIT; } @@ -696,4 +823,24 @@ void USBDevice_::poll() { } +bool USBDevice_::wakeupHost() +{ + // clear any previous wakeup request which might have been set but could be processed at that time + // e.g. because the host was not suspended at that time + UDCON &= ~(1 << RMWKUP); + + if(!(UDCON & (1 << RMWKUP)) + && (_usbSuspendState & (1<<SUSPI)) + && (_usbCurrentStatus & FEATURE_REMOTE_WAKEUP_ENABLED)) + { + // This short version will only work, when the device has not been suspended. Currently the + // Arduino core doesn't handle SUSPEND at all, so this is ok. + USB_ClockEnable(); + UDCON |= (1 << RMWKUP); // send the wakeup request + return true; + } + + return false; +} + #endif /* if defined(USBCON) */ diff --git a/cores/arduino/USBCore.h b/cores/arduino/USBCore.h index 8d13806..4e08d71 100644 --- a/cores/arduino/USBCore.h +++ b/cores/arduino/USBCore.h @@ -18,6 +18,8 @@ #ifndef __USBCORE_H__ #define __USBCORE_H__ +#include "USBAPI.h" + // Standard requests #define GET_STATUS 0 #define CLEAR_FEATURE 1 @@ -47,25 +49,20 @@ #define REQUEST_OTHER 0x03 #define REQUEST_RECIPIENT 0x03 -#define REQUEST_DEVICETOHOST_CLASS_INTERFACE (REQUEST_DEVICETOHOST + REQUEST_CLASS + REQUEST_INTERFACE) -#define REQUEST_HOSTTODEVICE_CLASS_INTERFACE (REQUEST_HOSTTODEVICE + REQUEST_CLASS + REQUEST_INTERFACE) +#define REQUEST_DEVICETOHOST_CLASS_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_CLASS | REQUEST_INTERFACE) +#define REQUEST_HOSTTODEVICE_CLASS_INTERFACE (REQUEST_HOSTTODEVICE | REQUEST_CLASS | REQUEST_INTERFACE) +#define REQUEST_DEVICETOHOST_STANDARD_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_INTERFACE) // Class requests #define CDC_SET_LINE_CODING 0x20 #define CDC_GET_LINE_CODING 0x21 #define CDC_SET_CONTROL_LINE_STATE 0x22 +#define CDC_SEND_BREAK 0x23 #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 @@ -79,6 +76,15 @@ #define USB_INTERFACE_DESCRIPTOR_TYPE 4 #define USB_ENDPOINT_DESCRIPTOR_TYPE 5 +// usb_20.pdf Table 9.6 Standard Feature Selectors +#define DEVICE_REMOTE_WAKEUP 1 +#define ENDPOINT_HALT 2 +#define TEST_MODE 3 + +// usb_20.pdf Figure 9-4. Information Returned by a GetStatus() Request to a Device +#define FEATURE_SELFPOWERED_ENABLED (1 << 0) +#define FEATURE_REMOTE_WAKEUP_ENABLED (1 << 1) + #define USB_DEVICE_CLASS_COMMUNICATIONS 0x02 #define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03 #define USB_DEVICE_CLASS_STORAGE 0x08 @@ -94,8 +100,8 @@ // 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_OUT(addr) (lowByte((addr) | 0x00)) +#define USB_ENDPOINT_IN(addr) (lowByte((addr) | 0x80)) #define USB_ENDPOINT_TYPE_MASK 0x03 #define USB_ENDPOINT_TYPE_CONTROL 0x00 @@ -120,11 +126,6 @@ #define MSC_SUBCLASS_SCSI 0x06 #define MSC_PROTOCOL_BULK_ONLY 0x50 -#define HID_HID_DESCRIPTOR_TYPE 0x21 -#define HID_REPORT_DESCRIPTOR_TYPE 0x22 -#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23 - - // Device typedef struct { u8 len; // 18 @@ -257,32 +258,12 @@ typedef struct EndpointDescriptor out; } MSCDescriptor; -typedef struct -{ - u8 len; // 9 - u8 dtype; // 0x21 - u8 addr; - u8 versionL; // 0x101 - u8 versionH; // 0x101 - u8 country; - u8 desctype; // 0x22 report - u8 descLenL; - u8 descLenH; -} HIDDescDescriptor; - -typedef struct -{ - InterfaceDescriptor hid; - HIDDescDescriptor desc; - EndpointDescriptor in; -} HIDDescriptor; - #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_BUS_POWERED, USB_CONFIG_POWER_MA(500) } + { 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED | USB_CONFIG_REMOTE_WAKEUP, USB_CONFIG_POWER_MA(500) } #define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \ { 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 } @@ -293,11 +274,8 @@ typedef struct #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
\ No newline at end of file +#endif diff --git a/cores/arduino/USBDesc.h b/cores/arduino/USBDesc.h index 900713e..c0dce07 100644 --- a/cores/arduino/USBDesc.h +++ b/cores/arduino/USBDesc.h @@ -1,40 +1,33 @@ +/* + Copyright (c) 2011, Peter Barrett + Copyright (c) 2015, Arduino LLC + + 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. + */ + +#define PLUGGABLE_USB_ENABLED + +#if defined(EPRST6) +#define USB_ENDPOINTS 7 // AtMegaxxU4 +#else +#define USB_ENDPOINTS 5 // AtMegaxxU2 +#endif +#define ISERIAL_MAX_LEN 20 -/* 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. -*/ - -#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 @@ -43,21 +36,11 @@ #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 +#define IMANUFACTURER 1 +#define IPRODUCT 2 +#define ISERIAL 3
\ No newline at end of file diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index 71dd45c..7e9f717 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -32,7 +32,39 @@ #include "wiring_private.h" -static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS]; +static void nothing(void) { +} + +static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = { +#if EXTERNAL_NUM_INTERRUPTS > 8 + #warning There are more than 8 external interrupts. Some callbacks may not be initialized. + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 7 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 6 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 5 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 4 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 3 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 2 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 1 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 0 + nothing, +#endif +}; // volatile static voidFuncPtr twiIntFunc; void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) { @@ -238,7 +270,7 @@ void detachInterrupt(uint8_t interruptNum) { #endif } - intFunc[interruptNum] = 0; + intFunc[interruptNum] = nothing; } } @@ -250,87 +282,71 @@ void attachInterruptTwi(void (*userFunc)(void) ) { #if defined(__AVR_ATmega32U4__) ISR(INT0_vect) { - if(intFunc[EXTERNAL_INT_0]) - intFunc[EXTERNAL_INT_0](); + intFunc[EXTERNAL_INT_0](); } ISR(INT1_vect) { - if(intFunc[EXTERNAL_INT_1]) - intFunc[EXTERNAL_INT_1](); + intFunc[EXTERNAL_INT_1](); } ISR(INT2_vect) { - if(intFunc[EXTERNAL_INT_2]) - intFunc[EXTERNAL_INT_2](); + intFunc[EXTERNAL_INT_2](); } ISR(INT3_vect) { - if(intFunc[EXTERNAL_INT_3]) - intFunc[EXTERNAL_INT_3](); + intFunc[EXTERNAL_INT_3](); } ISR(INT6_vect) { - if(intFunc[EXTERNAL_INT_4]) - intFunc[EXTERNAL_INT_4](); + intFunc[EXTERNAL_INT_4](); } #elif defined(EICRA) && defined(EICRB) ISR(INT0_vect) { - if(intFunc[EXTERNAL_INT_2]) intFunc[EXTERNAL_INT_2](); } ISR(INT1_vect) { - if(intFunc[EXTERNAL_INT_3]) intFunc[EXTERNAL_INT_3](); } ISR(INT2_vect) { - if(intFunc[EXTERNAL_INT_4]) intFunc[EXTERNAL_INT_4](); } ISR(INT3_vect) { - if(intFunc[EXTERNAL_INT_5]) intFunc[EXTERNAL_INT_5](); } ISR(INT4_vect) { - if(intFunc[EXTERNAL_INT_0]) intFunc[EXTERNAL_INT_0](); } ISR(INT5_vect) { - if(intFunc[EXTERNAL_INT_1]) intFunc[EXTERNAL_INT_1](); } ISR(INT6_vect) { - if(intFunc[EXTERNAL_INT_6]) intFunc[EXTERNAL_INT_6](); } ISR(INT7_vect) { - if(intFunc[EXTERNAL_INT_7]) intFunc[EXTERNAL_INT_7](); } #else ISR(INT0_vect) { - if(intFunc[EXTERNAL_INT_0]) intFunc[EXTERNAL_INT_0](); } ISR(INT1_vect) { - if(intFunc[EXTERNAL_INT_1]) intFunc[EXTERNAL_INT_1](); } #if defined(EICRA) && defined(ISC20) ISR(INT2_vect) { - if(intFunc[EXTERNAL_INT_2]) intFunc[EXTERNAL_INT_2](); } #endif diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index dcd469d..cd3e0e8 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -43,7 +43,7 @@ String::String(const __FlashStringHelper *pstr) *this = pstr; } -#ifdef __GXX_EXPERIMENTAL_CXX0X__ +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) String::String(String &&rval) { init(); @@ -189,7 +189,7 @@ String & String::copy(const __FlashStringHelper *pstr, unsigned int length) return *this; } -#ifdef __GXX_EXPERIMENTAL_CXX0X__ +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) void String::move(String &rhs) { if (buffer) { @@ -221,7 +221,7 @@ String & String::operator = (const String &rhs) return *this; } -#ifdef __GXX_EXPERIMENTAL_CXX0X__ +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) String & String::operator = (String &&rval) { if (this != &rval) move(rval); diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index 7402430..b047980 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -59,7 +59,7 @@ public: String(const char *cstr = ""); String(const String &str); String(const __FlashStringHelper *str); - #ifdef __GXX_EXPERIMENTAL_CXX0X__ + #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) String(String &&rval); String(StringSumHelper &&rval); #endif @@ -86,7 +86,7 @@ public: String & operator = (const String &rhs); String & operator = (const char *cstr); String & operator = (const __FlashStringHelper *str); - #ifdef __GXX_EXPERIMENTAL_CXX0X__ + #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) String & operator = (String &&rval); String & operator = (StringSumHelper &&rval); #endif @@ -200,7 +200,7 @@ protected: // copy and move String & copy(const char *cstr, unsigned int length); String & copy(const __FlashStringHelper *pstr, unsigned int length); - #ifdef __GXX_EXPERIMENTAL_CXX0X__ + #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) void move(String &rhs); #endif }; diff --git a/cores/arduino/main.cpp b/cores/arduino/main.cpp index 72074de..434cd40 100644 --- a/cores/arduino/main.cpp +++ b/cores/arduino/main.cpp @@ -27,6 +27,9 @@ int atexit(void (* /*func*/ )()) { return 0; } void initVariant() __attribute__((weak)); void initVariant() { } +void setupUSB() __attribute__((weak)); +void setupUSB() { } + int main(void) { init(); diff --git a/cores/arduino/wiring.c b/cores/arduino/wiring.c index f1a14ef..b956f78 100644 --- a/cores/arduino/wiring.c +++ b/cores/arduino/wiring.c @@ -105,11 +105,11 @@ unsigned long micros() { void delay(unsigned long ms) { - uint16_t start = (uint16_t)micros(); + uint32_t start = micros(); while (ms > 0) { yield(); - if (((uint16_t)micros() - start) >= 1000) { + while ( ms > 0 && (micros() - start) >= 1000) { ms--; start += 1000; } @@ -303,8 +303,6 @@ void init() // put timer 1 in 8-bit phase correct pwm mode #if defined(TCCR1A) && defined(WGM10) sbi(TCCR1A, WGM10); -#elif defined(TCCR1) - #warning this needs to be finished #endif // set timer 2 prescale factor to 64 @@ -312,8 +310,8 @@ void init() sbi(TCCR2, CS22); #elif defined(TCCR2B) && defined(CS22) sbi(TCCR2B, CS22); -#else - #warning Timer 2 not finished (may not be present on this CPU) +//#else + // Timer 2 not finished (may not be present on this CPU) #endif // configure timer 2 for phase correct pwm (8-bit) @@ -321,8 +319,8 @@ void init() sbi(TCCR2, WGM20); #elif defined(TCCR2A) && defined(WGM20) sbi(TCCR2A, WGM20); -#else - #warning Timer 2 not finished (may not be present on this CPU) +//#else + // Timer 2 not finished (may not be present on this CPU) #endif #if defined(TCCR3B) && defined(CS31) && defined(WGM30) diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index 51adb2c..27a62fc 100644 --- a/cores/arduino/wiring_digital.c +++ b/cores/arduino/wiring_digital.c @@ -94,7 +94,7 @@ static void turnOffPWM(uint8_t timer) case TIMER0A: cbi(TCCR0A, COM0A1); break; #endif - #if defined(TIMER0B) && defined(COM0B1) + #if defined(TCCR0A) && defined(COM0B1) case TIMER0B: cbi(TCCR0A, COM0B1); break; #endif #if defined(TCCR2A) && defined(COM2A1) diff --git a/cores/arduino/wiring_private.h b/cores/arduino/wiring_private.h index ed7c8f0..a277b14 100644 --- a/cores/arduino/wiring_private.h +++ b/cores/arduino/wiring_private.h @@ -52,7 +52,8 @@ uint32_t countPulseASM(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, u #define EXTERNAL_INT_6 6 #define EXTERNAL_INT_7 7 -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega128RFA1__) || defined(__AVR_ATmega256RFR2__) +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega128RFA1__) || defined(__AVR_ATmega256RFR2__) || \ + defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__) #define EXTERNAL_NUM_INTERRUPTS 8 #elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) #define EXTERNAL_NUM_INTERRUPTS 3 diff --git a/cores/arduino/wiring_pulse.c b/cores/arduino/wiring_pulse.c index 76383e9..d6e0434 100644 --- a/cores/arduino/wiring_pulse.c +++ b/cores/arduino/wiring_pulse.c @@ -69,25 +69,24 @@ unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout) uint8_t port = digitalPinToPort(pin); uint8_t stateMask = (state ? bit : 0); - // convert the timeout from microseconds to a number of times through - // the initial loop; it takes 16 clock cycles per iteration. - unsigned long numloops = 0; - unsigned long maxloops = microsecondsToClockCycles(timeout); + unsigned long startMicros = micros(); // wait for any previous pulse to end - while ((*portInputRegister(port) & bit) == stateMask) - if (numloops++ == maxloops) + while ((*portInputRegister(port) & bit) == stateMask) { + if (micros() - startMicros > timeout) return 0; + } // wait for the pulse to start - while ((*portInputRegister(port) & bit) != stateMask) - if (numloops++ == maxloops) + while ((*portInputRegister(port) & bit) != stateMask) { + if (micros() - startMicros > timeout) return 0; + } unsigned long start = micros(); // wait for the pulse to stop while ((*portInputRegister(port) & bit) == stateMask) { - if (numloops++ == maxloops) + if (micros() - startMicros > timeout) return 0; } return micros() - start; |