From c51bcd77d151aa22dbb7c58fa9a8575c59192818 Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Thu, 10 May 2018 17:21:26 +0200 Subject: [PATCH] Add Hardware Serial Fallback to TasmotaSerial 5.13.1a * Update TasmotaSerial to 2.0.0 allowing Hardware Serial Fallback when correct connection are configured --- .../README.md | 5 +- .../examples/swsertest/swsertest.ino | 0 .../keywords.txt | 0 .../library.json | 4 +- .../library.properties | 4 +- .../src/TasmotaSerial.cpp | 118 +++++++++++------- .../src/TasmotaSerial.h | 4 +- sonoff/_releasenotes.ino | 1 + sonoff/support.ino | 11 +- sonoff/xdrv_03_energy.ino | 21 ++-- sonoff/xsns_15_mhz19.ino | 66 ++-------- sonoff/xsns_17_senseair.ino | 7 +- sonoff/xsns_18_pms5003.ino | 10 +- sonoff/xsns_20_novasds.ino | 8 +- 14 files changed, 131 insertions(+), 128 deletions(-) rename lib/{TasmotaSerial-1.3.0 => TasmotaSerial-2.0.0}/README.md (58%) rename lib/{TasmotaSerial-1.3.0 => TasmotaSerial-2.0.0}/examples/swsertest/swsertest.ino (100%) rename lib/{TasmotaSerial-1.3.0 => TasmotaSerial-2.0.0}/keywords.txt (100%) rename lib/{TasmotaSerial-1.3.0 => TasmotaSerial-2.0.0}/library.json (70%) rename lib/{TasmotaSerial-1.3.0 => TasmotaSerial-2.0.0}/library.properties (59%) rename lib/{TasmotaSerial-1.3.0 => TasmotaSerial-2.0.0}/src/TasmotaSerial.cpp (67%) rename lib/{TasmotaSerial-1.3.0 => TasmotaSerial-2.0.0}/src/TasmotaSerial.h (94%) diff --git a/lib/TasmotaSerial-1.3.0/README.md b/lib/TasmotaSerial-2.0.0/README.md similarity index 58% rename from lib/TasmotaSerial-1.3.0/README.md rename to lib/TasmotaSerial-2.0.0/README.md index 205a9597c..019aafc07 100644 --- a/lib/TasmotaSerial-1.3.0/README.md +++ b/lib/TasmotaSerial-2.0.0/README.md @@ -1,8 +1,7 @@ # TasmotaSerial -Implementation of software serial library for the ESP8266 +Implementation of software serial with hardware serial fallback library for the ESP8266 Allows for several instances to be active at the same time. -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. +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. diff --git a/lib/TasmotaSerial-1.3.0/examples/swsertest/swsertest.ino b/lib/TasmotaSerial-2.0.0/examples/swsertest/swsertest.ino similarity index 100% rename from lib/TasmotaSerial-1.3.0/examples/swsertest/swsertest.ino rename to lib/TasmotaSerial-2.0.0/examples/swsertest/swsertest.ino diff --git a/lib/TasmotaSerial-1.3.0/keywords.txt b/lib/TasmotaSerial-2.0.0/keywords.txt similarity index 100% rename from lib/TasmotaSerial-1.3.0/keywords.txt rename to lib/TasmotaSerial-2.0.0/keywords.txt diff --git a/lib/TasmotaSerial-1.3.0/library.json b/lib/TasmotaSerial-2.0.0/library.json similarity index 70% rename from lib/TasmotaSerial-1.3.0/library.json rename to lib/TasmotaSerial-2.0.0/library.json index 0183c43ce..00a2a9e0f 100644 --- a/lib/TasmotaSerial-1.3.0/library.json +++ b/lib/TasmotaSerial-2.0.0/library.json @@ -1,10 +1,10 @@ { "name": "TasmotaSerial", - "version": "1.3.0", + "version": "2.0.0", "keywords": [ "serial", "io", "TasmotaSerial" ], - "description": "Implementation of software serial for ESP8266.", + "description": "Implementation of software serial with hardware serial fallback for ESP8266.", "repository": { "type": "git", diff --git a/lib/TasmotaSerial-1.3.0/library.properties b/lib/TasmotaSerial-2.0.0/library.properties similarity index 59% rename from lib/TasmotaSerial-1.3.0/library.properties rename to lib/TasmotaSerial-2.0.0/library.properties index 531fab514..b250399b9 100644 --- a/lib/TasmotaSerial-1.3.0/library.properties +++ b/lib/TasmotaSerial-2.0.0/library.properties @@ -1,8 +1,8 @@ name=TasmotaSerial -version=1.3.0 +version=2.0.0 author=Theo Arends maintainer=Theo Arends -sentence=Implementation of software serial for ESP8266. +sentence=Implementation of software serial with hardware serial fallback for ESP8266. paragraph= category=Signal Input/Output url= diff --git a/lib/TasmotaSerial-1.3.0/src/TasmotaSerial.cpp b/lib/TasmotaSerial-2.0.0/src/TasmotaSerial.cpp similarity index 67% rename from lib/TasmotaSerial-1.3.0/src/TasmotaSerial.cpp rename to lib/TasmotaSerial-2.0.0/src/TasmotaSerial.cpp index 801384f23..cbd2a3523 100644 --- a/lib/TasmotaSerial-1.3.0/src/TasmotaSerial.cpp +++ b/lib/TasmotaSerial-2.0.0/src/TasmotaSerial.cpp @@ -76,27 +76,32 @@ static void (*ISRList[16])() = { tms_isr_15 }; -TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin) +TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, bool hardware_fallback) { m_valid = false; + m_hardserial = 0; if (!((isValidGPIOpin(receive_pin)) && (isValidGPIOpin(transmit_pin) || transmit_pin == 16))) { return; } m_rx_pin = receive_pin; m_tx_pin = transmit_pin; m_in_pos = m_out_pos = 0; - if (m_rx_pin > -1) { - m_buffer = (uint8_t*)malloc(TM_SERIAL_BUFFER_SIZE); - if (m_buffer == NULL) return; - // Use getCycleCount() loop to get as exact timing as possible - m_bit_time = ESP.getCpuFreqMHz() *1000000 /TM_SERIAL_BAUDRATE; - pinMode(m_rx_pin, INPUT); - tms_obj_list[m_rx_pin] = this; - attachInterrupt(m_rx_pin, ISRList[m_rx_pin], FALLING); - } - if (m_tx_pin > -1) { - pinMode(m_tx_pin, OUTPUT); - digitalWrite(m_tx_pin, HIGH); + if (hardware_fallback && (((1 == m_rx_pin) && (3 == m_tx_pin)) || ((3 == m_rx_pin) && (-1 == m_tx_pin)) || ((-1 == m_rx_pin) && (1 == m_tx_pin)))) { + m_hardserial = 1; + } else { + if (m_rx_pin > -1) { + m_buffer = (uint8_t*)malloc(TM_SERIAL_BUFFER_SIZE); + if (m_buffer == NULL) return; + // Use getCycleCount() loop to get as exact timing as possible + m_bit_time = ESP.getCpuFreqMHz() *1000000 /TM_SERIAL_BAUDRATE; + pinMode(m_rx_pin, INPUT); + tms_obj_list[m_rx_pin] = this; + attachInterrupt(m_rx_pin, ISRList[m_rx_pin], FALLING); + } + if (m_tx_pin > -1) { + pinMode(m_tx_pin, OUTPUT); + digitalWrite(m_tx_pin, HIGH); + } } m_valid = true; } @@ -107,9 +112,14 @@ bool TasmotaSerial::isValidGPIOpin(int pin) } bool TasmotaSerial::begin(long speed) { - // Use getCycleCount() loop to get as exact timing as possible - m_bit_time = ESP.getCpuFreqMHz() *1000000 /speed; - m_high_speed = (speed > 9600); + if (m_hardserial) { + Serial.flush(); + Serial.begin(speed, SERIAL_8N1); + } else { + // Use getCycleCount() loop to get as exact timing as possible + m_bit_time = ESP.getCpuFreqMHz() *1000000 /speed; + m_high_speed = (speed > 9600); + } return m_valid; } @@ -117,28 +127,48 @@ bool TasmotaSerial::begin() { return begin(TM_SERIAL_BAUDRATE); } +bool TasmotaSerial::hardwareSerial() { + return m_hardserial; +} + void TasmotaSerial::flush() { - m_in_pos = m_out_pos = 0; + if (m_hardserial) { + Serial.flush(); + } else { + m_in_pos = m_out_pos = 0; + } } int TasmotaSerial::peek() { - if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) return -1; - return m_buffer[m_out_pos]; + if (m_hardserial) { + return Serial.peek(); + } else { + if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) return -1; + return m_buffer[m_out_pos]; + } } int TasmotaSerial::read() { - if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) return -1; - uint8_t ch = m_buffer[m_out_pos]; - m_out_pos = (m_out_pos +1) % TM_SERIAL_BUFFER_SIZE; - return ch; + if (m_hardserial) { + return Serial.read(); + } else { + if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) return -1; + uint8_t ch = m_buffer[m_out_pos]; + m_out_pos = (m_out_pos +1) % TM_SERIAL_BUFFER_SIZE; + return ch; + } } int TasmotaSerial::available() { - int avail = m_in_pos - m_out_pos; - if (avail < 0) avail += TM_SERIAL_BUFFER_SIZE; - return avail; + if (m_hardserial) { + return Serial.available(); + } else { + int avail = m_in_pos - m_out_pos; + if (avail < 0) avail += TM_SERIAL_BUFFER_SIZE; + return avail; + } } #ifdef TM_SERIAL_USE_IRAM @@ -149,24 +179,28 @@ int TasmotaSerial::available() size_t TasmotaSerial::write(uint8_t b) { - if (-1 == m_tx_pin) return 0; - if (m_high_speed) cli(); // Disable interrupts in order to get a clean transmit - unsigned long wait = m_bit_time; - digitalWrite(m_tx_pin, HIGH); - unsigned long start = ESP.getCycleCount(); - // Start bit; - digitalWrite(m_tx_pin, LOW); - TM_SERIAL_WAIT; - for (int i = 0; i < 8; i++) { - digitalWrite(m_tx_pin, (b & 1) ? HIGH : LOW); + if (m_hardserial) { + return Serial.write(b); + } else { + if (-1 == m_tx_pin) return 0; + if (m_high_speed) cli(); // Disable interrupts in order to get a clean transmit + unsigned long wait = m_bit_time; + digitalWrite(m_tx_pin, HIGH); + unsigned long start = ESP.getCycleCount(); + // Start bit; + digitalWrite(m_tx_pin, LOW); TM_SERIAL_WAIT; - b >>= 1; + for (int i = 0; i < 8; i++) { + digitalWrite(m_tx_pin, (b & 1) ? HIGH : LOW); + TM_SERIAL_WAIT; + b >>= 1; + } + // Stop bit + digitalWrite(m_tx_pin, HIGH); + TM_SERIAL_WAIT; + if (m_high_speed) sei(); + return 1; } - // Stop bit - digitalWrite(m_tx_pin, HIGH); - TM_SERIAL_WAIT; - if (m_high_speed) sei(); - return 1; } #ifdef TM_SERIAL_USE_IRAM diff --git a/lib/TasmotaSerial-1.3.0/src/TasmotaSerial.h b/lib/TasmotaSerial-2.0.0/src/TasmotaSerial.h similarity index 94% rename from lib/TasmotaSerial-1.3.0/src/TasmotaSerial.h rename to lib/TasmotaSerial-2.0.0/src/TasmotaSerial.h index 0876590fe..d4c993368 100644 --- a/lib/TasmotaSerial-1.3.0/src/TasmotaSerial.h +++ b/lib/TasmotaSerial-2.0.0/src/TasmotaSerial.h @@ -37,9 +37,10 @@ class TasmotaSerial : public Stream { public: - TasmotaSerial(int receive_pin, int transmit_pin); + TasmotaSerial(int receive_pin, int transmit_pin, bool hardware_fallback = false); bool begin(long speed); bool begin(); + bool hardwareSerial(); int peek(); virtual size_t write(uint8_t byte); @@ -57,6 +58,7 @@ class TasmotaSerial : public Stream { // Member variables bool m_valid; + bool m_hardserial; bool m_high_speed; int m_rx_pin; int m_tx_pin; diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index 2e6c44bf9..04329ad25 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -10,6 +10,7 @@ * Add rule state test for On/Off in addition to 0/1 (#2613) * Add hardware serial option to MHZ-19 sensor (#2659) * Updated Italian language file (#2618) + * Update TasmotaSerial to 2.0.0 allowing Hardware Serial Fallback when correct connection are configured * Optimize command handling * * 5.13.1 20180501 diff --git a/sonoff/support.ino b/sonoff/support.ino index 1cf6713ab..d17776325 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -486,12 +486,13 @@ void SetSerialBaudrate(int baudrate) } } -void SetSerialLocal(bool slocal) +void ClaimSerial() { - serial_local = slocal; - if (slocal) { - SetSeriallog(LOG_LEVEL_NONE); - } + serial_local = 1; + AddLog_P(LOG_LEVEL_INFO, PSTR("SNS: Hardware Serial")); + SetSeriallog(LOG_LEVEL_NONE); + baudrate = Serial.baudRate(); + Settings.baudrate = baudrate / 1200; } uint32_t GetHash(const char *buffer, size_t size) diff --git a/sonoff/xdrv_03_energy.ino b/sonoff/xdrv_03_energy.ino index 499162223..c41af56a4 100644 --- a/sonoff/xdrv_03_energy.ino +++ b/sonoff/xdrv_03_energy.ino @@ -408,6 +408,8 @@ void CseEverySecond() * * Source: Victor Ferrer https://github.com/vicfergar/Sonoff-MQTT-OTA-Arduino * Based on: PZEM004T library https://github.com/olehs/PZEM004T + * + * Hardware Serial will be selected if GPIO1 = [PZEM Rx] and [GPIO3 = PZEM Tx] \*********************************************************************************************/ #include @@ -434,6 +436,8 @@ TasmotaSerial *PzemSerial; #define PZEM_DEFAULT_READ_TIMEOUT 500 +/*********************************************************************************************/ + struct PZEMCommand { uint8_t command; uint8_t addr[4]; @@ -564,12 +568,6 @@ void PzemEvery200ms() } } -bool PzemInit() -{ - PzemSerial = new TasmotaSerial(pin[GPIO_PZEM_RX], pin[GPIO_PZEM_TX]); - return PzemSerial->begin(); -} - /********************************************************************************************/ #endif // USE_PZEM004T @@ -1033,7 +1031,7 @@ void EnergyDrvInit() serial_config = SERIAL_8E1; energy_flg = ENERGY_CSE7766; #ifdef USE_PZEM004T - } else if ((pin[GPIO_PZEM_RX] < 99) && (pin[GPIO_PZEM_TX])) { // Any device with a Pzem004T + } else if ((pin[GPIO_PZEM_RX] < 99) && (pin[GPIO_PZEM_TX] < 99)) { // Any device with a Pzem004T energy_flg = ENERGY_PZEM004T; #endif // USE_PZEM004T } @@ -1044,8 +1042,13 @@ void EnergySnsInit() if (ENERGY_HLW8012 == energy_flg) HlwInit(); #ifdef USE_PZEM004T - if ((ENERGY_PZEM004T == energy_flg) && !PzemInit()) { // PzemInit needs to be done here as earlier (serial) interrupts may lead to Exceptions - energy_flg = ENERGY_NONE; + if (ENERGY_PZEM004T == energy_flg) { // Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions + PzemSerial = new TasmotaSerial(pin[GPIO_PZEM_RX], pin[GPIO_PZEM_TX], 1); + if (PzemSerial->begin(9600)) { + if (PzemSerial->hardwareSerial()) { ClaimSerial(); } + } else { + energy_flg = ENERGY_NONE; + } } #endif // USE_PZEM004T diff --git a/sonoff/xsns_15_mhz19.ino b/sonoff/xsns_15_mhz19.ino index 81069954a..3b9945bca 100644 --- a/sonoff/xsns_15_mhz19.ino +++ b/sonoff/xsns_15_mhz19.ino @@ -25,6 +25,8 @@ * MH-Z19 - CO2 sensor * * Adapted from EspEasy plugin P049 by Dmitry (rel22 ___ inbox.ru) + * + * Hardware Serial will be selected if GPIO1 = [MHZ Rx] and GPIO3 = [MHZ Tx] ********************************************************************************************** * Filter usage * @@ -91,46 +93,6 @@ uint8_t mhz_retry = MHZ19_RETRY_COUNT; uint8_t mhz_received = 0; uint8_t mhz_state = 0; -uint8_t mhz_hard_serial = 0; - -/*********************************************************************************************/ - -size_t MhzSerialAvailable() -{ - if (mhz_hard_serial) { - return Serial.available(); - } else { - return MhzSerial->available(); - } -} - -void MhzSerialFlush() -{ - if (mhz_hard_serial) { - Serial.flush(); - } else { - MhzSerial->flush(); - } -} - -size_t MhzSerialWrite(byte *array, size_t size) -{ - if (mhz_hard_serial) { - return Serial.write(array, size); - } else { - return MhzSerial->write(array, size); - } -} - -int MhzSerialRead() -{ - if (mhz_hard_serial) { - return Serial.read(); - } else { - return MhzSerial->read(); - } -} - /*********************************************************************************************/ byte MhzCalculateChecksum(byte *array) @@ -158,7 +120,7 @@ size_t MhzSendCmd(byte command_id) */ mhz_send[8] = MhzCalculateChecksum(mhz_send); - return MhzSerialWrite(mhz_send, sizeof(mhz_send)); + return MhzSerial->write(mhz_send, sizeof(mhz_send)); } /*********************************************************************************************/ @@ -212,7 +174,7 @@ void MhzEverySecond() } } - MhzSerialFlush(); // Sync reception + MhzSerial->flush(); // Sync reception MhzSendCmd(MHZ_CMND_READPPM); mhz_received = 0; } @@ -223,8 +185,8 @@ void MhzEverySecond() unsigned long start = millis(); uint8_t counter = 0; while (((millis() - start) < MHZ19_READ_TIMEOUT) && (counter < 9)) { - if (MhzSerialAvailable() > 0) { - mhz_response[counter++] = MhzSerialRead(); + if (MhzSerial->available() > 0) { + mhz_response[counter++] = MhzSerial->read(); } else { delay(5); } @@ -322,20 +284,12 @@ void MhzInit() { mhz_type = 0; if ((pin[GPIO_MHZ_RXD] < 99) && (pin[GPIO_MHZ_TXD] < 99)) { - if ((1 == pin[GPIO_MHZ_RXD]) && (3 == pin[GPIO_MHZ_TXD])) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("MHZ: Hardware serial")); - baudrate = 9600; - SetSerialBaudrate(baudrate); - SetSerialLocal(true); - mhz_hard_serial = 1; + MhzSerial = new TasmotaSerial(pin[GPIO_MHZ_RXD], pin[GPIO_MHZ_TXD], 1); + if (MhzSerial->begin(9600)) { + if (MhzSerial->hardwareSerial()) { ClaimSerial(); } mhz_type = 1; - } else { - MhzSerial = new TasmotaSerial(pin[GPIO_MHZ_RXD], pin[GPIO_MHZ_TXD]); - if (MhzSerial->begin(9600)) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("MHZ: Software serial")); - mhz_type = 1; - } } + } } diff --git a/sonoff/xsns_17_senseair.ino b/sonoff/xsns_17_senseair.ino index 3e938bdea..2c059bb1b 100644 --- a/sonoff/xsns_17_senseair.ino +++ b/sonoff/xsns_17_senseair.ino @@ -22,6 +22,8 @@ * SenseAir K30, K70 and S8 - CO2 sensor * * Adapted from EspEasy plugin P052 by Mikael Trieb (mikael__AT__triebconsulting.se) + * + * Hardware Serial will be selected if GPIO1 = [SAir Rx] and GPIO3 = [SAir Tx] \*********************************************************************************************/ #include @@ -191,8 +193,9 @@ void SenseairInit() { senseair_type = 0; if ((pin[GPIO_SAIR_RX] < 99) && (pin[GPIO_SAIR_TX] < 99)) { - SensairSerial = new TasmotaSerial(pin[GPIO_SAIR_RX], pin[GPIO_SAIR_TX]); - if (SensairSerial->begin()) { + SensairSerial = new TasmotaSerial(pin[GPIO_SAIR_RX], pin[GPIO_SAIR_TX], 1); + if (SensairSerial->begin(9600)) { + if (SensairSerial->hardwareSerial()) { ClaimSerial(); } senseair_type = 1; } } diff --git a/sonoff/xsns_18_pms5003.ino b/sonoff/xsns_18_pms5003.ino index 55a3b134e..fb2aca0fb 100644 --- a/sonoff/xsns_18_pms5003.ino +++ b/sonoff/xsns_18_pms5003.ino @@ -21,6 +21,8 @@ /*********************************************************************************************\ * PlanTower PMS5003 and PMS7003 particle concentration sensor * For background information see http://aqicn.org/sensor/pms5003-7003/ + * + * Hardware Serial will be selected if GPIO3 = [PMS5003] \*********************************************************************************************/ #include @@ -39,6 +41,8 @@ struct pms5003data { uint16_t checksum; } pms_data; +/*********************************************************************************************/ + boolean PmsReadData() { if (! PmsSerial->available()) { @@ -97,10 +101,10 @@ void PmsSecond() // Every second void PmsInit() { pms_type = 0; - if (pin[GPIO_PMS5003] < 99) { - PmsSerial = new TasmotaSerial(pin[GPIO_PMS5003], -1); - if (PmsSerial->begin()) { + PmsSerial = new TasmotaSerial(pin[GPIO_PMS5003], -1, 1); + if (PmsSerial->begin(9600)) { + if (PmsSerial->hardwareSerial()) { ClaimSerial(); } pms_type = 1; } } diff --git a/sonoff/xsns_20_novasds.ino b/sonoff/xsns_20_novasds.ino index 5c38ff0f5..dc5f0ab66 100644 --- a/sonoff/xsns_20_novasds.ino +++ b/sonoff/xsns_20_novasds.ino @@ -21,6 +21,8 @@ /*********************************************************************************************\ * Nova Fitness SDS011 (and possibly SDS021) particle concentration sensor * For background information see http://aqicn.org/sensor/sds011/ + * + * Hardware Serial will be selected if GPIO3 = [SDS0X01] \*********************************************************************************************/ #include @@ -81,10 +83,10 @@ void NovaSdsSecond() // Every second void NovaSdsInit() { novasds_type = 0; - if (pin[GPIO_SDS0X1] < 99) { - NovaSdsSerial = new TasmotaSerial(pin[GPIO_SDS0X1], -1); - if (NovaSdsSerial->begin()) { + NovaSdsSerial = new TasmotaSerial(pin[GPIO_SDS0X1], -1, 1); + if (NovaSdsSerial->begin(9600)) { + if (NovaSdsSerial->hardwareSerial()) { ClaimSerial(); } novasds_type = 1; } }