diff options
Diffstat (limited to 'cores')
-rw-r--r-- | cores/arduino/CDC.cpp | 92 | ||||
-rw-r--r-- | cores/arduino/HID.cpp | 145 | ||||
-rw-r--r-- | cores/arduino/USBAPI.h | 65 | ||||
-rw-r--r-- | cores/arduino/USBCore.cpp | 10 | ||||
-rw-r--r-- | cores/arduino/USBDesc.h | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | cores/arduino/WInterrupts.c | 38 | ||||
-rw-r--r--[-rwxr-xr-x] | cores/arduino/wiring.c | 15 | ||||
-rw-r--r-- | cores/arduino/wiring_analog.c | 18 | ||||
-rw-r--r--[-rwxr-xr-x] | cores/arduino/wiring_digital.c | 8 |
9 files changed, 297 insertions, 96 deletions
diff --git a/cores/arduino/CDC.cpp b/cores/arduino/CDC.cpp index 14a0eae..7206aa6 100644 --- a/cores/arduino/CDC.cpp +++ b/cores/arduino/CDC.cpp @@ -23,12 +23,20 @@ #if defined(USBCON) #ifdef CDC_ENABLED -void Reboot() +#if (RAMEND < 1000) +#define SERIAL_BUFFER_SIZE 16 +#else +#define SERIAL_BUFFER_SIZE 64 +#endif + +struct ring_buffer { - USB.detach(); - cli(); - asm volatile("jmp 0x7800"); // jump to bootloader - DiskLoader takes up last 2 kB -} + unsigned char buffer[SERIAL_BUFFER_SIZE]; + volatile int head; + volatile int tail; +}; + +ring_buffer cdc_rx_buffer = { { 0 }, 0, 0}; typedef struct { @@ -92,9 +100,29 @@ bool WEAK CDC_Setup(Setup& setup) if (CDC_SET_CONTROL_LINE_STATE == r) { - if (0 != _usbLineInfo.lineState && 1200 == _usbLineInfo.dwDTERate) // auto-reset is triggered when the port, already open at 1200 bps, is closed - Reboot(); _usbLineInfo.lineState = setup.wValueL; + + // auto-reset into the bootloader is triggered when the port, already + // open at 1200 bps, is closed. this is the signal to start the watchdog + // with a relatively long period so it can finish housekeeping tasks + // like servicing endpoints before the sketch ends + if (1200 == _usbLineInfo.dwDTERate) { + // We check DTR state to determine if host port is open (bit 0 of lineState). + // Serial1.print(">"); Serial1.println(_usbLineInfo.lineState, HEX); + if ((_usbLineInfo.lineState & 0x01) == 0) { + *(uint16_t *)0x0A00 = 0x7777; + wdt_enable(WDTO_120MS); + } else { + // Most OSs do some intermediate steps when configuring ports and DTR can + // twiggle more than once before stabilizing. + // To avoid spurious resets we set the watchdog to 250ms and eventually + // cancel if DTR goes back high. + + wdt_disable(); + wdt_reset(); + *(uint16_t *)0x0A00 = 0x0; + } + } return true; } } @@ -111,33 +139,49 @@ void Serial_::end(void) { } +void Serial_::accept(void) +{ + ring_buffer *buffer = &cdc_rx_buffer; + int c = USB_Recv(CDC_RX); + int i = (unsigned int)(buffer->head+1) % 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. + if (i != buffer->tail) { + buffer->buffer[buffer->head] = c; + buffer->head = i; + } +} + int Serial_::available(void) { - u8 avail = USB_Available(CDC_RX); - if (_serialPeek != -1) - avail++; - return avail; + ring_buffer *buffer = &cdc_rx_buffer; + return (unsigned int)(SERIAL_BUFFER_SIZE + buffer->head - buffer->tail) % SERIAL_BUFFER_SIZE; } -// peek is nasty int Serial_::peek(void) { - if (_serialPeek == -1) - _serialPeek = read(); - return _serialPeek; + ring_buffer *buffer = &cdc_rx_buffer; + if (buffer->head == buffer->tail) { + return -1; + } else { + return buffer->buffer[buffer->tail]; + } } int Serial_::read(void) { - int c; - if (_serialPeek != -1) - { - c = _serialPeek; - _serialPeek = -1; + 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 { - c = USB_Recv(CDC_RX); - } - return c; + unsigned char c = buffer->buffer[buffer->tail]; + buffer->tail = (unsigned int)(buffer->tail + 1) % SERIAL_BUFFER_SIZE; + return c; + } } void Serial_::flush(void) @@ -172,4 +216,4 @@ size_t Serial_::write(uint8_t c) Serial_ Serial; #endif -#endif /* if defined(USBCON) */
\ No newline at end of file +#endif /* if defined(USBCON) */ diff --git a/cores/arduino/HID.cpp b/cores/arduino/HID.cpp index 8ed1566..378a157 100644 --- a/cores/arduino/HID.cpp +++ b/cores/arduino/HID.cpp @@ -144,7 +144,6 @@ u8 _hid_protocol = 1; u8 _hid_idle = 1; #define WEAK __attribute__ ((weak)) -#define WEAK int WEAK HID_GetInterface(u8* interfaceNum) { @@ -245,7 +244,7 @@ void Mouse_::release(uint8_t b) bool Mouse_::isPressed(uint8_t b) { - if (b & _buttons > 0) + if ((b & _buttons) > 0) return true; return false; } @@ -254,7 +253,7 @@ bool Mouse_::isPressed(uint8_t b) //================================================================================ // Keyboard -Keyboard_::Keyboard_() : _keyMap(0) +Keyboard_::Keyboard_() { } @@ -263,11 +262,6 @@ void Keyboard_::sendReport(KeyReport* keys) HID_SendReport(2,keys,sizeof(KeyReport)); } -void Keyboard_::setKeyMap(KeyMap* keyMap) -{ - _keyMap = keyMap; -} - extern const uint8_t _asciimap[128] PROGMEM; @@ -406,38 +400,119 @@ const uint8_t _asciimap[128] = }; uint8_t USBPutChar(uint8_t c); -size_t Keyboard_::write(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) { - // Keydown - { - KeyReport keys = {0}; - if (_keyMap) - _keyMap->charToKey(c,&keys); - else - { - if (c >= 128) { - setWriteError(); - return 0; - } - c = pgm_read_byte(_asciimap + c); - if (!c) { - setWriteError(); - return 0; - } - if (c & 0x80) - { - keys.modifiers |= KEY_MODIFIER_LEFT_SHIFT; - c &= 0x7F; + 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) { + _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; } - keys.keys[0] = c; } - sendReport(&keys); + if (i == 6) { + setWriteError(); + return 0; + } } - // Keyup - { - KeyReport keys = {0}; - sendReport(&keys); + 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; + k = pgm_read_byte(_asciimap + k); + if (!k) { + return 0; + } + if (k & 0x80) { + _keyReport.modifiers |= 0x02; // the left shift modifier + k &= 0x7F; + } + */ + 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) { + _keyReport.modifiers &= ~(0x02); // the left shift modifier + k &= 0x7F; + } + } + + // Test the key report to see if k is present. Clear it if it exists. + for (i=0; i<6; i++) { + if (_keyReport.keys[i] == k) { + _keyReport.keys[i] = 0x00; + break; + } + } + if (i == 6) { + return 0; } + 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); +} + +// type() does a press and release of the specified key. +size_t Keyboard_::type(uint8_t c) +{ + releaseAll(); + // Keydown + press(c); + // Keyup + releaseAll(); return 1; } diff --git a/cores/arduino/USBAPI.h b/cores/arduino/USBAPI.h index 26a2032..05f7318 100644 --- a/cores/arduino/USBAPI.h +++ b/cores/arduino/USBAPI.h @@ -27,11 +27,14 @@ extern USB_ USB; class Serial_ : public Stream { +private: + ring_buffer *_cdc_rx_buffer; public: void begin(uint16_t baud_count); void end(void); virtual int available(void); + virtual void accept(void); virtual int peek(void); virtual int read(void); virtual void flush(void); @@ -67,14 +70,42 @@ extern Mouse_ Mouse; //================================================================================ // Keyboard -#define KEY_MODIFIER_LEFT_CTRL 0x01 -#define KEY_MODIFIER_LEFT_SHIFT 0x02 -#define KEY_MODIFIER_LEFT_ALT 0x04 -#define KEY_MODIFIER_LEFT_GUI 0x08 -#define KEY_MODIFIER_RIGHT_CTRL 0x010 -#define KEY_MODIFIER_RIGHT_SHIFT 0x020 -#define KEY_MODIFIER_RIGHT_ALT 0x040 -#define KEY_MODIFIER_RIGHT_GUI 0x080 +#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 @@ -84,24 +115,18 @@ typedef struct uint8_t keys[6]; } KeyReport; -// Map a character into a key report -// Called from Print to map text to keycodes -class KeyMap -{ -public: - virtual void charToKey(int c, KeyReport* keyReport) = 0; -}; - -// class Keyboard_ : public Print { private: - KeyMap* _keyMap; + KeyReport _keyReport; void sendReport(KeyReport* keys); - void setKeyMap(KeyMap* keyMap); public: Keyboard_(); - virtual size_t write(uint8_t); + virtual size_t write(uint8_t k) {return type(k);}; + virtual size_t type(uint8_t k); + virtual size_t press(uint8_t k); + virtual size_t release(uint8_t k); + virtual void releaseAll(void); }; extern Keyboard_ Keyboard; diff --git a/cores/arduino/USBCore.cpp b/cores/arduino/USBCore.cpp index 398bc73..c360d26 100644 --- a/cores/arduino/USBCore.cpp +++ b/cores/arduino/USBCore.cpp @@ -599,6 +599,8 @@ ISR(USB_GEN_vect) { #ifdef CDC_ENABLED USB_Flush(CDC_TX); // Send a tx frame if found + while (USB_Available(CDC_RX)) // Handle received bytes (if any) + Serial.accept(); #endif // check whether the one-shot period has elapsed. if so, turn off the LED @@ -635,6 +637,12 @@ void USB_::attach() PLLCSR = 0x12; // Need 16 MHz xtal while (!(PLLCSR & (1<<PLOCK))) // wait for lock pll ; + + // 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 @@ -657,4 +665,4 @@ void USB_::poll() { } -#endif /* if defined(USBCON) */
\ No newline at end of file +#endif /* if defined(USBCON) */ diff --git a/cores/arduino/USBDesc.h b/cores/arduino/USBDesc.h index 549ed9e..5cd90ad 100644 --- a/cores/arduino/USBDesc.h +++ b/cores/arduino/USBDesc.h @@ -60,7 +60,7 @@ #define IMANUFACTURER 1 #define IPRODUCT 2 -#define USB_PID_LEONARDO 0x0034 +#define USB_PID_LEONARDO 0x0801 #define USB_PID_MICRO 0x0035 #define USB_VID 0x2341 // arduino LLC vid #define USB_PID ARDUINO_MODEL_USB_PID diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index 3b9fe08..8f3ec84 100755..100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -47,7 +47,19 @@ void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) { // Enable the interrupt. switch (interruptNum) { -#if defined(EICRA) && defined(EICRB) && defined(EIMSK) +#if defined(__AVR_ATmega32U4__) + // I hate doing this, but the register assignment differs between the 1280/2560 + // and the 32U4. Since avrlib defines registers PCMSK1 and PCMSK2 that aren't + // even present on the 32U4 this is the only way to distinguish between them. + case 0: + EICRA = (EICRA & ~((1<<ISC00) | (1<<ISC01))) | (mode << ISC00); + EIMSK |= (1<<INT0); + break; + case 1: + EICRA = (EICRA & ~((1<<ISC10) | (1<<ISC11))) | (mode << ISC10); + EIMSK |= (1<<INT1); + break; +#elif defined(EICRA) && defined(EICRB) && defined(EIMSK) case 2: EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00); EIMSK |= (1 << INT0); @@ -80,7 +92,7 @@ void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) { EICRB = (EICRB & ~((1 << ISC70) | (1 << ISC71))) | (mode << ISC70); EIMSK |= (1 << INT7); break; -#else +#else case 0: #if defined(EICRA) && defined(ISC00) && defined(EIMSK) EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00); @@ -134,7 +146,14 @@ void detachInterrupt(uint8_t interruptNum) { // to the number of the EIMSK bit to clear, as this isn't true on the // ATmega8. There, INT0 is 6 and INT1 is 7.) switch (interruptNum) { -#if defined(EICRA) && defined(EICRB) && defined(EIMSK) +#if defined(__AVR_ATmega32U4__) + case 0: + EIMSK &= ~(1<<INT0); + break; + case 1: + EIMSK &= ~(1<<INT1); + break; +#elif defined(EICRA) && defined(EICRB) && defined(EIMSK) case 2: EIMSK &= ~(1 << INT0); break; @@ -196,7 +215,18 @@ void attachInterruptTwi(void (*userFunc)(void) ) { } */ -#if defined(EICRA) && defined(EICRB) +#if defined(__AVR_ATmega32U4__) +SIGNAL(INT0_vect) { + if(intFunc[EXTERNAL_INT_0]) + intFunc[EXTERNAL_INT_0](); +} + +SIGNAL(INT1_vect) { + if(intFunc[EXTERNAL_INT_1]) + intFunc[EXTERNAL_INT_1](); +} + +#elif defined(EICRA) && defined(EICRB) SIGNAL(INT0_vect) { if(intFunc[EXTERNAL_INT_2]) diff --git a/cores/arduino/wiring.c b/cores/arduino/wiring.c index e7f7cde..fb447eb 100755..100644 --- a/cores/arduino/wiring.c +++ b/cores/arduino/wiring.c @@ -278,12 +278,25 @@ void init() sbi(TCCR3B, CS30); sbi(TCCR3A, WGM30); // put timer 3 in 8-bit phase correct pwm mode #endif - + +#if defined(TCCR4A) && defined(TCCR4B) && defined(TCCR4D) /* beginning of timer4 block for 32U4 and similar */ + sbi(TCCR4A, COM4A1); // clear channel A on output compare match + cbi(TCCR4A, COM4A0); + sbi(TCCR4C, COM4D1); // clear channel D on output compare match + cbi(TCCR4C, COM4D0); + sbi(TCCR4B, CS42); // set timer4 prescale factor to 64 + sbi(TCCR4B, CS41); + sbi(TCCR4B, CS40); + sbi(TCCR4D, WGM40); // put timer 4 in phase- and frequency-correct PWM mode + sbi(TCCR4A, PWM4A); // enable PWM mode for comparator OCR4A + sbi(TCCR4C, PWM4D); // enable PWM mode for comparator OCR4D +#else /* beginning of timer4 block for ATMEGA1280 and ATMEGA2560 */ #if defined(TCCR4B) && defined(CS41) && defined(WGM40) sbi(TCCR4B, CS41); // set timer 4 prescale factor to 64 sbi(TCCR4B, CS40); sbi(TCCR4A, WGM40); // put timer 4 in 8-bit phase correct pwm mode #endif +#endif /* end timer4 block for ATMEGA1280/2560 and similar */ #if defined(TCCR5B) && defined(CS51) && defined(WGM50) sbi(TCCR5B, CS51); // set timer 5 prescale factor to 64 diff --git a/cores/arduino/wiring_analog.c b/cores/arduino/wiring_analog.c index a8bc817..40a3363 100644 --- a/cores/arduino/wiring_analog.c +++ b/cores/arduino/wiring_analog.c @@ -206,14 +206,14 @@ void analogWrite(uint8_t pin, int val) break; #endif - #if defined(TCCR4A) && defined(COM4A1) + #if defined(TCCR4A) case TIMER4A: - // connect pwm to pin on timer 4, channel A + //connect pwm to pin on timer 4, channel A sbi(TCCR4A, COM4A1); - OCR4A = val; // set pwm duty + OCR4A = val; // set pwm duty break; #endif - + #if defined(TCCR4A) && defined(COM4B1) case TIMER4B: // connect pwm to pin on timer 4, channel B @@ -230,14 +230,15 @@ void analogWrite(uint8_t pin, int val) break; #endif - #if defined(TCCR4A) && defined(COM4D1) - case TIMER4D: + #if defined(TCCR4C) + case TIMER4D: // connect pwm to pin on timer 4, channel D - sbi(TCCR4A, COM4D1); - OCR4D = val; // set pwm duty + sbi(TCCR4C, COM4D1); + OCR4D = val; // set pwm duty break; #endif + #if defined(TCCR5A) && defined(COM5A1) case TIMER5A: // connect pwm to pin on timer 5, channel A @@ -272,3 +273,4 @@ void analogWrite(uint8_t pin, int val) } } } + diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index 584a28a..be323b1 100755..100644 --- a/cores/arduino/wiring_digital.c +++ b/cores/arduino/wiring_digital.c @@ -115,13 +115,17 @@ static void turnOffPWM(uint8_t timer) #if defined(TCCR4A) && defined(COM4A1) case TIMER4A: cbi(TCCR4A, COM4A1); break; - #endif + #endif #if defined(TCCR4A) && defined(COM4B1) case TIMER4B: cbi(TCCR4A, COM4B1); break; #endif #if defined(TCCR4A) && defined(COM4C1) case TIMER4C: cbi(TCCR4A, COM4C1); break; - #endif + #endif + #if defined(TCCR4C) && defined(COM4D1) + case TIMER4D: cbi(TCCR4C, COM4D1); break; + #endif + #if defined(TCCR5A) case TIMER5A: cbi(TCCR5A, COM5A1); break; case TIMER5B: cbi(TCCR5A, COM5B1); break; |