diff --git a/Arduino.h b/Arduino.h index 4796f219..8f66e32f 100755 --- a/Arduino.h +++ b/Arduino.h @@ -152,7 +152,8 @@ void yield(void); #define bitRead(value, bit) (((value) >> (bit)) & 0x01) #define bitSet(value, bit) ((value) |= (1UL << (bit))) #define bitClear(value, bit) ((value) &= ~(1UL << (bit))) -#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) +#define bitToggle(value, bit) ((value) ^= (1UL << (bit))) +#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit)) // avr-libc defines _NOP() since 1.6.2 #ifndef _NOP diff --git a/HardwareSerial.cpp b/HardwareSerial.cpp index 048ea69e..095bd1cb 100755 --- a/HardwareSerial.cpp +++ b/HardwareSerial.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "Arduino.h" #include "HardwareSerial.h" @@ -76,6 +77,13 @@ void serialEventRun(void) #endif } +// macro to guard critical sections when needed for large TX buffer sizes +#if (SERIAL_TX_BUFFER_SIZE>256) +#define TX_BUFFER_ATOMIC ATOMIC_BLOCK(ATOMIC_RESTORESTATE) +#else +#define TX_BUFFER_ATOMIC +#endif + // Actual interrupt handlers ////////////////////////////////////////////////////////////// void HardwareSerial::_tx_udr_empty_irq(void) @@ -89,8 +97,14 @@ void HardwareSerial::_tx_udr_empty_irq(void) // clear the TXC bit -- "can be cleared by writing a one to its bit // location". This makes sure flush() won't return until the bytes - // actually got written - *_ucsra |= _BV(TXC0); + // actually got written. Other r/w bits are preserved, and zeroes + // written to the rest. + + #ifdef MPCM0 + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0); + #else + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << TXC0))); + #endif if (_tx_buffer_head == _tx_buffer_tail) { // Buffer empty, so disable interrupts @@ -174,15 +188,13 @@ int HardwareSerial::read(void) 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 + tx_buffer_index_t head; + tx_buffer_index_t tail; + + TX_BUFFER_ATOMIC { + head = _tx_buffer_head; + tail = _tx_buffer_tail; + } if (head >= tail) return SERIAL_TX_BUFFER_SIZE - 1 - head + tail; return tail - head - 1; } @@ -215,8 +227,22 @@ size_t HardwareSerial::write(uint8_t c) // significantly improve the effective datarate at high (> // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown. if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) { - *_udr = c; - *_ucsra |= _BV(TXC0); + // If TXC is cleared before writing UDR and the previous byte + // completes before writing to UDR, TXC will be set but a byte + // is still being transmitted causing flush() to return too soon. + // So writing UDR must happen first. + // Writing UDR and clearing TC must be done atomically, otherwise + // interrupts might delay the TXC clear so the byte written to UDR + // is transmitted (setting TXC) before clearing TXC. Then TXC will + // be cleared when no bytes are left, causing flush() to hang + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + *_udr = c; + #ifdef MPCM0 + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0); + #else + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << TXC0))); + #endif + } return 1; } tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE; @@ -237,9 +263,13 @@ size_t HardwareSerial::write(uint8_t c) } _tx_buffer[_tx_buffer_head] = c; - _tx_buffer_head = i; - - *_ucsrb |= _BV(UDRIE0); + // make atomic to prevent execution of ISR between setting the + // head pointer and setting the interrupt flag resulting in buffer + // retransmission + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + _tx_buffer_head = i; + *_ucsrb |= _BV(UDRIE0); + } return 1; } diff --git a/Stream.cpp b/Stream.cpp index f6654653..e717fc15 100755 --- a/Stream.cpp +++ b/Stream.cpp @@ -218,7 +218,6 @@ size_t Stream::readBytes(char *buffer, size_t length) size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) { - if (length < 1) return 0; size_t index = 0; while (index < length) { int c = timedRead(); diff --git a/Tone.cpp b/Tone.cpp index d113e32e..ed289afa 100755 --- a/Tone.cpp +++ b/Tone.cpp @@ -279,7 +279,7 @@ static int8_t toneBegin(uint8_t _pin) void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) { - uint8_t prescalarbits = 0b001; + uint8_t prescalarbits = 0x01; long toggle_count = 0; uint32_t ocr = 0; int8_t _timer; @@ -295,38 +295,38 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) if (_timer == 0 || _timer == 2) { ocr = F_CPU / frequency / 2 - 1; - prescalarbits = 0b001; // ck/1: same for both timers + prescalarbits = 0x01; // ck/1: same for both timers if (ocr > 255) { ocr = F_CPU / frequency / 2 / 8 - 1; - prescalarbits = 0b010; // ck/8: same for both timers + prescalarbits = 0x02; // ck/8: same for both timers if (_timer == TIMER_WITH_FULL_PRESCALER && ocr > 255) { ocr = F_CPU / frequency / 2 / 32 - 1; - prescalarbits = 0b011; + prescalarbits = 0x03; } if (ocr > 255) { ocr = F_CPU / frequency / 2 / 64 - 1; - prescalarbits = _timer != TIMER_WITH_FULL_PRESCALER ? 0b011 : 0b100; + prescalarbits = _timer != TIMER_WITH_FULL_PRESCALER ? 0x03 : 0x04; if (_timer == TIMER_WITH_FULL_PRESCALER && ocr > 255) { ocr = F_CPU / frequency / 2 / 128 - 1; - prescalarbits = 0b101; + prescalarbits = 0x05; } if (ocr > 255) { ocr = F_CPU / frequency / 2 / 256 - 1; - prescalarbits = _timer != TIMER_WITH_FULL_PRESCALER ? 0b100 : 0b110; + prescalarbits = _timer != TIMER_WITH_FULL_PRESCALER ? 0x04 : 0x06; if (ocr > 255) { // Can't do any better than /1024 ocr = F_CPU / frequency / 2 / 1024 - 1; - prescalarbits = _timer != TIMER_WITH_FULL_PRESCALER ? 0b101 : 0b111; + prescalarbits = _timer != TIMER_WITH_FULL_PRESCALER ? 0x05 : 0x07; } } } @@ -335,13 +335,13 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) #if defined(TCCR0B) if (_timer == 0) { - TCCR0B = (TCCR0B & 0b11111000) | prescalarbits; + TCCR0B = (TCCR0B & 0xf8) | prescalarbits; } else #endif #if defined(TCCR2B) { - TCCR2B = (TCCR2B & 0b11111000) | prescalarbits; + TCCR2B = (TCCR2B & 0xf8) | prescalarbits; } #else { @@ -354,30 +354,30 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) // two choices for the 16 bit timers: ck/1 or ck/64 ocr = F_CPU / frequency / 2 - 1; - prescalarbits = 0b001; + prescalarbits = 0x01; if (ocr > 0xffff) { ocr = F_CPU / frequency / 2 / 64 - 1; - prescalarbits = 0b011; + prescalarbits = 0x03; } if (_timer == 1) { #if defined(TCCR1B) - TCCR1B = (TCCR1B & 0b11111000) | prescalarbits; + TCCR1B = (TCCR1B & 0xf8) | prescalarbits; #endif } #if defined(TCCR3B) else if (_timer == 3) - TCCR3B = (TCCR3B & 0b11111000) | prescalarbits; + TCCR3B = (TCCR3B & 0xf8) | prescalarbits; #endif #if defined(TCCR4B) else if (_timer == 4) - TCCR4B = (TCCR4B & 0b11111000) | prescalarbits; + TCCR4B = (TCCR4B & 0xf8) | prescalarbits; #endif #if defined(TCCR5B) else if (_timer == 5) - TCCR5B = (TCCR5B & 0b11111000) | prescalarbits; + TCCR5B = (TCCR5B & 0xf8) | prescalarbits; #endif } @@ -486,7 +486,7 @@ void disableTimer(uint8_t _timer) TCCR2A = (1 << WGM20); #endif #if defined(TCCR2B) && defined(CS22) - TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22); + TCCR2B = (TCCR2B & 0xf8) | (1 << CS22); #endif #if defined(OCR2A) OCR2A = 0; diff --git a/WString.cpp b/WString.cpp index 2e2a7aff..ca06d4ee 100755 --- a/WString.cpp +++ b/WString.cpp @@ -121,7 +121,8 @@ String::String(double value, unsigned char decimalPlaces) String::~String() { - free(buffer); + if(buffer) + free(buffer); } /*********************************************/ diff --git a/abi.cpp b/abi.cpp old mode 100755 new mode 100644 index 8d719b8e..6e1b0f8a --- a/abi.cpp +++ b/abi.cpp @@ -21,15 +21,16 @@ extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__)); extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__)); +namespace std { + [[gnu::weak, noreturn]] void terminate() { + abort(); + } +} + void __cxa_pure_virtual(void) { - // We might want to write some diagnostics to uart in this case - //std::terminate(); - abort(); + std::terminate(); } void __cxa_deleted_virtual(void) { - // We might want to write some diagnostics to uart in this case - //std::terminate(); - abort(); + std::terminate(); } - diff --git a/new b/new new file mode 100644 index 00000000..8f2fa0e4 --- /dev/null +++ b/new @@ -0,0 +1,66 @@ +/* + 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 + +#include + +namespace std { + struct nothrow_t {}; + extern const nothrow_t nothrow; + + // These are not actually implemented, to prevent overhead and + // complexity. They are still declared to allow implementing + // them in user code if needed. + typedef void (*new_handler)(); + new_handler set_new_handler(new_handler new_p) noexcept; + new_handler get_new_handler() noexcept; + + // This is normally declared in various headers that we do not have + // available, so just define it here. We could also use ::size_t + // below, but then anyone including can no longer assume + // std::size_t is available. + using size_t = ::size_t; +} // namespace std + +void * operator new(std::size_t size); +void * operator new[](std::size_t size); + +void * operator new(std::size_t size, const std::nothrow_t tag) noexcept; +void * operator new[](std::size_t size, const std::nothrow_t& tag) noexcept; + +void * operator new(std::size_t size, void *place) noexcept; +void * operator new[](std::size_t size, void *place) noexcept; + +void operator delete(void * ptr) noexcept; +void operator delete[](void * ptr) noexcept; + +#if __cplusplus >= 201402L +void operator delete(void* ptr, std::size_t size) noexcept; +void operator delete[](void * ptr, std::size_t size) noexcept; +#endif // __cplusplus >= 201402L + +void operator delete(void* ptr, const std::nothrow_t& tag) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& tag) noexcept; + +void operator delete(void* ptr, void* place) noexcept; +void operator delete[](void* ptr, void* place) noexcept; + +#endif + diff --git a/new.cpp b/new.cpp old mode 100755 new mode 100644 index 614e4e5e..768bf0f8 --- a/new.cpp +++ b/new.cpp @@ -16,36 +16,102 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include "new.h" -void *operator new(size_t size) { - return malloc(size); +// The C++ spec dictates that allocation failure should cause the +// (non-nothrow version of the) operator new to throw an exception. +// Since we expect to have exceptions disabled, it would be more +// appropriate (and probably standards-compliant) to terminate instead. +// Historically failure causes null to be returned, but this define +// allows switching to more robust terminating behaviour (that might +// become the default at some point in the future). Note that any code +// that wants null to be returned can (and should) use the nothrow +// versions of the new statement anyway and is unaffected by this. +// #define NEW_TERMINATES_ON_FAILURE + +namespace std { + // Defined in abi.cpp + void terminate(); + + const nothrow_t nothrow; } -void *operator new[](size_t size) { +static void * new_helper(std::size_t size) { + // Even zero-sized allocations should return a unique pointer, but + // malloc does not guarantee this + if (size == 0) + size = 1; return malloc(size); } +[[gnu::weak]] void * operator new(std::size_t size) { + void *res = new_helper(size); +#if defined(NEW_TERMINATES_ON_FAILURE) + if (!res) + std::terminate(); +#endif + return res; +} -void operator delete(void * ptr) { - free(ptr); +[[gnu::weak]] void * operator new[](std::size_t size) { + return operator new(size); } -void operator delete[](void * ptr) { - free(ptr); +[[gnu::weak]] void * operator new(std::size_t size, [[gnu::unused]] const std::nothrow_t tag) noexcept { +#if defined(NEW_TERMINATES_ON_FAILURE) + // Cannot call throwing operator new as standard suggests, so call + // new_helper directly then + return new_helper(size); +#else + return operator new(size); +#endif +} +[[gnu::weak]] void * operator new[](std::size_t size, [[gnu::unused]] const std::nothrow_t& tag) noexcept { +#if defined(NEW_TERMINATES_ON_FAILURE) + // Cannot call throwing operator new[] as standard suggests, so call + // malloc directly then + return new_helper(size); +#else + return operator new[](size); +#endif +} + +void * operator new(std::size_t size, void *place) noexcept { + // Nothing to do + (void)size; // unused + return place; +} +void * operator new[](std::size_t size, void *place) noexcept { + return operator new(size, place); } +[[gnu::weak]] void operator delete(void * ptr) noexcept { + free(ptr); +} +[[gnu::weak]] void operator delete[](void * ptr) noexcept { + operator delete(ptr); +} -// C++14 introduces additional delete operators #if __cplusplus >= 201402L - -void operator delete(void * ptr, size_t) -{ - ::operator delete(ptr); +[[gnu::weak]] void operator delete(void* ptr, [[gnu::unused]] std::size_t size) noexcept { + operator delete(ptr); } +[[gnu::weak]] void operator delete[](void * ptr, [[gnu::unused]] std::size_t size) noexcept { + operator delete[](ptr); +} +#endif // __cplusplus >= 201402L -void operator delete[](void * ptr, size_t) -{ - ::operator delete(ptr); +[[gnu::weak]] void operator delete(void* ptr, [[gnu::unused]] const std::nothrow_t& tag) noexcept { + operator delete(ptr); +} +[[gnu::weak]] void operator delete[](void* ptr, [[gnu::unused]] const std::nothrow_t& tag) noexcept { + operator delete[](ptr); } -#endif // end language is C++14 or greater +void operator delete(void* ptr, void* place) noexcept { + (void)ptr; (void)place; // unused + // Nothing to do +} +void operator delete[](void* ptr, void* place) noexcept { + (void)ptr; (void)place; // unused + // Nothing to do +} diff --git a/new.h b/new.h old mode 100755 new mode 100644 index a8a27050..d5298536 --- a/new.h +++ b/new.h @@ -1,36 +1,3 @@ -/* - 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 - -#include - -void * operator new(size_t size); -void * operator new[](size_t size); -void operator delete(void * ptr); -void operator delete[](void * ptr); - -// C++14 introduces additional delete operators -#if __cplusplus >= 201402L -void operator delete(void * ptr, size_t); -void operator delete[](void * ptr, size_t); -#endif // end language is C++14 or greater - -#endif - +// This file originally used a non-standard name for this Arduino core +// only, so still expose the old new.h name for compatibility. +#include "new" diff --git a/wiring_analog.c b/wiring_analog.c index 64010031..8f6c2a9c 100755 --- a/wiring_analog.c +++ b/wiring_analog.c @@ -43,7 +43,6 @@ void analogReference(uint8_t mode) int analogRead(uint8_t pin) { - uint8_t low, high; // Macro located in the pins_arduino.h file #ifdef analogPinToChannel @@ -72,27 +71,19 @@ int analogRead(uint8_t pin) // without a delay, we seem to read from the wrong channel //delay(1); -#if defined(ADCSRA) && defined(ADCL) +#if defined(ADCSRA) && defined(ADC) // start the conversion ADCSRA |= _BV(ADSC); // ADSC is cleared when the conversion finishes - while (ADCSRA & _BV(ADSC)); - - // we have to read ADCL first; doing so locks both ADCL - // and ADCH until ADCH is read. reading ADCL second would - // cause the results of each conversion to be discarded, - // as ADCL and ADCH would be locked when it completed. - low = ADCL; - high = ADCH; + while (ADCSRA & _BV(ADSC)) {}; + + // ADC macro takes care of reading ADC register. + // avr-gcc implements the proper reading order: ADCL is read first. + return ADC; #else - // we dont have an ADC, return 0 - low = 0; - high = 0; + return 0; #endif - - // combine the two bytes - return (high << 8) | low; } @@ -306,4 +297,3 @@ void analogWrite(uint8_t pin, int val) } } } - diff --git a/wiring_shift.c b/wiring_shift.c index 83ab448c..2aefa6be 100755 --- a/wiring_shift.c +++ b/wiring_shift.c @@ -42,12 +42,14 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) uint8_t i; for (i = 0; i < 8; i++) { - if (bitOrder == LSBFIRST) - digitalWrite(dataPin, !!(val & (1 << i))); - else - digitalWrite(dataPin, !!(val & (1 << (7 - i)))); - + if (bitOrder == LSBFIRST) { + digitalWrite(dataPin, val & 1); + val >>= 1; + } else { + digitalWrite(dataPin, (val & 0x80) != 0); + val <<= 1; + } digitalWrite(clockPin, HIGH); - digitalWrite(clockPin, LOW); + digitalWrite(clockPin, LOW); } }