aboutsummaryrefslogtreecommitdiff
path: root/cores/arduino
diff options
context:
space:
mode:
Diffstat (limited to 'cores/arduino')
-rw-r--r--cores/arduino/Arduino.h42
-rw-r--r--cores/arduino/CDC.cpp99
-rw-r--r--cores/arduino/HID.cpp14
-rw-r--r--cores/arduino/HardwareSerial.cpp30
-rw-r--r--cores/arduino/HardwareSerial.h43
-rw-r--r--cores/arduino/HardwareSerial0.cpp4
-rw-r--r--cores/arduino/HardwareSerial1.cpp28
-rw-r--r--cores/arduino/HardwareSerial2.cpp32
-rw-r--r--cores/arduino/HardwareSerial3.cpp32
-rw-r--r--cores/arduino/HardwareSerial_private.h7
-rw-r--r--cores/arduino/IPAddress.cpp24
-rw-r--r--cores/arduino/IPAddress.h16
-rw-r--r--cores/arduino/Platform.h23
-rw-r--r--cores/arduino/Print.cpp4
-rw-r--r--cores/arduino/Printable.h2
-rw-r--r--cores/arduino/Server.h2
-rw-r--r--cores/arduino/Stream.cpp105
-rw-r--r--cores/arduino/Stream.h13
-rw-r--r--cores/arduino/Tone.cpp24
-rw-r--r--cores/arduino/USBAPI.h42
-rw-r--r--cores/arduino/USBCore.cpp25
-rw-r--r--cores/arduino/WInterrupts.c12
-rw-r--r--cores/arduino/WMath.cpp2
-rw-r--r--cores/arduino/WString.cpp11
-rw-r--r--cores/arduino/abi.cpp35
-rw-r--r--cores/arduino/avr-libc/malloc.c267
-rw-r--r--cores/arduino/avr-libc/realloc.c150
-rw-r--r--cores/arduino/avr-libc/sectionname.h49
-rw-r--r--cores/arduino/avr-libc/stdlib_private.h58
-rw-r--r--cores/arduino/main.cpp10
-rw-r--r--cores/arduino/new.cpp38
-rw-r--r--cores/arduino/new.h28
-rw-r--r--cores/arduino/wiring.c151
-rw-r--r--cores/arduino/wiring_analog.c8
-rw-r--r--cores/arduino/wiring_digital.c3
-rw-r--r--cores/arduino/wiring_private.h4
-rw-r--r--cores/arduino/wiring_pulse.S178
-rw-r--r--cores/arduino/wiring_pulse.c55
38 files changed, 788 insertions, 882 deletions
diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h
index e12ac82..f1da68d 100644
--- a/cores/arduino/Arduino.h
+++ b/cores/arduino/Arduino.h
@@ -21,6 +21,7 @@
#define Arduino_h
#include <stdlib.h>
+#include <stdbool.h>
#include <string.h>
#include <math.h>
@@ -43,9 +44,6 @@ void yield(void);
#define OUTPUT 0x1
#define INPUT_PULLUP 0x2
-#define true 0x1
-#define false 0x0
-
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define TWO_PI 6.283185307179586476925286766559
@@ -116,10 +114,13 @@ typedef unsigned int word;
#define bit(b) (1UL << (b))
-typedef uint8_t boolean;
+typedef bool boolean;
typedef uint8_t byte;
void init(void);
+void initVariant(void);
+
+int atexit(void (*func)()) __attribute__((weak));
void pinMode(uint8_t, uint8_t);
void digitalWrite(uint8_t, uint8_t);
@@ -133,6 +134,7 @@ unsigned long micros(void);
void delay(unsigned long);
void delayMicroseconds(unsigned int us);
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout);
+unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout);
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
@@ -196,20 +198,21 @@ extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
#define TIMER0B 2
#define TIMER1A 3
#define TIMER1B 4
-#define TIMER2 5
-#define TIMER2A 6
-#define TIMER2B 7
-
-#define TIMER3A 8
-#define TIMER3B 9
-#define TIMER3C 10
-#define TIMER4A 11
-#define TIMER4B 12
-#define TIMER4C 13
-#define TIMER4D 14
-#define TIMER5A 15
-#define TIMER5B 16
-#define TIMER5C 17
+#define TIMER1C 5
+#define TIMER2 6
+#define TIMER2A 7
+#define TIMER2B 8
+
+#define TIMER3A 9
+#define TIMER3B 10
+#define TIMER3C 11
+#define TIMER4A 12
+#define TIMER4B 13
+#define TIMER4C 14
+#define TIMER4D 15
+#define TIMER5A 16
+#define TIMER5B 17
+#define TIMER5C 18
#ifdef __cplusplus
} // extern "C"
@@ -230,6 +233,7 @@ uint16_t makeWord(byte h, byte l);
#define word(...) makeWord(__VA_ARGS__)
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
+unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
void noTone(uint8_t _pin);
@@ -237,7 +241,7 @@ void noTone(uint8_t _pin);
// WMath prototypes
long random(long);
long random(long, long);
-void randomSeed(unsigned int);
+void randomSeed(unsigned long);
long map(long, long, long, long, long);
#endif
diff --git a/cores/arduino/CDC.cpp b/cores/arduino/CDC.cpp
index a691306..5d4f2a0 100644
--- a/cores/arduino/CDC.cpp
+++ b/cores/arduino/CDC.cpp
@@ -16,7 +16,6 @@
** SOFTWARE.
*/
-#include "Platform.h"
#include "USBAPI.h"
#include <avr/wdt.h>
@@ -80,98 +79,81 @@ bool WEAK CDC_Setup(Setup& setup)
if (CDC_SET_LINE_CODING == r)
{
USB_RecvControl((void*)&_usbLineInfo,7);
- return true;
}
if (CDC_SET_CONTROL_LINE_STATE == r)
{
_usbLineInfo.lineState = setup.wValueL;
+ }
+ if (CDC_SET_LINE_CODING == r || CDC_SET_CONTROL_LINE_STATE == r)
+ {
// 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).
- if ((_usbLineInfo.lineState & 0x01) == 0) {
- *(uint16_t *)0x0800 = 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 *)0x0800 = 0x0;
- }
+
+ // 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;
+ 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 *)0x0800 = 0x0;
}
- return true;
}
+ return true;
}
return false;
}
-int _serialPeek = -1;
-void Serial_::begin(unsigned long baud_count)
+void Serial_::begin(unsigned long /* baud_count */)
{
+ peek_buffer = -1;
}
-void Serial_::begin(unsigned long baud_count, byte config)
+void Serial_::begin(unsigned long /* baud_count */, byte /* config */)
{
+ peek_buffer = -1;
}
void Serial_::end(void)
{
}
-void Serial_::accept(void)
-{
- int i = (unsigned int)(_rx_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.
-
- // while we have room to store a byte
- while (i != _rx_buffer_tail) {
- int c = USB_Recv(CDC_RX);
- if (c == -1)
- break; // no more data
- _rx_buffer[_rx_buffer_head] = c;
- _rx_buffer_head = i;
-
- i = (unsigned int)(_rx_buffer_head+1) % SERIAL_BUFFER_SIZE;
- }
-}
-
int Serial_::available(void)
{
- return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail) % SERIAL_BUFFER_SIZE;
+ if (peek_buffer >= 0) {
+ return 1 + USB_Available(CDC_RX);
+ }
+ return USB_Available(CDC_RX);
}
int Serial_::peek(void)
{
- if (_rx_buffer_head == _rx_buffer_tail) {
- return -1;
- } else {
- return _rx_buffer[_rx_buffer_tail];
- }
+ if (peek_buffer < 0)
+ peek_buffer = USB_Recv(CDC_RX);
+ return peek_buffer;
}
int Serial_::read(void)
{
- // if the head isn't ahead of the tail, we don't have any characters
- if (_rx_buffer_head == _rx_buffer_tail) {
- return -1;
- } else {
- unsigned char c = _rx_buffer[_rx_buffer_tail];
- _rx_buffer_tail = (unsigned int)(_rx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
+ if (peek_buffer >= 0) {
+ int c = peek_buffer;
+ peek_buffer = -1;
return c;
- }
+ }
+ return USB_Recv(CDC_RX);
}
void Serial_::flush(void)
@@ -181,6 +163,11 @@ void Serial_::flush(void)
size_t Serial_::write(uint8_t c)
{
+ return write(&c, 1);
+}
+
+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.
@@ -191,7 +178,7 @@ size_t Serial_::write(uint8_t c)
// 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 = USB_Send(CDC_TX,&c,1);
+ int r = USB_Send(CDC_TX,buffer,size);
if (r > 0) {
return r;
} else {
diff --git a/cores/arduino/HID.cpp b/cores/arduino/HID.cpp
index ac63608..75c37b2 100644
--- a/cores/arduino/HID.cpp
+++ b/cores/arduino/HID.cpp
@@ -16,9 +16,7 @@
** SOFTWARE.
*/
-#include "Platform.h"
#include "USBAPI.h"
-#include "USBDesc.h"
#if defined(USBCON)
#ifdef HID_ENABLED
@@ -106,7 +104,7 @@ const u8 _hidReportDescriptor[] = {
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0, // END_COLLECTION
-#if RAWHID_ENABLED
+#ifdef RAWHID_ENABLED
// RAW HID
0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), // 30
0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE),
@@ -151,7 +149,7 @@ int WEAK HID_GetInterface(u8* interfaceNum)
return USB_SendControl(TRANSFER_PGM,&_hidInterface,sizeof(_hidInterface));
}
-int WEAK HID_GetDescriptor(int i)
+int WEAK HID_GetDescriptor(int /* i */)
{
return USB_SendControl(TRANSFER_PGM,_hidReportDescriptor,sizeof(_hidReportDescriptor));
}
@@ -510,11 +508,11 @@ void Keyboard_::releaseAll(void)
size_t Keyboard_::write(uint8_t c)
{
- uint8_t p = press(c); // Keydown
- uint8_t r = release(c); // Keyup
- return (p); // just return the result of press() since release() almost always returns 1
+ 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) */ \ No newline at end of file
+#endif /* if defined(USBCON) */
diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp
index a270ace..a2029a8 100644
--- a/cores/arduino/HardwareSerial.cpp
+++ b/cores/arduino/HardwareSerial.cpp
@@ -72,7 +72,7 @@ void serialEventRun(void)
if (Serial2_available && serialEvent2 && Serial2_available()) serialEvent2();
#endif
#if defined(HAVE_HWSERIAL3)
- if (Serial3_available && serialEvent2 && Serial3_available()) serialEvent3();
+ if (Serial3_available && serialEvent3 && Serial3_available()) serialEvent3();
#endif
}
@@ -83,7 +83,7 @@ void HardwareSerial::_tx_udr_empty_irq(void)
// If interrupts are enabled, there must be more data in the output
// buffer. Send the next byte
unsigned char c = _tx_buffer[_tx_buffer_tail];
- _tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
+ _tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_TX_BUFFER_SIZE;
*_udr = c;
@@ -117,7 +117,7 @@ void HardwareSerial::begin(unsigned long baud, byte config)
baud_setting = (F_CPU / 8 / baud - 1) / 2;
}
- // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
+ // assign the baud_setting, a.k.a. ubrr (USART Baud Rate Register)
*_ubrrh = baud_setting >> 8;
*_ubrrl = baud_setting;
@@ -152,7 +152,7 @@ void HardwareSerial::end()
int HardwareSerial::available(void)
{
- return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail) % SERIAL_BUFFER_SIZE;
+ return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE;
}
int HardwareSerial::peek(void)
@@ -171,11 +171,26 @@ int HardwareSerial::read(void)
return -1;
} else {
unsigned char c = _rx_buffer[_rx_buffer_tail];
- _rx_buffer_tail = (uint8_t)(_rx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
+ _rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE;
return c;
}
}
+int HardwareSerial::availableForWrite(void)
+{
+#if (SERIAL_TX_BUFFER_SIZE>256)
+ uint8_t oldSREG = SREG;
+ cli();
+#endif
+ tx_buffer_index_t head = _tx_buffer_head;
+ tx_buffer_index_t tail = _tx_buffer_tail;
+#if (SERIAL_TX_BUFFER_SIZE>256)
+ SREG = oldSREG;
+#endif
+ if (head >= tail) return SERIAL_TX_BUFFER_SIZE - 1 - head + tail;
+ return tail - head - 1;
+}
+
void HardwareSerial::flush()
{
// If we have never written a byte, no need to flush. This special
@@ -198,6 +213,7 @@ void HardwareSerial::flush()
size_t HardwareSerial::write(uint8_t c)
{
+ _written = true;
// If the buffer and the data register is empty, just write the byte
// to the data register and be done. This shortcut helps
// significantly improve the effective datarate at high (>
@@ -207,7 +223,7 @@ size_t HardwareSerial::write(uint8_t c)
sbi(*_ucsra, TXC0);
return 1;
}
- uint8_t i = (_tx_buffer_head + 1) % SERIAL_BUFFER_SIZE;
+ tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE;
// If the output buffer is full, there's nothing for it other than to
// wait for the interrupt handler to empty it a bit
@@ -228,10 +244,8 @@ size_t HardwareSerial::write(uint8_t c)
_tx_buffer_head = i;
sbi(*_ucsrb, UDRIE0);
- _written = true;
return 1;
}
-
#endif // whole file
diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h
index 226bf57..1beafc5 100644
--- a/cores/arduino/HardwareSerial.h
+++ b/cores/arduino/HardwareSerial.h
@@ -32,10 +32,36 @@
// using a ring buffer (I think), in which head is the index of the location
// to which to write the next incoming character and tail is the index of the
// location from which to read.
+// NOTE: a "power of 2" buffer size is reccomended to dramatically
+// optimize all the modulo operations for ring buffers.
+// WARNING: When buffer sizes are increased to > 256, the buffer index
+// variables are automatically increased in size, but the extra
+// atomicity guards needed for that are not implemented. This will
+// 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)
- #define SERIAL_BUFFER_SIZE 16
+#define SERIAL_TX_BUFFER_SIZE 16
#else
- #define SERIAL_BUFFER_SIZE 64
+#define SERIAL_TX_BUFFER_SIZE 64
+#endif
+#endif
+#if !defined(SERIAL_RX_BUFFER_SIZE)
+#if (RAMEND < 1000)
+#define SERIAL_RX_BUFFER_SIZE 16
+#else
+#define SERIAL_RX_BUFFER_SIZE 64
+#endif
+#endif
+#if (SERIAL_TX_BUFFER_SIZE>256)
+typedef uint16_t tx_buffer_index_t;
+#else
+typedef uint8_t tx_buffer_index_t;
+#endif
+#if (SERIAL_RX_BUFFER_SIZE>256)
+typedef uint16_t rx_buffer_index_t;
+#else
+typedef uint8_t rx_buffer_index_t;
#endif
// Define config for Serial.begin(baud, config);
@@ -76,16 +102,16 @@ class HardwareSerial : public Stream
// Has any byte been written to the UART since begin()
bool _written;
- volatile uint8_t _rx_buffer_head;
- volatile uint8_t _rx_buffer_tail;
- volatile uint8_t _tx_buffer_head;
- volatile uint8_t _tx_buffer_tail;
+ volatile rx_buffer_index_t _rx_buffer_head;
+ volatile rx_buffer_index_t _rx_buffer_tail;
+ volatile tx_buffer_index_t _tx_buffer_head;
+ volatile tx_buffer_index_t _tx_buffer_tail;
// Don't put any members after these buffers, since only the first
// 32 bytes of this struct can be accessed quickly using the ldd
// instruction.
- unsigned char _rx_buffer[SERIAL_BUFFER_SIZE];
- unsigned char _tx_buffer[SERIAL_BUFFER_SIZE];
+ unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE];
+ unsigned char _tx_buffer[SERIAL_TX_BUFFER_SIZE];
public:
inline HardwareSerial(
@@ -98,6 +124,7 @@ class HardwareSerial : public Stream
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);
inline size_t write(unsigned long n) { return write((uint8_t)n); }
diff --git a/cores/arduino/HardwareSerial0.cpp b/cores/arduino/HardwareSerial0.cpp
index 67495ad..1146eeb 100644
--- a/cores/arduino/HardwareSerial0.cpp
+++ b/cores/arduino/HardwareSerial0.cpp
@@ -43,7 +43,7 @@
#elif defined(USART_RXC_vect)
ISR(USART_RXC_vect) // ATmega8
#else
- #error "Don't know what the Data Received vector is called for the first UART"
+ #error "Don't know what the Data Received vector is called for Serial"
#endif
{
Serial._rx_complete_irq();
@@ -58,7 +58,7 @@ ISR(USART0_UDRE_vect)
#elif defined(USART_UDRE_vect)
ISR(USART_UDRE_vect)
#else
- #error "Don't know what the Data Register Empty vector is called for the first UART"
+ #error "Don't know what the Data Register Empty vector is called for Serial"
#endif
{
Serial._tx_udr_empty_irq();
diff --git a/cores/arduino/HardwareSerial1.cpp b/cores/arduino/HardwareSerial1.cpp
index ec076e7..19625e2 100644
--- a/cores/arduino/HardwareSerial1.cpp
+++ b/cores/arduino/HardwareSerial1.cpp
@@ -36,39 +36,29 @@
#if defined(HAVE_HWSERIAL1)
-#if defined(USART_RX_vect)
- ISR(USART_RX_vect)
+#if defined(UART1_RX_vect)
+ISR(UART1_RX_vect)
#elif defined(USART1_RX_vect)
- ISR(USART1_RX_vect)
-#elif defined(USART_RXC_vect)
- ISR(USART_RXC_vect) // ATmega8
+ISR(USART1_RX_vect)
#else
- #error "Don't know what the Data Received vector is called for the first UART"
+#error "Don't know what the Data Register Empty vector is called for Serial1"
#endif
- {
- Serial1._rx_complete_irq();
- }
+{
+ Serial1._rx_complete_irq();
+}
#if defined(UART1_UDRE_vect)
ISR(UART1_UDRE_vect)
-#elif defined(UART_UDRE_vect)
-ISR(UART_UDRE_vect)
#elif defined(USART1_UDRE_vect)
ISR(USART1_UDRE_vect)
-#elif defined(USART_UDRE_vect)
-ISR(USART_UDRE_vect)
#else
- #error "Don't know what the Data Register Empty vector is called for the first UART"
+#error "Don't know what the Data Register Empty vector is called for Serial1"
#endif
{
Serial1._tx_udr_empty_irq();
}
-#if defined(UBRRH) && defined(UBRRL)
- HardwareSerial Serial1(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR);
-#else
- HardwareSerial Serial1(&UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1);
-#endif
+HardwareSerial Serial1(&UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1);
// Function that can be weakly referenced by serialEventRun to prevent
// pulling in this file if it's not otherwise used.
diff --git a/cores/arduino/HardwareSerial2.cpp b/cores/arduino/HardwareSerial2.cpp
index e700770..fd334ae 100644
--- a/cores/arduino/HardwareSerial2.cpp
+++ b/cores/arduino/HardwareSerial2.cpp
@@ -36,39 +36,17 @@
#if defined(HAVE_HWSERIAL2)
-#if defined(USART_RX_vect)
- ISR(USART_RX_vect)
-#elif defined(USART2_RX_vect)
- ISR(USART2_RX_vect)
-#elif defined(USART_RXC_vect)
- ISR(USART_RXC_vect) // ATmega8
-#else
- #error "Don't know what the Data Received vector is called for the first UART"
-#endif
- {
- Serial2._rx_complete_irq();
- }
+ISR(USART2_RX_vect)
+{
+ Serial2._rx_complete_irq();
+}
-#if defined(UART2_UDRE_vect)
-ISR(UART2_UDRE_vect)
-#elif defined(UART_UDRE_vect)
-ISR(UART_UDRE_vect)
-#elif defined(USART2_UDRE_vect)
ISR(USART2_UDRE_vect)
-#elif defined(USART_UDRE_vect)
-ISR(USART_UDRE_vect)
-#else
- #error "Don't know what the Data Register Empty vector is called for the first UART"
-#endif
{
Serial2._tx_udr_empty_irq();
}
-#if defined(UBRRH) && defined(UBRRL)
- HardwareSerial Serial2(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR);
-#else
- HardwareSerial Serial2(&UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2);
-#endif
+HardwareSerial Serial2(&UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2);
// Function that can be weakly referenced by serialEventRun to prevent
// pulling in this file if it's not otherwise used.
diff --git a/cores/arduino/HardwareSerial3.cpp b/cores/arduino/HardwareSerial3.cpp
index 300c4bd..a68095b 100644
--- a/cores/arduino/HardwareSerial3.cpp
+++ b/cores/arduino/HardwareSerial3.cpp
@@ -36,39 +36,17 @@
#if defined(HAVE_HWSERIAL3)
-#if defined(USART_RX_vect)
- ISR(USART_RX_vect)
-#elif defined(USART3_RX_vect)
- ISR(USART3_RX_vect)
-#elif defined(USART_RXC_vect)
- ISR(USART_RXC_vect) // ATmega8
-#else
- #error "Don't know what the Data Received vector is called for the first UART"
-#endif
- {
- Serial3._rx_complete_irq();
- }
+ISR(USART3_RX_vect)
+{
+ Serial3._rx_complete_irq();
+}
-#if defined(UART3_UDRE_vect)
-ISR(UART3_UDRE_vect)
-#elif defined(UART_UDRE_vect)
-ISR(UART_UDRE_vect)
-#elif defined(USART3_UDRE_vect)
ISR(USART3_UDRE_vect)
-#elif defined(USART_UDRE_vect)
-ISR(USART_UDRE_vect)
-#else
- #error "Don't know what the Data Register Empty vector is called for the first UART"
-#endif
{
Serial3._tx_udr_empty_irq();
}
-#if defined(UBRRH) && defined(UBRRL)
- HardwareSerial Serial3(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR);
-#else
- HardwareSerial Serial3(&UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3);
-#endif
+HardwareSerial Serial3(&UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3);
// Function that can be weakly referenced by serialEventRun to prevent
// pulling in this file if it's not otherwise used.
diff --git a/cores/arduino/HardwareSerial_private.h b/cores/arduino/HardwareSerial_private.h
index 915d7a1..761a5e5 100644
--- a/cores/arduino/HardwareSerial_private.h
+++ b/cores/arduino/HardwareSerial_private.h
@@ -34,6 +34,11 @@
// slower.
#if !defined(TXC0)
#if defined(TXC)
+// Some chips like ATmega8 don't have UPE, only PE. The other bits are
+// named as expected.
+#if !defined(UPE) && defined(PE)
+#define UPE PE
+#endif
// On ATmega8, the uart and its bits are not numbered, so there is no TXC0 etc.
#define TXC0 TXC
#define RXEN0 RXEN
@@ -99,7 +104,7 @@ void HardwareSerial::_rx_complete_irq(void)
// No Parity error, read byte and store it in the buffer if there is
// room
unsigned char c = *_udr;
- int i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_BUFFER_SIZE;
+ rx_buffer_index_t i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_RX_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
diff --git a/cores/arduino/IPAddress.cpp b/cores/arduino/IPAddress.cpp
index 22a0e42..899cbd4 100644
--- a/cores/arduino/IPAddress.cpp
+++ b/cores/arduino/IPAddress.cpp
@@ -22,42 +22,42 @@
IPAddress::IPAddress()
{
- memset(_address, 0, sizeof(_address));
+ _address.dword = 0;
}
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
{
- _address[0] = first_octet;
- _address[1] = second_octet;
- _address[2] = third_octet;
- _address[3] = fourth_octet;
+ _address.bytes[0] = first_octet;
+ _address.bytes[1] = second_octet;
+ _address.bytes[2] = third_octet;
+ _address.bytes[3] = fourth_octet;
}
IPAddress::IPAddress(uint32_t address)
{
- memcpy(_address, &address, sizeof(_address));
+ _address.dword = address;
}
IPAddress::IPAddress(const uint8_t *address)
{
- memcpy(_address, address, sizeof(_address));
+ memcpy(_address.bytes, address, sizeof(_address.bytes));
}
IPAddress& IPAddress::operator=(const uint8_t *address)
{
- memcpy(_address, address, sizeof(_address));
+ memcpy(_address.bytes, address, sizeof(_address.bytes));
return *this;
}
IPAddress& IPAddress::operator=(uint32_t address)
{
- memcpy(_address, (const uint8_t *)&address, sizeof(_address));
+ _address.dword = address;
return *this;
}
bool IPAddress::operator==(const uint8_t* addr) const
{
- return memcmp(addr, _address, sizeof(_address)) == 0;
+ return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
}
size_t IPAddress::printTo(Print& p) const
@@ -65,10 +65,10 @@ size_t IPAddress::printTo(Print& p) const
size_t n = 0;
for (int i =0; i < 3; i++)
{
- n += p.print(_address[i], DEC);
+ n += p.print(_address.bytes[i], DEC);
n += p.print('.');
}
- n += p.print(_address[3], DEC);
+ n += p.print(_address.bytes[3], DEC);
return n;
}
diff --git a/cores/arduino/IPAddress.h b/cores/arduino/IPAddress.h
index 6ea8127..94acdc4 100644
--- a/cores/arduino/IPAddress.h
+++ b/cores/arduino/IPAddress.h
@@ -27,12 +27,16 @@
class IPAddress : public Printable {
private:
- uint8_t _address[4]; // IPv4 address
+ union {
+ uint8_t bytes[4]; // IPv4 address
+ uint32_t dword;
+ } _address;
+
// Access the raw byte array containing the address. Because this returns a pointer
// to the internal structure rather than a copy of the address this function should only
// be used when you know that the usage of the returned uint8_t* will be transient and not
// stored.
- uint8_t* raw_address() { return _address; };
+ uint8_t* raw_address() { return _address.bytes; };
public:
// Constructors
@@ -43,13 +47,13 @@ public:
// 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 *((uint32_t*)_address); };
- bool operator==(const IPAddress& addr) const { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };
+ operator uint32_t() const { return _address.dword; };
+ bool operator==(const IPAddress& addr) const { return _address.dword == addr._address.dword; };
bool operator==(const uint8_t* addr) const;
// Overloaded index operator to allow getting and setting individual octets of the address
- uint8_t operator[](int index) const { return _address[index]; };
- uint8_t& operator[](int index) { return _address[index]; };
+ uint8_t operator[](int index) const { return _address.bytes[index]; };
+ uint8_t& operator[](int index) { return _address.bytes[index]; };
// Overloaded copy operators to allow initialisation of IPAddress objects from other types
IPAddress& operator=(const uint8_t *address);
diff --git a/cores/arduino/Platform.h b/cores/arduino/Platform.h
deleted file mode 100644
index 8b8f742..0000000
--- a/cores/arduino/Platform.h
+++ /dev/null
@@ -1,23 +0,0 @@
-
-#ifndef __PLATFORM_H__
-#define __PLATFORM_H__
-
-#include <inttypes.h>
-#include <avr/pgmspace.h>
-#include <avr/eeprom.h>
-#include <avr/interrupt.h>
-#include <util/delay.h>
-
-typedef unsigned char u8;
-typedef unsigned short u16;
-typedef unsigned long u32;
-
-#include "Arduino.h"
-
-#if defined(USBCON)
- #include "USBDesc.h"
- #include "USBCore.h"
- #include "USBAPI.h"
-#endif /* if defined(USBCON) */
-
-#endif
diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp
index 5df5630..782d50b 100644
--- a/cores/arduino/Print.cpp
+++ b/cores/arduino/Print.cpp
@@ -122,9 +122,7 @@ size_t Print::print(const Printable& x)
size_t Print::println(void)
{
- size_t n = print('\r');
- n += print('\n');
- return n;
+ return write("\r\n");
}
size_t Print::println(const String &s)
diff --git a/cores/arduino/Printable.h b/cores/arduino/Printable.h
index d03c9af..2a1b2e9 100644
--- a/cores/arduino/Printable.h
+++ b/cores/arduino/Printable.h
@@ -20,7 +20,7 @@
#ifndef Printable_h
#define Printable_h
-#include <new.h>
+#include <stdlib.h>
class Print;
diff --git a/cores/arduino/Server.h b/cores/arduino/Server.h
index 77c415c..69e3e39 100644
--- a/cores/arduino/Server.h
+++ b/cores/arduino/Server.h
@@ -20,6 +20,8 @@
#ifndef server_h
#define server_h
+#include "Print.h"
+
class Server : public Print {
public:
virtual void begin() =0;
diff --git a/cores/arduino/Stream.cpp b/cores/arduino/Stream.cpp
index aafb7fc..b31942f 100644
--- a/cores/arduino/Stream.cpp
+++ b/cores/arduino/Stream.cpp
@@ -18,6 +18,8 @@
Created July 2011
parsing functions based on TextFinder library by Michael Margolis
+
+ findMulti/findUntil routines written by Jim Leonard/Xuth
*/
#include "Arduino.h"
@@ -75,7 +77,7 @@ void Stream::setTimeout(unsigned long timeout) // sets the maximum number of mi
// find returns true if the target string is found
bool Stream::find(char *target)
{
- return findUntil(target, NULL);
+ return findUntil(target, strlen(target), NULL, 0);
}
// reads data from the stream until the target string of given length is found
@@ -96,32 +98,13 @@ bool Stream::findUntil(char *target, char *terminator)
// returns true if target string is found, false if terminated or timed out
bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen)
{
- size_t index = 0; // maximum target string length is 64k bytes!
- size_t termIndex = 0;
- int c;
-
- if( *target == 0)
- return true; // return true if target is a null string
- while( (c = timedRead()) > 0){
-
- if(c != target[index])
- index = 0; // reset index if any char does not match
-
- if( c == target[index]){
- //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
- if(++index >= targetLen){ // return true if all chars in the target match
- return true;
- }
- }
-
- if(termLen > 0 && c == terminator[termIndex]){
- if(++termIndex >= termLen)
- return false; // return false if terminate string found before target string
- }
- else
- termIndex = 0;
+ if (terminator == NULL) {
+ MultiTarget t[1] = {{target, targetLen, 0}};
+ return findMulti(t, 1) == 0 ? true : false;
+ } else {
+ MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
+ return findMulti(t, 2) == 0 ? true : false;
}
- return false;
}
@@ -137,7 +120,7 @@ long Stream::parseInt()
// this allows format characters (typically commas) in values to be ignored
long Stream::parseInt(char skipChar)
{
- boolean isNegative = false;
+ bool isNegative = false;
long value = 0;
int c;
@@ -173,8 +156,8 @@ float Stream::parseFloat()
// as above but the given skipChar is ignored
// this allows format characters (typically commas) in values to be ignored
float Stream::parseFloat(char skipChar){
- boolean isNegative = false;
- boolean isFraction = false;
+ bool isNegative = false;
+ bool isFraction = false;
long value = 0;
char c;
float fraction = 1.0;
@@ -268,3 +251,67 @@ String Stream::readStringUntil(char terminator)
return ret;
}
+int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) {
+ // any zero length target string automatically matches and would make
+ // a mess of the rest of the algorithm.
+ for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
+ if (t->len <= 0)
+ return t - targets;
+ }
+
+ while (1) {
+ int c = timedRead();
+ if (c < 0)
+ return -1;
+
+ for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
+ // the simple case is if we match, deal with that first.
+ if (c == t->str[t->index]) {
+ if (++t->index == t->len)
+ return t - targets;
+ else
+ continue;
+ }
+
+ // if not we need to walk back and see if we could have matched further
+ // down the stream (ie '1112' doesn't match the first position in '11112'
+ // but it will match the second position so we can't just reset the current
+ // index to 0 when we find a mismatch.
+ if (t->index == 0)
+ continue;
+
+ int origIndex = t->index;
+ do {
+ --t->index;
+ // first check if current char works against the new current index
+ if (c != t->str[t->index])
+ continue;
+
+ // if it's the only char then we're good, nothing more to check
+ if (t->index == 0) {
+ t->index++;
+ break;
+ }
+
+ // otherwise we need to check the rest of the found string
+ int diff = origIndex - t->index;
+ size_t i;
+ for (i = 0; i < t->index; ++i) {
+ if (t->str[i] != t->str[i + diff])
+ break;
+ }
+
+ // if we successfully got through the previous loop then our current
+ // index is good.
+ if (i == t->index) {
+ t->index++;
+ break;
+ }
+
+ // otherwise we just try the next index
+ } while (t->index);
+ }
+ }
+ // unreachable
+ return -1;
+}
diff --git a/cores/arduino/Stream.h b/cores/arduino/Stream.h
index 5cf5ddf..15f6761 100644
--- a/cores/arduino/Stream.h
+++ b/cores/arduino/Stream.h
@@ -64,6 +64,8 @@ class Stream : public Print
bool find(uint8_t *target, size_t length) { return find ((char *)target, length); }
// returns true if target string is found, false if timed out
+ bool find(char target) { return find (&target, 1); }
+
bool findUntil(char *target, char *terminator); // as find but search ends if the terminator string is found
bool findUntil(uint8_t *target, char *terminator) { return findUntil((char *)target, terminator); }
@@ -97,6 +99,17 @@ class Stream : public Print
// this allows format characters (typically commas) in values to be ignored
float parseFloat(char skipChar); // as above but the given skipChar is ignored
+
+ struct MultiTarget {
+ const char *str; // string you're searching for
+ size_t len; // length of string you're searching for
+ size_t index; // index used by the search routine.
+ };
+
+ // This allows you to search for an arbitrary number of strings.
+ // Returns index of the target that is found first or -1 if timeout occurs.
+ int findMulti(struct MultiTarget *targets, int tCount);
};
+
#endif
diff --git a/cores/arduino/Tone.cpp b/cores/arduino/Tone.cpp
index 9bb6fe7..7216219 100644
--- a/cores/arduino/Tone.cpp
+++ b/cores/arduino/Tone.cpp
@@ -30,6 +30,8 @@ Version Modified By Date Comments
0006 D Mellis 09/12/29 Replaced objects with functions
0007 M Sproul 10/08/29 Changed #ifdefs from cpu to register
0008 S Kanemoto 12/06/22 Fixed for Leonardo by @maris_HY
+0009 J Reucker 15/04/10 Issue #292 Fixed problems with ATmega8 (thanks to Pete62)
+0010 jipp 15/04/13 added additional define check #2923
*************************************************/
#include <avr/interrupt.h>
@@ -151,7 +153,7 @@ static int8_t toneBegin(uint8_t _pin)
// whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
switch (_timer)
{
- #if defined(TCCR0A) && defined(TCCR0B)
+ #if defined(TCCR0A) && defined(TCCR0B) && defined(WGM01)
case 0:
// 8 bit timer
TCCR0A = 0;
@@ -296,13 +298,13 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
#if defined(TCCR0B)
if (_timer == 0)
{
- TCCR0B = prescalarbits;
+ TCCR0B = (TCCR0B & 0b11111000) | prescalarbits;
}
else
#endif
#if defined(TCCR2B)
{
- TCCR2B = prescalarbits;
+ TCCR2B = (TCCR2B & 0b11111000) | prescalarbits;
}
#else
{
@@ -389,7 +391,7 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
break;
#endif
-#if defined(TIMSK3)
+#if defined(OCR3A) && defined(TIMSK3) && defined(OCIE3A)
case 3:
OCR3A = ocr;
timer3_toggle_count = toggle_count;
@@ -397,7 +399,7 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
break;
#endif
-#if defined(TIMSK4)
+#if defined(OCR4A) && defined(TIMSK4) && defined(OCIE4A)
case 4:
OCR4A = ocr;
timer4_toggle_count = toggle_count;
@@ -454,21 +456,21 @@ void disableTimer(uint8_t _timer)
#endif
break;
-#if defined(TIMSK3)
+#if defined(TIMSK3) && defined(OCIE3A)
case 3:
- TIMSK3 = 0;
+ bitWrite(TIMSK3, OCIE3A, 0);
break;
#endif
-#if defined(TIMSK4)
+#if defined(TIMSK4) && defined(OCIE4A)
case 4:
- TIMSK4 = 0;
+ bitWrite(TIMSK4, OCIE4A, 0);
break;
#endif
-#if defined(TIMSK5)
+#if defined(TIMSK5) && defined(OCIE5A)
case 5:
- TIMSK5 = 0;
+ bitWrite(TIMSK5, OCIE5A, 0);
break;
#endif
}
diff --git a/cores/arduino/USBAPI.h b/cores/arduino/USBAPI.h
index 5a33002..5837b3e 100644
--- a/cores/arduino/USBAPI.h
+++ b/cores/arduino/USBAPI.h
@@ -1,10 +1,42 @@
+/*
+ USBAPI.h
+ Copyright (c) 2005-2014 Arduino. All right reserved.
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
#ifndef __USBAPI__
#define __USBAPI__
+#include <inttypes.h>
+#include <avr/pgmspace.h>
+#include <avr/eeprom.h>
+#include <avr/interrupt.h>
+#include <util/delay.h>
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+#include "Arduino.h"
+
#if defined(USBCON)
+#include "USBDesc.h"
+#include "USBCore.h"
+
//================================================================================
//================================================================================
// USB
@@ -27,25 +59,33 @@ extern USBDevice_ USBDevice;
struct ring_buffer;
+#ifndef SERIAL_BUFFER_SIZE
#if (RAMEND < 1000)
#define SERIAL_BUFFER_SIZE 16
#else
#define SERIAL_BUFFER_SIZE 64
#endif
+#endif
+#if (SERIAL_BUFFER_SIZE>256)
+#error Please lower the CDC Buffer size
+#endif
class Serial_ : public Stream
{
+private:
+ int peek_buffer;
public:
+ Serial_() { peek_buffer = -1; };
void begin(unsigned long);
void begin(unsigned long, uint8_t);
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*, size_t);
using Print::write; // pull in write(str) and write(buf, size) from Print
operator bool();
diff --git a/cores/arduino/USBCore.cpp b/cores/arduino/USBCore.cpp
index c46c75f..b4f7bed 100644
--- a/cores/arduino/USBCore.cpp
+++ b/cores/arduino/USBCore.cpp
@@ -16,9 +16,7 @@
** SOFTWARE.
*/
-#include "Platform.h"
#include "USBAPI.h"
-#include "USBDesc.h"
#if defined(USBCON)
@@ -57,12 +55,18 @@ const u16 STRING_LANGUAGE[2] = {
const u8 STRING_PRODUCT[] PROGMEM = USB_PRODUCT;
#if USB_VID == 0x2341
-#define USB_MANUFACTURER "Arduino LLC"
+# if defined(USB_MANUFACTURER)
+# undef USB_MANUFACTURER
+# endif
+# define USB_MANUFACTURER "Arduino LLC"
#elif USB_VID == 0x1b4f
-#define USB_MANUFACTURER "SparkFun"
+# if defined(USB_MANUFACTURER)
+# undef USB_MANUFACTURER
+# endif
+# define USB_MANUFACTURER "SparkFun"
#elif !defined(USB_MANUFACTURER)
// Fall through to unknown if no manufacturer name was provided in a macro
-#define USB_MANUFACTURER "Unknown"
+# define USB_MANUFACTURER "Unknown"
#endif
const u8 STRING_MANUFACTURER[] PROGMEM = USB_MANUFACTURER;
@@ -88,7 +92,8 @@ volatile u8 _usbConfiguration = 0;
static inline void WaitIN(void)
{
- while (!(UEINTX & (1<<TXINI)));
+ while (!(UEINTX & (1<<TXINI)))
+ ;
}
static inline void ClearIN(void)
@@ -268,7 +273,6 @@ int USB_Send(u8 ep, const void* d, int len)
int r = len;
const u8* data = (const u8*)d;
- u8 zero = ep & TRANSFER_ZERO;
u8 timeout = 250; // 250ms timeout on send? TODO
while (len)
{
@@ -283,9 +287,12 @@ int USB_Send(u8 ep, const void* d, int len)
if (n > len)
n = len;
- len -= n;
{
LockEP lock(ep);
+ // Frame may have been released by the SOF interrupt handler
+ if (!ReadWriteAllowed())
+ continue;
+ len -= n;
if (ep & TRANSFER_ZERO)
{
while (n--)
@@ -621,8 +628,6 @@ ISR(USB_GEN_vect)
{
#ifdef CDC_ENABLED
USB_Flush(CDC_TX); // Send a tx frame if found
- if (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
diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c
index d3fbf10..71dd45c 100644
--- a/cores/arduino/WInterrupts.c
+++ b/cores/arduino/WInterrupts.c
@@ -223,6 +223,18 @@ void detachInterrupt(uint8_t interruptNum) {
#warning detachInterrupt may need some more work for this cpu (case 1)
#endif
break;
+
+ case 2:
+ #if defined(EIMSK) && defined(INT2)
+ EIMSK &= ~(1 << INT2);
+ #elif defined(GICR) && defined(INT2)
+ GICR &= ~(1 << INT2); // atmega32
+ #elif defined(GIMSK) && defined(INT2)
+ GIMSK &= ~(1 << INT2);
+ #elif defined(INT2)
+ #warning detachInterrupt may need some more work for this cpu (case 2)
+ #endif
+ break;
#endif
}
diff --git a/cores/arduino/WMath.cpp b/cores/arduino/WMath.cpp
index 2120c4c..214ccdc 100644
--- a/cores/arduino/WMath.cpp
+++ b/cores/arduino/WMath.cpp
@@ -27,7 +27,7 @@ extern "C" {
#include "stdlib.h"
}
-void randomSeed(unsigned int seed)
+void randomSeed(unsigned long seed)
{
if (seed != 0) {
srandom(seed);
diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp
index ed880ce..dcd469d 100644
--- a/cores/arduino/WString.cpp
+++ b/cores/arduino/WString.cpp
@@ -619,7 +619,7 @@ String String::substring(unsigned int left, unsigned int right) const
left = temp;
}
String out;
- if (left > len) return out;
+ if (left >= len) return out;
if (right > len) right = len;
char temp = buffer[right]; // save the replaced character
buffer[right] = '\0';
@@ -684,15 +684,16 @@ void String::replace(const String& find, const String& replace)
}
void String::remove(unsigned int index){
- if (index >= len) { return; }
- int count = len - index;
- remove(index, count);
+ // Pass the biggest integer as the count. The remove method
+ // below will take care of truncating it at the end of the
+ // string.
+ remove(index, (unsigned int)-1);
}
void String::remove(unsigned int index, unsigned int count){
if (index >= len) { return; }
if (count <= 0) { return; }
- if (index + count > len) { count = len - index; }
+ if (count > len - index) { count = len - index; }
char *writeTo = buffer + index;
len = len - count;
strncpy(writeTo, buffer + index + count,len - index);
diff --git a/cores/arduino/abi.cpp b/cores/arduino/abi.cpp
new file mode 100644
index 0000000..8d719b8
--- /dev/null
+++ b/cores/arduino/abi.cpp
@@ -0,0 +1,35 @@
+/*
+ Copyright (c) 2014 Arduino. All right reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <stdlib.h>
+
+extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__));
+extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__));
+
+void __cxa_pure_virtual(void) {
+ // We might want to write some diagnostics to uart in this case
+ //std::terminate();
+ abort();
+}
+
+void __cxa_deleted_virtual(void) {
+ // We might want to write some diagnostics to uart in this case
+ //std::terminate();
+ abort();
+}
+
diff --git a/cores/arduino/avr-libc/malloc.c b/cores/arduino/avr-libc/malloc.c
deleted file mode 100644
index 9dcfe21..0000000
--- a/cores/arduino/avr-libc/malloc.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/* Copyright (c) 2002, 2004, 2010 Joerg Wunsch
- Copyright (c) 2010 Gerben van den Broeke
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
- * Neither the name of the copyright holders nor the names of
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-*/
-
-
-/* $Id: malloc.c 2149 2010-06-09 20:45:37Z joerg_wunsch $ */
-
-#include <stdlib.h>
-#include "sectionname.h"
-#include "stdlib_private.h"
-
-#include <avr/io.h>
-
-/*
- * Exported interface:
- *
- * When extending the data segment, the allocator will not try to go
- * beyond the current stack limit, decreased by __malloc_margin bytes.
- * Thus, all possible stack frames of interrupt routines that could
- * interrupt the current function, plus all further nested function
- * calls must not require more stack space, or they'll risk to collide
- * with the data segment.
- */
-
-/* May be changed by the user only before the first malloc() call. */
-
-size_t __malloc_margin = 128;
-char *__malloc_heap_start = &__heap_start;
-char *__malloc_heap_end = &__heap_end;
-
-char *__brkval;
-struct __freelist *__flp;
-
-ATTRIBUTE_CLIB_SECTION
-void *
-malloc(size_t len)
-{
- struct __freelist *fp1, *fp2, *sfp1, *sfp2;
- char *cp;
- size_t s, avail;
-
- /*
- * Our minimum chunk size is the size of a pointer (plus the
- * size of the "sz" field, but we don't need to account for
- * this), otherwise we could not possibly fit a freelist entry
- * into the chunk later.
- */
- if (len < sizeof(struct __freelist) - sizeof(size_t))
- len = sizeof(struct __freelist) - sizeof(size_t);
-
- /*
- * First, walk the free list and try finding a chunk that
- * would match exactly. If we found one, we are done. While
- * walking, note down the smallest chunk we found that would
- * still fit the request -- we need it for step 2.
- *
- */
- for (s = 0, fp1 = __flp, fp2 = 0;
- fp1;
- fp2 = fp1, fp1 = fp1->nx) {
- if (fp1->sz < len)
- continue;
- if (fp1->sz == len) {
- /*
- * Found it. Disconnect the chunk from the
- * freelist, and return it.
- */
- if (fp2)
- fp2->nx = fp1->nx;
- else
- __flp = fp1->nx;
- return &(fp1->nx);
- }
- else {
- if (s == 0 || fp1->sz < s) {
- /* this is the smallest chunk found so far */
- s = fp1->sz;
- sfp1 = fp1;
- sfp2 = fp2;
- }
- }
- }
- /*
- * Step 2: If we found a chunk on the freelist that would fit
- * (but was too large), look it up again and use it, since it
- * is our closest match now. Since the freelist entry needs
- * to be split into two entries then, watch out that the
- * difference between the requested size and the size of the
- * chunk found is large enough for another freelist entry; if
- * not, just enlarge the request size to what we have found,
- * and use the entire chunk.
- */
- if (s) {
- if (s - len < sizeof(struct __freelist)) {
- /* Disconnect it from freelist and return it. */
- if (sfp2)
- sfp2->nx = sfp1->nx;
- else
- __flp = sfp1->nx;
- return &(sfp1->nx);
- }
- /*
- * Split them up. Note that we leave the first part
- * as the new (smaller) freelist entry, and return the
- * upper portion to the caller. This saves us the
- * work to fix up the freelist chain; we just need to
- * fixup the size of the current entry, and note down
- * the size of the new chunk before returning it to
- * the caller.
- */
- cp = (char *)sfp1;
- s -= len;
- cp += s;
- sfp2 = (struct __freelist *)cp;
- sfp2->sz = len;
- sfp1->sz = s - sizeof(size_t);
- return &(sfp2->nx);
- }
- /*
- * Step 3: If the request could not be satisfied from a
- * freelist entry, just prepare a new chunk. This means we
- * need to obtain more memory first. The largest address just
- * not allocated so far is remembered in the brkval variable.
- * Under Unix, the "break value" was the end of the data
- * segment as dynamically requested from the operating system.
- * Since we don't have an operating system, just make sure
- * that we don't collide with the stack.
- */
- if (__brkval == 0)
- __brkval = __malloc_heap_start;
- cp = __malloc_heap_end;
- if (cp == 0)
- cp = STACK_POINTER() - __malloc_margin;
- if (cp <= __brkval)
- /*
- * Memory exhausted.
- */
- return 0;
- avail = cp - __brkval;
- /*
- * Both tests below are needed to catch the case len >= 0xfffe.
- */
- if (avail >= len && avail >= len + sizeof(size_t)) {
- fp1 = (struct __freelist *)__brkval;
- __brkval += len + sizeof(size_t);
- fp1->sz = len;
- return &(fp1->nx);
- }
- /*
- * Step 4: There's no help, just fail. :-/
- */
- return 0;
-}
-
-
-ATTRIBUTE_CLIB_SECTION
-void
-free(void *p)
-{
- struct __freelist *fp1, *fp2, *fpnew;
- char *cp1, *cp2, *cpnew;
-
- /* ISO C says free(NULL) must be a no-op */
- if (p == 0)
- return;
-
- cpnew = p;
- cpnew -= sizeof(size_t);
- fpnew = (struct __freelist *)cpnew;
- fpnew->nx = 0;
-
- /*
- * Trivial case first: if there's no freelist yet, our entry
- * will be the only one on it. If this is the last entry, we
- * can reduce __brkval instead.
- */
- if (__flp == 0) {
- if ((char *)p + fpnew->sz == __brkval)
- __brkval = cpnew;
- else
- __flp = fpnew;
- return;
- }
-
- /*
- * Now, find the position where our new entry belongs onto the
- * freelist. Try to aggregate the chunk with adjacent chunks
- * if possible.
- */
- for (fp1 = __flp, fp2 = 0;
- fp1;
- fp2 = fp1, fp1 = fp1->nx) {
- if (fp1 < fpnew)
- continue;
- cp1 = (char *)fp1;
- fpnew->nx = fp1;
- if ((char *)&(fpnew->nx) + fpnew->sz == cp1) {
- /* upper chunk adjacent, assimilate it */
- fpnew->sz += fp1->sz + sizeof(size_t);
- fpnew->nx = fp1->nx;
- }
- if (fp2 == 0) {
- /* new head of freelist */
- __flp = fpnew;
- return;
- }
- break;
- }
- /*
- * Note that we get here either if we hit the "break" above,
- * or if we fell off the end of the loop. The latter means
- * we've got a new topmost chunk. Either way, try aggregating
- * with the lower chunk if possible.
- */
- fp2->nx = fpnew;
- cp2 = (char *)&(fp2->nx);
- if (cp2 + fp2->sz == cpnew) {
- /* lower junk adjacent, merge */
- fp2->sz += fpnew->sz + sizeof(size_t);
- fp2->nx = fpnew->nx;
- }
- /*
- * If there's a new topmost chunk, lower __brkval instead.
- */
- for (fp1 = __flp, fp2 = 0;
- fp1->nx != 0;
- fp2 = fp1, fp1 = fp1->nx)
- /* advance to entry just before end of list */;
- cp2 = (char *)&(fp1->nx);
- if (cp2 + fp1->sz == __brkval) {
- if (fp2 == NULL)
- /* Freelist is empty now. */
- __flp = NULL;
- else
- fp2->nx = NULL;
- __brkval = cp2 - sizeof(size_t);
- }
-}
-
diff --git a/cores/arduino/avr-libc/realloc.c b/cores/arduino/avr-libc/realloc.c
deleted file mode 100644
index b76ce56..0000000
--- a/cores/arduino/avr-libc/realloc.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/* Copyright (c) 2004, 2010 Joerg Wunsch
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
- * Neither the name of the copyright holders nor the names of
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-*/
-/* $Id: realloc.c 2127 2010-06-07 14:49:37Z joerg_wunsch $ */
-
-#include <stdlib.h>
-#include <string.h>
-#include "sectionname.h"
-#include "stdlib_private.h"
-
-#include <avr/io.h>
-
-ATTRIBUTE_CLIB_SECTION
-void *
-realloc(void *ptr, size_t len)
-{
- struct __freelist *fp1, *fp2, *fp3, *ofp3;
- char *cp, *cp1;
- void *memp;
- size_t s, incr;
-
- /* Trivial case, required by C standard. */
- if (ptr == 0)
- return malloc(len);
-
- cp1 = (char *)ptr;
- cp1 -= sizeof(size_t);
- fp1 = (struct __freelist *)cp1;
-
- cp = (char *)ptr + len; /* new next pointer */
- if (cp < cp1)
- /* Pointer wrapped across top of RAM, fail. */
- return 0;
-
- /*
- * See whether we are growing or shrinking. When shrinking,
- * we split off a chunk for the released portion, and call
- * free() on it. Therefore, we can only shrink if the new
- * size is at least sizeof(struct __freelist) smaller than the
- * previous size.
- */
- if (len <= fp1->sz) {
- /* The first test catches a possible unsigned int
- * rollover condition. */
- if (fp1->sz <= sizeof(struct __freelist) ||
- len > fp1->sz - sizeof(struct __freelist))
- return ptr;
- fp2 = (struct __freelist *)cp;
- fp2->sz = fp1->sz - len - sizeof(size_t);
- fp1->sz = len;
- free(&(fp2->nx));
- return ptr;
- }
-
- /*
- * If we get here, we are growing. First, see whether there
- * is space in the free list on top of our current chunk.
- */
- incr = len - fp1->sz;
- cp = (char *)ptr + fp1->sz;
- fp2 = (struct __freelist *)cp;
- for (s = 0, ofp3 = 0, fp3 = __flp;
- fp3;
- ofp3 = fp3, fp3 = fp3->nx) {
- if (fp3 == fp2 && fp3->sz + sizeof(size_t) >= incr) {
- /* found something that fits */
- if (fp3->sz + sizeof(size_t) - incr > sizeof(struct __freelist)) {
- /* split off a new freelist entry */
- cp = (char *)ptr + len;
- fp2 = (struct __freelist *)cp;
- fp2->nx = fp3->nx;
- fp2->sz = fp3->sz - incr;
- fp1->sz = len;
- } else {
- /* it just fits, so use it entirely */
- fp1->sz += fp3->sz + sizeof(size_t);
- fp2 = fp3->nx;
- }
- if (ofp3)
- ofp3->nx = fp2;
- else
- __flp = fp2;
- return ptr;
- }
- /*
- * Find the largest chunk on the freelist while
- * walking it.
- */
- if (fp3->sz > s)
- s = fp3->sz;
- }
- /*
- * If we are the topmost chunk in memory, and there was no
- * large enough chunk on the freelist that could be re-used
- * (by a call to malloc() below), quickly extend the
- * allocation area if possible, without need to copy the old
- * data.
- */
- if (__brkval == (char *)ptr + fp1->sz && len > s) {
- cp1 = __malloc_heap_end;
- cp = (char *)ptr + len;
- if (cp1 == 0)
- cp1 = STACK_POINTER() - __malloc_margin;
- if (cp < cp1) {
- __brkval = cp;
- fp1->sz = len;
- return ptr;
- }
- /* If that failed, we are out of luck. */
- return 0;
- }
-
- /*
- * Call malloc() for a new chunk, then copy over the data, and
- * release the old region.
- */
- if ((memp = malloc(len)) == 0)
- return 0;
- memcpy(memp, ptr, fp1->sz);
- free(ptr);
- return memp;
-}
-
diff --git a/cores/arduino/avr-libc/sectionname.h b/cores/arduino/avr-libc/sectionname.h
deleted file mode 100644
index 8e0f448..0000000
--- a/cores/arduino/avr-libc/sectionname.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (c) 2009 Atmel Corporation
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
- * Neither the name of the copyright holders nor the names of
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#ifndef __SECTIONNAME_H__
-#define __SECTIONNAME_H__
-
-/* Put all avr-libc functions in a common, unique sub-section name under .text. */
-
-#define CLIB_SECTION .text.avr-libc
-#define MLIB_SECTION .text.avr-libc.fplib
-
-#define STR(x) _STR(x)
-#define _STR(x) #x
-
-#define ATTRIBUTE_CLIB_SECTION __attribute__ ((section (STR(CLIB_SECTION))))
-#define ATTRIBUTE_MLIB_SECTION __attribute__ ((section (STR(MLIB_SECTION))))
-
-#define ASSEMBLY_CLIB_SECTION .section CLIB_SECTION, "ax", @progbits
-#define ASSEMBLY_MLIB_SECTION .section MLIB_SECTION, "ax", @progbits
-
-#endif
diff --git a/cores/arduino/avr-libc/stdlib_private.h b/cores/arduino/avr-libc/stdlib_private.h
deleted file mode 100644
index 65c3427..0000000
--- a/cores/arduino/avr-libc/stdlib_private.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright (c) 2004, Joerg Wunsch
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of the copyright holders nor the names of
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-*/
-
-/* $Id: stdlib_private.h 1657 2008-03-24 17:11:08Z arcanum $ */
-
-#include <inttypes.h>
-#include <stdlib.h>
-#include <avr/io.h>
-
-#if !defined(__DOXYGEN__)
-
-struct __freelist {
- size_t sz;
- struct __freelist *nx;
-};
-
-#endif
-
-extern char *__brkval; /* first location not yet allocated */
-extern struct __freelist *__flp; /* freelist pointer (head of freelist) */
-extern size_t __malloc_margin; /* user-changeable before the first malloc() */
-extern char *__malloc_heap_start;
-extern char *__malloc_heap_end;
-
-extern char __heap_start;
-extern char __heap_end;
-
-/* Needed for definition of AVR_STACK_POINTER_REG. */
-#include <avr/io.h>
-
-#define STACK_POINTER() ((char *)AVR_STACK_POINTER_REG)
-
diff --git a/cores/arduino/main.cpp b/cores/arduino/main.cpp
index 0ad6962..72074de 100644
--- a/cores/arduino/main.cpp
+++ b/cores/arduino/main.cpp
@@ -19,10 +19,20 @@
#include <Arduino.h>
+// Declared weak in Arduino.h to allow user redefinitions.
+int atexit(void (* /*func*/ )()) { return 0; }
+
+// Weak empty variant initialization function.
+// May be redefined by variant files.
+void initVariant() __attribute__((weak));
+void initVariant() { }
+
int main(void)
{
init();
+ initVariant();
+
#if defined(USBCON)
USBDevice.attach();
#endif
diff --git a/cores/arduino/new.cpp b/cores/arduino/new.cpp
index b81031e..cf6f89c 100644
--- a/cores/arduino/new.cpp
+++ b/cores/arduino/new.cpp
@@ -1,28 +1,36 @@
-#include <new.h>
+/*
+ Copyright (c) 2014 Arduino. All right reserved.
-void * operator new(size_t size)
-{
+ 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 <stdlib.h>
+
+void *operator new(size_t size) {
return malloc(size);
}
-void * operator new[](size_t size)
-{
+void *operator new[](size_t size) {
return malloc(size);
}
-void operator delete(void * ptr)
-{
+void operator delete(void * ptr) {
free(ptr);
}
-void operator delete[](void * ptr)
-{
+void operator delete[](void * ptr) {
free(ptr);
}
-int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);};
-void __cxa_guard_release (__guard *g) {*(char *)g = 1;};
-void __cxa_guard_abort (__guard *) {};
-
-void __cxa_pure_virtual(void) {};
-
diff --git a/cores/arduino/new.h b/cores/arduino/new.h
index 991c86c..6e1b68f 100644
--- a/cores/arduino/new.h
+++ b/cores/arduino/new.h
@@ -1,6 +1,20 @@
-/* Header to define new/delete operators as they aren't provided by avr-gcc by default
- Taken from http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453
- */
+/*
+ Copyright (c) 2014 Arduino. All right reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
#ifndef NEW_H
#define NEW_H
@@ -12,13 +26,5 @@ void * operator new[](size_t size);
void operator delete(void * ptr);
void operator delete[](void * ptr);
-__extension__ typedef int __guard __attribute__((mode (__DI__)));
-
-extern "C" int __cxa_guard_acquire(__guard *);
-extern "C" void __cxa_guard_release (__guard *);
-extern "C" void __cxa_guard_abort (__guard *);
-
-extern "C" void __cxa_pure_virtual(void);
-
#endif
diff --git a/cores/arduino/wiring.c b/cores/arduino/wiring.c
index 5cbe241..6cb22c0 100644
--- a/cores/arduino/wiring.c
+++ b/cores/arduino/wiring.c
@@ -92,7 +92,6 @@ unsigned long micros() {
#error TIMER 0 not defined
#endif
-
#ifdef TIFR0
if ((TIFR0 & _BV(TOV0)) && (t < 255))
m++;
@@ -119,65 +118,118 @@ void delay(unsigned long ms)
}
}
-/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */
+/* Delay for the given number of microseconds. Assumes a 1, 8, 12, 16, 20 or 24 MHz clock. */
void delayMicroseconds(unsigned int us)
{
+ // call = 4 cycles + 2 to 4 cycles to init us(2 for constant delay, 4 for variable)
+
// calling avrlib's delay_us() function with low values (e.g. 1 or
// 2 microseconds) gives delays longer than desired.
//delay_us(us);
-#if F_CPU >= 20000000L
+#if F_CPU >= 24000000L
+ // for the 24 MHz clock for the aventurous ones, trying to overclock
+
+ // zero delay fix
+ if (!us) return; // = 3 cycles, (4 when true)
+
+ // the following loop takes a 1/6 of a microsecond (4 cycles)
+ // per iteration, so execute it six times for each microsecond of
+ // delay requested.
+ us *= 6; // x6 us, = 7 cycles
+
+ // account for the time taken in the preceeding commands.
+ // we just burned 22 (24) cycles above, remove 5, (5*4=20)
+ // us is at least 6 so we can substract 5
+ us -= 5; //=2 cycles
+
+#elif F_CPU >= 20000000L
// for the 20 MHz clock on rare Arduino boards
- // for a one-microsecond delay, simply wait 2 cycle and return. The overhead
- // of the function call yields a delay of exactly a one microsecond.
+ // for a one-microsecond delay, simply return. the overhead
+ // of the function call takes 18 (20) cycles, which is 1us
__asm__ __volatile__ (
"nop" "\n\t"
- "nop"); //just waiting 2 cycle
- if (--us == 0)
- return;
+ "nop" "\n\t"
+ "nop" "\n\t"
+ "nop"); //just waiting 4 cycles
+ if (us <= 1) return; // = 3 cycles, (4 when true)
// the following loop takes a 1/5 of a microsecond (4 cycles)
// per iteration, so execute it five times for each microsecond of
// delay requested.
- us = (us<<2) + us; // x5 us
+ us = (us << 2) + us; // x5 us, = 7 cycles
// account for the time taken in the preceeding commands.
- us -= 2;
+ // we just burned 26 (28) cycles above, remove 7, (7*4=28)
+ // us is at least 10 so we can substract 7
+ us -= 7; // 2 cycles
#elif F_CPU >= 16000000L
// for the 16 MHz clock on most Arduino boards
// for a one-microsecond delay, simply return. the overhead
- // of the function call yields a delay of approximately 1 1/8 us.
- if (--us == 0)
- return;
+ // of the function call takes 14 (16) cycles, which is 1us
+ if (us <= 1) return; // = 3 cycles, (4 when true)
- // the following loop takes a quarter of a microsecond (4 cycles)
+ // the following loop takes 1/4 of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
- us <<= 2;
+ us <<= 2; // x4 us, = 4 cycles
// account for the time taken in the preceeding commands.
- us -= 2;
-#else
- // for the 8 MHz internal clock on the ATmega168
+ // we just burned 19 (21) cycles above, remove 5, (5*4=20)
+ // us is at least 8 so we can substract 5
+ us -= 5; // = 2 cycles,
+
+#elif F_CPU >= 12000000L
+ // for the 12 MHz clock if somebody is working with USB
+
+ // for a 1 microsecond delay, simply return. the overhead
+ // of the function call takes 14 (16) cycles, which is 1.5us
+ if (us <= 1) return; // = 3 cycles, (4 when true)
- // for a one- or two-microsecond delay, simply return. the overhead of
- // the function calls takes more than two microseconds. can't just
- // subtract two, since us is unsigned; we'd overflow.
- if (--us == 0)
- return;
- if (--us == 0)
- return;
+ // the following loop takes 1/3 of a microsecond (4 cycles)
+ // per iteration, so execute it three times for each microsecond of
+ // delay requested.
+ us = (us << 1) + us; // x3 us, = 5 cycles
+
+ // account for the time taken in the preceeding commands.
+ // we just burned 20 (22) cycles above, remove 5, (5*4=20)
+ // us is at least 6 so we can substract 5
+ us -= 5; //2 cycles
+
+#elif F_CPU >= 8000000L
+ // for the 8 MHz internal clock
- // the following loop takes half of a microsecond (4 cycles)
+ // for a 1 and 2 microsecond delay, simply return. the overhead
+ // of the function call takes 14 (16) cycles, which is 2us
+ if (us <= 2) return; // = 3 cycles, (4 when true)
+
+ // the following loop takes 1/2 of a microsecond (4 cycles)
// per iteration, so execute it twice for each microsecond of
// delay requested.
- us <<= 1;
-
- // partially compensate for the time taken by the preceeding commands.
- // we can't subtract any more than this or we'd overflow w/ small delays.
- us--;
+ us <<= 1; //x2 us, = 2 cycles
+
+ // account for the time taken in the preceeding commands.
+ // we just burned 17 (19) cycles above, remove 4, (4*4=16)
+ // us is at least 6 so we can substract 4
+ us -= 4; // = 2 cycles
+
+#else
+ // for the 1 MHz internal clock (default settings for common Atmega microcontrollers)
+
+ // the overhead of the function calls is 14 (16) cycles
+ if (us <= 16) return; //= 3 cycles, (4 when true)
+ if (us <= 25) return; //= 3 cycles, (4 when true), (must be at least 25 if we want to substract 22)
+
+ // compensate for the time taken by the preceeding and next commands (about 22 cycles)
+ us -= 22; // = 2 cycles
+ // the following loop takes 4 microseconds (4 cycles)
+ // per iteration, so execute it us/4 times
+ // us is at least 4, divided by 4 gives us 1 (no zero delay bug)
+ us >>= 2; // us div 4, = 4 cycles
+
+
#endif
// busy wait
@@ -185,6 +237,7 @@ void delayMicroseconds(unsigned int us)
"1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
);
+ // return = 4 cycles
}
void init()
@@ -199,7 +252,7 @@ void init()
#if defined(TCCR0A) && defined(WGM01)
sbi(TCCR0A, WGM01);
sbi(TCCR0A, WGM00);
-#endif
+#endif
// set timer 0 prescale factor to 64
#if defined(__AVR_ATmega128__)
@@ -302,14 +355,32 @@ void init()
#endif
#if defined(ADCSRA)
- // set a2d prescale factor to 128
- // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
- // XXX: this will not work properly for other clock speeds, and
- // this code should use F_CPU to determine the prescale factor.
- sbi(ADCSRA, ADPS2);
- sbi(ADCSRA, ADPS1);
- sbi(ADCSRA, ADPS0);
-
+ // set a2d prescaler so we are inside the desired 50-200 KHz range.
+ #if F_CPU >= 16000000 // 16 MHz / 128 = 125 KHz
+ sbi(ADCSRA, ADPS2);
+ sbi(ADCSRA, ADPS1);
+ sbi(ADCSRA, ADPS0);
+ #elif F_CPU >= 8000000 // 8 MHz / 64 = 125 KHz
+ sbi(ADCSRA, ADPS2);
+ sbi(ADCSRA, ADPS1);
+ cbi(ADCSRA, ADPS0);
+ #elif F_CPU >= 4000000 // 4 MHz / 32 = 125 KHz
+ sbi(ADCSRA, ADPS2);
+ cbi(ADCSRA, ADPS1);
+ sbi(ADCSRA, ADPS0);
+ #elif F_CPU >= 2000000 // 2 MHz / 16 = 125 KHz
+ sbi(ADCSRA, ADPS2);
+ cbi(ADCSRA, ADPS1);
+ cbi(ADCSRA, ADPS0);
+ #elif F_CPU >= 1000000 // 1 MHz / 8 = 125 KHz
+ cbi(ADCSRA, ADPS2);
+ sbi(ADCSRA, ADPS1);
+ sbi(ADCSRA, ADPS0);
+ #else // 128 kHz / 2 = 64 KHz -> This is the closest you can get, the prescaler is 2
+ cbi(ADCSRA, ADPS2);
+ cbi(ADCSRA, ADPS1);
+ sbi(ADCSRA, ADPS0);
+ #endif
// enable a2d conversions
sbi(ADCSRA, ADEN);
#endif
diff --git a/cores/arduino/wiring_analog.c b/cores/arduino/wiring_analog.c
index 8feead9..48a9ef5 100644
--- a/cores/arduino/wiring_analog.c
+++ b/cores/arduino/wiring_analog.c
@@ -160,6 +160,14 @@ void analogWrite(uint8_t pin, int val)
break;
#endif
+ #if defined(TCCR1A) && defined(COM1C1)
+ case TIMER1C:
+ // connect pwm to pin on timer 1, channel B
+ sbi(TCCR1A, COM1C1);
+ OCR1C = val; // set pwm duty
+ break;
+ #endif
+
#if defined(TCCR2) && defined(COM21)
case TIMER2:
// connect pwm to pin on timer 2
diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c
index be323b1..df94cc1 100644
--- a/cores/arduino/wiring_digital.c
+++ b/cores/arduino/wiring_digital.c
@@ -84,6 +84,9 @@ static void turnOffPWM(uint8_t timer)
#if defined(TCCR1A) && defined(COM1B1)
case TIMER1B: cbi(TCCR1A, COM1B1); break;
#endif
+ #if defined(TCCR1A) && defined(COM1C1)
+ case TIMER1C: cbi(TCCR1A, COM1C1); break;
+ #endif
#if defined(TCCR2) && defined(COM21)
case TIMER2: cbi(TCCR2, COM21); break;
diff --git a/cores/arduino/wiring_private.h b/cores/arduino/wiring_private.h
index c366005..3bd2900 100644
--- a/cores/arduino/wiring_private.h
+++ b/cores/arduino/wiring_private.h
@@ -43,6 +43,8 @@ extern "C"{
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
+uint32_t countPulseASM(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops);
+
#define EXTERNAL_INT_0 0
#define EXTERNAL_INT_1 1
#define EXTERNAL_INT_2 2
@@ -52,7 +54,7 @@ extern "C"{
#define EXTERNAL_INT_6 6
#define EXTERNAL_INT_7 7
-#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega128RFA1__) || defined(__AVR_ATmega256RFR2__)
#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.S b/cores/arduino/wiring_pulse.S
new file mode 100644
index 0000000..1dd22e6
--- /dev/null
+++ b/cores/arduino/wiring_pulse.S
@@ -0,0 +1,178 @@
+/*
+ wiring_pulse.s - pulseInASM() function in different flavours
+ Part of Arduino - http://www.arduino.cc/
+
+ Copyright (c) 2014 Martino Facchin
+
+ 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., 59 Temple Place, Suite 330,
+ Boston, MA 02111-1307 USA
+*/
+
+/*
+ * The following routine was generated by avr-gcc 4.8.3 with the following parameters
+ * -gstabs -Wa,-ahlmsd=output.lst -dp -fverbose-asm -O2
+ * on the original C function
+ *
+ * unsigned long pulseInSimpl(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops)
+ * {
+ * unsigned long width = 0;
+ * // wait for any previous pulse to end
+ * while ((*port & bit) == stateMask)
+ * if (--maxloops == 0)
+ * return 0;
+ *
+ * // wait for the pulse to start
+ * while ((*port & bit) != stateMask)
+ * if (--maxloops == 0)
+ * return 0;
+ *
+ * // wait for the pulse to stop
+ * while ((*port & bit) == stateMask) {
+ * if (++width == maxloops)
+ * return 0;
+ * }
+ * return width;
+ * }
+ *
+ * some compiler outputs were removed but the rest of the code is untouched
+ */
+
+#include <avr/io.h>
+
+.section .text
+
+.global countPulseASM
+
+countPulseASM:
+
+.LM0:
+.LFBB1:
+ push r12 ; ; 130 pushqi1/1 [length = 1]
+ push r13 ; ; 131 pushqi1/1 [length = 1]
+ push r14 ; ; 132 pushqi1/1 [length = 1]
+ push r15 ; ; 133 pushqi1/1 [length = 1]
+ push r16 ; ; 134 pushqi1/1 [length = 1]
+ push r17 ; ; 135 pushqi1/1 [length = 1]
+/* prologue: function */
+/* frame size = 0 */
+/* stack size = 6 */
+.L__stack_usage = 6
+ mov r30,r24 ; port, port ; 2 *movhi/1 [length = 2]
+ mov r31,r25 ; port, port
+/* unsigned long width = 0;
+*** // wait for any previous pulse to end
+*** while ((*port & bit) == stateMask)
+*/
+.LM1:
+ rjmp .L2 ; ; 181 jump [length = 1]
+.L4:
+/* if (--maxloops == 0) */
+.LM2:
+ subi r16,1 ; maxloops, ; 17 addsi3/2 [length = 4]
+ sbc r17, r1 ; maxloops
+ sbc r18, r1 ; maxloops
+ sbc r19, r1 ; maxloops
+ breq .L13 ; , ; 19 branch [length = 1]
+.L2:
+/* if (--maxloops == 0) */
+.LM3:
+ ld r25,Z ; D.1554, *port_7(D) ; 22 movqi_insn/4 [length = 1]
+ and r25,r22 ; D.1554, bit ; 24 andqi3/1 [length = 1]
+ cp r25,r20 ; D.1554, stateMask ; 25 *cmpqi/2 [length = 1]
+ breq .L4 ; , ; 26 branch [length = 1]
+ rjmp .L6 ; ; 184 jump [length = 1]
+.L7:
+/* return 0;
+***
+*** // wait for the pulse to start
+*** while ((*port & bit) != stateMask)
+*** if (--maxloops == 0)
+*/
+.LM4:
+ subi r16,1 ; maxloops, ; 31 addsi3/2 [length = 4]
+ sbc r17, r1 ; maxloops
+ sbc r18, r1 ; maxloops
+ sbc r19, r1 ; maxloops
+ breq .L13 ; , ; 33 branch [length = 1]
+.L6:
+/* if (--maxloops == 0) */
+.LM5:
+ ld r25,Z ; D.1554, *port_7(D) ; 41 movqi_insn/4 [length = 1]
+ and r25,r22 ; D.1554, bit ; 43 andqi3/1 [length = 1]
+ cpse r25,r20 ; D.1554, stateMask ; 44 enable_interrupt-3 [length = 1]
+ rjmp .L7 ;
+ mov r12, r1 ; width ; 7 *movsi/2 [length = 4]
+ mov r13, r1 ; width
+ mov r14, r1 ; width
+ mov r15, r1 ; width
+ rjmp .L9 ; ; 186 jump [length = 1]
+.L10:
+/* return 0;
+***
+*** // wait for the pulse to stop
+*** while ((*port & bit) == stateMask) {
+*** if (++width == maxloops)
+*/
+.LM6:
+ ldi r24,-1 ; , ; 50 addsi3/3 [length = 5]
+ sub r12,r24 ; width,
+ sbc r13,r24 ; width,
+ sbc r14,r24 ; width,
+ sbc r15,r24 ; width,
+ cp r16,r12 ; maxloops, width ; 51 *cmpsi/2 [length = 4]
+ cpc r17,r13 ; maxloops, width
+ cpc r18,r14 ; maxloops, width
+ cpc r19,r15 ; maxloops, width
+ breq .L13 ; , ; 52 branch [length = 1]
+.L9:
+/* if (++width == maxloops) */
+.LM7:
+ ld r24,Z ; D.1554, *port_7(D) ; 60 movqi_insn/4 [length = 1]
+ and r24,r22 ; D.1554, bit ; 62 andqi3/1 [length = 1]
+ cp r24,r20 ; D.1554, stateMask ; 63 *cmpqi/2 [length = 1]
+ breq .L10 ; , ; 64 branch [length = 1]
+/* return 0;
+*** }
+*** return width;
+*/
+.LM8:
+ mov r22,r12 ; D.1553, width ; 108 movqi_insn/1 [length = 1]
+ mov r23,r13 ; D.1553, width ; 109 movqi_insn/1 [length = 1]
+ mov r24,r14 ; D.1553, width ; 110 movqi_insn/1 [length = 1]
+ mov r25,r15 ; D.1553, width ; 111 movqi_insn/1 [length = 1]
+/* epilogue start */
+.LM9:
+ pop r17 ; ; 171 popqi [length = 1]
+ pop r16 ; ; 172 popqi [length = 1]
+ pop r15 ; ; 173 popqi [length = 1]
+ pop r14 ; ; 174 popqi [length = 1]
+ pop r13 ; ; 175 popqi [length = 1]
+ pop r12 ; ; 176 popqi [length = 1]
+ ret ; 177 return_from_epilogue [length = 1]
+.L13:
+.LM10:
+ ldi r22,0 ; D.1553 ; 120 movqi_insn/1 [length = 1]
+ ldi r23,0 ; D.1553 ; 121 movqi_insn/1 [length = 1]
+ ldi r24,0 ; D.1553 ; 122 movqi_insn/1 [length = 1]
+ ldi r25,0 ; D.1553 ; 123 movqi_insn/1 [length = 1]
+/* epilogue start */
+.LM11:
+ pop r17 ; ; 138 popqi [length = 1]
+ pop r16 ; ; 139 popqi [length = 1]
+ pop r15 ; ; 140 popqi [length = 1]
+ pop r14 ; ; 141 popqi [length = 1]
+ pop r13 ; ; 142 popqi [length = 1]
+ pop r12 ; ; 143 popqi [length = 1]
+ ret ; 144 return_from_epilogue [length = 1]
diff --git a/cores/arduino/wiring_pulse.c b/cores/arduino/wiring_pulse.c
index 0d96886..4c44d1c 100644
--- a/cores/arduino/wiring_pulse.c
+++ b/cores/arduino/wiring_pulse.c
@@ -28,7 +28,10 @@
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
* to 3 minutes in length, but must be called at least a few dozen microseconds
- * before the start of the pulse. */
+ * before the start of the pulse.
+ *
+ * This function performs better with short pulses in noInterrupt() context
+ */
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
{
// cache the port and bit of the pin in order to speed up the
@@ -37,33 +40,57 @@ unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
uint8_t stateMask = (state ? bit : 0);
- unsigned long width = 0; // keep initialization out of time critical area
-
+
+ // convert the timeout from microseconds to a number of times through
+ // the initial loop; it takes approximately 16 clock cycles per iteration
+ unsigned long maxloops = microsecondsToClockCycles(timeout)/16;
+
+ unsigned long width = countPulseASM(portInputRegister(port), bit, stateMask, maxloops);
+
+ // prevent clockCyclesToMicroseconds to return bogus values if countPulseASM timed out
+ if (width)
+ return clockCyclesToMicroseconds(width * 16 + 16);
+ else
+ return 0;
+}
+
+/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
+ * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
+ * to 3 minutes in length, but must be called at least a few dozen microseconds
+ * before the start of the pulse.
+ *
+ * ATTENTION:
+ * this function relies on micros() so cannot be used in noInterrupt() context
+ */
+unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout)
+{
+ // cache the port and bit of the pin in order to speed up the
+ // pulse width measuring loop and achieve finer resolution. calling
+ // digitalRead() instead yields much coarser resolution.
+ uint8_t bit = digitalPinToBitMask(pin);
+ 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) / 16;
-
+ unsigned long maxloops = microsecondsToClockCycles(timeout);
+
// wait for any previous pulse to end
while ((*portInputRegister(port) & bit) == stateMask)
if (numloops++ == maxloops)
return 0;
-
+
// wait for the pulse to start
while ((*portInputRegister(port) & bit) != stateMask)
if (numloops++ == maxloops)
return 0;
-
+
+ unsigned long start = micros();
// wait for the pulse to stop
while ((*portInputRegister(port) & bit) == stateMask) {
if (numloops++ == maxloops)
return 0;
- width++;
}
-
- // convert the reading to microseconds. The loop has been determined
- // to be 20 clock cycles long and have about 16 clocks between the edge
- // and the start of the loop. There will be some error introduced by
- // the interrupt handlers.
- return clockCyclesToMicroseconds(width * 21 + 16);
+ return micros() - start;
}