diff --git a/lib/EspSoftwareSerial-3.3.1/README.md b/lib/EspSoftwareSerial-3.3.1/README.md new file mode 100644 index 000000000000..43c4ef4a64aa --- /dev/null +++ b/lib/EspSoftwareSerial-3.3.1/README.md @@ -0,0 +1,11 @@ +# EspSoftwareSerial + +Implementation of the Arduino software serial library for the ESP8266 + +Same functionality as the corresponding AVR library but several instances can be active at the same time. +Speed up to 115200 baud is supported. The constructor also has an optional input buffer size. + +Please note that due to the fact that the ESP always have other activities ongoing, there will be some inexactness in interrupt +timings. This may lead to bit errors when having heavy data traffic in high baud rates. + + diff --git a/lib/EspSoftwareSerial-3.3.1/SoftwareSerial.cpp b/lib/EspSoftwareSerial-3.3.1/SoftwareSerial.cpp new file mode 100644 index 000000000000..c498b7505368 --- /dev/null +++ b/lib/EspSoftwareSerial-3.3.1/SoftwareSerial.cpp @@ -0,0 +1,228 @@ +/* + +SoftwareSerial.cpp - Implementation of the Arduino software serial for ESP8266. +Copyright (c) 2015-2016 Peter Lerup. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include + +// The Arduino standard GPIO routines are not enough, +// must use some from the Espressif SDK as well +extern "C" { +#include "gpio.h" +} + +#include + +#define MAX_PIN 15 + +// As the Arduino attachInterrupt has no parameter, lists of objects +// and callbacks corresponding to each possible GPIO pins have to be defined +SoftwareSerial *ObjList[MAX_PIN+1]; + +void ICACHE_RAM_ATTR sws_isr_0() { ObjList[0]->rxRead(); }; +void ICACHE_RAM_ATTR sws_isr_1() { ObjList[1]->rxRead(); }; +void ICACHE_RAM_ATTR sws_isr_2() { ObjList[2]->rxRead(); }; +void ICACHE_RAM_ATTR sws_isr_3() { ObjList[3]->rxRead(); }; +void ICACHE_RAM_ATTR sws_isr_4() { ObjList[4]->rxRead(); }; +void ICACHE_RAM_ATTR sws_isr_5() { ObjList[5]->rxRead(); }; +// Pin 6 to 11 can not be used +void ICACHE_RAM_ATTR sws_isr_12() { ObjList[12]->rxRead(); }; +void ICACHE_RAM_ATTR sws_isr_13() { ObjList[13]->rxRead(); }; +void ICACHE_RAM_ATTR sws_isr_14() { ObjList[14]->rxRead(); }; +void ICACHE_RAM_ATTR sws_isr_15() { ObjList[15]->rxRead(); }; + +static void (*ISRList[MAX_PIN+1])() = { + sws_isr_0, + sws_isr_1, + sws_isr_2, + sws_isr_3, + sws_isr_4, + sws_isr_5, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + sws_isr_12, + sws_isr_13, + sws_isr_14, + sws_isr_15 +}; + +SoftwareSerial::SoftwareSerial(int receivePin, int transmitPin, bool inverse_logic, unsigned int buffSize) { + m_rxValid = m_txValid = m_txEnableValid = false; + m_buffer = NULL; + m_invert = inverse_logic; + m_overflow = false; + m_rxEnabled = false; + if (isValidGPIOpin(receivePin)) { + m_rxPin = receivePin; + m_buffSize = buffSize; + m_buffer = (uint8_t*)malloc(m_buffSize); + if (m_buffer != NULL) { + m_rxValid = true; + m_inPos = m_outPos = 0; + pinMode(m_rxPin, INPUT); + ObjList[m_rxPin] = this; + enableRx(true); + } + } + if (isValidGPIOpin(transmitPin) || transmitPin == 16) { + m_txValid = true; + m_txPin = transmitPin; + pinMode(m_txPin, OUTPUT); + digitalWrite(m_txPin, !m_invert); + } + // Default speed + begin(9600); +} + +SoftwareSerial::~SoftwareSerial() { + enableRx(false); + if (m_rxValid) + ObjList[m_rxPin] = NULL; + if (m_buffer) + free(m_buffer); +} + +bool SoftwareSerial::isValidGPIOpin(int pin) { + return (pin >= 0 && pin <= 5) || (pin >= 12 && pin <= MAX_PIN); +} + +void SoftwareSerial::begin(long speed) { + // Use getCycleCount() loop to get as exact timing as possible + m_bitTime = ESP.getCpuFreqMHz()*1000000/speed; + m_highSpeed = speed > 9600; + + if (!m_rxEnabled) + enableRx(true); +} + +long SoftwareSerial::baudRate() { + return ESP.getCpuFreqMHz()*1000000/m_bitTime; +} + +void SoftwareSerial::setTransmitEnablePin(int transmitEnablePin) { + if (isValidGPIOpin(transmitEnablePin)) { + m_txEnableValid = true; + m_txEnablePin = transmitEnablePin; + pinMode(m_txEnablePin, OUTPUT); + digitalWrite(m_txEnablePin, LOW); + } else { + m_txEnableValid = false; + } +} + +void SoftwareSerial::enableRx(bool on) { + if (m_rxValid) { + if (on) + attachInterrupt(m_rxPin, ISRList[m_rxPin], m_invert ? RISING : FALLING); + else + detachInterrupt(m_rxPin); + m_rxEnabled = on; + } +} + +int SoftwareSerial::read() { + if (!m_rxValid || (m_inPos == m_outPos)) return -1; + uint8_t ch = m_buffer[m_outPos]; + m_outPos = (m_outPos+1) % m_buffSize; + return ch; +} + +int SoftwareSerial::available() { + if (!m_rxValid) return 0; + int avail = m_inPos - m_outPos; + if (avail < 0) avail += m_buffSize; + return avail; +} + +#define WAIT { while (ESP.getCycleCount()-start < wait) if (!m_highSpeed) optimistic_yield(1); wait += m_bitTime; } + +size_t SoftwareSerial::write(uint8_t b) { + if (!m_txValid) return 0; + + if (m_invert) b = ~b; + if (m_highSpeed) + // Disable interrupts in order to get a clean transmit + cli(); + if (m_txEnableValid) digitalWrite(m_txEnablePin, HIGH); + unsigned long wait = m_bitTime; + digitalWrite(m_txPin, HIGH); + unsigned long start = ESP.getCycleCount(); + // Start bit; + digitalWrite(m_txPin, LOW); + WAIT; + for (int i = 0; i < 8; i++) { + digitalWrite(m_txPin, (b & 1) ? HIGH : LOW); + WAIT; + b >>= 1; + } + // Stop bit + digitalWrite(m_txPin, HIGH); + WAIT; + if (m_txEnableValid) digitalWrite(m_txEnablePin, LOW); + if (m_highSpeed) + sei(); + return 1; +} + +void SoftwareSerial::flush() { + m_inPos = m_outPos = 0; +} + +bool SoftwareSerial::overflow() { + bool res = m_overflow; + m_overflow = false; + return res; +} + +int SoftwareSerial::peek() { + if (!m_rxValid || (m_inPos == m_outPos)) return -1; + return m_buffer[m_outPos]; +} + +void ICACHE_RAM_ATTR SoftwareSerial::rxRead() { + // Advance the starting point for the samples but compensate for the + // initial delay which occurs before the interrupt is delivered + unsigned long wait = m_bitTime + m_bitTime/3 - 500; + unsigned long start = ESP.getCycleCount(); + uint8_t rec = 0; + for (int i = 0; i < 8; i++) { + WAIT; + rec >>= 1; + if (digitalRead(m_rxPin)) + rec |= 0x80; + } + if (m_invert) rec = ~rec; + // Stop bit + WAIT; + // Store the received value in the buffer unless we have an overflow + int next = (m_inPos+1) % m_buffSize; + if (next != m_outPos) { + m_buffer[m_inPos] = rec; + m_inPos = next; + } else { + m_overflow = true; + } + // Must clear this bit in the interrupt register, + // it gets set even when interrupts are disabled + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << m_rxPin); +} diff --git a/lib/EspSoftwareSerial-3.3.1/SoftwareSerial.h b/lib/EspSoftwareSerial-3.3.1/SoftwareSerial.h new file mode 100644 index 000000000000..75905ff39a05 --- /dev/null +++ b/lib/EspSoftwareSerial-3.3.1/SoftwareSerial.h @@ -0,0 +1,88 @@ +/* +SoftwareSerial.h + +SoftwareSerial.cpp - Implementation of the Arduino software serial for ESP8266. +Copyright (c) 2015-2016 Peter Lerup. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef SoftwareSerial_h +#define SoftwareSerial_h + +#include +#include + + +// This class is compatible with the corresponding AVR one, +// the constructor however has an optional rx buffer size. +// Speed up to 115200 can be used. + + +class SoftwareSerial : public Stream +{ +public: + SoftwareSerial(int receivePin, int transmitPin, bool inverse_logic = false, unsigned int buffSize = 64); + ~SoftwareSerial(); + + void begin(long speed); + long baudRate(); + void setTransmitEnablePin(int transmitEnablePin); + + bool overflow(); + int peek(); + + virtual size_t write(uint8_t byte); + virtual int read(); + virtual int available(); + virtual void flush(); + operator bool() {return m_rxValid || m_txValid;} + + // Disable or enable interrupts on the rx pin + void enableRx(bool on); + + void rxRead(); + + // AVR compatibility methods + bool listen() { enableRx(true); return true; } + void end() { stopListening(); } + bool isListening() { return m_rxEnabled; } + bool stopListening() { enableRx(false); return true; } + + using Print::write; + +private: + bool isValidGPIOpin(int pin); + + // Member variables + int m_rxPin, m_txPin, m_txEnablePin; + bool m_rxValid, m_rxEnabled; + bool m_txValid, m_txEnableValid; + bool m_invert; + bool m_overflow; + unsigned long m_bitTime; + bool m_highSpeed; + unsigned int m_inPos, m_outPos; + int m_buffSize; + uint8_t *m_buffer; + +}; + +// If only one tx or rx wanted then use this as parameter for the unused pin +#define SW_SERIAL_UNUSED_PIN -1 + + +#endif diff --git a/lib/EspSoftwareSerial-3.3.1/examples/swsertest/swsertest.ino b/lib/EspSoftwareSerial-3.3.1/examples/swsertest/swsertest.ino new file mode 100644 index 000000000000..b3ae697110a5 --- /dev/null +++ b/lib/EspSoftwareSerial-3.3.1/examples/swsertest/swsertest.ino @@ -0,0 +1,27 @@ + +#include + +SoftwareSerial swSer(14, 12, false, 256); + +void setup() { + Serial.begin(115200); + swSer.begin(115200); + + Serial.println("\nSoftware serial test started"); + + for (char ch = ' '; ch <= 'z'; ch++) { + swSer.write(ch); + } + swSer.println(""); + +} + +void loop() { + while (swSer.available() > 0) { + Serial.write(swSer.read()); + } + while (Serial.available() > 0) { + swSer.write(Serial.read()); + } + +} diff --git a/lib/EspSoftwareSerial-3.3.1/keywords.txt b/lib/EspSoftwareSerial-3.3.1/keywords.txt new file mode 100644 index 000000000000..5faea2a963b1 --- /dev/null +++ b/lib/EspSoftwareSerial-3.3.1/keywords.txt @@ -0,0 +1,31 @@ +####################################### +# Syntax Coloring Map for SoftwareSerial +# (esp8266) +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SoftwareSerial KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +read KEYWORD2 +write KEYWORD2 +available KEYWORD2 +flush KEYWORD2 +overflow KEYWORD2 +peek KEYWORD2 +listen KEYWORD2 +end KEYWORD2 +isListening KEYWORD2 +stopListening KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/lib/EspSoftwareSerial-3.3.1/library.json b/lib/EspSoftwareSerial-3.3.1/library.json new file mode 100644 index 000000000000..46e18b6bee3d --- /dev/null +++ b/lib/EspSoftwareSerial-3.3.1/library.json @@ -0,0 +1,15 @@ +{ + "name": "EspSoftwareSerial", + "version": "3.3.1", + "keywords": [ + "serial", "io", "softwareserial" + ], + "description": "Implementation of the Arduino software serial for ESP8266.", + "repository": + { + "type": "git", + "url": "https://github.com/plerup/espsoftwareserial" + }, + "frameworks": "arduino", + "platforms": "espressif8266" +} diff --git a/lib/EspSoftwareSerial-3.3.1/library.properties b/lib/EspSoftwareSerial-3.3.1/library.properties new file mode 100644 index 000000000000..9e53e159cc12 --- /dev/null +++ b/lib/EspSoftwareSerial-3.3.1/library.properties @@ -0,0 +1,9 @@ +name=SoftwareSerial +version=1.0 +author=Peter Lerup +maintainer=Peter Lerup +sentence=Implementation of the Arduino software serial for ESP8266. +paragraph= +category=Signal Input/Output +url= +architectures=esp8266 diff --git a/sonoff/user_config.h b/sonoff/user_config.h index c49e1e3486ed..6d04f7a55d70 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -191,6 +191,7 @@ //#define USE_MHZ19 // Add support for MH-Z19 CO2 sensor using hardware serial interface at 9600 bps (+1k1 code) //#define USE_MHZ19_SOFT_SERIAL // Add support for MH-Z19 CO2 sensor using iram free software serial interface at 9600 bps (+2k3 code) +// #define USE_SERIAL_NO_ICACHE // Use no iram with SoftwareSerial (may loose characters) #define USE_ARILUX_RF // Add support for Arilux RF remote controller (+0k8 code) diff --git a/sonoff/xsns_15_mhz_softserial.ino b/sonoff/xsns_15_mhz_softserial.ino index fe928a16fc9e..a91dd8c3b9b9 100644 --- a/sonoff/xsns_15_mhz_softserial.ino +++ b/sonoff/xsns_15_mhz_softserial.ino @@ -28,8 +28,13 @@ * Select filter usage on low stability readings \*********************************************************************************************/ -#include -SoftwareSerialNoIram *SoftSerial; +#ifdef USE_SERIAL_NO_ICACHE + #include + SoftwareSerialNoIram *SoftSerial; +#else + #include + SoftwareSerial *SoftSerial; +#endif // USE_SERIAL_NO_ICACHE enum Mhz19FilterOptions {MHZ19_FILTER_OFF, MHZ19_FILTER_OFF_ALLSAMPLES, MHZ19_FILTER_FAST, MHZ19_FILTER_MEDIUM, MHZ19_FILTER_SLOW}; @@ -206,9 +211,13 @@ bool Mhz19Read(uint16_t &p, float &t) void Mhz19Init() { +#ifdef USE_SERIAL_NO_ICACHE SoftSerial = new SoftwareSerialNoIram(pin[GPIO_MHZ_RXD], pin[GPIO_MHZ_TXD]); - SoftSerial->begin(9600); +#else + SoftSerial = new SoftwareSerial(pin[GPIO_MHZ_RXD], pin[GPIO_MHZ_TXD]); +#endif // USE_SERIAL_NO_ICACHE + SoftSerial->begin(9600); mhz19_type = 1; }