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_ */ -