From 49d1112fa1e42b78114c7baa3b27c52c46bceb49 Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Sun, 1 Nov 2020 11:40:53 +0100 Subject: [PATCH 01/36] update of https://github.com/SlashDevin/NeoHWSerial Update of NeoHWSerial (https://github.com/SlashDevin/NeoHWSerial). Changes: - add required files for Arduino IDE >=v1.5.6 - renamed attachInterrupt()/detachInterrupt() to attachRxInterrupt()/attachTxInterrupt() - add attachTxInterrupt()/detachTxInterrupt() for user function on Tx-empty interrupt. Useful e.g. for sync break handling in LIN bus - call user Rx-ISR function with UART status byte. Useful e.g. for sync break handling in LIN bus - enable optional default action in user function via return value --- 1.0.5/NeoHWSerial.cpp | 493 --------------------- 1.0.5/NeoHWSerial.h | 125 ------ LICENSE | 21 + README.md | 28 +- {1.0.5/examples => examples}/echo/echo.ino | 29 +- keywords.txt | 65 +++ library.properties | 9 + {1.6.5r2 => src}/NeoHWSerial.cpp | 138 ++++-- {1.6.5r2 => src}/NeoHWSerial.h | 45 +- {1.6.5r2 => src}/NeoHWSerial0.cpp | 70 +-- {1.6.5r2 => src}/NeoHWSerial1.cpp | 54 ++- {1.6.5r2 => src}/NeoHWSerial2.cpp | 30 +- {1.6.5r2 => src}/NeoHWSerial3.cpp | 30 +- {1.6.5r2 => src}/NeoHWSerial_private.h | 104 +++-- 14 files changed, 427 insertions(+), 814 deletions(-) delete mode 100644 1.0.5/NeoHWSerial.cpp delete mode 100644 1.0.5/NeoHWSerial.h create mode 100644 LICENSE rename {1.0.5/examples => examples}/echo/echo.ino (66%) create mode 100644 keywords.txt create mode 100644 library.properties rename {1.6.5r2 => src}/NeoHWSerial.cpp (62%) rename {1.6.5r2 => src}/NeoHWSerial.h (81%) rename {1.6.5r2 => src}/NeoHWSerial0.cpp (57%) rename {1.6.5r2 => src}/NeoHWSerial1.cpp (63%) rename {1.6.5r2 => src}/NeoHWSerial2.cpp (75%) rename {1.6.5r2 => src}/NeoHWSerial3.cpp (75%) rename {1.6.5r2 => src}/NeoHWSerial_private.h (64%) diff --git a/1.0.5/NeoHWSerial.cpp b/1.0.5/NeoHWSerial.cpp deleted file mode 100644 index 91bd919..0000000 --- a/1.0.5/NeoHWSerial.cpp +++ /dev/null @@ -1,493 +0,0 @@ -/* - NeoHWSerial.h - Hardware serial library - - 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 - - Created 2006 Nicholas Zambetti - Modified 28 September 2010 by Mark Sproul - Modified 14 August 2012 by Alarus - Modified 31 October 2015 by SlashDev -*/ - -#include -#include -#include -#include "Arduino.h" -#include "wiring_private.h" -#include "NeoHWSerial.h" - -// this next line disables the entire NeoHWSerial.cpp, -// this is so I can support Attiny series and any other chip without a uart -#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H) - -#include "NeoHWSerial.h" - -/* - * on ATmega8, the uart and its bits are not numbered, so there is no "TXC0" - * definition. - */ -#if !defined(TXC0) -#if defined(TXC) -#define TXC0 TXC -#elif defined(TXC1) -// Some devices have uart1 but no uart0 -#define TXC0 TXC1 -#else -#error TXC0 not definable in NeoHWSerial.h -#endif -#endif - -// Define constants and variables for buffering incoming serial data. We're -// 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. -#if (RAMEND < 1000) - #define SERIAL_BUFFER_SIZE 16 -#else - #define SERIAL_BUFFER_SIZE 64 -#endif - -struct ring_buffer -{ - unsigned char buffer[SERIAL_BUFFER_SIZE]; - volatile unsigned int head; - volatile unsigned int tail; -}; - -#if defined(USBCON) - ring_buffer rx_buffer = { { 0 }, 0, 0}; - ring_buffer tx_buffer = { { 0 }, 0, 0}; -#endif -#if defined(UBRRH) || defined(UBRR0H) - ring_buffer rx_buffer = { { 0 }, 0, 0 }; - ring_buffer tx_buffer = { { 0 }, 0, 0 }; -#endif -#if defined(UBRR1H) - ring_buffer rx_buffer1 = { { 0 }, 0, 0 }; - ring_buffer tx_buffer1 = { { 0 }, 0, 0 }; -#endif -#if defined(UBRR2H) - ring_buffer rx_buffer2 = { { 0 }, 0, 0 }; - ring_buffer tx_buffer2 = { { 0 }, 0, 0 }; -#endif -#if defined(UBRR3H) - ring_buffer rx_buffer3 = { { 0 }, 0, 0 }; - ring_buffer tx_buffer3 = { { 0 }, 0, 0 }; -#endif - -void NeoHWSerial::store_char( uint8_t c ) -{ - if (_isr) - _isr( c ); - else { - 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. - if (i != _rx_buffer->tail) { - _rx_buffer->buffer[ _rx_buffer->head ] = c; - _rx_buffer->head = i; - } - } -} - -#if !defined(USART0_RX_vect) && defined(USART1_RX_vect) -// do nothing - on the 32u4 the first USART is USART1 -#else -#if !defined(USART_RX_vect) && !defined(USART0_RX_vect) && \ - !defined(USART_RXC_vect) - #error "Don't know what the Data Received vector is called for the first UART" -#else -#if defined(USART_RX_vect) - ISR(USART_RX_vect) -#elif defined(USART0_RX_vect) - ISR(USART0_RX_vect) -#elif defined(USART_RXC_vect) - ISR(USART_RXC_vect) // ATmega8 -#endif - { - #if defined(UDR0) - if (bit_is_clear(UCSR0A, UPE0)) { - unsigned char c = UDR0; - NeoSerial.store_char(c); - } else { - unsigned char c = UDR0; - }; - #elif defined(UDR) - if (bit_is_clear(UCSRA, PE)) { - unsigned char c = UDR; - NeoSerial.store_char(c); - } else { - unsigned char c = UDR; - }; - #else - #error UDR not defined - #endif - } -#endif -#endif - -#if defined(USART1_RX_vect) - ISR(USART1_RX_vect) - { - if (bit_is_clear(UCSR1A, UPE1)) { - unsigned char c = UDR1; - NeoSerial1.store_char(c); - } else { - unsigned char c = UDR1; - }; - } -#endif - -#if defined(USART2_RX_vect) && defined(UDR2) - ISR(USART2_RX_vect) - { - if (bit_is_clear(UCSR2A, UPE2)) { - unsigned char c = UDR2; - NeoSerial2.store_char(c); - } else { - unsigned char c = UDR2; - }; - } -#endif - -#if defined(USART3_RX_vect) && defined(UDR3) - ISR(USART3_RX_vect) - { - if (bit_is_clear(UCSR3A, UPE3)) { - unsigned char c = UDR3; - NeoSerial3.store_char(c); - } else { - unsigned char c = UDR3; - }; - } -#endif - - -#if !defined(USART0_UDRE_vect) && defined(USART1_UDRE_vect) -// do nothing - on the 32u4 the first USART is USART1 -#else -#if !defined(UART0_UDRE_vect) && !defined(UART_UDRE_vect) && !defined(USART0_UDRE_vect) && !defined(USART_UDRE_vect) - #error "Don't know what the Data Register Empty vector is called for the first UART" -#else -#if defined(UART0_UDRE_vect) -ISR(UART0_UDRE_vect) -#elif defined(UART_UDRE_vect) -ISR(UART_UDRE_vect) -#elif defined(USART0_UDRE_vect) -ISR(USART0_UDRE_vect) -#elif defined(USART_UDRE_vect) -ISR(USART_UDRE_vect) -#endif -{ - if (tx_buffer.head == tx_buffer.tail) { - // Buffer empty, so disable interrupts -#if defined(UCSR0B) - cbi(UCSR0B, UDRIE0); -#else - cbi(UCSRB, UDRIE); -#endif - } - else { - // There is more data in the output buffer. Send the next byte - unsigned char c = tx_buffer.buffer[tx_buffer.tail]; - tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE; - - #if defined(UDR0) - UDR0 = c; - #elif defined(UDR) - UDR = c; - #else - #error UDR not defined - #endif - } -} -#endif -#endif - -#ifdef USART1_UDRE_vect -ISR(USART1_UDRE_vect) -{ - if (tx_buffer1.head == tx_buffer1.tail) { - // Buffer empty, so disable interrupts - cbi(UCSR1B, UDRIE1); - } - else { - // There is more data in the output buffer. Send the next byte - unsigned char c = tx_buffer1.buffer[tx_buffer1.tail]; - tx_buffer1.tail = (tx_buffer1.tail + 1) % SERIAL_BUFFER_SIZE; - - UDR1 = c; - } -} -#endif - -#ifdef USART2_UDRE_vect -ISR(USART2_UDRE_vect) -{ - if (tx_buffer2.head == tx_buffer2.tail) { - // Buffer empty, so disable interrupts - cbi(UCSR2B, UDRIE2); - } - else { - // There is more data in the output buffer. Send the next byte - unsigned char c = tx_buffer2.buffer[tx_buffer2.tail]; - tx_buffer2.tail = (tx_buffer2.tail + 1) % SERIAL_BUFFER_SIZE; - - UDR2 = c; - } -} -#endif - -#ifdef USART3_UDRE_vect -ISR(USART3_UDRE_vect) -{ - if (tx_buffer3.head == tx_buffer3.tail) { - // Buffer empty, so disable interrupts - cbi(UCSR3B, UDRIE3); - } - else { - // There is more data in the output buffer. Send the next byte - unsigned char c = tx_buffer3.buffer[tx_buffer3.tail]; - tx_buffer3.tail = (tx_buffer3.tail + 1) % SERIAL_BUFFER_SIZE; - - UDR3 = c; - } -} -#endif - - -// Constructors //////////////////////////////////////////////////////////////// - -NeoHWSerial::NeoHWSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer, - volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, - volatile uint8_t *ucsra, volatile uint8_t *ucsrb, - volatile uint8_t *ucsrc, volatile uint8_t *udr, - uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x) -{ - _rx_buffer = rx_buffer; - _tx_buffer = tx_buffer; - _ubrrh = ubrrh; - _ubrrl = ubrrl; - _ucsra = ucsra; - _ucsrb = ucsrb; - _ucsrc = ucsrc; - _udr = udr; - _rxen = rxen; - _txen = txen; - _rxcie = rxcie; - _udrie = udrie; - _u2x = u2x; - _isr = (isr_t) NULL; -} - -// Public Methods ////////////////////////////////////////////////////////////// - -void NeoHWSerial::begin(unsigned long baud) -{ - uint16_t baud_setting; - bool use_u2x = true; - -#if F_CPU == 16000000UL - // hardcoded exception for compatibility with the bootloader shipped - // with the Duemilanove and previous boards and the firmware on the 8U2 - // on the Uno and Mega 2560. - if (baud == 57600) { - use_u2x = false; - } -#endif - -try_again: - - if (use_u2x) { - *_ucsra = 1 << _u2x; - baud_setting = (F_CPU / 4 / baud - 1) / 2; - } else { - *_ucsra = 0; - baud_setting = (F_CPU / 8 / baud - 1) / 2; - } - - if ((baud_setting > 4095) && use_u2x) - { - use_u2x = false; - goto try_again; - } - - // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) - *_ubrrh = baud_setting >> 8; - *_ubrrl = baud_setting; - - transmitting = false; - - sbi(*_ucsrb, _rxen); - sbi(*_ucsrb, _txen); - sbi(*_ucsrb, _rxcie); - cbi(*_ucsrb, _udrie); -} - -void NeoHWSerial::begin(unsigned long baud, byte config) -{ - uint16_t baud_setting; - uint8_t current_config; - bool use_u2x = true; - -#if F_CPU == 16000000UL - // hardcoded exception for compatibility with the bootloader shipped - // with the Duemilanove and previous boards and the firmware on the 8U2 - // on the Uno and Mega 2560. - if (baud == 57600) { - use_u2x = false; - } -#endif - -try_again: - - if (use_u2x) { - *_ucsra = 1 << _u2x; - baud_setting = (F_CPU / 4 / baud - 1) / 2; - } else { - *_ucsra = 0; - baud_setting = (F_CPU / 8 / baud - 1) / 2; - } - - if ((baud_setting > 4095) && use_u2x) - { - use_u2x = false; - goto try_again; - } - - // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) - *_ubrrh = baud_setting >> 8; - *_ubrrl = baud_setting; - - //set the data bits, parity, and stop bits -#if defined(__AVR_ATmega8__) - config |= 0x80; // select UCSRC register (shared with UBRRH) -#endif - *_ucsrc = config; - - sbi(*_ucsrb, _rxen); - sbi(*_ucsrb, _txen); - sbi(*_ucsrb, _rxcie); - cbi(*_ucsrb, _udrie); -} - -void NeoHWSerial::end() -{ - // wait for transmission of outgoing data - while (_tx_buffer->head != _tx_buffer->tail) - ; - - cbi(*_ucsrb, _rxen); - cbi(*_ucsrb, _txen); - cbi(*_ucsrb, _rxcie); - cbi(*_ucsrb, _udrie); - - // clear any received data - _rx_buffer->head = _rx_buffer->tail; -} - -int NeoHWSerial::available(void) -{ - return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE; -} - -int NeoHWSerial::peek(void) -{ - if (_rx_buffer->head == _rx_buffer->tail) { - return -1; - } else { - return _rx_buffer->buffer[_rx_buffer->tail]; - } -} - -int NeoHWSerial::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->buffer[_rx_buffer->tail]; - _rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE; - return c; - } -} - -void NeoHWSerial::flush() -{ - // UDR is kept full while the buffer is not empty, so TXC triggers when EMPTY && SENT - while (transmitting && ! (*_ucsra & _BV(TXC0))); - transmitting = false; -} - -size_t NeoHWSerial::write(uint8_t c) -{ - int i = (_tx_buffer->head + 1) % SERIAL_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 - // ???: return 0 here instead? - while (i == _tx_buffer->tail) - ; - - _tx_buffer->buffer[_tx_buffer->head] = c; - _tx_buffer->head = i; - - sbi(*_ucsrb, _udrie); - // clear the TXC bit -- "can be cleared by writing a one to its bit location" - transmitting = true; - sbi(*_ucsra, TXC0); - - return 1; -} - -NeoHWSerial::operator bool() { - return true; -} - -void NeoHWSerial::attachInterrupt( isr_t fn ) -{ - uint8_t oldSREG = SREG; - cli(); - _isr = fn; - SREG = oldSREG; -} - -// Preinstantiate Objects ////////////////////////////////////////////////////// - -#if defined(UBRRH) && defined(UBRRL) - NeoHWSerial NeoSerial(&rx_buffer, &tx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR, RXEN, TXEN, RXCIE, UDRIE, U2X); -#elif defined(UBRR0H) && defined(UBRR0L) - NeoHWSerial NeoSerial(&rx_buffer, &tx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UCSR0C, &UDR0, RXEN0, TXEN0, RXCIE0, UDRIE0, U2X0); -#elif defined(USBCON) - // do nothing - Serial object and buffers are initialized in CDC code -#else - #error no serial port defined (port 0) -#endif - -#if defined(UBRR1H) - NeoHWSerial NeoSerial1(&rx_buffer1, &tx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1, RXEN1, TXEN1, RXCIE1, UDRIE1, U2X1); -#endif -#if defined(UBRR2H) - NeoHWSerial NeoSerial2(&rx_buffer2, &tx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2, RXEN2, TXEN2, RXCIE2, UDRIE2, U2X2); -#endif -#if defined(UBRR3H) - NeoHWSerial NeoSerial3(&rx_buffer3, &tx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3, RXEN3, TXEN3, RXCIE3, UDRIE3, U2X3); -#endif - -#endif // whole file - diff --git a/1.0.5/NeoHWSerial.h b/1.0.5/NeoHWSerial.h deleted file mode 100644 index 93192dc..0000000 --- a/1.0.5/NeoHWSerial.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - NeoHWSerial.h - Hardware serial library - - 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 - - Created 2006 Nicholas Zambetti - Modified 28 September 2010 by Mark Sproul - Modified 14 August 2012 by Alarus - Modified 31 October 2015 by SlashDev -*/ - -#ifndef NeoHWSerial_h -#define NeoHWSerial_h - -#include - -#include "Stream.h" - -struct ring_buffer; - -class NeoHWSerial : public Stream -{ - private: - NeoHWSerial( const NeoHWSerial & ); - NeoHWSerial & operator =( const NeoHWSerial &); - - ring_buffer *_rx_buffer; - ring_buffer *_tx_buffer; - volatile uint8_t *_ubrrh; - volatile uint8_t *_ubrrl; - volatile uint8_t *_ucsra; - volatile uint8_t *_ucsrb; - volatile uint8_t *_ucsrc; - volatile uint8_t *_udr; - uint8_t _rxen; - uint8_t _txen; - uint8_t _rxcie; - uint8_t _udrie; - uint8_t _u2x; - bool transmitting; - public: - NeoHWSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer, - volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, - volatile uint8_t *ucsra, volatile uint8_t *ucsrb, - volatile uint8_t *ucsrc, volatile uint8_t *udr, - uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x); - void begin(unsigned long); - void begin(unsigned long, uint8_t); - void end(); - virtual int available(void); - virtual int peek(void); - virtual int read(void); - virtual void flush(void); - virtual size_t write(uint8_t); - inline size_t write(unsigned long n) { return write((uint8_t)n); } - inline size_t write(long n) { return write((uint8_t)n); } - inline size_t write(unsigned int n) { return write((uint8_t)n); } - inline size_t write(int n) { return write((uint8_t)n); } - using Print::write; // pull in write(str) and write(buf, size) from Print - operator bool(); - - typedef void (* isr_t)( uint8_t ); - void attachInterrupt( isr_t fn ); - void detachInterrupt() { attachInterrupt( (isr_t) NULL ); }; - - void store_char( uint8_t rx ); - private: - isr_t _isr; -}; - -// Define config for Serial.begin(baud, config); -#define SERIAL_5N1 0x00 -#define SERIAL_6N1 0x02 -#define SERIAL_7N1 0x04 -#define SERIAL_8N1 0x06 -#define SERIAL_5N2 0x08 -#define SERIAL_6N2 0x0A -#define SERIAL_7N2 0x0C -#define SERIAL_8N2 0x0E -#define SERIAL_5E1 0x20 -#define SERIAL_6E1 0x22 -#define SERIAL_7E1 0x24 -#define SERIAL_8E1 0x26 -#define SERIAL_5E2 0x28 -#define SERIAL_6E2 0x2A -#define SERIAL_7E2 0x2C -#define SERIAL_8E2 0x2E -#define SERIAL_5O1 0x30 -#define SERIAL_6O1 0x32 -#define SERIAL_7O1 0x34 -#define SERIAL_8O1 0x36 -#define SERIAL_5O2 0x38 -#define SERIAL_6O2 0x3A -#define SERIAL_7O2 0x3C -#define SERIAL_8O2 0x3E - -#if defined(UBRRH) || defined(UBRR0H) - extern NeoHWSerial NeoSerial; -#elif defined(USBCON) - #include "USBAPI.h" -// extern NeoHWSerial Serial_; -#endif -#if defined(UBRR1H) - extern NeoHWSerial NeoSerial1; -#endif -#if defined(UBRR2H) - extern NeoHWSerial NeoSerial2; -#endif -#if defined(UBRR3H) - extern NeoHWSerial NeoSerial3; -#endif - -#endif diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4e0ab09 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 gicking + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 34ddd3a..dbf4c58 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,32 @@ -The **NeoHWSerial** class is a drop-in replacement for the Arduino built-in class `HardwareSerial`. It adds the capability to handle received characters with a user-defined function *during* the RX interrupt. This can improve performance significantly by eliminating all processing associated with storing and retrieving characters in the ring buffer **and** all polling code that constantly checked for new characters: `available` and `read` are unnecessary. +The **NeoHWSerial** class is a drop-in replacement for the Arduino built-in class `HardwareSerial`. It adds the capability to handle received characters with a user-defined function *during* the RX interrupt. This can improve performance significantly by eliminating all processing associated with storing and retrieving characters in the ring buffer **and** all polling code that constantly checked for new characters: `available` and `read` are unnecessary. + +Note: This is a minor update of [NeoHWSerial by SlashDevin](https://github.com/SlashDevin/NeoHWSerial) for AVR. Changes: + - updated to Arduino IDE >=v1.5.6 library format (see [here](https://arduino.github.io/arduino-cli/latest/library-specification/)) + - pass UART status byte to user receive function. Required e.g. for break detection in [LIN bus](https://en.wikipedia.org/wiki/Local_Interconnect_Network) + - support optional storing to ring buffer after return from user routine via return value + ### Installation 1. Download the NeoHWSerial master zip file. 2. Extract all files into a tempory working directory. -3. Create a `NeoHWSerial` subdirectory in your `Arduino/Libraries` directory. -4. Copy all files from the version number subdirectory that corresponds to your IDE version into the `NeoHWSerial` subdirectory you created in step 1. For example, if you are using Arduino IDE version 1.0.5, copy all files from the extracted `NeoHWSerial-master/1.0.5` subdirectory into your `Arduino/Libraries/NeoHWSerial` subdirectory. +3. Create a `NeoHWSerial` subdirectory in your `Arduino/libraries` directory. ### Usage To handle all received characters with your function, you must register it with the specific `NeoSerial[n]` instance: #include - + volatile uint32_t newlines = 0UL; - - static void handleRxChar( uint8_t c ) + + static bool handleRxChar( uint8_t c, uint8_t status ) { if (c == '\n') newlines++; + return false; // don't store c in ring buffer } - + void setup() { NeoSerial1.attachInterrupt( handleRxChar ); @@ -29,14 +35,14 @@ To handle all received characters with your function, you must register it with Remember that the registered function is called from an interrupt context, and it should return as quickly as possible. Taking too much time in the function will cause many unpredictable behaviors, including loss of received data. See the similar warnings for the built-in [`attachInterrupt`](https://www.arduino.cc/en/Reference/AttachInterrupt) for digital pins. -The registered function will be called from the ISR whenever a character is received. The received character **will not** be stored in the `rx_buffer`, and it **will not** be returned from `read()`. Any characters that were received and buffered before `attachInterrupt` was called remain in `rx_buffer`, and could be retrieved by calling `read()`. +The registered function will be called from the ISR whenever a character is received. The received character is stored in the `rx_buffer` after return from the user function, if the user function returns a _true_ value. Characters that were received and buffered before `attachInterrupt` was called remain in `rx_buffer`, and could be retrieved by calling `read()`. If `attachInterrupt` is never called, or it is passed a `NULL` function, the normal buffering occurs, and all received characters must be obtained by calling `read()`. The original `HardwareSerial` files were modified to include two new methods, `attachInterrupt` and `detachInterrupt`, and one new data member, the private `_isr`: ``` - typedef void (* isr_t)( uint8_t ); + typedef void (* isr_t)( uint8_t, uint8_t ); void attachInterrupt( isr_t fn ); void detachInterrupt() { attachInterrupt( (isr_t) NULL ); }; @@ -48,9 +54,9 @@ The original `HardwareSerial` files were modified to include two new methods, `a To avoid name collisions, all `HardwareSerial` instances are prefixed with "Neo" in this replacement library. All parts of your sketch, including other libraries, must use -* `NeoSerial` instead of `Serial`, +* `NeoSerial` instead of `Serial`, * `NeoSerial1` instead of `Serial1`, -* `NeoSerial2` instead of `Serial2`, and +* `NeoSerial2` instead of `Serial2`, and * `NeoSerial3` instead of `Serial3`. If there are any references to the original `HardwareSerial` instances, you will get one or more linker errors: diff --git a/1.0.5/examples/echo/echo.ino b/examples/echo/echo.ino similarity index 66% rename from 1.0.5/examples/echo/echo.ino rename to examples/echo/echo.ino index ebb213e..5cc7629 100644 --- a/1.0.5/examples/echo/echo.ino +++ b/examples/echo/echo.ino @@ -5,16 +5,17 @@ // interrupt with NeoHWSerial. // -static volatile uint16_t count = 0; +static volatile uint16_t ISR_count = 0; -static void char_received( uint8_t c ) +static bool char_received( uint8_t c, uint8_t status ) { // This is a little naughty, as it will try to block // in this ISR if the tx_buffer is full. For this example, // we are only sending as many characters as we have received, // and they arrive at the same rate we are sending them. NeoSerial.write( c ); - count++; + ISR_count++; + return false; // do not store received data to ring buffer } void setup() @@ -28,17 +29,21 @@ void loop() { delay( 1000 ); - uint8_t oldSREG = SREG; + // get number of calls to char_received() noInterrupts(); - uint16_t old_count = count; - count = 0; - SREG = oldSREG; - - if (old_count) { + uint16_t echo_count = ISR_count; + ISR_count = 0; + interrupts(); + + if (echo_count) + { NeoSerial.print( '\n' ); - NeoSerial.print( old_count ); + NeoSerial.print( echo_count ); NeoSerial.println( F(" characters echoed") ); - } else + } + else + { NeoSerial.print( '.' ); + } NeoSerial.flush(); -} \ No newline at end of file +} diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..8c46adb --- /dev/null +++ b/keywords.txt @@ -0,0 +1,65 @@ +############################################### +# Syntax coloring for NeoHWSerial library +############################################### + +################################### +# Classes and Datatypes (KEYWORD1) +################################### + +NeoSerial KEYWORD1 +NeoSerial0 KEYWORD1 +NeoSerial1 KEYWORD1 +NeoSerial2 KEYWORD1 +NeoSerial3 KEYWORD1 + +################################### +# Methods and Functions (KEYWORD2) +################################### + +begin KEYWORD2 +end KEYWORD2 +available KEYWORD2 +peek KEYWORD2 +read KEYWORD2 +availableForWrite KEYWORD2 +flush KEYWORD2 +write KEYWORD2 +attachInterrupt KEYWORD2 +detachInterrupt KEYWORD2 +serialEventRun KEYWORD2 + +################################### +# Constants (LITERAL1) +################################### + +HAVE_HWSERIAL0 LITERAL1 +HAVE_HWSERIAL1 LITERAL1 +HAVE_HWSERIAL2 LITERAL1 +HAVE_HWSERIAL3 LITERAL1 +SERIAL_TX_BUFFER_SIZE LITERAL1 +SERIAL_5N1 LITERAL1 +SERIAL_6N1 LITERAL1 +SERIAL_7N1 LITERAL1 +SERIAL_8N1 LITERAL1 +SERIAL_5N2 LITERAL1 +SERIAL_6N2 LITERAL1 +SERIAL_7N2 LITERAL1 +SERIAL_8N2 LITERAL1 +SERIAL_5E1 LITERAL1 +SERIAL_6E1 LITERAL1 +SERIAL_7E1 LITERAL1 +SERIAL_8E1 LITERAL1 +SERIAL_5E2 LITERAL1 +SERIAL_6E2 LITERAL1 +SERIAL_7E2 LITERAL1 +SERIAL_8E2 LITERAL1 +SERIAL_5O1 LITERAL1 +SERIAL_6O1 LITERAL1 +SERIAL_7O1 LITERAL1 +SERIAL_8O1 LITERAL1 +SERIAL_5O2 LITERAL1 +SERIAL_6O2 LITERAL1 +SERIAL_7O2 LITERAL1 +SERIAL_8O2 LITERAL1 + +##################### END ##################### diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..d9e863f --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=NeoHWSerial +version=1.6.6 +author=Georg Icking-Konert +maintainer=Georg Icking-Konert +sentence=NeoHWSerial for AVR +paragraph=Adaptation of NeoHWSerial by SlashDevin for AVR +category=Communication +url=https://github.com/gicking/NeoHWSerial +architectures=avr diff --git a/1.6.5r2/NeoHWSerial.cpp b/src/NeoHWSerial.cpp similarity index 62% rename from 1.6.5r2/NeoHWSerial.cpp rename to src/NeoHWSerial.cpp index 24cc147..da4945e 100644 --- a/1.6.5r2/NeoHWSerial.cpp +++ b/src/NeoHWSerial.cpp @@ -15,31 +15,82 @@ 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 - + Modified 23 November 2006 by David A. Mellis 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 31 October 2020 by Georg Icking-Konert */ #include #include #include #include +#include #include "Arduino.h" -#include -#include +#include "NeoHWSerial.h" +#include "NeoHWSerial_private.h" -// this next line disables the entire HardwareSerial.cpp, +// this next line disables the entire HardwareSerial.cpp, // this is so I can support Attiny series and any other chip without a uart #if defined(HAVE_HWSERIAL0) || defined(HAVE_HWSERIAL1) || defined(HAVE_HWSERIAL2) || defined(HAVE_HWSERIAL3) -// Actual interrupt handlers ////////////////////////////////////////////////////////////// +// NeoSerialEvent functions are weak, so when the user doesn't define them, +// the linker just sets their address to 0 (which is checked below). +// The NeoSerialx_available is just a wrapper around NeoSerialx.available(), +// but we can refer to it weakly so we don't pull in the entire +// NeoHWSerial instance if the user doesn't also refer to it. +#if defined(HAVE_HWSERIAL0) + void serialEvent() __attribute__((weak)); // called by main() -> name fixed + bool NeoSerial0_available() __attribute__((weak)); +#endif -void NeoHWSerial::_tx_udr_empty_irq(void) +#if defined(HAVE_HWSERIAL1) + void serialEvent1() __attribute__((weak)); // called by main() -> name fixed + bool NeoSerial1_available() __attribute__((weak)); +#endif + +#if defined(HAVE_HWSERIAL2) + void serialEvent2() __attribute__((weak)); // called by main() -> name fixed + bool NeoSerial2_available() __attribute__((weak)); +#endif + +#if defined(HAVE_HWSERIAL3) + void serialEvent3() __attribute__((weak)); // called by main() -> name fixed + bool NeoSerial3_available() __attribute__((weak)); +#endif + +void serialEventRun(void) // called by main() -> name fixed { +#if defined(HAVE_HWSERIAL0) + if (NeoSerial0_available && serialEvent && NeoSerial0_available()) serialEvent(); +#endif +#if defined(HAVE_HWSERIAL1) + if (NeoSerial1_available && serialEvent1 && NeoSerial1_available()) serialEvent1(); +#endif +#if defined(HAVE_HWSERIAL2) + if (NeoSerial2_available && serialEvent2 && NeoSerial2_available()) serialEvent2(); +#endif +#if defined(HAVE_HWSERIAL3) + if (NeoSerial3_available && serialEvent3 && NeoSerial3_available()) serialEvent3(); +#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 NeoHWSerial::_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]; @@ -49,8 +100,14 @@ void NeoHWSerial::_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 - sbi(*_ucsra, 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 @@ -58,6 +115,7 @@ void NeoHWSerial::_tx_udr_empty_irq(void) } } + // Public Methods ////////////////////////////////////////////////////////////// void NeoHWSerial::begin(unsigned long baud, byte config) @@ -88,7 +146,7 @@ void NeoHWSerial::begin(unsigned long baud, byte config) config |= 0x80; // select UCSRC register (shared with UBRRH) #endif *_ucsrc = config; - + sbi(*_ucsrb, RXEN0); sbi(*_ucsrb, TXEN0); sbi(*_ucsrb, RXCIE0); @@ -98,14 +156,13 @@ void NeoHWSerial::begin(unsigned long baud, byte config) void NeoHWSerial::end() { // wait for transmission of outgoing data - while (_tx_buffer_head != _tx_buffer_tail) - ; + flush(); cbi(*_ucsrb, RXEN0); cbi(*_ucsrb, TXEN0); cbi(*_ucsrb, RXCIE0); cbi(*_ucsrb, UDRIE0); - + // clear any received data _rx_buffer_head = _rx_buffer_tail; } @@ -138,15 +195,13 @@ int NeoHWSerial::read(void) int NeoHWSerial::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; } @@ -179,13 +234,27 @@ size_t NeoHWSerial::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; - sbi(*_ucsra, 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; - - // If the output buffer is full, there's nothing for it other than to + + // If the output buffer is full, there's nothing for it other than to // wait for the interrupt handler to empty it a bit while (i == _tx_buffer_tail) { if (bit_is_clear(SREG, SREG_I)) { @@ -194,17 +263,22 @@ size_t NeoHWSerial::write(uint8_t c) // interrupt has happened and call the handler to free up // space for us. if(bit_is_set(*_ucsra, UDRE0)) - _tx_udr_empty_irq(); + _tx_udr_empty_irq(); } else { // nop, the interrupt handler will free up space for us } } _tx_buffer[_tx_buffer_head] = c; - _tx_buffer_head = i; - - sbi(*_ucsrb, 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; + sbi(*_ucsrb, UDRIE0); + } + return 1; } @@ -212,8 +286,8 @@ void NeoHWSerial::attachInterrupt( isr_t fn ) { uint8_t oldSREG = SREG; cli(); - _isr = fn; + _isr = fn; SREG = oldSREG; } -#endif // whole file +#endif // HAVE_HWSERIAL0 || HAVE_HWSERIAL1 || HAVE_HWSERIAL2 || HAVE_HWSERIAL3 diff --git a/1.6.5r2/NeoHWSerial.h b/src/NeoHWSerial.h similarity index 81% rename from 1.6.5r2/NeoHWSerial.h rename to src/NeoHWSerial.h index 0606c65..c098725 100644 --- a/1.6.5r2/NeoHWSerial.h +++ b/src/NeoHWSerial.h @@ -20,6 +20,7 @@ Modified 14 August 2012 by Alarus Modified 3 December 2013 by Matthijs Kooijman Modified 2 November 2015 by SlashDev + Modified 31 October 2020 by Georg Icking-Konert */ #ifndef NeoHWSerial_h @@ -35,29 +36,34 @@ // 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 +// NeoHWSerial behave erratically. See https://github.com/arduino/Arduino/issues/2405 #if !defined(SERIAL_TX_BUFFER_SIZE) -#if (RAMEND < 1000) -#define SERIAL_TX_BUFFER_SIZE 16 -#else -#define SERIAL_TX_BUFFER_SIZE 64 -#endif + #if ((RAMEND - RAMSTART) < 1023) + #define SERIAL_TX_BUFFER_SIZE 16 + #else + #define SERIAL_TX_BUFFER_SIZE 64 + #endif #endif #if !defined(SERIAL_RX_BUFFER_SIZE) -#if (RAMEND < 1000) -#define SERIAL_RX_BUFFER_SIZE 16 -#else -#define SERIAL_RX_BUFFER_SIZE 64 -#endif + #if ((RAMEND - RAMSTART) < 1023) + #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; + typedef uint16_t tx_buffer_index_t; #else -typedef uint8_t tx_buffer_index_t; + typedef uint8_t tx_buffer_index_t; #endif #if (SERIAL_RX_BUFFER_SIZE>256) -typedef uint16_t rx_buffer_index_t; + typedef uint16_t rx_buffer_index_t; #else -typedef uint8_t rx_buffer_index_t; + typedef uint8_t rx_buffer_index_t; #endif // Define config for Serial.begin(baud, config); @@ -120,7 +126,7 @@ class NeoHWSerial : public Stream virtual int available(void); virtual int peek(void); virtual int read(void); - int availableForWrite(void); + virtual 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); } @@ -132,11 +138,12 @@ class NeoHWSerial : 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_udr_empty_irq(void); - typedef void (* isr_t)( uint8_t ); + typedef bool (* isr_t)( uint8_t d=0x00, uint8_t s=0x00 ); void attachInterrupt( isr_t fn ); void detachInterrupt() { attachInterrupt( (isr_t) NULL ); }; + private: isr_t _isr; @@ -161,4 +168,6 @@ class NeoHWSerial : public Stream #define HAVE_HWSERIAL3 #endif -#endif +extern void serialEventRun(void) __attribute__((weak)); // called by main() -> name fixed + +#endif // NeoHWSerial_h diff --git a/1.6.5r2/NeoHWSerial0.cpp b/src/NeoHWSerial0.cpp similarity index 57% rename from 1.6.5r2/NeoHWSerial0.cpp rename to src/NeoHWSerial0.cpp index 7ccd93d..b57adcd 100644 --- a/1.6.5r2/NeoHWSerial0.cpp +++ b/src/NeoHWSerial0.cpp @@ -21,11 +21,12 @@ Modified 14 August 2012 by Alarus Modified 3 December 2013 by Matthijs Kooijman Modified 2 November 2015 by SlashDev + Modified 31 October 2020 by Georg Icking-Konert */ #include "Arduino.h" -#include -#include +#include "NeoHWSerial.h" +#include "NeoHWSerial_private.h" // Each NeoHWSerial is defined in its own file, sine the linker pulls // in the entire file when any element inside is used. --gc-sections can @@ -37,38 +38,45 @@ #if defined(HAVE_HWSERIAL0) -#if defined(USART_RX_vect) - ISR(USART_RX_vect) -#elif defined(USART0_RX_vect) - ISR(USART0_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 NeoSerial" -#endif + #if defined(USART_RX_vect) + ISR(USART_RX_vect) + #elif defined(USART0_RX_vect) + ISR(USART0_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 NeoSerial" + #endif + { + NeoSerial._rx_complete_irq(); + } + + #if defined(UART0_UDRE_vect) + ISR(UART0_UDRE_vect) + #elif defined(UART_UDRE_vect) + ISR(UART_UDRE_vect) + #elif defined(USART0_UDRE_vect) + 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 Serial" + #endif { - NeoSerial._rx_complete_irq(); + NeoSerial._tx_udr_empty_irq(); } -#if defined(UART0_UDRE_vect) -ISR(UART0_UDRE_vect) -#elif defined(UART_UDRE_vect) -ISR(UART_UDRE_vect) -#elif defined(USART0_UDRE_vect) -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 Serial" -#endif -{ - NeoSerial._tx_udr_empty_irq(); -} + #if defined(UBRRH) && defined(UBRRL) + NeoHWSerial NeoSerial(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR); + #else + NeoHWSerial NeoSerial(&UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UCSR0C, &UDR0); + #endif -#if defined(UBRRH) && defined(UBRRL) - NeoHWSerial NeoSerial(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR); -#else - NeoHWSerial NeoSerial(&UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UCSR0C, &UDR0); -#endif + // Function that can be weakly referenced by serialEventRun to prevent + // pulling in this file if it's not otherwise used. + bool NeoSerial0_available() + { + return NeoSerial.available(); + } #endif // HAVE_HWSERIAL0 diff --git a/1.6.5r2/NeoHWSerial1.cpp b/src/NeoHWSerial1.cpp similarity index 63% rename from 1.6.5r2/NeoHWSerial1.cpp rename to src/NeoHWSerial1.cpp index f96165c..60f55a0 100644 --- a/1.6.5r2/NeoHWSerial1.cpp +++ b/src/NeoHWSerial1.cpp @@ -21,11 +21,12 @@ Modified 14 August 2012 by Alarus Modified 3 December 2013 by Matthijs Kooijman Modified 2 November 2015 by SlashDev + Modified 31 October 2020 by Georg Icking-Konert */ #include "Arduino.h" -#include -#include +#include "NeoHWSerial.h" +#include "NeoHWSerial_private.h" // Each NeoHWSerial is defined in its own file, sine the linker pulls // in the entire file when any element inside is used. --gc-sections can @@ -37,28 +38,35 @@ #if defined(HAVE_HWSERIAL1) -#if defined(UART1_RX_vect) -ISR(UART1_RX_vect) -#elif defined(USART1_RX_vect) -ISR(USART1_RX_vect) -#else -#error "Don't know what the Data Register Empty vector is called for Serial1" -#endif -{ - NeoSerial1._rx_complete_irq(); -} + #if defined(UART1_RX_vect) + ISR(UART1_RX_vect) + #elif defined(USART1_RX_vect) + ISR(USART1_RX_vect) + #else + #error "Don't know what the Data Register Empty vector is called for Serial1" + #endif + { + NeoSerial1._rx_complete_irq(); + } -#if defined(UART1_UDRE_vect) -ISR(UART1_UDRE_vect) -#elif defined(USART1_UDRE_vect) -ISR(USART1_UDRE_vect) -#else -#error "Don't know what the Data Register Empty vector is called for Serial1" -#endif -{ - NeoSerial1._tx_udr_empty_irq(); -} + #if defined(UART1_UDRE_vect) + ISR(UART1_UDRE_vect) + #elif defined(USART1_UDRE_vect) + ISR(USART1_UDRE_vect) + #else + #error "Don't know what the Data Register Empty vector is called for Serial1" + #endif + { + NeoSerial1._tx_udr_empty_irq(); + } -NeoHWSerial NeoSerial1(&UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1); + NeoHWSerial NeoSerial1(&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. + bool NeoSerial1_available() + { + return NeoSerial1.available(); + } #endif // HAVE_HWSERIAL1 diff --git a/1.6.5r2/NeoHWSerial2.cpp b/src/NeoHWSerial2.cpp similarity index 75% rename from 1.6.5r2/NeoHWSerial2.cpp rename to src/NeoHWSerial2.cpp index f51a1ce..367caa5 100644 --- a/1.6.5r2/NeoHWSerial2.cpp +++ b/src/NeoHWSerial2.cpp @@ -21,11 +21,12 @@ Modified 14 August 2012 by Alarus Modified 3 December 2013 by Matthijs Kooijman Modified 2 November 2015 by SlashDev + Modified 31 October 2020 by Georg Icking-Konert */ #include "Arduino.h" -#include -#include +#include "NeoHWSerial.h" +#include "NeoHWSerial_private.h" // Each NeoHWSerial is defined in its own file, sine the linker pulls // in the entire file when any element inside is used. --gc-sections can @@ -37,16 +38,23 @@ #if defined(HAVE_HWSERIAL2) -ISR(USART2_RX_vect) -{ - NeoSerial2._rx_complete_irq(); -} + ISR(USART2_RX_vect) + { + NeoSerial2._rx_complete_irq(); + } -ISR(USART2_UDRE_vect) -{ - NeoSerial2._tx_udr_empty_irq(); -} + ISR(USART2_UDRE_vect) + { + NeoSerial2._tx_udr_empty_irq(); + } -NeoHWSerial NeoSerial2(&UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2); + NeoHWSerial NeoSerial2(&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. + bool NeoSerial2_available() + { + return NeoSerial2.available(); + } #endif // HAVE_HWSERIAL2 diff --git a/1.6.5r2/NeoHWSerial3.cpp b/src/NeoHWSerial3.cpp similarity index 75% rename from 1.6.5r2/NeoHWSerial3.cpp rename to src/NeoHWSerial3.cpp index 783f148..8b2ab1a 100644 --- a/1.6.5r2/NeoHWSerial3.cpp +++ b/src/NeoHWSerial3.cpp @@ -21,11 +21,12 @@ Modified 14 August 2012 by Alarus Modified 3 December 2013 by Matthijs Kooijman Modified 2 November 2015 by SlashDev + Modified 31 October 2020 by Georg Icking-Konert */ #include "Arduino.h" -#include -#include +#include "NeoHWSerial.h" +#include "NeoHWSerial_private.h" // Each NeoHWSerial is defined in its own file, sine the linker pulls // in the entire file when any element inside is used. --gc-sections can @@ -37,16 +38,23 @@ #if defined(HAVE_HWSERIAL3) -ISR(USART3_RX_vect) -{ - NeoSerial3._rx_complete_irq(); -} + ISR(USART3_RX_vect) + { + NeoSerial3._rx_complete_irq(); + } -ISR(USART3_UDRE_vect) -{ - NeoSerial3._tx_udr_empty_irq(); -} + ISR(USART3_UDRE_vect) + { + NeoSerial3._tx_udr_empty_irq(); + } -NeoHWSerial NeoSerial3(&UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3); + NeoHWSerial NeoSerial3(&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. + bool NeoSerial3_available() + { + return NeoSerial3.available(); + } #endif // HAVE_HWSERIAL3 diff --git a/1.6.5r2/NeoHWSerial_private.h b/src/NeoHWSerial_private.h similarity index 64% rename from 1.6.5r2/NeoHWSerial_private.h rename to src/NeoHWSerial_private.h index 816e6e3..072b2fd 100644 --- a/1.6.5r2/NeoHWSerial_private.h +++ b/src/NeoHWSerial_private.h @@ -20,11 +20,12 @@ Modified 28 September 2010 by Mark Sproul Modified 14 August 2012 by Alarus Modified 2 November 2015 by SlashDev + Modified 31 October 2020 by Georg Icking-Konert */ #include "wiring_private.h" -// this next line disables the entire HardwareSerial.cpp, +// this next line disables the entire HardwareSerial.cpp, // this is so I can support Attiny series and any other chip without a uart #if defined(HAVE_HWSERIAL0) || defined(HAVE_HWSERIAL1) || defined(HAVE_HWSERIAL2) || defined(HAVE_HWSERIAL3) @@ -34,34 +35,34 @@ // HardwareSerial constructor also works, but makes the code bigger and // 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 -#define TXEN0 TXEN -#define RXCIE0 RXCIE -#define UDRIE0 UDRIE -#define U2X0 U2X -#define UPE0 UPE -#define UDRE0 UDRE -#elif defined(TXC1) -// Some devices have uart1 but no uart0 -#define TXC0 TXC1 -#define RXEN0 RXEN1 -#define TXEN0 TXEN1 -#define RXCIE0 RXCIE1 -#define UDRIE0 UDRIE1 -#define U2X0 U2X1 -#define UPE0 UPE1 -#define UDRE0 UDRE1 -#else -#error No UART found in NeoHWSerial.cpp -#endif + #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 + #define TXEN0 TXEN + #define RXCIE0 RXCIE + #define UDRIE0 UDRIE + #define U2X0 U2X + #define UPE0 UPE + #define UDRE0 UDRE + #elif defined(TXC1) + // Some devices have uart1 but no uart0 + #define TXC0 TXC1 + #define RXEN0 RXEN1 + #define TXEN0 TXEN1 + #define RXCIE0 RXCIE1 + #define UDRIE0 UDRIE1 + #define U2X0 U2X1 + #define UPE0 UPE1 + #define UDRE0 UDRE1 + #else + #error No UART found in NeoHWSerial.cpp + #endif // defined(TXC) #endif // !defined TXC0 // Check at compiletime that it is really ok to use the bit positions of @@ -70,17 +71,17 @@ #if defined(TXC1) && (TXC1 != TXC0 || RXEN1 != RXEN0 || RXCIE1 != RXCIE0 || \ UDRIE1 != UDRIE0 || U2X1 != U2X0 || UPE1 != UPE0 || \ UDRE1 != UDRE0) -#error "Not all bit positions for UART1 are the same as for UART0" + #error "Not all bit positions for UART1 are the same as for UART0" #endif #if defined(TXC2) && (TXC2 != TXC0 || RXEN2 != RXEN0 || RXCIE2 != RXCIE0 || \ UDRIE2 != UDRIE0 || U2X2 != U2X0 || UPE2 != UPE0 || \ UDRE2 != UDRE0) -#error "Not all bit positions for UART2 are the same as for UART0" + #error "Not all bit positions for UART2 are the same as for UART0" #endif #if defined(TXC3) && (TXC3 != TXC0 || RXEN3 != RXEN0 || RXCIE3 != RXCIE0 || \ UDRIE3 != UDRIE0 || U3X3 != U3X0 || UPE3 != UPE0 || \ UDRE3 != UDRE0) -#error "Not all bit positions for UART3 are the same as for UART0" + #error "Not all bit positions for UART3 are the same as for UART0" #endif // Constructors //////////////////////////////////////////////////////////////// @@ -94,21 +95,29 @@ NeoHWSerial::NeoHWSerial( _udr(udr), _rx_buffer_head(0), _rx_buffer_tail(0), _tx_buffer_head(0), _tx_buffer_tail(0), - _isr(0) + _isr(NULL) { } // Actual interrupt handlers ////////////////////////////////////////////////////////////// -void NeoHWSerial::_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; - if (_isr) - _isr( c ); - else { +void NeoHWSerial::_rx_complete_irq(void) { + + volatile bool saveToBuffer = true; + + // user receive function was attached -> call it with data and status byte + if (_isr) { + unsigned char status = *_ucsra; + unsigned char data = *_udr; + saveToBuffer = _isr( data, status ); + } + + // default: save data in ring buffer + if (saveToBuffer) { + 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 @@ -120,10 +129,11 @@ void NeoHWSerial::_rx_complete_irq(void) _rx_buffer_head = i; } } - } else { - // Parity error, read byte but discard it - *_udr; - }; + else { + // Parity error, read byte but discard it + *_udr; + } + } // if saveToBuffer } -#endif // whole file +#endif // HAVE_HWSERIAL0 || HAVE_HWSERIAL1 || HAVE_HWSERIAL2 || HAVE_HWSERIAL3 From 14c5daee3a60a57f0c0ce95513e008c25e9b34ec Mon Sep 17 00:00:00 2001 From: gicking Date: Fri, 25 Oct 2024 07:57:27 +0200 Subject: [PATCH 02/36] fixed index bug in storing data to ring buffer --- .gitattributes | 17 -- .gitignore | 0 LICENSE | 0 README.md | 9 +- .../LIN_sniffer/LIN_master/LIN_master.ino | 63 ++++++ examples/LIN_sniffer/LIN_sniffer.ino | 212 ++++++++++++++++++ examples/detect_BRK/detect_BRK.ino | 109 +++++++++ examples/echo/echo.ino | 4 +- keywords.txt | 0 library.properties | 2 +- src/NeoHWSerial.cpp | 0 src/NeoHWSerial.h | 3 +- src/NeoHWSerial0.cpp | 0 src/NeoHWSerial1.cpp | 0 src/NeoHWSerial2.cpp | 0 src/NeoHWSerial3.cpp | 0 src/NeoHWSerial_private.h | 22 +- 17 files changed, 404 insertions(+), 37 deletions(-) delete mode 100644 .gitattributes mode change 100644 => 100755 .gitignore mode change 100644 => 100755 LICENSE mode change 100644 => 100755 README.md create mode 100755 examples/LIN_sniffer/LIN_master/LIN_master.ino create mode 100755 examples/LIN_sniffer/LIN_sniffer.ino create mode 100644 examples/detect_BRK/detect_BRK.ino mode change 100644 => 100755 examples/echo/echo.ino mode change 100644 => 100755 keywords.txt mode change 100644 => 100755 library.properties mode change 100644 => 100755 src/NeoHWSerial.cpp mode change 100644 => 100755 src/NeoHWSerial.h mode change 100644 => 100755 src/NeoHWSerial0.cpp mode change 100644 => 100755 src/NeoHWSerial1.cpp mode change 100644 => 100755 src/NeoHWSerial2.cpp mode change 100644 => 100755 src/NeoHWSerial3.cpp mode change 100644 => 100755 src/NeoHWSerial_private.h diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index bdb0cab..0000000 --- a/.gitattributes +++ /dev/null @@ -1,17 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto - -# Custom for Visual Studio -*.cs diff=csharp - -# Standard to msysgit -*.doc diff=astextplain -*.DOC diff=astextplain -*.docx diff=astextplain -*.DOCX diff=astextplain -*.dot diff=astextplain -*.DOT diff=astextplain -*.pdf diff=astextplain -*.PDF diff=astextplain -*.rtf diff=astextplain -*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index dbf4c58..8a01570 --- a/README.md +++ b/README.md @@ -1,16 +1,15 @@ The **NeoHWSerial** class is a drop-in replacement for the Arduino built-in class `HardwareSerial`. It adds the capability to handle received characters with a user-defined function *during* the RX interrupt. This can improve performance significantly by eliminating all processing associated with storing and retrieving characters in the ring buffer **and** all polling code that constantly checked for new characters: `available` and `read` are unnecessary. Note: This is a minor update of [NeoHWSerial by SlashDevin](https://github.com/SlashDevin/NeoHWSerial) for AVR. Changes: - - updated to Arduino IDE >=v1.5.6 library format (see [here](https://arduino.github.io/arduino-cli/latest/library-specification/)) - - pass UART status byte to user receive function. Required e.g. for break detection in [LIN bus](https://en.wikipedia.org/wiki/Local_Interconnect_Network) + - updated library structure to Arduino IDE >=v1.5.6 library format (see [here](https://arduino.github.io/arduino-cli/latest/library-specification/)) + - pass UART status byte to user receive function. Required e.g. for break detection for [LIN bus](https://en.wikipedia.org/wiki/Local_Interconnect_Network) - support optional storing to ring buffer after return from user routine via return value ### Installation -1. Download the NeoHWSerial master zip file. -2. Extract all files into a tempory working directory. -3. Create a `NeoHWSerial` subdirectory in your `Arduino/libraries` directory. +This library can be installed via the library manager of the Arduino IDE. + ### Usage diff --git a/examples/LIN_sniffer/LIN_master/LIN_master.ino b/examples/LIN_sniffer/LIN_master/LIN_master.ino new file mode 100755 index 0000000..38b2234 --- /dev/null +++ b/examples/LIN_sniffer/LIN_master/LIN_master.ino @@ -0,0 +1,63 @@ +/* + Simple LIN 2.x master to generate frames for the LIN sniffer + Create alternating frames of lengths 8 and 2. +*/ + +// include files +#include "LIN_master3.h" // send LIN frames via Serial3 + +// pause between LIN frames +#define LIN_PAUSE 200 + + +void setup(void) +{ + // initialize LIN master (blocking operation) + LIN_master3.begin(19200, LIN_V2, false); + +} // setup() + + + +void loop(void) +{ + static uint32_t lastCall = LIN_PAUSE; + static uint8_t count = 0; + static uint8_t Tx[8] = {0,0,0,0,0,0,0,0}; // daty bytes + + + // simple LIN scheduler + if (millis() - lastCall > LIN_PAUSE) { + lastCall = millis(); + + // send frame 1 + if (count == 0) + { + // increase frame index + count++; + + // send master request + LIN_master3.sendMasterRequest(0x07, 8, Tx); + + // increase data_byte[0] + Tx[0]++; + + } + + // send frame 2 + else + { + // revert frame index + count = 0; + + // send master request + LIN_master3.sendMasterRequest(0x04, 2, Tx); + + // decrease data_byte[1] + Tx[1]--; + + } + + } // scheduler + +} // loop() diff --git a/examples/LIN_sniffer/LIN_sniffer.ino b/examples/LIN_sniffer/LIN_sniffer.ino new file mode 100755 index 0000000..1635b83 --- /dev/null +++ b/examples/LIN_sniffer/LIN_sniffer.ino @@ -0,0 +1,212 @@ +//////////////// +// INCLUDE LIBRARIES +//////////////// + +#include + + +//////////////// +// GLOBAL MACROS / DEFINES +//////////////// + +// LIN versions (required for checksum calculation) +#define LIN_V1 1 +#define LIN_V2 2 + + +//////////////// +// GLOBAL STRUCTS / TYPEDEFS +//////////////// + +// frame type +typedef struct +{ + int numData; // number of data bytes + + union + { + uint8_t bufRx[12]; // raw frame: BRK, SYNC, ID, DATA0..8, CHK + + // access to individual bytes by name + struct + { + uint8_t BRK; // sync break (always 0x00) + uint8_t SYNC; // sync field (always 0x55) + uint8_t ID; // frame ID + uint8_t DATA[8]; // data bytes (max. 8) + uint8_t CHK; // frame checksum + }; + + }; + +} frame_t; + + +//////////////// +// GLOBAL VARIABLES +//////////////// + +// global frame buffer +frame_t frame; + +// flag to indicate that frame was received. Set in Serial Rx-ISR on reception of next BRK +bool flagFrame = false; + + +//////////////// +// GLOBAL FUNCTIONS +//////////////// + +///////////////////// +// calculate the LIN frame checksum +// note: checksum is different for v1.x and v2.x; exceptions are diagnostic frames which use v1.x checksum +///////////////////// +uint8_t LIN_checksum(uint8_t version, uint8_t id, uint8_t numData, uint8_t *data) +{ + uint16_t chk=0x00; + + // LIN2.x uses extended checksum which includes protected ID, i.e. including parity bits + // LIN1.x uses classical checksum only over data bytes + // Diagnostic frames with ID 0x3C and 0x3D/0x7D always use classical checksum (see LIN spec "2.3.1.5 Checkum") + if (!((version == LIN_V1) || (id == 0x3C) || (id == 0x7D))) // if version 2 & no diagnostic frames (0x3C=60 (PID=0x3C) or 0x3D=61 (PID=0x7D)) + chk = (uint16_t) id; + + // loop over data bytes + for (uint8_t i = 0; i < numData; i++) + { + chk += (uint16_t) (data[i]); + if (chk>255) + chk -= 255; + } + chk = (uint8_t)(0xFF - ((uint8_t) chk)); // bitwise invert + + // return frame checksum + return chk; + +} // LIN_checksum() + + + +///////////////////// +// custom Serial receive interrupt function +///////////////////// +static bool ISR_Rx( uint8_t rx, uint8_t UCSRA ) +{ + static uint8_t idx = 0; // byte index in frame + static uint8_t Rx[12]; + + // check for LIN sync break (=0x00 with framing error) + if ((rx == 0x00) && (UCSRA & (1< set flag. Skip for first frame + if (frame.BRK != 0xFF) + flagFrame = true; + + // copy previous frame to global variables to avoid conflict + frame.numData = (int) idx - 3; + memcpy(frame.bufRx, Rx, 12); + frame.CHK = Rx[idx]; + + // reset byte index in frame + idx=0; + + } // sync break received + + + // normal frame bytes -> just increase byte index in frame + else + { + // avoid buffer overrun + if (idx<11) + idx++; + + } // normal frame bytes + + + // copy received byte to local buffer + Rx[idx] = rx; + + // do not store received data to Serial ring buffer + return false; + +} // ISR_Rx() + + + +///////////////////// +// initialization +///////////////////// +void setup() +{ + // initialize BRK to 0xFF to indicate 1st frame + frame.BRK = 0xFF; + + // initilize PC connection + NeoSerial.begin(115200); + + // initialize LIN interface + NeoSerial2.begin(19200); + + // attach protocol handler to used Serial + NeoSerial2.attachInterrupt( ISR_Rx ); + +} // setup() + + + +///////////////////// +// main loop +///////////////////// +void loop() +{ + // a LIN frame was received --> handle it + if (flagFrame) + { + // handle each frame only once + flagFrame = false; + + // check sync break (must be 0x00 w/ framing error) + if (frame.BRK != 0x00) + { + NeoSerial.print("error: wrong BRK, expect 0x00, read 0x"); + NeoSerial.println((int) (frame.BRK), HEX); + } + + // check sync field (must be 0x55) + else if (frame.SYNC != 0x55) + { + NeoSerial.print("error: wrong SYNC, expect 0x55, read 0x"); + NeoSerial.println((int) (frame.SYNC), HEX); + } + + // check frame checksum (different for LIN v1.x and v2.x!) + else if (frame.CHK != LIN_checksum(LIN_V2, frame.ID, frame.numData, frame.DATA)) + { + NeoSerial.print("error: checksum error, expect 0x"); + NeoSerial.print((int) (LIN_checksum(LIN_V2, frame.ID, frame.numData, frame.DATA)), HEX); + NeoSerial.print(", read 0x"); + NeoSerial.println((int) (frame.CHK), HEX); + } + + // no error -> handle frame (here only print) + else { + + // print ID + NeoSerial.print("ID:"); + NeoSerial.print((int) frame.ID, HEX); + NeoSerial.print(" "); + + // print data bytes + NeoSerial.print("DATA:"); + for (int i=0; i + + +//////////////// +// GLOBAL VARIABLES +//////////////// + +// flag to indicate a BRK (set in rx_handler()) +bool BRK = false; + + +//////////////// +// GLOBAL FUNCTIONS +//////////////// + +///////////////////// +// custom Serial receive interrupt handler +///////////////////// +bool rx_handler(uint8_t byte, uint8_t status) +{ + // avoid compiler warnings + (void)(byte); + (void)(status); + + // check for framing error + BRK = (bool) (status & (1< byte is stored in Serial buffer + return true; + +} // rx_handler() + + +///////////////////// +// initialization +///////////////////// +void setup() +{ + // serial console + NeoSerial.begin(115200); + + // sender + NeoSerial1.begin(19200); + + // receiver + NeoSerial2.begin(19200); + NeoSerial2.attachInterrupt(rx_handler); + +} // setup() + + +///////////////////// +// main loop +///////////////////// +void loop() { + + uint8_t c; + + // send BRK via Serial1 (0x00 w/o stop bit) + NeoSerial1.begin(9600); + NeoSerial1.write(0x00); + NeoSerial1.flush(); + + // receive BRK via Serial2 + c = NeoSerial2.read(); + NeoSerial.print("loop: Rx=0x"); + NeoSerial.print(c, HEX); + if (BRK) + NeoSerial.print(", BRK"); + NeoSerial.println(); + BRK = false; + + // send SYNC via Serial1 (0x55) + NeoSerial1.begin(19200); + NeoSerial1.write(0x55); + NeoSerial1.flush(); + + // receive BRK via Serial2 + c = NeoSerial2.read(); + NeoSerial.print("loop: Rx=0x"); + NeoSerial.print(c, HEX); + if (BRK) + NeoSerial.print(", BRK"); + NeoSerial.println("\n"); + BRK = false; + + // wait some time + delay(2000); + +} // loop() diff --git a/examples/echo/echo.ino b/examples/echo/echo.ino old mode 100644 new mode 100755 index 5cc7629..be540e4 --- a/examples/echo/echo.ino +++ b/examples/echo/echo.ino @@ -1,10 +1,10 @@ -#include - // // Example program to show how to attach to the received character // interrupt with NeoHWSerial. // +#include + static volatile uint16_t ISR_count = 0; static bool char_received( uint8_t c, uint8_t status ) diff --git a/keywords.txt b/keywords.txt old mode 100644 new mode 100755 diff --git a/library.properties b/library.properties old mode 100644 new mode 100755 index d9e863f..6be6f6d --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=NeoHWSerial -version=1.6.6 +version=1.6.7 author=Georg Icking-Konert maintainer=Georg Icking-Konert sentence=NeoHWSerial for AVR diff --git a/src/NeoHWSerial.cpp b/src/NeoHWSerial.cpp old mode 100644 new mode 100755 diff --git a/src/NeoHWSerial.h b/src/NeoHWSerial.h old mode 100644 new mode 100755 index c098725..bccd7ae --- a/src/NeoHWSerial.h +++ b/src/NeoHWSerial.h @@ -140,7 +140,8 @@ class NeoHWSerial : public Stream inline void _rx_complete_irq(void); inline void _tx_udr_empty_irq(void); - typedef bool (* isr_t)( uint8_t d=0x00, uint8_t s=0x00 ); + typedef bool (* isr_t)( uint8_t d, uint8_t s ); + //typedef bool (* isr_t)( uint8_t d=0x00, uint8_t s=0x00 ); void attachInterrupt( isr_t fn ); void detachInterrupt() { attachInterrupt( (isr_t) NULL ); }; diff --git a/src/NeoHWSerial0.cpp b/src/NeoHWSerial0.cpp old mode 100644 new mode 100755 diff --git a/src/NeoHWSerial1.cpp b/src/NeoHWSerial1.cpp old mode 100644 new mode 100755 diff --git a/src/NeoHWSerial2.cpp b/src/NeoHWSerial2.cpp old mode 100644 new mode 100755 diff --git a/src/NeoHWSerial3.cpp b/src/NeoHWSerial3.cpp old mode 100644 new mode 100755 diff --git a/src/NeoHWSerial_private.h b/src/NeoHWSerial_private.h old mode 100644 new mode 100755 index 072b2fd..f7e1d06 --- a/src/NeoHWSerial_private.h +++ b/src/NeoHWSerial_private.h @@ -104,20 +104,20 @@ NeoHWSerial::NeoHWSerial( void NeoHWSerial::_rx_complete_irq(void) { volatile bool saveToBuffer = true; + volatile unsigned char status, data; // user receive function was attached -> call it with data and status byte - if (_isr) { - unsigned char status = *_ucsra; - unsigned char data = *_udr; + if (_isr){ + status = *_ucsra; + data = *_udr; saveToBuffer = _isr( data, status ); } // default: save data in ring buffer if (saveToBuffer) { + + // No Parity error, read byte and store it in the buffer if there is room 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 @@ -125,14 +125,14 @@ void NeoHWSerial::_rx_complete_irq(void) { // 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[_rx_buffer_head] = data; _rx_buffer_head = i; } } - else { - // Parity error, read byte but discard it - *_udr; - } + + // Parity error, don't do anything (data is dropped) + else { } + } // if saveToBuffer } From 19b354d83f2a964590fa11297c006b027fe3ddad Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 13:57:46 +0100 Subject: [PATCH 03/36] Create compile_examples.yml --- .github/workflows/compile_examples.yml | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/compile_examples.yml diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml new file mode 100644 index 0000000..a4ef241 --- /dev/null +++ b/.github/workflows/compile_examples.yml @@ -0,0 +1,28 @@ +name: Compile Sketch + +# The workflow will run on every push and pull request to the repository +on: + - push + - pull_request + +jobs: + compile-sketch: + runs-on: ubuntu-latest + + steps: + # This step makes the contents of the repository available to the workflow + - name: Checkout repository + uses: actions/checkout@v4 + + # For more information: https://github.com/arduino/compile-sketches#readme + - name: Compile sketch + uses: arduino/compile-sketches@v1 + with: + # The default is to compile for the Arduino Uno board. If you want to compile for other boards, use the `fqbn` input. + sketch-paths: | + # Configure the action to search all folders under the root of the repository for sketches and compile them. + # This is formatted as a YAML list, which makes it possible to have multiple sketch paths if needed. + - ./ + libraries: | + # The "blink" sketch being compiled in this demo doesn't use any libraries, so just use an empty list + - From 3a39a0fc8b9c317fe65828ae8a59a91e398b9f76 Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 14:07:10 +0100 Subject: [PATCH 04/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index a4ef241..ae2da91 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -12,13 +12,14 @@ jobs: steps: # This step makes the contents of the repository available to the workflow - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v4.2.2 # For more information: https://github.com/arduino/compile-sketches#readme - name: Compile sketch - uses: arduino/compile-sketches@v1 + uses: arduino/compile-sketches@v1.1.2 with: - # The default is to compile for the Arduino Uno board. If you want to compile for other boards, use the `fqbn` input. + fqbn: | + - arduino:avr:mega sketch-paths: | # Configure the action to search all folders under the root of the repository for sketches and compile them. # This is formatted as a YAML list, which makes it possible to have multiple sketch paths if needed. From 94675a9e8c97ee85fe02aeaa14a704ccce02e1e5 Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 14:12:22 +0100 Subject: [PATCH 05/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index ae2da91..cb14bc3 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -18,8 +18,9 @@ jobs: - name: Compile sketch uses: arduino/compile-sketches@v1.1.2 with: - fqbn: | - - arduino:avr:mega + verbose: true + enable-warnings-report: true + fqbn: arduino:avr:mega sketch-paths: | # Configure the action to search all folders under the root of the repository for sketches and compile them. # This is formatted as a YAML list, which makes it possible to have multiple sketch paths if needed. From c89cf9bee2008c8a44ca880d0643c707d6182afb Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 14:13:37 +0100 Subject: [PATCH 06/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index cb14bc3..43b233b 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -20,7 +20,7 @@ jobs: with: verbose: true enable-warnings-report: true - fqbn: arduino:avr:mega + fqbn: "arduino:avr:mega" sketch-paths: | # Configure the action to search all folders under the root of the repository for sketches and compile them. # This is formatted as a YAML list, which makes it possible to have multiple sketch paths if needed. From 8011e56d8ec94f6572e46736ec3d7f1bd9310826 Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 14:23:33 +0100 Subject: [PATCH 07/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index 43b233b..e4aa9f3 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -9,22 +9,28 @@ jobs: compile-sketch: runs-on: ubuntu-latest + # Sequence of steps / actions for CI steps: - # This step makes the contents of the repository available to the workflow + + # Makes content of this repository available to the workflow - name: Checkout repository + # action from marketplace (see right) uses: actions/checkout@v4.2.2 - # For more information: https://github.com/arduino/compile-sketches#readme + # Compile Arduino examples. See https://github.com/arduino/compile-sketches#readme - name: Compile sketch + # action from marketplace (see right). For docu see https://github.com/marketplace/actions/compile-arduino-sketches uses: arduino/compile-sketches@v1.1.2 + # options for action with: verbose: true enable-warnings-report: true - fqbn: "arduino:avr:mega" + # Specify all bards to compile for. Get qualifier via "arduino-cli board listall" in terminal + fqbn: | + - "arduino:avr:mega" + # Compile all Arduino examples sketch-paths: | - # Configure the action to search all folders under the root of the repository for sketches and compile them. - # This is formatted as a YAML list, which makes it possible to have multiple sketch paths if needed. - - ./ + - ./examples + # Add required libraries (including the repo's) libraries: | - # The "blink" sketch being compiled in this demo doesn't use any libraries, so just use an empty list - - + - https://github.com/gicking/NeoHWSerial From 2c72094c15cf7c759081db6604bc10531cd9cd0a Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 14:25:38 +0100 Subject: [PATCH 08/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index e4aa9f3..9127c0d 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -26,8 +26,7 @@ jobs: verbose: true enable-warnings-report: true # Specify all bards to compile for. Get qualifier via "arduino-cli board listall" in terminal - fqbn: | - - "arduino:avr:mega" + fqbn: "arduino:avr:mega" # Compile all Arduino examples sketch-paths: | - ./examples From eeb3b22a81df644186a5f0d1385484b6bf98c862 Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 14:36:34 +0100 Subject: [PATCH 09/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index 9127c0d..34b7edd 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -1,9 +1,7 @@ -name: Compile Sketch +name: Compile Examples # The workflow will run on every push and pull request to the repository -on: - - push - - pull_request +on: [push, pull_request] jobs: compile-sketch: @@ -15,21 +13,20 @@ jobs: # Makes content of this repository available to the workflow - name: Checkout repository # action from marketplace (see right) - uses: actions/checkout@v4.2.2 + uses: actions/checkout@master # Compile Arduino examples. See https://github.com/arduino/compile-sketches#readme - name: Compile sketch # action from marketplace (see right). For docu see https://github.com/marketplace/actions/compile-arduino-sketches - uses: arduino/compile-sketches@v1.1.2 + uses: arduino/compile-sketches@master # options for action with: verbose: true enable-warnings-report: true # Specify all bards to compile for. Get qualifier via "arduino-cli board listall" in terminal - fqbn: "arduino:avr:mega" + fqbn: arduino:avr:mega # Compile all Arduino examples - sketch-paths: | - - ./examples + sketch-paths: ./examples # Add required libraries (including the repo's) libraries: | - https://github.com/gicking/NeoHWSerial From f63e08e47b0dfd70d00167fb728f91c1a3b11a4d Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 14:39:05 +0100 Subject: [PATCH 10/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index 34b7edd..6242e7b 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -13,12 +13,12 @@ jobs: # Makes content of this repository available to the workflow - name: Checkout repository # action from marketplace (see right) - uses: actions/checkout@master + uses: actions/checkout@latest # Compile Arduino examples. See https://github.com/arduino/compile-sketches#readme - name: Compile sketch # action from marketplace (see right). For docu see https://github.com/marketplace/actions/compile-arduino-sketches - uses: arduino/compile-sketches@master + uses: arduino/compile-sketches@latest # options for action with: verbose: true From c78e34a092d1cb1914bfd5ad8e2a60184fb03df3 Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 14:41:19 +0100 Subject: [PATCH 11/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index 6242e7b..7019cb5 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -13,12 +13,12 @@ jobs: # Makes content of this repository available to the workflow - name: Checkout repository # action from marketplace (see right) - uses: actions/checkout@latest + uses: actions/checkout@v4.2.2 # Compile Arduino examples. See https://github.com/arduino/compile-sketches#readme - name: Compile sketch # action from marketplace (see right). For docu see https://github.com/marketplace/actions/compile-arduino-sketches - uses: arduino/compile-sketches@latest + uses: arduino/compile-sketches@v1.1.2 # options for action with: verbose: true From 3c351a7f3fb6a321349f843cb30fde6b7abdccd7 Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 15:36:51 +0100 Subject: [PATCH 12/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 41 +++++++++++--------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index 7019cb5..9930cd6 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -1,32 +1,27 @@ -name: Compile Examples +name: Build Examples -# The workflow will run on every push and pull request to the repository -on: [push, pull_request] +on: + push: + branches: + - main + pull_request: + branches: + - main jobs: - compile-sketch: + build: runs-on: ubuntu-latest - # Sequence of steps / actions for CI steps: + - name: Checkout code + uses: actions/checkout@latest - # Makes content of this repository available to the workflow - - name: Checkout repository - # action from marketplace (see right) - uses: actions/checkout@v4.2.2 + - name: Set up Arduino CLI + uses: arduino/setup-cli@latest - # Compile Arduino examples. See https://github.com/arduino/compile-sketches#readme - - name: Compile sketch - # action from marketplace (see right). For docu see https://github.com/marketplace/actions/compile-arduino-sketches - uses: arduino/compile-sketches@v1.1.2 - # options for action + - name: Compile All Example Sketches + uses: arduino/compile-sketches@latest with: - verbose: true - enable-warnings-report: true - # Specify all bards to compile for. Get qualifier via "arduino-cli board listall" in terminal - fqbn: arduino:avr:mega - # Compile all Arduino examples - sketch-paths: ./examples - # Add required libraries (including the repo's) - libraries: | - - https://github.com/gicking/NeoHWSerial + board: arduino:avr:mega + sketch: ./examples + From 01c93ce4ceb5adb807ed44af81575ff299c03e06 Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 15:39:25 +0100 Subject: [PATCH 13/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index 9930cd6..43cea08 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -1,12 +1,6 @@ name: Build Examples -on: - push: - branches: - - main - pull_request: - branches: - - main +on: [push, pull_request] jobs: build: @@ -23,5 +17,5 @@ jobs: uses: arduino/compile-sketches@latest with: board: arduino:avr:mega - sketch: ./examples + sketch: examples From 5a2d8c07604dd392d3093bdb375906dbbdf566af Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 15:41:37 +0100 Subject: [PATCH 14/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index 43cea08..f2b3dc7 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -8,7 +8,8 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@latest + uses: actions/checkout@Latest + #v4.2.2 - name: Set up Arduino CLI uses: arduino/setup-cli@latest From 38e3529235968221ecf8b03423743cae17b28ae8 Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 15:42:25 +0100 Subject: [PATCH 15/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index f2b3dc7..2d75fe5 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -8,8 +8,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@Latest - #v4.2.2 + uses: actions/checkout@v4.2.2 - name: Set up Arduino CLI uses: arduino/setup-cli@latest From a5ba841a3d51f673cc16fc90cda56c537363a3c7 Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 15:44:56 +0100 Subject: [PATCH 16/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index 2d75fe5..5c11808 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -14,7 +14,7 @@ jobs: uses: arduino/setup-cli@latest - name: Compile All Example Sketches - uses: arduino/compile-sketches@latest + uses: arduino/compile-sketches@v1.1.2 with: board: arduino:avr:mega sketch: examples From 2fc2bfc4107f61a154887c76c4031453e9c843bd Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 15:48:55 +0100 Subject: [PATCH 17/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index 5c11808..7a49f69 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -9,13 +9,16 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4.2.2 - + - name: Set up Arduino CLI - uses: arduino/setup-cli@latest + uses: arduino/setup-arduino-cli@v2.0.0 - - name: Compile All Example Sketches + - name: Compile Examples uses: arduino/compile-sketches@v1.1.2 with: board: arduino:avr:mega sketch: examples - + +# - name: Compile examples +# run: | +# arduino-cli compile --fqbn arduino:avr:mega --build-path examples --verbose From 83c19c77f637ae0b478ee88c0cc06a0946e9d814 Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 15:52:23 +0100 Subject: [PATCH 18/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index 7a49f69..80494e9 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -13,12 +13,12 @@ jobs: - name: Set up Arduino CLI uses: arduino/setup-arduino-cli@v2.0.0 - - name: Compile Examples - uses: arduino/compile-sketches@v1.1.2 - with: - board: arduino:avr:mega - sketch: examples +# - name: Compile Examples +# uses: arduino/compile-sketches@v1.1.2 +# with: +# board: arduino:avr:mega +# sketch: examples -# - name: Compile examples -# run: | -# arduino-cli compile --fqbn arduino:avr:mega --build-path examples --verbose + - name: Compile examples + run: | + arduino-cli compile --fqbn arduino:avr:mega --build-path examples --verbose From a69a157b39352062ad5abc6934eafe5ca15adf26 Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 16:02:48 +0100 Subject: [PATCH 19/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 44 +++++++++++++++++++------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index 80494e9..eecc0af 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -4,21 +4,41 @@ on: [push, pull_request] jobs: build: + name: ${{ matrix.board.fqbn }} runs-on: ubuntu-latest + strategy: + fail-fast: false + + matrix: + board: + - fqbn: arduino:avr:nano + platforms: | + - name: arduino:avr + artifact-name-suffix: arduino-avr-nano + - fqbn: arduino:avr:mega + platforms: | + - name: arduino:avr + artifact-name-suffix: arduino-avr-mega + - fqbn: arduino:avr:leonardo + platforms: | + - name: arduino:avr + artifact-name-suffix: arduino-avr-leonardo + steps: - - name: Checkout code + - name: Checkout repository uses: actions/checkout@v4.2.2 - - - name: Set up Arduino CLI - uses: arduino/setup-arduino-cli@v2.0.0 - -# - name: Compile Examples -# uses: arduino/compile-sketches@v1.1.2 -# with: -# board: arduino:avr:mega -# sketch: examples - name: Compile examples - run: | - arduino-cli compile --fqbn arduino:avr:mega --build-path examples --verbose + uses: arduino/compile-sketches@v1.1.2 + with: + fqbn: ${{ matrix.board.fqbn }} + platforms: ${{ matrix.board.platforms }} + libraries: | + # Install the library from the local path. + - source-path: ./ + # Additional library dependencies can be listed here. + # See: https://github.com/arduino/compile-sketches#libraries + sketch-paths: | + - examples + enable-deltas-report: true From d123ecdde0a7070357b9f141dc3691e47adbd5bd Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 16:06:55 +0100 Subject: [PATCH 20/36] Update compile_examples.yml --- .github/workflows/compile_examples.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml index eecc0af..682c737 100644 --- a/.github/workflows/compile_examples.yml +++ b/.github/workflows/compile_examples.yml @@ -37,8 +37,8 @@ jobs: libraries: | # Install the library from the local path. - source-path: ./ - # Additional library dependencies can be listed here. - # See: https://github.com/arduino/compile-sketches#libraries + # Additional library dependencies can be listed here. See https://github.com/arduino/compile-sketches#libraries + - https://github.com/gicking/LIN_master_Arduino sketch-paths: | - examples enable-deltas-report: true From eb8befa9b3d9f9894a602603b74c41a68e1ed975 Mon Sep 17 00:00:00 2001 From: gicking Date: Tue, 29 Oct 2024 16:11:29 +0100 Subject: [PATCH 21/36] Test CI --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 96374c4..1b9ee8e 100755 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,6 @@ $RECYCLE.BIN/ Network Trash Folder Temporary Items .apdisk + +# Misc +.development From bc519ba6f86662ad9d095f1ab88a8df72bd48ca5 Mon Sep 17 00:00:00 2001 From: gicking Date: Tue, 29 Oct 2024 16:12:42 +0100 Subject: [PATCH 22/36] xxx --- .../LIN_sniffer/LIN_master/LIN_master.ino | 63 ------------------- 1 file changed, 63 deletions(-) delete mode 100755 examples/LIN_sniffer/LIN_master/LIN_master.ino diff --git a/examples/LIN_sniffer/LIN_master/LIN_master.ino b/examples/LIN_sniffer/LIN_master/LIN_master.ino deleted file mode 100755 index 38b2234..0000000 --- a/examples/LIN_sniffer/LIN_master/LIN_master.ino +++ /dev/null @@ -1,63 +0,0 @@ -/* - Simple LIN 2.x master to generate frames for the LIN sniffer - Create alternating frames of lengths 8 and 2. -*/ - -// include files -#include "LIN_master3.h" // send LIN frames via Serial3 - -// pause between LIN frames -#define LIN_PAUSE 200 - - -void setup(void) -{ - // initialize LIN master (blocking operation) - LIN_master3.begin(19200, LIN_V2, false); - -} // setup() - - - -void loop(void) -{ - static uint32_t lastCall = LIN_PAUSE; - static uint8_t count = 0; - static uint8_t Tx[8] = {0,0,0,0,0,0,0,0}; // daty bytes - - - // simple LIN scheduler - if (millis() - lastCall > LIN_PAUSE) { - lastCall = millis(); - - // send frame 1 - if (count == 0) - { - // increase frame index - count++; - - // send master request - LIN_master3.sendMasterRequest(0x07, 8, Tx); - - // increase data_byte[0] - Tx[0]++; - - } - - // send frame 2 - else - { - // revert frame index - count = 0; - - // send master request - LIN_master3.sendMasterRequest(0x04, 2, Tx); - - // decrease data_byte[1] - Tx[1]--; - - } - - } // scheduler - -} // loop() From 0ec3e9000059c8d175d45239d3ca4edf8f498801 Mon Sep 17 00:00:00 2001 From: gicking Date: Tue, 29 Oct 2024 16:15:13 +0100 Subject: [PATCH 23/36] test CI --- .../LIN_sniffer/LIN_master/LIN_master.ino | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100755 examples/LIN_sniffer/LIN_master/LIN_master.ino diff --git a/examples/LIN_sniffer/LIN_master/LIN_master.ino b/examples/LIN_sniffer/LIN_master/LIN_master.ino new file mode 100755 index 0000000..38b2234 --- /dev/null +++ b/examples/LIN_sniffer/LIN_master/LIN_master.ino @@ -0,0 +1,63 @@ +/* + Simple LIN 2.x master to generate frames for the LIN sniffer + Create alternating frames of lengths 8 and 2. +*/ + +// include files +#include "LIN_master3.h" // send LIN frames via Serial3 + +// pause between LIN frames +#define LIN_PAUSE 200 + + +void setup(void) +{ + // initialize LIN master (blocking operation) + LIN_master3.begin(19200, LIN_V2, false); + +} // setup() + + + +void loop(void) +{ + static uint32_t lastCall = LIN_PAUSE; + static uint8_t count = 0; + static uint8_t Tx[8] = {0,0,0,0,0,0,0,0}; // daty bytes + + + // simple LIN scheduler + if (millis() - lastCall > LIN_PAUSE) { + lastCall = millis(); + + // send frame 1 + if (count == 0) + { + // increase frame index + count++; + + // send master request + LIN_master3.sendMasterRequest(0x07, 8, Tx); + + // increase data_byte[0] + Tx[0]++; + + } + + // send frame 2 + else + { + // revert frame index + count = 0; + + // send master request + LIN_master3.sendMasterRequest(0x04, 2, Tx); + + // decrease data_byte[1] + Tx[1]--; + + } + + } // scheduler + +} // loop() From 79068ccff73aa8462f4b69765964f7d6969f5a8b Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Tue, 29 Oct 2024 16:17:37 +0100 Subject: [PATCH 24/36] Delete .github/workflows/compile_examples.yml --- .github/workflows/compile_examples.yml | 44 -------------------------- 1 file changed, 44 deletions(-) delete mode 100644 .github/workflows/compile_examples.yml diff --git a/.github/workflows/compile_examples.yml b/.github/workflows/compile_examples.yml deleted file mode 100644 index 682c737..0000000 --- a/.github/workflows/compile_examples.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Build Examples - -on: [push, pull_request] - -jobs: - build: - name: ${{ matrix.board.fqbn }} - runs-on: ubuntu-latest - - strategy: - fail-fast: false - - matrix: - board: - - fqbn: arduino:avr:nano - platforms: | - - name: arduino:avr - artifact-name-suffix: arduino-avr-nano - - fqbn: arduino:avr:mega - platforms: | - - name: arduino:avr - artifact-name-suffix: arduino-avr-mega - - fqbn: arduino:avr:leonardo - platforms: | - - name: arduino:avr - artifact-name-suffix: arduino-avr-leonardo - - steps: - - name: Checkout repository - uses: actions/checkout@v4.2.2 - - - name: Compile examples - uses: arduino/compile-sketches@v1.1.2 - with: - fqbn: ${{ matrix.board.fqbn }} - platforms: ${{ matrix.board.platforms }} - libraries: | - # Install the library from the local path. - - source-path: ./ - # Additional library dependencies can be listed here. See https://github.com/arduino/compile-sketches#libraries - - https://github.com/gicking/LIN_master_Arduino - sketch-paths: | - - examples - enable-deltas-report: true From 5d0ef8ab25a0e5e2f796822dbcd6691348022f53 Mon Sep 17 00:00:00 2001 From: gicking Date: Sun, 3 Nov 2024 12:12:35 +0100 Subject: [PATCH 25/36] moved inline ISRs to headers to avoid compiler warnings if not used --- examples/detect_BRK/detect_BRK.ino | 47 ++++++++++++++------ src/NeoHWSerial.cpp | 31 +------------- src/NeoHWSerial.h | 69 +++++++++++++++++++++++++++--- src/NeoHWSerial2.cpp | 3 +- src/NeoHWSerial_private.h | 39 +---------------- 5 files changed, 102 insertions(+), 87 deletions(-) diff --git a/examples/detect_BRK/detect_BRK.ino b/examples/detect_BRK/detect_BRK.ino index 02710f1..5d30f74 100644 --- a/examples/detect_BRK/detect_BRK.ino +++ b/examples/detect_BRK/detect_BRK.ino @@ -14,6 +14,14 @@ #include +//////////////// +// INCLUDE MACROS +//////////////// + +// comment out for handling only in ISR +//#define STORE_BUFFER + + //////////////// // GLOBAL VARIABLES //////////////// @@ -45,7 +53,13 @@ bool rx_handler(uint8_t byte, uint8_t status) NeoSerial.println(); // return true -> byte is stored in Serial buffer - return true; + #if defined(STORE_BUFFER) + return true; + + // return false -> byte is not stored in Serial buffer + #else + return false; + #endif } // rx_handler() @@ -81,12 +95,15 @@ void loop() { NeoSerial1.flush(); // receive BRK via Serial2 - c = NeoSerial2.read(); - NeoSerial.print("loop: Rx=0x"); - NeoSerial.print(c, HEX); - if (BRK) - NeoSerial.print(", BRK"); - NeoSerial.println(); + if (NeoSerial2.available()) + { + c = NeoSerial2.read(); + NeoSerial.print("loop: Rx=0x"); + NeoSerial.print(c, HEX); + if (BRK) + NeoSerial.print(", BRK"); + NeoSerial.println(); + } BRK = false; // send SYNC via Serial1 (0x55) @@ -95,15 +112,19 @@ void loop() { NeoSerial1.flush(); // receive BRK via Serial2 - c = NeoSerial2.read(); - NeoSerial.print("loop: Rx=0x"); - NeoSerial.print(c, HEX); - if (BRK) - NeoSerial.print(", BRK"); - NeoSerial.println("\n"); + if (NeoSerial2.available()) + { + c = NeoSerial2.read(); + NeoSerial.print("loop: Rx=0x"); + NeoSerial.print(c, HEX); + if (BRK) + NeoSerial.print(", BRK"); + NeoSerial.println(); + } BRK = false; // wait some time delay(2000); + NeoSerial.println(); } // loop() diff --git a/src/NeoHWSerial.cpp b/src/NeoHWSerial.cpp index da4945e..3e124a3 100755 --- a/src/NeoHWSerial.cpp +++ b/src/NeoHWSerial.cpp @@ -29,7 +29,7 @@ #include #include #include -#include "Arduino.h" +#include #include "NeoHWSerial.h" #include "NeoHWSerial_private.h" @@ -87,35 +87,6 @@ void serialEventRun(void) // called by main() -> name fixed #endif -// Actual interrupt handlers ////////////////////////////////////////////////////////////// - -void NeoHWSerial::_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_TX_BUFFER_SIZE; - - *_udr = c; - - // 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. 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 - cbi(*_ucsrb, UDRIE0); - } -} - - // Public Methods ////////////////////////////////////////////////////////////// void NeoHWSerial::begin(unsigned long baud, byte config) diff --git a/src/NeoHWSerial.h b/src/NeoHWSerial.h index bccd7ae..c475ae0 100755 --- a/src/NeoHWSerial.h +++ b/src/NeoHWSerial.h @@ -27,8 +27,8 @@ #define NeoHWSerial_h #include - -#include "Stream.h" +#include +#include // Define constants and variables for buffering incoming serial data. We're // using a ring buffer (I think), in which head is the index of the location @@ -136,9 +136,68 @@ class NeoHWSerial : public Stream using Print::write; // pull in write(str) and write(buf, size) from Print operator bool() { return true; } - // Interrupt handlers - Not intended to be called externally - inline void _rx_complete_irq(void); - inline void _tx_udr_empty_irq(void); + // Receive interrupt handler - Not intended to be called externally + inline void _rx_complete_irq(void) + { + volatile bool saveToBuffer = true; + volatile unsigned char status, data; + + // user receive function was attached -> call it with data and status byte + if (_isr){ + status = *_ucsra; + data = *_udr; + saveToBuffer = _isr( data, status ); + } + + // default: save data in ring buffer + if (saveToBuffer) { + + // No Parity error, read byte and store it in the buffer if there is room + if (bit_is_clear(*_ucsra, UPE0)) { + 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] = data; + _rx_buffer_head = i; + } + } + + // Parity error, don't do anything (data is dropped) + else { } + + } // if saveToBuffer + } // _rx_complete_irq() + + // Transmit interrupt handler - Not intended to be called externally + inline void _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_TX_BUFFER_SIZE; + + *_udr = c; + + // 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. 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 + cbi(*_ucsrb, UDRIE0); + } + } // _tx_udr_empty_irq() typedef bool (* isr_t)( uint8_t d, uint8_t s ); //typedef bool (* isr_t)( uint8_t d=0x00, uint8_t s=0x00 ); diff --git a/src/NeoHWSerial2.cpp b/src/NeoHWSerial2.cpp index 367caa5..5de5872 100755 --- a/src/NeoHWSerial2.cpp +++ b/src/NeoHWSerial2.cpp @@ -24,7 +24,8 @@ Modified 31 October 2020 by Georg Icking-Konert */ -#include "Arduino.h" +#include + #include "NeoHWSerial.h" #include "NeoHWSerial_private.h" diff --git a/src/NeoHWSerial_private.h b/src/NeoHWSerial_private.h index f7e1d06..f5eff71 100755 --- a/src/NeoHWSerial_private.h +++ b/src/NeoHWSerial_private.h @@ -23,7 +23,7 @@ Modified 31 October 2020 by Georg Icking-Konert */ -#include "wiring_private.h" +#include // this next line disables the entire HardwareSerial.cpp, // this is so I can support Attiny series and any other chip without a uart @@ -99,41 +99,4 @@ NeoHWSerial::NeoHWSerial( { } -// Actual interrupt handlers ////////////////////////////////////////////////////////////// - -void NeoHWSerial::_rx_complete_irq(void) { - - volatile bool saveToBuffer = true; - volatile unsigned char status, data; - - // user receive function was attached -> call it with data and status byte - if (_isr){ - status = *_ucsra; - data = *_udr; - saveToBuffer = _isr( data, status ); - } - - // default: save data in ring buffer - if (saveToBuffer) { - - // No Parity error, read byte and store it in the buffer if there is room - if (bit_is_clear(*_ucsra, UPE0)) { - 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] = data; - _rx_buffer_head = i; - } - } - - // Parity error, don't do anything (data is dropped) - else { } - - } // if saveToBuffer -} - #endif // HAVE_HWSERIAL0 || HAVE_HWSERIAL1 || HAVE_HWSERIAL2 || HAVE_HWSERIAL3 From 046ed11120c0f258e4b9169bd4ac872fa4ea5745 Mon Sep 17 00:00:00 2001 From: Georg Icking-Konert Date: Sun, 3 Nov 2024 16:07:48 +0100 Subject: [PATCH 26/36] Create build_examples.yml initial CI test --- .github/workflows/build_examples.yml | 47 ++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/build_examples.yml diff --git a/.github/workflows/build_examples.yml b/.github/workflows/build_examples.yml new file mode 100644 index 0000000..8f7fad4 --- /dev/null +++ b/.github/workflows/build_examples.yml @@ -0,0 +1,47 @@ +# based on https://github.com/arduino-libraries/ArduinoBLE/blob/master/.github/workflows/compile-examples.yml +name: Build Lib Examples + +on: + + # Trigger workflow on every push and pull request + push: + pull_request: + + # Also run every 7 days to catch breakage caused by changes to external resources (libraries, platforms). + schedule: + # Minute, Hour, Day of Month, Month, Day of Week -> every 7 days at 9.25pm + - cron: '25 21 */7 * *' + +jobs: + + # Build for AVR + build-for-avr: + runs-on: ubuntu-latest + env: + SKETCHES_REPORTS_PATH: sketches-reports + strategy: + fail-fast: false + matrix: + board: + - fqbn: arduino:avr:mega # Arduino Mega2560 + artifact-name-suffix: arduino_avr_mega + - fqbn: arduino:avr:nano # Arduino Nano + artifact-name-suffix: arduino_avr_nano + steps: + - uses: actions/checkout@v4.2.2 # check-out this repo + - uses: arduino/compile-sketches@v1.1.2 # build Arduino examples + with: + github-token: ${{ secrets.GITHUB_TOKEN }} # required for private repos + fqbn: ${{ matrix.board.fqbn }} + libraries: | + - source-path: ./ + - source-url: https://github.com/gicking/NeoHWSerial.git + sketch-paths: | + - examples + cli-compile-flags: | + - --warnings="all" + - uses: actions/upload-artifact@v4.4.3 # upload test reports + with: + if-no-files-found: error + path: ${{ env.SKETCHES_REPORTS_PATH }} + name: sketches-report-${{ matrix.board.artifact-name-suffix }} From c521cc41b5189f062381988af9bab100e59fab49 Mon Sep 17 00:00:00 2001 From: gicking Date: Sun, 3 Nov 2024 16:17:33 +0100 Subject: [PATCH 27/36] updated example & CI script --- .github/workflows/build_examples.yml | 2 +- .../LIN_sniffer/LIN_master/LIN_master.ino | 75 ++++++++----------- 2 files changed, 33 insertions(+), 44 deletions(-) diff --git a/.github/workflows/build_examples.yml b/.github/workflows/build_examples.yml index 8f7fad4..bfb25e1 100644 --- a/.github/workflows/build_examples.yml +++ b/.github/workflows/build_examples.yml @@ -35,7 +35,7 @@ jobs: fqbn: ${{ matrix.board.fqbn }} libraries: | - source-path: ./ - - source-url: https://github.com/gicking/NeoHWSerial.git + - source-url: https://github.com/gicking/LIN_master_portable_Arduino.git sketch-paths: | - examples cli-compile-flags: | diff --git a/examples/LIN_sniffer/LIN_master/LIN_master.ino b/examples/LIN_sniffer/LIN_master/LIN_master.ino index 38b2234..d68eb4f 100755 --- a/examples/LIN_sniffer/LIN_master/LIN_master.ino +++ b/examples/LIN_sniffer/LIN_master/LIN_master.ino @@ -1,63 +1,52 @@ /* Simple LIN 2.x master to generate frames for the LIN sniffer Create alternating frames of lengths 8 and 2. + + Requires LIN master library from https://github.com/gicking/LIN_master_portable_Arduino */ // include files -#include "LIN_master3.h" // send LIN frames via Serial3 +#include "LIN_master_HardwareSerial.h" // pause between LIN frames #define LIN_PAUSE 200 +// setup LIN node +LIN_Master_HardwareSerial LIN(Serial3, "LIN_HW"); // parameter: HW-interface, name + +// call once void setup(void) { - // initialize LIN master (blocking operation) - LIN_master3.begin(19200, LIN_V2, false); + // open LIN interface + LIN.begin(19200); } // setup() - +// call repeatedly void loop(void) { - static uint32_t lastCall = LIN_PAUSE; - static uint8_t count = 0; - static uint8_t Tx[8] = {0,0,0,0,0,0,0,0}; // daty bytes - - - // simple LIN scheduler - if (millis() - lastCall > LIN_PAUSE) { - lastCall = millis(); - - // send frame 1 - if (count == 0) - { - // increase frame index - count++; - - // send master request - LIN_master3.sendMasterRequest(0x07, 8, Tx); - - // increase data_byte[0] - Tx[0]++; - - } - - // send frame 2 - else - { - // revert frame index - count = 0; - - // send master request - LIN_master3.sendMasterRequest(0x04, 2, Tx); - - // decrease data_byte[1] - Tx[1]--; - - } - - } // scheduler - + // transmit buffers + static uint8_t Tx_1[8] = {0,0,0,0,0,0,0,0}; // data bytes + static uint8_t Tx_2[8] = {0,0,0,0,0,0,0,0}; // data bytes + + // send frame 1 and increase Tx[0] + LIN.sendMasterRequestBlocking(LIN_Master::LIN_V2, 0x07, 8, Tx_1); + LIN.resetStateMachine(); + LIN.resetError(); + Tx_1[0]++; + + // wait a bit + delay(LIN_PAUSE); + + // send frame 1 and increase Tx[1] + LIN.sendMasterRequestBlocking(LIN_Master::LIN_V2, 0x04, 2, Tx_2); + LIN.resetStateMachine(); + LIN.resetError(); + Tx_2[1]++; + + // wait a bit + delay(LIN_PAUSE); + } // loop() From 9f3f7bcff83e607b7311534488e9b74ea686d4c3 Mon Sep 17 00:00:00 2001 From: gicking Date: Sun, 3 Nov 2024 17:08:56 +0100 Subject: [PATCH 28/36] remove Nano --- .github/workflows/build_examples.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/build_examples.yml b/.github/workflows/build_examples.yml index bfb25e1..f3898d6 100644 --- a/.github/workflows/build_examples.yml +++ b/.github/workflows/build_examples.yml @@ -25,8 +25,6 @@ jobs: board: - fqbn: arduino:avr:mega # Arduino Mega2560 artifact-name-suffix: arduino_avr_mega - - fqbn: arduino:avr:nano # Arduino Nano - artifact-name-suffix: arduino_avr_nano steps: - uses: actions/checkout@v4.2.2 # check-out this repo - uses: arduino/compile-sketches@v1.1.2 # build Arduino examples From 1bd3015d0241f1f8ebd2c7ea6f0f58142f30527a Mon Sep 17 00:00:00 2001 From: gicking Date: Tue, 3 Dec 2024 06:19:00 +0100 Subject: [PATCH 29/36] fix LIN master example --- .github/workflows/build_examples.yml | 1 - .../LIN_sniffer/LIN-Master/LIN-Master.ino | 56 +++++ .../LIN_sniffer/LIN-Master/LIN_protocol.ino | 210 ++++++++++++++++++ .../LIN_sniffer/LIN_master/LIN_master.ino | 52 ----- 4 files changed, 266 insertions(+), 53 deletions(-) create mode 100644 examples/LIN_sniffer/LIN-Master/LIN-Master.ino create mode 100644 examples/LIN_sniffer/LIN-Master/LIN_protocol.ino delete mode 100755 examples/LIN_sniffer/LIN_master/LIN_master.ino diff --git a/.github/workflows/build_examples.yml b/.github/workflows/build_examples.yml index f3898d6..95272be 100644 --- a/.github/workflows/build_examples.yml +++ b/.github/workflows/build_examples.yml @@ -33,7 +33,6 @@ jobs: fqbn: ${{ matrix.board.fqbn }} libraries: | - source-path: ./ - - source-url: https://github.com/gicking/LIN_master_portable_Arduino.git sketch-paths: | - examples cli-compile-flags: | diff --git a/examples/LIN_sniffer/LIN-Master/LIN-Master.ino b/examples/LIN_sniffer/LIN-Master/LIN-Master.ino new file mode 100644 index 0000000..7d83176 --- /dev/null +++ b/examples/LIN_sniffer/LIN-Master/LIN-Master.ino @@ -0,0 +1,56 @@ +////// +// LIN communication error codes +////// +#define SUCCESS 0 // no error +#define ERROR_TIMOUT 1 // receive timeout +#define ERROR_CHK 2 // checksum error +#define ERROR_MISC 255 // misc error + + +////// +// global macros +////// +#define LIN_SERIAL Serial1 // used Serial interface +#define LIN_BAUDRATE 19200 // LIN baudrate + + +////// +// global variables +////// +uint8_t LIN_err = SUCCESS; + + +////// +// setup routine (called once) +////// +void setup() +{ + // communication to PC + Serial.begin(115200); + while (!Serial); + + // initialize LIN interface + LIN_SERIAL.begin(LIN_BAUDRATE); + while (!LIN_SERIAL); + +} // setup + + +////// +// loop routine (called periodically) +////// +void loop() +{ + static uint8_t Tx[8] = {0,1,2,3,4,5,6,7}; + uint8_t Rx[8]; + + // send master request + LIN_sendMasterRequest(2, 0x12, 8, Tx); + Tx[0]++; + delay(100); + + // send/ receive slave response + LIN_receiveSlaveResponse(2, 0x23, 8, Rx); + delay(100); + +} // loop diff --git a/examples/LIN_sniffer/LIN-Master/LIN_protocol.ino b/examples/LIN_sniffer/LIN-Master/LIN_protocol.ino new file mode 100644 index 0000000..a09dadf --- /dev/null +++ b/examples/LIN_sniffer/LIN-Master/LIN_protocol.ino @@ -0,0 +1,210 @@ +/** + \fn byte LIN_protectID(byte id) + + \brief protect LIN ID with parity + + \param[in] id frame ID (protection optional) + + \return protected LIN identifier + + calculate protected LIN identifier as described in LIN2.0 spec "2.3.1.3 Protected identifier field" +*/ +byte LIN_protectID(byte id) +{ + byte pid; + uint8_t tmp; // temporary variable use to calculate the parity bits + + // copy (unprotected) ID + pid = id; + + // protect ID with parity bits + pid = (uint8_t) (pid & 0x3F); //0x3F = 00111111 =63 + tmp = (uint8_t) ((pid ^ (pid>>1) ^ (pid>>2) ^ (pid>>4)) & 0x01); // -> tmp[0] = PI0 = ID0^ID1^ID2^ID4 + pid |= (uint8_t) (tmp<<6); + tmp = (uint8_t) (~((pid>>1) ^ (pid>>3) ^ (pid>>4) ^ (pid>>5)) & 0x01); // -> tmp[0] = PI1 = ~(ID1^ID3^ID4^ID5) + pid |= (uint8_t) (tmp<<7); + + // return protected identifier + return(pid); + +} // LIN_protectID + + + +/** + \fn byte LIN_sendMasterRequest(uint8_t vers, byte id, uint8_t numData, byte *data) + + \brief send LIN master request frame + + \param[in] vers LIN version (for checksum) + \param[in] id frame ID (protection optional) + \param[in] numData number of data bytes (0..8) + \param[in] data Tx data bytes (up to 8) + + \return error code + + send a LIN master request frame. For an explanation of the LIN bus + and protocoll e.g. see https://en.wikipedia.org/wiki/Local_Interconnect_Network +*/ +byte LIN_sendMasterRequest(uint8_t vers, byte id, uint8_t numData, byte *data) +{ + uint8_t chk; // tmp, + uint16_t chk_tmp=0; + byte buf[11]; // frame Tx buffer: 0x55 + id + 8B data + chk + + // protect ID (see LIN2.0 spec "2.3.1.3 Protected identifier field") + id = LIN_protectID(id); + + // LIN2.x uses extended checksum which includes protected ID, i.e. including parity bits + // LIN1.x uses classical checksum only over data bytes + // Diagnostic frames with ID=0x3C/PID=0x3C and ID=0x3D/PID=0x7D always use classical checksum (see LIN2.0 spec "2.3.1.5 Checkum") + if (!((vers == 1) || (id == 0x3C) || (id == 0x7D))) + chk_tmp = (uint16_t) id; + for (uint8_t i=0; i255) + chk_tmp -= 255; + } + chk = (uint8_t)(0xFF - ((uint8_t) chk_tmp)); + + // construct Tx frame + buf[0] = 0x55; // sync field + buf[1] = id; // protected identifier + for (uint8_t i=0; i13bit @ baudrate) + LIN_SERIAL.begin(LIN_BAUDRATE / 2); + LIN_SERIAL.write(0x00); + LIN_SERIAL.flush(); + LIN_SERIAL.begin(LIN_BAUDRATE); + + // send sync field + frame ID + data + checksum + LIN_SERIAL.write(buf, 3+numData); + + // wait for the send is complete + LIN_SERIAL.flush(); + + // empty receive buffer, just to be sure + while(LIN_SERIAL.available()) + LIN_SERIAL.read(); + + // return error status + return(SUCCESS); + +} // LIN_sendMasterRequest + + + +/** + \fn byte LIN_receiveSlaveResponse(uint8_t vers, byte id, uint8_t numData, byte *data) + + \brief receive LIN slave response frame + + \param[in] vers LIN version 1 or 2 (for checksum) + \param[in] id frame ID (protection optional) + \param[in] numData number of data bytes (0..8) + \param[out] data Rx data bytes (up to 8) + + \return error code + + receive a LIN slave response frame. For an explanation of the LIN bus + and protocoll e.g. see https://en.wikipedia.org/wiki/Local_Interconnect_Network + +*/ +byte LIN_receiveSlaveResponse(uint8_t vers, byte id, uint8_t numData, byte *data) +{ + uint8_t tmp, chkCalc, numRx; //chkRcv, + uint16_t chk_tmp=0; + byte buf[3]; // frame Tx buffer: 0x55 + id + + // protect ID (see LIN2.0 spec "2.3.1.3 Protected identifier field") + id = LIN_protectID(id); + + // LIN2.x uses extended checksum which includes protected ID, i.e. including parity bits + // LIN1.x uses classical checksum only over data bytes + // Diagnostic frames with ID 0x3C and 0x3D always use classical checksum (see LIN spec "2.3.1.5 Checkum") + if (!((vers == 1) || (id == 0x3C) || (id == 0x3D))) // 3C = 00111100 = 60; 3D = 00111101 = 61 + chk_tmp = (uint16_t) id; + + // construct Tx frame + buf[0] = 0x55; // sync field + buf[1] = id; // protected identifier + + // clear Rx buffer + for (uint8_t i=0; i<8; i++) + data[i] = 0x00; + + // set timeout for data reception + LIN_SERIAL.setTimeout(10); + + // empty receive buffer, just to be sure + while(LIN_SERIAL.available()) + LIN_SERIAL.read(); + + // generate sync break (low for >13bit @ baudrate) + LIN_SERIAL.begin(LIN_BAUDRATE / 2); + LIN_SERIAL.write(0x00); + LIN_SERIAL.flush(); + LIN_SERIAL.begin(LIN_BAUDRATE); + + // send sync field + frame ID + LIN_SERIAL.write(buf, 2); + + // wait for the send is complete and clear receive buffer + LIN_SERIAL.flush(); + + // read 3B LIN echo (break+sync+id) + for (tmp=0; tmp<3; tmp++) + LIN_SERIAL.read(); + + // receive data+chk with timeout + numRx = LIN_SERIAL.readBytes(data, numData+1); + + + // check for timeout + if (numRx != numData+1) { + + // clear Rx buffer + for (uint8_t i=0; i<8; i++) + data[i] = 0x00; + + // return error code + return(ERROR_TIMOUT); + + } // if timeout + + // calculate checksum over received bytes + for (uint8_t i=0; i255) + chk_tmp -= 255; + + } // checksum calculation + + // bitwise invert claculated checksum + chkCalc = (uint8_t) (0xFF - ((uint8_t) chk_tmp)); + + // compare calculated vs. received checksum + if (data[numData] != chkCalc) + { + // clear Rx buffer + for (uint8_t i=0; i Date: Sat, 7 Dec 2024 16:20:59 +0100 Subject: [PATCH 30/36] reduced test frequency --- .github/workflows/build_examples.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_examples.yml b/.github/workflows/build_examples.yml index 95272be..3287024 100644 --- a/.github/workflows/build_examples.yml +++ b/.github/workflows/build_examples.yml @@ -7,10 +7,11 @@ on: push: pull_request: - # Also run every 7 days to catch breakage caused by changes to external resources (libraries, platforms). + # Also run periodically to catch breakage caused by changes to external resources (libraries, platforms). schedule: - # Minute, Hour, Day of Month, Month, Day of Week -> every 7 days at 9.25pm - - cron: '25 21 */7 * *' + # Minute, Hour, Day of Month, Month, Day of Week (UTC timezone) + #- cron: '20 21 */7 * *' + - cron: '0 3 2 * *' jobs: From 4fcd1d2c58730252067b269e8ec37fd5a70edce8 Mon Sep 17 00:00:00 2001 From: gicking Date: Sun, 26 Jan 2025 08:12:50 +0100 Subject: [PATCH 31/36] conditional compile for AVR architecture only --- .github/workflows/build_examples.yml | 2 +- README.md | 23 +++++++++++++++++++---- library.properties | 2 +- src/NeoHWSerial.cpp | 5 +++++ src/NeoHWSerial.h | 6 ++++++ src/NeoHWSerial0.cpp | 5 +++++ src/NeoHWSerial1.cpp | 5 +++++ src/NeoHWSerial2.cpp | 5 +++++ src/NeoHWSerial3.cpp | 5 +++++ src/NeoHWSerial_private.h | 5 +++++ 10 files changed, 57 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build_examples.yml b/.github/workflows/build_examples.yml index 3287024..35fcca9 100644 --- a/.github/workflows/build_examples.yml +++ b/.github/workflows/build_examples.yml @@ -25,7 +25,7 @@ jobs: matrix: board: - fqbn: arduino:avr:mega # Arduino Mega2560 - artifact-name-suffix: arduino_avr_mega + artifact-name-suffix: arduino_avr_mega steps: - uses: actions/checkout@v4.2.2 # check-out this repo - uses: arduino/compile-sketches@v1.1.2 # build Arduino examples diff --git a/README.md b/README.md index 8a01570..be68408 100755 --- a/README.md +++ b/README.md @@ -6,12 +6,12 @@ Note: This is a minor update of [NeoHWSerial by SlashDevin](https://github.com/S - support optional storing to ring buffer after return from user routine via return value -### Installation +## Installation -This library can be installed via the library manager of the Arduino IDE. +This library can be installed via the library manager of the Arduino IDE. Alternatively download repository and copy the folder to your Arduino library path. -### Usage +## Usage To handle all received characters with your function, you must register it with the specific `NeoSerial[n]` instance: @@ -49,7 +49,7 @@ The original `HardwareSerial` files were modified to include two new methods, `a isr_t _isr; ``` -### NOTES +## Notes To avoid name collisions, all `HardwareSerial` instances are prefixed with "Neo" in this replacement library. All parts of your sketch, including other libraries, must use @@ -76,3 +76,18 @@ As new Arduino IDEs are released, new versions will appear in the root of this r ### See Also If you are also using software serial ports, you may be interested in [NeoICSerial](https://github.com/SlashDevin/NeoICSerial) or [NeoSWSerial](https://github.com/SlashDevin/NeoSWSerial). + + +---------------- + +Revision History +---------------- + +**v1.6.8 (2025-01-26)** + - conditional compile for AVR architecture only + +**v1.6.7 (2024-10-25)** + - started revision history + - fixed indexing bug for ring buffer storage + - added CI tests via Github Actions + \ No newline at end of file diff --git a/library.properties b/library.properties index 6be6f6d..2a1c55f 100755 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=NeoHWSerial -version=1.6.7 +version=1.6.8 author=Georg Icking-Konert maintainer=Georg Icking-Konert sentence=NeoHWSerial for AVR diff --git a/src/NeoHWSerial.cpp b/src/NeoHWSerial.cpp index 3e124a3..27e8857 100755 --- a/src/NeoHWSerial.cpp +++ b/src/NeoHWSerial.cpp @@ -24,6 +24,9 @@ Modified 31 October 2020 by Georg Icking-Konert */ +// only compile for AVR architecture +#if defined(ARDUINO_ARCH_AVR) + #include #include #include @@ -262,3 +265,5 @@ void NeoHWSerial::attachInterrupt( isr_t fn ) } #endif // HAVE_HWSERIAL0 || HAVE_HWSERIAL1 || HAVE_HWSERIAL2 || HAVE_HWSERIAL3 + +#endif // ARDUINO_ARCH_AVR diff --git a/src/NeoHWSerial.h b/src/NeoHWSerial.h index c475ae0..bab434d 100755 --- a/src/NeoHWSerial.h +++ b/src/NeoHWSerial.h @@ -21,8 +21,12 @@ Modified 3 December 2013 by Matthijs Kooijman Modified 2 November 2015 by SlashDev Modified 31 October 2020 by Georg Icking-Konert + Modified 26 January 2025 by Georg Icking-Konert */ +// only compile for AVR architecture +#if defined(ARDUINO_ARCH_AVR) + #ifndef NeoHWSerial_h #define NeoHWSerial_h @@ -231,3 +235,5 @@ class NeoHWSerial : public Stream extern void serialEventRun(void) __attribute__((weak)); // called by main() -> name fixed #endif // NeoHWSerial_h + +#endif // ARDUINO_ARCH_AVR diff --git a/src/NeoHWSerial0.cpp b/src/NeoHWSerial0.cpp index b57adcd..4b01caa 100755 --- a/src/NeoHWSerial0.cpp +++ b/src/NeoHWSerial0.cpp @@ -24,6 +24,9 @@ Modified 31 October 2020 by Georg Icking-Konert */ +// only compile for AVR architecture +#if defined(ARDUINO_ARCH_AVR) + #include "Arduino.h" #include "NeoHWSerial.h" #include "NeoHWSerial_private.h" @@ -80,3 +83,5 @@ } #endif // HAVE_HWSERIAL0 + +#endif // ARDUINO_ARCH_AVR diff --git a/src/NeoHWSerial1.cpp b/src/NeoHWSerial1.cpp index 60f55a0..675603e 100755 --- a/src/NeoHWSerial1.cpp +++ b/src/NeoHWSerial1.cpp @@ -24,6 +24,9 @@ Modified 31 October 2020 by Georg Icking-Konert */ +// only compile for AVR architecture +#if defined(ARDUINO_ARCH_AVR) + #include "Arduino.h" #include "NeoHWSerial.h" #include "NeoHWSerial_private.h" @@ -70,3 +73,5 @@ } #endif // HAVE_HWSERIAL1 + +#endif // ARDUINO_ARCH_AVR diff --git a/src/NeoHWSerial2.cpp b/src/NeoHWSerial2.cpp index 5de5872..9b894b4 100755 --- a/src/NeoHWSerial2.cpp +++ b/src/NeoHWSerial2.cpp @@ -24,6 +24,9 @@ Modified 31 October 2020 by Georg Icking-Konert */ +// only compile for AVR architecture +#if defined(ARDUINO_ARCH_AVR) + #include #include "NeoHWSerial.h" @@ -59,3 +62,5 @@ } #endif // HAVE_HWSERIAL2 + +#endif // ARDUINO_ARCH_AVR diff --git a/src/NeoHWSerial3.cpp b/src/NeoHWSerial3.cpp index 8b2ab1a..f3013ee 100755 --- a/src/NeoHWSerial3.cpp +++ b/src/NeoHWSerial3.cpp @@ -24,6 +24,9 @@ Modified 31 October 2020 by Georg Icking-Konert */ +// only compile for AVR architecture +#if defined(ARDUINO_ARCH_AVR) + #include "Arduino.h" #include "NeoHWSerial.h" #include "NeoHWSerial_private.h" @@ -58,3 +61,5 @@ } #endif // HAVE_HWSERIAL3 + +#endif // ARDUINO_ARCH_AVR diff --git a/src/NeoHWSerial_private.h b/src/NeoHWSerial_private.h index f5eff71..f682565 100755 --- a/src/NeoHWSerial_private.h +++ b/src/NeoHWSerial_private.h @@ -23,6 +23,9 @@ Modified 31 October 2020 by Georg Icking-Konert */ +// only compile for AVR architecture +#if defined(ARDUINO_ARCH_AVR) + #include // this next line disables the entire HardwareSerial.cpp, @@ -100,3 +103,5 @@ NeoHWSerial::NeoHWSerial( } #endif // HAVE_HWSERIAL0 || HAVE_HWSERIAL1 || HAVE_HWSERIAL2 || HAVE_HWSERIAL3 + +#endif // ARDUINO_ARCH_AVR From 87ff841e2f9911ee18f480453bd45d5a0a8a6309 Mon Sep 17 00:00:00 2001 From: gicking Date: Sun, 26 Jan 2025 08:16:08 +0100 Subject: [PATCH 32/36] conditional compile for AVR architecture only --- .github/workflows/build_examples.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_examples.yml b/.github/workflows/build_examples.yml index 35fcca9..3287024 100644 --- a/.github/workflows/build_examples.yml +++ b/.github/workflows/build_examples.yml @@ -25,7 +25,7 @@ jobs: matrix: board: - fqbn: arduino:avr:mega # Arduino Mega2560 - artifact-name-suffix: arduino_avr_mega + artifact-name-suffix: arduino_avr_mega steps: - uses: actions/checkout@v4.2.2 # check-out this repo - uses: arduino/compile-sketches@v1.1.2 # build Arduino examples From 9347985185dbaa4430ae0d4ea46d68937c761fb4 Mon Sep 17 00:00:00 2001 From: gicking Date: Sun, 26 Jan 2025 08:23:24 +0100 Subject: [PATCH 33/36] added initial tag in revision history --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index be68408..dcddcde 100755 --- a/README.md +++ b/README.md @@ -87,7 +87,11 @@ Revision History - conditional compile for AVR architecture only **v1.6.7 (2024-10-25)** - - started revision history - - fixed indexing bug for ring buffer storage - - added CI tests via Github Actions - \ No newline at end of file + - fix indexing bug for ring buffer storage + - add CI tests via Github Actions + +**v1.6.6 (2020-11-01)** + - fork from [NeoHWSerial by SlashDevin](https://github.com/SlashDevin/NeoHWSerial) + - update library structure to Arduino IDE >=v1.5.6 format (see [here](https://arduino.github.io/arduino-cli/latest/library-specification/)) + - pass UART status byte to user receive function. Required e.g. for break detection for [LIN bus](https://en.wikipedia.org/wiki/Local_Interconnect_Network) + - support optional storing to ring buffer after return from user routine via return value From 12fab92fe5628ace31d5a73cadcca4fd0f32c054 Mon Sep 17 00:00:00 2001 From: gicking Date: Sun, 26 Jan 2025 08:28:17 +0100 Subject: [PATCH 34/36] updated Readme.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dcddcde..a17a47a 100755 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Revision History ---------------- **v1.6.8 (2025-01-26)** - - conditional compile for AVR architecture only + - add conditional compile for AVR architecture only **v1.6.7 (2024-10-25)** - fix indexing bug for ring buffer storage From 76a964324facc7ab3e4c4088beff428123ae51e6 Mon Sep 17 00:00:00 2001 From: gicking Date: Sat, 13 Sep 2025 15:37:20 +0200 Subject: [PATCH 35/36] fix bug that corrupts buffer storage if no user function is attached to Rx-ISR --- .gitignore | 2 +- README.md | 3 +++ library.properties | 2 +- src/NeoHWSerial.h | 20 ++++++++++++-------- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 1b9ee8e..04b2abc 100755 --- a/.gitignore +++ b/.gitignore @@ -42,5 +42,5 @@ Network Trash Folder Temporary Items .apdisk -# Misc +# permit editing examples in Arduino IDE .development diff --git a/README.md b/README.md index a17a47a..6962b9c 100755 --- a/README.md +++ b/README.md @@ -83,6 +83,9 @@ If you are also using software serial ports, you may be interested in [NeoICSeri Revision History ---------------- +**v1.6.9 (2025-09-13)** + - fix bug that corrupts buffer storage if no user function is attached to Rx-ISR + **v1.6.8 (2025-01-26)** - add conditional compile for AVR architecture only diff --git a/library.properties b/library.properties index 2a1c55f..132ab63 100755 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=NeoHWSerial -version=1.6.8 +version=1.6.9 author=Georg Icking-Konert maintainer=Georg Icking-Konert sentence=NeoHWSerial for AVR diff --git a/src/NeoHWSerial.h b/src/NeoHWSerial.h index bab434d..e4713f4 100755 --- a/src/NeoHWSerial.h +++ b/src/NeoHWSerial.h @@ -143,21 +143,26 @@ class NeoHWSerial : public Stream // Receive interrupt handler - Not intended to be called externally inline void _rx_complete_irq(void) { - volatile bool saveToBuffer = true; + volatile bool saveToBuffer; volatile unsigned char status, data; + // get Rx status and data + status = *_ucsra; + data = *_udr; + // user receive function was attached -> call it with data and status byte - if (_isr){ - status = *_ucsra; - data = *_udr; + if (_isr) saveToBuffer = _isr( data, status ); - } + + // no user routine attached -> save data in ring buffer + else + saveToBuffer = true; // default: save data in ring buffer if (saveToBuffer) { // No Parity error, read byte and store it in the buffer if there is room - if (bit_is_clear(*_ucsra, UPE0)) { + if (bit_is_clear(status, UPE0)) { 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 @@ -170,7 +175,7 @@ class NeoHWSerial : public Stream } } - // Parity error, don't do anything (data is dropped) + // Parity or framing error, don't do anything (data is dropped) else { } } // if saveToBuffer @@ -204,7 +209,6 @@ class NeoHWSerial : public Stream } // _tx_udr_empty_irq() typedef bool (* isr_t)( uint8_t d, uint8_t s ); - //typedef bool (* isr_t)( uint8_t d=0x00, uint8_t s=0x00 ); void attachInterrupt( isr_t fn ); void detachInterrupt() { attachInterrupt( (isr_t) NULL ); }; From 12196cb1edc2bdc77dd39a3756b17fc036d8cc24 Mon Sep 17 00:00:00 2001 From: gicking Date: Sat, 13 Sep 2025 19:11:55 +0200 Subject: [PATCH 36/36] add methods to disable & enable receiver --- README.md | 1 + src/NeoHWSerial.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6962b9c..b18cbc6 100755 --- a/README.md +++ b/README.md @@ -85,6 +85,7 @@ Revision History **v1.6.9 (2025-09-13)** - fix bug that corrupts buffer storage if no user function is attached to Rx-ISR + - add methods to disable & enable receiver **v1.6.8 (2025-01-26)** - add conditional compile for AVR architecture only diff --git a/src/NeoHWSerial.h b/src/NeoHWSerial.h index e4713f4..72358c3 100755 --- a/src/NeoHWSerial.h +++ b/src/NeoHWSerial.h @@ -139,7 +139,9 @@ class NeoHWSerial : public Stream inline size_t write(int n) { return write((uint8_t)n); } using Print::write; // pull in write(str) and write(buf, size) from Print operator bool() { return true; } - + inline void enable_rx(void) { sbi(*_ucsrb, RXEN0); } + inline void disable_rx(void) { cbi(*_ucsrb, RXEN0); } + // Receive interrupt handler - Not intended to be called externally inline void _rx_complete_irq(void) {