From 626cc96b5ebfc3e37c061400f4a7ad148f4aa8a4 Mon Sep 17 00:00:00 2001 From: dhineshkumarmcci Date: Fri, 6 Jan 2023 02:35:42 +0530 Subject: [PATCH 1/5] fix #4: prepare for release --- SoftwareSerial.cpp => MCCI_SoftSerial.cpp | 6 +++--- SoftwareSerial.h => MCCI_SoftSerial.h | 10 +++++----- README.md | 16 ++++++++++++---- library.properties | 6 +++--- 4 files changed, 23 insertions(+), 15 deletions(-) rename SoftwareSerial.cpp => MCCI_SoftSerial.cpp (97%) rename SoftwareSerial.h => MCCI_SoftSerial.h (93%) diff --git a/SoftwareSerial.cpp b/MCCI_SoftSerial.cpp similarity index 97% rename from SoftwareSerial.cpp rename to MCCI_SoftSerial.cpp index 7c23ece..5653417 100644 --- a/SoftwareSerial.cpp +++ b/MCCI_SoftSerial.cpp @@ -1,8 +1,8 @@ /* - SoftwareSerial.cpp - library for Arduino M0/M0 pro + MCCI_SoftSerial.cpp - library for Arduino M0/M0 pro Copyright (c) 2016 Arduino Srl. All rights reserved. Written by Chiara Ruggeri (chiara@arduino.org) - Portions copyright (c) 2018 MCCI Corporation. All rights reserved. + Portions copyright (c) 2018, 2021, 2023 MCCI Corporation. All rights reserved. Written by Terry Moore (tmm@mcci.com) This library is free software; you can redistribute it and/or @@ -24,7 +24,7 @@ #include -#include +#include #include #include diff --git a/SoftwareSerial.h b/MCCI_SoftSerial.h similarity index 93% rename from SoftwareSerial.h rename to MCCI_SoftSerial.h index de74246..f01d7aa 100644 --- a/SoftwareSerial.h +++ b/MCCI_SoftSerial.h @@ -1,8 +1,8 @@ /* - SoftwareSerial.cpp - library for Arduino M0/M0 pro + MCCI_SoftSerial.cpp - library for Arduino M0/M0 pro Copyright (c) 2016 Arduino Srl. All rights reserved. Written by Chiara Ruggeri (chiara@arduino.org) - Portions copyright (c) 2018 MCCI Corporation. All rights reserved. + Portions copyright (c) 2018, 2021, 2023 MCCI Corporation. All rights reserved. Written by Terry Moore (tmm@mcci.com) This library is free software; you can redistribute it and/or @@ -22,8 +22,8 @@ Enjoy! */ -#ifndef SoftwareSerial_h -#define SoftwareSerial_h +#ifndef _MCCI_SoftSerial_h_ +#define _MCCI_SoftSerial_h_ #include #include @@ -110,5 +110,5 @@ class SoftwareSerial : public Stream #undef abs #undef round -#endif +#endif /* _MCCI_SoftSerial_h_ */ diff --git a/README.md b/README.md index 2c65bcd..8a65910 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,20 @@ -# SoftwareSerial library for Arduino +# MCCI_SoftSerial library for Arduino This directory contains the SoftwareSerial library split out from https://github.com/Arduino-org/Arduino. All relevant history is retained. We split it out because it needs some TLC to be compatible with our Modbus library (in particular, the APIs didn't match the modern serial port APIs, and it will no longer compile with modern compilers -- see [issue 234](https://github.com/arduino/ArduinoCore-samd/issues/234)). -[![GitHub release](https://img.shields.io/github/release/mcci-catena/SoftwareSerial/all.svg)](https://github.com/mcci-catena/SoftwareSerial/releases/latest) ![GitHub commits](https://img.shields.io/github/commits-since/mcci-catena/SoftwareSerial/latest.svg) +[![GitHub release](https://img.shields.io/github/release/mcci-catena/MCCI_SoftSerial/all.svg)](https://github.com/mcci-catena/MCCI_SoftSerial/releases/latest) ![GitHub commits](https://img.shields.io/github/commits-since/mcci-catena/MCCI_SoftSerial/latest.svg) ## Change Summary -### v1.0.0 +### v3.0.0 -This is the version as imported from Arduino. +The changes are: + +- Fixed issue - ```call of overloaded 'begin(int)' is ambiguous```. + +- Modify file names to get library added in Library Manager. ### v2.0.0 @@ -27,3 +31,7 @@ The changes: - Added `SoftwareSerial::drainRead()` to do what flush() used to do, in case you are not happy with the recommended `while (mySerial.read() >= 0) /* spin */;` work-around. - Added fix for [issue 234](https://github.com/arduino/ArduinoCore-samd/issues/234). + +### v1.0.0 + +This is the version as imported from Arduino. diff --git a/library.properties b/library.properties index 00c6e35..9594992 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ -name=SofwareSerial (MCCI version) -version=2.0.0 +name=MCCI_SoftSerial +version=3.0.0 author=Chiara Ruggeri (chiara@arduino.org) maintainer=Terry Moore sentence=Software UART for Arduino paragraph=This library allows any pair of pins to be used as a UART implemented by software. The MCCI version incorporates bug fixes and makes it more compatible with the UART and USB serial classes. category=Communication -url=https://github.com/mcci-catena/SoftwareSerial +url=https://github.com/mcci-catena/MCCI_SoftSerial architectures=* From b63c48b9395217794ef8689840c6d5920a40e460 Mon Sep 17 00:00:00 2001 From: Dhinesh Kumar Pitchai Date: Thu, 12 Jan 2023 22:26:55 +0530 Subject: [PATCH 2/5] remove files with modified name --- MCCI_SoftSerial.cpp | 325 -------------------------------------------- MCCI_SoftSerial.h | 114 ---------------- 2 files changed, 439 deletions(-) delete mode 100644 MCCI_SoftSerial.cpp delete mode 100644 MCCI_SoftSerial.h diff --git a/MCCI_SoftSerial.cpp b/MCCI_SoftSerial.cpp deleted file mode 100644 index 5653417..0000000 --- a/MCCI_SoftSerial.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/* - MCCI_SoftSerial.cpp - library for Arduino M0/M0 pro - Copyright (c) 2016 Arduino Srl. All rights reserved. - Written by Chiara Ruggeri (chiara@arduino.org) - Portions copyright (c) 2018, 2021, 2023 MCCI Corporation. All rights reserved. - Written by Terry Moore (tmm@mcci.com) - - 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 - - Enjoy! -*/ - - -#include -#include -#include -#include - -SoftwareSerial *SoftwareSerial::active_object = 0; -char SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF]; -volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0; -volatile uint8_t SoftwareSerial::_receive_buffer_head = 0; - - -bool SoftwareSerial::listen() -{ - if (!_rx_delay_stopbit) - return false; - - if (active_object != this) - { - if (active_object) - active_object->stopListening(); - - _buffer_overflow = false; - _receive_buffer_head = _receive_buffer_tail = 0; - active_object = this; - - if(_inverse_logic) - //Start bit high - attachInterrupt(_receivePin, handle_interrupt, RISING); - else - //Start bit low - attachInterrupt(_receivePin, handle_interrupt, FALLING); - - - return true; - } - return false; -} - -bool SoftwareSerial::stopListening() -{ - if (active_object == this) - { - EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT( 1 << digitalPinToInterrupt( _receivePin )) ; - active_object = NULL; - return true; - } - return false; -} - - -void SoftwareSerial::recv() -{ - - uint8_t d = 0; - - // If RX line is high, then we don't see any start bit - // so interrupt is probably not for us - if (_inverse_logic ? rx_pin_read() : !rx_pin_read()) - { - - EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT( 1 << digitalPinToInterrupt(_receivePin)); - - // Wait approximately 1/2 of a bit width to "center" the sample - delayMicroseconds(_rx_delay_centering); - - // Read each of the 8 bits - for (uint8_t i=8; i > 0; --i) - { - - delayMicroseconds(_rx_delay_intrabit); - d >>= 1; - if (rx_pin_read()){ - d |= 0x80; - } - - } - if (_inverse_logic){ - d = ~d; - } - - // if buffer full, set the overflow flag and return - uint8_t next = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF; - if (next != _receive_buffer_head) - { - // save new data in buffer: tail points to where byte goes - _receive_buffer[_receive_buffer_tail] = d; // save new byte - _receive_buffer_tail = next; - } - else - { - _buffer_overflow = true; - } - - // skip the stop bit - delayMicroseconds(_rx_delay_stopbit); - - EIC->INTENSET.reg = EIC_INTENSET_EXTINT( 1 << digitalPinToInterrupt(_receivePin)); - } -} - - -uint32_t SoftwareSerial::rx_pin_read() -{ - return _receivePortRegister->reg & digitalPinToBitMask(_receivePin); -} - -/* static */ -inline void SoftwareSerial::handle_interrupt() -{ - if (active_object) - { - active_object->recv(); - } -} - - -// Constructor -SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) : - _rx_delay_centering(0), - _rx_delay_intrabit(0), - _rx_delay_stopbit(0), - _tx_delay(0), - _buffer_overflow(false), - _inverse_logic(inverse_logic) -{ - _receivePin = receivePin; - _transmitPin = transmitPin; -} - -// Destructor -SoftwareSerial::~SoftwareSerial() -{ - end(); -} - -void SoftwareSerial::setTX(uint8_t tx) -{ - // First write, then set output. If we do this the other way around, - // the pin would be output low for a short while before switching to - // output hihg. Now, it is input with pullup for a short while, which - // is fine. With inverse logic, either order is fine. - digitalWrite(tx, _inverse_logic ? LOW : HIGH); - pinMode(tx, OUTPUT); - _transmitBitMask = digitalPinToBitMask(tx); - PortGroup * port = digitalPinToPort(tx); - _transmitPortRegister = (decltype(_transmitPortRegister)) portOutputRegister(port); - -} - -void SoftwareSerial::setRX(uint8_t rx) -{ - pinMode(rx, INPUT); - if (!_inverse_logic) - digitalWrite(rx, HIGH); // pullup for normal logic! - _receivePin = rx; - _receiveBitMask = digitalPinToBitMask(rx); - PortGroup * port = digitalPinToPort(rx); - _receivePortRegister = (decltype(_receivePortRegister)) portInputRegister(port); - -} - - -void SoftwareSerial::begin(unsigned long speed) -{ - setTX(_transmitPin); - setRX(_receivePin); - // Precalculate the various delays - //Calculate the distance between bit in micro seconds - uint32_t bit_delay = (float(1)/speed)*1000000; - - _tx_delay = bit_delay; - - // Only setup rx when we have a valid PCINT for this pin - if (digitalPinToInterrupt(_receivePin)!=NOT_AN_INTERRUPT) { - //Wait 1/2 bit - 2 micro seconds (time for interrupt to be served) - _rx_delay_centering = (bit_delay/2) - 2; - //Wait 1 bit - 2 micro seconds (time in each loop iteration) - _rx_delay_intrabit = bit_delay - 2; - //Wait 1 bit (the stop one) - _rx_delay_stopbit = bit_delay; - - - delayMicroseconds(_tx_delay); - } - listen(); -} - -void SoftwareSerial::end() -{ - stopListening(); -} - -int SoftwareSerial::read() -{ - if (!isListening()){ - return -1;} - - - // Empty buffer? - if (_receive_buffer_head == _receive_buffer_tail){ - return -1;} - - // Read from "head" - uint8_t d = _receive_buffer[_receive_buffer_head]; // grab next byte - _receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF; - return d; -} - - -int SoftwareSerial::available() -{ - if (!isListening()) - return 0; - - return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head) % _SS_MAX_RX_BUFF; -} - - -size_t SoftwareSerial::write(uint8_t b) -{ - if (_tx_delay == 0) { - setWriteError(); - return 0; - } - - // By declaring these as local variables, the compiler will put them - // in registers _before_ disabling interrupts and entering the - // critical timing sections below, which makes it a lot easier to - // verify the cycle timings - volatile PORT_OUT_Type *reg = _transmitPortRegister; - uint32_t reg_mask = _transmitBitMask; - uint32_t inv_mask = ~_transmitBitMask; - bool inv = _inverse_logic; - uint16_t delay = _tx_delay; - - if (inv) - b = ~b; - // turn off interrupts for a clean txmit - EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT( 1 << digitalPinToInterrupt( _receivePin )); - - // Write the start bit - if (inv) - reg->reg |= reg_mask; - else - reg->reg &= inv_mask; - - delayMicroseconds(delay); - - - // Write each of the 8 bits - for (uint8_t i = 8; i > 0; --i) - { - if (b & 1) // choose bit - reg->reg |= reg_mask; // send 1 - else - reg->reg &= inv_mask; // send 0 - - delayMicroseconds(delay); - b >>= 1; - } - - // restore pin to natural state - if (inv) - reg->reg &= inv_mask; - else - reg->reg |= reg_mask; - - - EIC->INTENSET.reg = EIC_INTENSET_EXTINT( 1 << digitalPinToInterrupt( _receivePin ) ) ; - - delayMicroseconds(delay); - - return 1; -} - -void SoftwareSerial::drainRead() -{ - if (!isListening()) - return; - - EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT( 1 << digitalPinToInterrupt( _receivePin ) ) ; - - _receive_buffer_head = _receive_buffer_tail = 0; - - EIC->INTENSET.reg = EIC_INTENSET_EXTINT( 1 << digitalPinToInterrupt( _receivePin ) ) ; - -} - -int SoftwareSerial::peek() -{ - if (!isListening()) - return -1; - - // Empty buffer? - if (_receive_buffer_head == _receive_buffer_tail) - return -1; - - // Read from "head" - return _receive_buffer[_receive_buffer_head]; -} diff --git a/MCCI_SoftSerial.h b/MCCI_SoftSerial.h deleted file mode 100644 index f01d7aa..0000000 --- a/MCCI_SoftSerial.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - MCCI_SoftSerial.cpp - library for Arduino M0/M0 pro - Copyright (c) 2016 Arduino Srl. All rights reserved. - Written by Chiara Ruggeri (chiara@arduino.org) - Portions copyright (c) 2018, 2021, 2023 MCCI Corporation. All rights reserved. - Written by Terry Moore (tmm@mcci.com) - - 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 - - Enjoy! -*/ - -#ifndef _MCCI_SoftSerial_h_ -#define _MCCI_SoftSerial_h_ - -#include -#include -#include - -/****************************************************************************** -* Definitions -******************************************************************************/ - -#define _SS_MAX_RX_BUFF 64 // RX buffer size -#ifndef GCC_VERSION -#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -#endif - -class SoftwareSerial : public Stream -{ -private: - // per object data - uint8_t _transmitPin; - uint8_t _receivePin; - uint32_t _receiveBitMask; - volatile PORT_IN_Type *_receivePortRegister; - uint32_t _transmitBitMask; - volatile PORT_OUT_Type *_transmitPortRegister; - - // Expressed as 4-cycle delays (must never be 0!) - uint16_t _rx_delay_centering; - uint16_t _rx_delay_intrabit; - uint16_t _rx_delay_stopbit; - uint16_t _tx_delay; - - uint16_t _buffer_overflow:1; - uint16_t _inverse_logic:1; - - // static data - static char _receive_buffer[_SS_MAX_RX_BUFF]; - static volatile uint8_t _receive_buffer_tail; - static volatile uint8_t _receive_buffer_head; - static SoftwareSerial *active_object; - - // private methods - void recv() __attribute__((__always_inline__)); - uint32_t rx_pin_read(); - void tx_pin_write(uint8_t pin_state) __attribute__((__always_inline__)); - void setTX(uint8_t transmitPin); - void setRX(uint8_t receivePin); - void setRxIntMsk(bool enable) __attribute__((__always_inline__)); - - -public: - // public methods - SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false); - ~SoftwareSerial(); - void begin(unsigned long speed); - void begin(unsigned long speed, uint16_t config) { this->begin(speed); } - bool listen(); - void end(); - bool isListening() { return this == active_object; } - bool stopListening(); - bool overflow() { bool ret = _buffer_overflow; if (ret) _buffer_overflow = false; return ret; } - int peek(); - - virtual size_t write(uint8_t byte); - virtual int read(); - virtual int available(); - virtual void flush() { /* nothing */ }; - operator bool() { return true; } - - using Print::write; - - // drain receive queue all at once - virtual void drainRead(void); - - // public only for easy access by interrupt handlers - static inline void handle_interrupt() __attribute__((__always_inline__)); -}; - -// Arduino 0012 workaround -#undef int -#undef char -#undef long -#undef byte -#undef float -#undef abs -#undef round - -#endif /* _MCCI_SoftSerial_h_ */ - From c2a6342bc23b521863f846f24872bfd1f8676ac2 Mon Sep 17 00:00:00 2001 From: Dhinesh Kumar Pitchai Date: Thu, 12 Jan 2023 22:27:53 +0530 Subject: [PATCH 3/5] update year in copyrights --- SoftwareSerial.cpp | 325 +++++++++++++++++++++++++++++++++++++++++++++ SoftwareSerial.h | 114 ++++++++++++++++ 2 files changed, 439 insertions(+) create mode 100644 SoftwareSerial.cpp create mode 100644 SoftwareSerial.h diff --git a/SoftwareSerial.cpp b/SoftwareSerial.cpp new file mode 100644 index 0000000..3ce104f --- /dev/null +++ b/SoftwareSerial.cpp @@ -0,0 +1,325 @@ +/* + SoftwareSerial.cpp - library for Arduino M0/M0 pro + Copyright (c) 2016 Arduino Srl. All rights reserved. + Written by Chiara Ruggeri (chiara@arduino.org) + Portions copyright (c) 2018, 2021 MCCI Corporation. All rights reserved. + Written by Terry Moore (tmm@mcci.com) + + 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 + + Enjoy! +*/ + + +#include +#include +#include +#include + +SoftwareSerial *SoftwareSerial::active_object = 0; +char SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF]; +volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0; +volatile uint8_t SoftwareSerial::_receive_buffer_head = 0; + + +bool SoftwareSerial::listen() +{ + if (!_rx_delay_stopbit) + return false; + + if (active_object != this) + { + if (active_object) + active_object->stopListening(); + + _buffer_overflow = false; + _receive_buffer_head = _receive_buffer_tail = 0; + active_object = this; + + if(_inverse_logic) + //Start bit high + attachInterrupt(_receivePin, handle_interrupt, RISING); + else + //Start bit low + attachInterrupt(_receivePin, handle_interrupt, FALLING); + + + return true; + } + return false; +} + +bool SoftwareSerial::stopListening() +{ + if (active_object == this) + { + EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT( 1 << digitalPinToInterrupt( _receivePin )) ; + active_object = NULL; + return true; + } + return false; +} + + +void SoftwareSerial::recv() +{ + + uint8_t d = 0; + + // If RX line is high, then we don't see any start bit + // so interrupt is probably not for us + if (_inverse_logic ? rx_pin_read() : !rx_pin_read()) + { + + EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT( 1 << digitalPinToInterrupt(_receivePin)); + + // Wait approximately 1/2 of a bit width to "center" the sample + delayMicroseconds(_rx_delay_centering); + + // Read each of the 8 bits + for (uint8_t i=8; i > 0; --i) + { + + delayMicroseconds(_rx_delay_intrabit); + d >>= 1; + if (rx_pin_read()){ + d |= 0x80; + } + + } + if (_inverse_logic){ + d = ~d; + } + + // if buffer full, set the overflow flag and return + uint8_t next = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF; + if (next != _receive_buffer_head) + { + // save new data in buffer: tail points to where byte goes + _receive_buffer[_receive_buffer_tail] = d; // save new byte + _receive_buffer_tail = next; + } + else + { + _buffer_overflow = true; + } + + // skip the stop bit + delayMicroseconds(_rx_delay_stopbit); + + EIC->INTENSET.reg = EIC_INTENSET_EXTINT( 1 << digitalPinToInterrupt(_receivePin)); + } +} + + +uint32_t SoftwareSerial::rx_pin_read() +{ + return _receivePortRegister->reg & digitalPinToBitMask(_receivePin); +} + +/* static */ +inline void SoftwareSerial::handle_interrupt() +{ + if (active_object) + { + active_object->recv(); + } +} + + +// Constructor +SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) : + _rx_delay_centering(0), + _rx_delay_intrabit(0), + _rx_delay_stopbit(0), + _tx_delay(0), + _buffer_overflow(false), + _inverse_logic(inverse_logic) +{ + _receivePin = receivePin; + _transmitPin = transmitPin; +} + +// Destructor +SoftwareSerial::~SoftwareSerial() +{ + end(); +} + +void SoftwareSerial::setTX(uint8_t tx) +{ + // First write, then set output. If we do this the other way around, + // the pin would be output low for a short while before switching to + // output hihg. Now, it is input with pullup for a short while, which + // is fine. With inverse logic, either order is fine. + digitalWrite(tx, _inverse_logic ? LOW : HIGH); + pinMode(tx, OUTPUT); + _transmitBitMask = digitalPinToBitMask(tx); + PortGroup * port = digitalPinToPort(tx); + _transmitPortRegister = (decltype(_transmitPortRegister)) portOutputRegister(port); + +} + +void SoftwareSerial::setRX(uint8_t rx) +{ + pinMode(rx, INPUT); + if (!_inverse_logic) + digitalWrite(rx, HIGH); // pullup for normal logic! + _receivePin = rx; + _receiveBitMask = digitalPinToBitMask(rx); + PortGroup * port = digitalPinToPort(rx); + _receivePortRegister = (decltype(_receivePortRegister)) portInputRegister(port); + +} + + +void SoftwareSerial::begin(unsigned long speed) +{ + setTX(_transmitPin); + setRX(_receivePin); + // Precalculate the various delays + //Calculate the distance between bit in micro seconds + uint32_t bit_delay = (float(1)/speed)*1000000; + + _tx_delay = bit_delay; + + // Only setup rx when we have a valid PCINT for this pin + if (digitalPinToInterrupt(_receivePin)!=NOT_AN_INTERRUPT) { + //Wait 1/2 bit - 2 micro seconds (time for interrupt to be served) + _rx_delay_centering = (bit_delay/2) - 2; + //Wait 1 bit - 2 micro seconds (time in each loop iteration) + _rx_delay_intrabit = bit_delay - 2; + //Wait 1 bit (the stop one) + _rx_delay_stopbit = bit_delay; + + + delayMicroseconds(_tx_delay); + } + listen(); +} + +void SoftwareSerial::end() +{ + stopListening(); +} + +int SoftwareSerial::read() +{ + if (!isListening()){ + return -1;} + + + // Empty buffer? + if (_receive_buffer_head == _receive_buffer_tail){ + return -1;} + + // Read from "head" + uint8_t d = _receive_buffer[_receive_buffer_head]; // grab next byte + _receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF; + return d; +} + + +int SoftwareSerial::available() +{ + if (!isListening()) + return 0; + + return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head) % _SS_MAX_RX_BUFF; +} + + +size_t SoftwareSerial::write(uint8_t b) +{ + if (_tx_delay == 0) { + setWriteError(); + return 0; + } + + // By declaring these as local variables, the compiler will put them + // in registers _before_ disabling interrupts and entering the + // critical timing sections below, which makes it a lot easier to + // verify the cycle timings + volatile PORT_OUT_Type *reg = _transmitPortRegister; + uint32_t reg_mask = _transmitBitMask; + uint32_t inv_mask = ~_transmitBitMask; + bool inv = _inverse_logic; + uint16_t delay = _tx_delay; + + if (inv) + b = ~b; + // turn off interrupts for a clean txmit + EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT( 1 << digitalPinToInterrupt( _receivePin )); + + // Write the start bit + if (inv) + reg->reg |= reg_mask; + else + reg->reg &= inv_mask; + + delayMicroseconds(delay); + + + // Write each of the 8 bits + for (uint8_t i = 8; i > 0; --i) + { + if (b & 1) // choose bit + reg->reg |= reg_mask; // send 1 + else + reg->reg &= inv_mask; // send 0 + + delayMicroseconds(delay); + b >>= 1; + } + + // restore pin to natural state + if (inv) + reg->reg &= inv_mask; + else + reg->reg |= reg_mask; + + + EIC->INTENSET.reg = EIC_INTENSET_EXTINT( 1 << digitalPinToInterrupt( _receivePin ) ) ; + + delayMicroseconds(delay); + + return 1; +} + +void SoftwareSerial::drainRead() +{ + if (!isListening()) + return; + + EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT( 1 << digitalPinToInterrupt( _receivePin ) ) ; + + _receive_buffer_head = _receive_buffer_tail = 0; + + EIC->INTENSET.reg = EIC_INTENSET_EXTINT( 1 << digitalPinToInterrupt( _receivePin ) ) ; + +} + +int SoftwareSerial::peek() +{ + if (!isListening()) + return -1; + + // Empty buffer? + if (_receive_buffer_head == _receive_buffer_tail) + return -1; + + // Read from "head" + return _receive_buffer[_receive_buffer_head]; +} diff --git a/SoftwareSerial.h b/SoftwareSerial.h new file mode 100644 index 0000000..eb55da7 --- /dev/null +++ b/SoftwareSerial.h @@ -0,0 +1,114 @@ +/* + SoftwareSerial.cpp - library for Arduino M0/M0 pro + Copyright (c) 2016 Arduino Srl. All rights reserved. + Written by Chiara Ruggeri (chiara@arduino.org) + Portions copyright (c) 2018, 2021 MCCI Corporation. All rights reserved. + Written by Terry Moore (tmm@mcci.com) + + 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 + + Enjoy! +*/ + +#ifndef SoftwareSerial_h +#define SoftwareSerial_h + +#include +#include +#include + +/****************************************************************************** +* Definitions +******************************************************************************/ + +#define _SS_MAX_RX_BUFF 64 // RX buffer size +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +class SoftwareSerial : public Stream +{ +private: + // per object data + uint8_t _transmitPin; + uint8_t _receivePin; + uint32_t _receiveBitMask; + volatile PORT_IN_Type *_receivePortRegister; + uint32_t _transmitBitMask; + volatile PORT_OUT_Type *_transmitPortRegister; + + // Expressed as 4-cycle delays (must never be 0!) + uint16_t _rx_delay_centering; + uint16_t _rx_delay_intrabit; + uint16_t _rx_delay_stopbit; + uint16_t _tx_delay; + + uint16_t _buffer_overflow:1; + uint16_t _inverse_logic:1; + + // static data + static char _receive_buffer[_SS_MAX_RX_BUFF]; + static volatile uint8_t _receive_buffer_tail; + static volatile uint8_t _receive_buffer_head; + static SoftwareSerial *active_object; + + // private methods + void recv() __attribute__((__always_inline__)); + uint32_t rx_pin_read(); + void tx_pin_write(uint8_t pin_state) __attribute__((__always_inline__)); + void setTX(uint8_t transmitPin); + void setRX(uint8_t receivePin); + void setRxIntMsk(bool enable) __attribute__((__always_inline__)); + + +public: + // public methods + SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false); + ~SoftwareSerial(); + void begin(unsigned long speed); + void begin(unsigned long speed, uint16_t config) { this->begin(speed); } + bool listen(); + void end(); + bool isListening() { return this == active_object; } + bool stopListening(); + bool overflow() { bool ret = _buffer_overflow; if (ret) _buffer_overflow = false; return ret; } + int peek(); + + virtual size_t write(uint8_t byte); + virtual int read(); + virtual int available(); + virtual void flush() { /* nothing */ }; + operator bool() { return true; } + + using Print::write; + + // drain receive queue all at once + virtual void drainRead(void); + + // public only for easy access by interrupt handlers + static inline void handle_interrupt() __attribute__((__always_inline__)); +}; + +// Arduino 0012 workaround +#undef int +#undef char +#undef long +#undef byte +#undef float +#undef abs +#undef round + +#endif + From 37a33936d257d556c8b155905cb509c128b8e8a3 Mon Sep 17 00:00:00 2001 From: Dhinesh Kumar Pitchai Date: Thu, 12 Jan 2023 22:28:27 +0530 Subject: [PATCH 4/5] update README --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 8a65910..becc7ef 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,16 @@ -# MCCI_SoftSerial library for Arduino +# SoftwareSerial library for Arduino This directory contains the SoftwareSerial library split out from https://github.com/Arduino-org/Arduino. All relevant history is retained. We split it out because it needs some TLC to be compatible with our Modbus library (in particular, the APIs didn't match the modern serial port APIs, and it will no longer compile with modern compilers -- see [issue 234](https://github.com/arduino/ArduinoCore-samd/issues/234)). -[![GitHub release](https://img.shields.io/github/release/mcci-catena/MCCI_SoftSerial/all.svg)](https://github.com/mcci-catena/MCCI_SoftSerial/releases/latest) ![GitHub commits](https://img.shields.io/github/commits-since/mcci-catena/MCCI_SoftSerial/latest.svg) +[![GitHub release](https://img.shields.io/github/release/mcci-catena/SoftwareSerial/all.svg)](https://github.com/mcci-catena/SoftwareSerial/releases/latest) ![GitHub commits](https://img.shields.io/github/commits-since/mcci-catena/SoftwareSerial/latest.svg) ## Change Summary -### v3.0.0 - -The changes are: - -- Fixed issue - ```call of overloaded 'begin(int)' is ambiguous```. +### v1.0.0 -- Modify file names to get library added in Library Manager. +This is the version as imported from Arduino. ### v2.0.0 @@ -32,6 +28,10 @@ The changes: - Added fix for [issue 234](https://github.com/arduino/ArduinoCore-samd/issues/234). -### v1.0.0 +### v3.0.0 -This is the version as imported from Arduino. +The changes are: + +- Fixed issue - ```call of overloaded 'begin(int)' is ambiguous```. + +- Modify file names to get library added in Library Manager. \ No newline at end of file From 09f0e0c621dc8b1cdd180a9c2ddae682ca924261 Mon Sep 17 00:00:00 2001 From: Dhinesh Kumar Pitchai Date: Thu, 12 Jan 2023 22:28:54 +0530 Subject: [PATCH 5/5] update name in library properties --- library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 9594992..f3b5091 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ -name=MCCI_SoftSerial +name=MCCI SofwareSerial version=3.0.0 author=Chiara Ruggeri (chiara@arduino.org) maintainer=Terry Moore sentence=Software UART for Arduino paragraph=This library allows any pair of pins to be used as a UART implemented by software. The MCCI version incorporates bug fixes and makes it more compatible with the UART and USB serial classes. category=Communication -url=https://github.com/mcci-catena/MCCI_SoftSerial +url=https://github.com/mcci-catena/SoftwareSerial architectures=*