diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index 561127f9f..b43052f6c 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -20,6 +20,8 @@ Modified 28 September 2010 by Mark Sproul Modified 14 August 2012 by Alarus Modified 3 December 2013 by Matthijs Kooijman + Modified 2 November 2015 by SlashDev + Modified 23 November 2019 by Georg Icking-Konert */ #include @@ -84,6 +86,9 @@ void serialEventRun(void) #define TX_BUFFER_ATOMIC #endif +// dummy custom function for TxC interrupt. Is faster than check if(fct==NULL) +void dummyTxFct(void) { /* dummy */} + // Actual interrupt handlers ////////////////////////////////////////////////////////////// void HardwareSerial::_tx_udr_empty_irq(void) @@ -147,6 +152,7 @@ void HardwareSerial::begin(unsigned long baud, byte config) sbi(*_ucsrb, TXEN0); sbi(*_ucsrb, RXCIE0); cbi(*_ucsrb, UDRIE0); + //cbi(*_ucsrb, TXCIE0); } void HardwareSerial::end() @@ -158,6 +164,7 @@ void HardwareSerial::end() cbi(*_ucsrb, TXEN0); cbi(*_ucsrb, RXCIE0); cbi(*_ucsrb, UDRIE0); + cbi(*_ucsrb, TXCIE0); // clear any received data _rx_buffer_head = _rx_buffer_tail; @@ -278,4 +285,30 @@ size_t HardwareSerial::write(uint8_t c) return 1; } +void HardwareSerial::attachInterrupt_Receive( isrRx_t fn, void* args ) +{ + uint8_t oldSREG = SREG; + cli(); + _isrRx = fn; + _rxArg = args; + SREG = oldSREG; +} + +void HardwareSerial::attachInterrupt_Send( isrTx_t fn ) +{ + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + _isrTx = fn; // set custom function + sbi(*_ucsra, TXC0); // clear TXC status + sbi(*_ucsrb, TXCIE0); // activate TXC interrupt + } +} + +void HardwareSerial::detachInterrupt_Send() +{ + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + _isrTx = dummyTxFct; // restore dummy function + cbi(*_ucsrb, TXCIE0); // deactivate TXC interrupt + } +} + #endif // whole file diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h index 6ff29d0b9..7d1c9c91b 100644 --- a/cores/arduino/HardwareSerial.h +++ b/cores/arduino/HardwareSerial.h @@ -19,6 +19,8 @@ Modified 28 September 2010 by Mark Sproul Modified 14 August 2012 by Alarus Modified 3 December 2013 by Matthijs Kooijman + Modified 2 November 2015 by SlashDev + Modified 23 November 2019 by Georg Icking-Konert */ #ifndef HardwareSerial_h @@ -90,6 +92,9 @@ typedef uint8_t rx_buffer_index_t; #define SERIAL_7O2 0x3C #define SERIAL_8O2 0x3E +// dummy custom function for TxC interrupt. Is faster than check if(fct==NULL) +void dummyTxFct(void); + class HardwareSerial : public Stream { protected: @@ -112,6 +117,13 @@ class HardwareSerial : public Stream // instruction. unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE]; unsigned char _tx_buffer[SERIAL_TX_BUFFER_SIZE]; + + // custom handlers for RX and TXC interrupts + typedef void (* isrRx_t)( uint8_t data, uint8_t status, void* args ); + typedef void (* isrTx_t)( void ); + isrRx_t _isrRx; + isrTx_t _isrTx; + void* _rxArg; public: inline HardwareSerial( @@ -137,6 +149,18 @@ class HardwareSerial : public Stream // Interrupt handlers - Not intended to be called externally inline void _rx_complete_irq(void); void _tx_udr_empty_irq(void); + inline void _tx_complete_irq(void); + + // attach custom handlers for RX and TXC interrupts + void attachInterrupt_Receive( isrRx_t fn, void *args = NULL ); + void detachInterrupt_Receive( void ) { attachInterrupt_Receive( (isrRx_t) NULL ); }; + void attachInterrupt_Send( isrTx_t fn ); + void detachInterrupt_Send( void ); + + private: + + HardwareSerial( const HardwareSerial & ); + HardwareSerial & operator =( const HardwareSerial &); }; #if defined(UBRRH) || defined(UBRR0H) diff --git a/cores/arduino/HardwareSerial0.cpp b/cores/arduino/HardwareSerial0.cpp index 7d47ed2f6..ab2120560 100644 --- a/cores/arduino/HardwareSerial0.cpp +++ b/cores/arduino/HardwareSerial0.cpp @@ -20,6 +20,7 @@ Modified 28 September 2010 by Mark Sproul Modified 14 August 2012 by Alarus Modified 3 December 2013 by Matthijs Kooijman + Modified 23 November 2019 by Georg Icking-Konert */ #include "Arduino.h" @@ -64,6 +65,19 @@ ISR(USART_UDRE_vect) Serial._tx_udr_empty_irq(); } +#if defined(UART0_TX_vect) +ISR(UART0_TX_vect) +#elif defined(USART0_TX_vect) +ISR(USART0_TX_vect) +#elif defined(USART_TX_vect) +ISR(USART_TX_vect) +#else + #error "Don't know what the Transmission Complete vector is called for Serial" +#endif +{ + Serial._tx_complete_irq(); +} + #if defined(UBRRH) && defined(UBRRL) HardwareSerial Serial(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR); #else diff --git a/cores/arduino/HardwareSerial1.cpp b/cores/arduino/HardwareSerial1.cpp index a345cdbbc..02e988a67 100644 --- a/cores/arduino/HardwareSerial1.cpp +++ b/cores/arduino/HardwareSerial1.cpp @@ -20,6 +20,7 @@ Modified 28 September 2010 by Mark Sproul Modified 14 August 2012 by Alarus Modified 3 December 2013 by Matthijs Kooijman + Modified 23 November 2019 by Georg Icking-Konert */ #include "Arduino.h" @@ -58,6 +59,17 @@ ISR(USART1_UDRE_vect) Serial1._tx_udr_empty_irq(); } +#if defined(UART1_TX_vect) +ISR(UART1_TX_vect) +#elif defined(USART1_TX_vect) +ISR(USART1_TX_vect) +#else + #error "Don't know what the Transmission Complete vector is called for Serial1" +#endif +{ + Serial1._tx_complete_irq(); +} + HardwareSerial Serial1(&UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1); // Function that can be weakly referenced by serialEventRun to prevent diff --git a/cores/arduino/HardwareSerial2.cpp b/cores/arduino/HardwareSerial2.cpp index 8e433b6fc..265cc3845 100644 --- a/cores/arduino/HardwareSerial2.cpp +++ b/cores/arduino/HardwareSerial2.cpp @@ -20,6 +20,7 @@ Modified 28 September 2010 by Mark Sproul Modified 14 August 2012 by Alarus Modified 3 December 2013 by Matthijs Kooijman + Modified 23 November 2019 by Georg Icking-Konert */ #include "Arduino.h" @@ -46,6 +47,11 @@ ISR(USART2_UDRE_vect) Serial2._tx_udr_empty_irq(); } +ISR(USART2_TX_vect) +{ + Serial2._tx_complete_irq(); +} + HardwareSerial Serial2(&UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2); // Function that can be weakly referenced by serialEventRun to prevent diff --git a/cores/arduino/HardwareSerial3.cpp b/cores/arduino/HardwareSerial3.cpp index 26aaee81d..2b37c7529 100644 --- a/cores/arduino/HardwareSerial3.cpp +++ b/cores/arduino/HardwareSerial3.cpp @@ -20,6 +20,7 @@ Modified 28 September 2010 by Mark Sproul Modified 14 August 2012 by Alarus Modified 3 December 2013 by Matthijs Kooijman + Modified 23 November 2019 by Georg Icking-Konert */ #include "Arduino.h" @@ -46,6 +47,11 @@ ISR(USART3_UDRE_vect) Serial3._tx_udr_empty_irq(); } +ISR(USART3_TX_vect) +{ + Serial3._tx_complete_irq(); +} + HardwareSerial Serial3(&UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3); // Function that can be weakly referenced by serialEventRun to prevent diff --git a/cores/arduino/HardwareSerial_private.h b/cores/arduino/HardwareSerial_private.h index 2e23cec0c..ad5354789 100644 --- a/cores/arduino/HardwareSerial_private.h +++ b/cores/arduino/HardwareSerial_private.h @@ -19,6 +19,8 @@ Modified 23 November 2006 by David A. Mellis Modified 28 September 2010 by Mark Sproul Modified 14 August 2012 by Alarus + Modified 2 November 2015 by SlashDev + Modified 23 November 2019 by Georg Icking-Konert */ #include "wiring_private.h" @@ -92,7 +94,8 @@ HardwareSerial::HardwareSerial( _ucsra(ucsra), _ucsrb(ucsrb), _ucsrc(ucsrc), _udr(udr), _rx_buffer_head(0), _rx_buffer_tail(0), - _tx_buffer_head(0), _tx_buffer_tail(0) + _tx_buffer_head(0), _tx_buffer_tail(0), + _isrRx(NULL), _isrTx(dummyTxFct), _rxArg(NULL) { } @@ -100,24 +103,41 @@ HardwareSerial::HardwareSerial( void HardwareSerial::_rx_complete_irq(void) { - if (bit_is_clear(*_ucsra, UPE0)) { - // No Parity error, read byte and store it in the buffer if there is - // room - unsigned char c = *_udr; - 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 - // current location of the tail), we're about to overflow the buffer - // and so we don't write the character or advance the head. - if (i != _rx_buffer_tail) { - _rx_buffer[_rx_buffer_head] = c; - _rx_buffer_head = i; - } - } else { - // Parity error, read byte but discard it - *_udr; - }; + // user receive function was attached -> call it with data, status byte and optional argument pointer + if (_isrRx) { + unsigned char status = *_ucsra; + unsigned char data = *_udr; + _isrRx( data, status, _rxArg ); + } + + // default: save data in ring buffer + else { + if (bit_is_clear(*_ucsra, UPE0)) { + unsigned char c = *_udr; + // No Parity error, read byte and store it in the buffer if there is + // room + 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 + // current location of the tail), we're about to overflow the buffer + // and so we don't write the character or advance the head. + if (i != _rx_buffer_tail) { + _rx_buffer[_rx_buffer_head] = c; + _rx_buffer_head = i; + } + } + else { + // Parity error, read byte but discard it + *_udr; + }; + } +} + +void HardwareSerial::_tx_complete_irq(void) +{ + // user send function was attached -> call it + _isrTx(); } #endif // whole file