Merge branch 'development' of https://github.com/arendst/Sonoff-Tasmota into development

This commit is contained in:
Gennaro Tortone 2018-05-10 17:34:06 +02:00
commit 4109922538
14 changed files with 131 additions and 128 deletions

View File

@ -1,8 +1,7 @@
# TasmotaSerial # 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. 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 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.
timings. This may lead to bit errors when having heavy data traffic.

View File

@ -1,10 +1,10 @@
{ {
"name": "TasmotaSerial", "name": "TasmotaSerial",
"version": "1.3.0", "version": "2.0.0",
"keywords": [ "keywords": [
"serial", "io", "TasmotaSerial" "serial", "io", "TasmotaSerial"
], ],
"description": "Implementation of software serial for ESP8266.", "description": "Implementation of software serial with hardware serial fallback for ESP8266.",
"repository": "repository":
{ {
"type": "git", "type": "git",

View File

@ -1,8 +1,8 @@
name=TasmotaSerial name=TasmotaSerial
version=1.3.0 version=2.0.0
author=Theo Arends author=Theo Arends
maintainer=Theo Arends <theo@arends.com> maintainer=Theo Arends <theo@arends.com>
sentence=Implementation of software serial for ESP8266. sentence=Implementation of software serial with hardware serial fallback for ESP8266.
paragraph= paragraph=
category=Signal Input/Output category=Signal Input/Output
url= url=

View File

@ -76,27 +76,32 @@ static void (*ISRList[16])() = {
tms_isr_15 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_valid = false;
m_hardserial = 0;
if (!((isValidGPIOpin(receive_pin)) && (isValidGPIOpin(transmit_pin) || transmit_pin == 16))) { if (!((isValidGPIOpin(receive_pin)) && (isValidGPIOpin(transmit_pin) || transmit_pin == 16))) {
return; return;
} }
m_rx_pin = receive_pin; m_rx_pin = receive_pin;
m_tx_pin = transmit_pin; m_tx_pin = transmit_pin;
m_in_pos = m_out_pos = 0; m_in_pos = m_out_pos = 0;
if (m_rx_pin > -1) { 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_buffer = (uint8_t*)malloc(TM_SERIAL_BUFFER_SIZE); m_hardserial = 1;
if (m_buffer == NULL) return; } else {
// Use getCycleCount() loop to get as exact timing as possible if (m_rx_pin > -1) {
m_bit_time = ESP.getCpuFreqMHz() *1000000 /TM_SERIAL_BAUDRATE; m_buffer = (uint8_t*)malloc(TM_SERIAL_BUFFER_SIZE);
pinMode(m_rx_pin, INPUT); if (m_buffer == NULL) return;
tms_obj_list[m_rx_pin] = this; // Use getCycleCount() loop to get as exact timing as possible
attachInterrupt(m_rx_pin, ISRList[m_rx_pin], FALLING); m_bit_time = ESP.getCpuFreqMHz() *1000000 /TM_SERIAL_BAUDRATE;
} pinMode(m_rx_pin, INPUT);
if (m_tx_pin > -1) { tms_obj_list[m_rx_pin] = this;
pinMode(m_tx_pin, OUTPUT); attachInterrupt(m_rx_pin, ISRList[m_rx_pin], FALLING);
digitalWrite(m_tx_pin, HIGH); }
if (m_tx_pin > -1) {
pinMode(m_tx_pin, OUTPUT);
digitalWrite(m_tx_pin, HIGH);
}
} }
m_valid = true; m_valid = true;
} }
@ -107,9 +112,14 @@ bool TasmotaSerial::isValidGPIOpin(int pin)
} }
bool TasmotaSerial::begin(long speed) { bool TasmotaSerial::begin(long speed) {
// Use getCycleCount() loop to get as exact timing as possible if (m_hardserial) {
m_bit_time = ESP.getCpuFreqMHz() *1000000 /speed; Serial.flush();
m_high_speed = (speed > 9600); 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; return m_valid;
} }
@ -117,28 +127,48 @@ bool TasmotaSerial::begin() {
return begin(TM_SERIAL_BAUDRATE); return begin(TM_SERIAL_BAUDRATE);
} }
bool TasmotaSerial::hardwareSerial() {
return m_hardserial;
}
void TasmotaSerial::flush() { 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() { int TasmotaSerial::peek() {
if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) return -1; if (m_hardserial) {
return m_buffer[m_out_pos]; 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() int TasmotaSerial::read()
{ {
if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) return -1; if (m_hardserial) {
uint8_t ch = m_buffer[m_out_pos]; return Serial.read();
m_out_pos = (m_out_pos +1) % TM_SERIAL_BUFFER_SIZE; } else {
return ch; 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 TasmotaSerial::available()
{ {
int avail = m_in_pos - m_out_pos; if (m_hardserial) {
if (avail < 0) avail += TM_SERIAL_BUFFER_SIZE; return Serial.available();
return avail; } else {
int avail = m_in_pos - m_out_pos;
if (avail < 0) avail += TM_SERIAL_BUFFER_SIZE;
return avail;
}
} }
#ifdef TM_SERIAL_USE_IRAM #ifdef TM_SERIAL_USE_IRAM
@ -149,24 +179,28 @@ int TasmotaSerial::available()
size_t TasmotaSerial::write(uint8_t b) size_t TasmotaSerial::write(uint8_t b)
{ {
if (-1 == m_tx_pin) return 0; if (m_hardserial) {
if (m_high_speed) cli(); // Disable interrupts in order to get a clean transmit return Serial.write(b);
unsigned long wait = m_bit_time; } else {
digitalWrite(m_tx_pin, HIGH); if (-1 == m_tx_pin) return 0;
unsigned long start = ESP.getCycleCount(); if (m_high_speed) cli(); // Disable interrupts in order to get a clean transmit
// Start bit; unsigned long wait = m_bit_time;
digitalWrite(m_tx_pin, LOW); digitalWrite(m_tx_pin, HIGH);
TM_SERIAL_WAIT; unsigned long start = ESP.getCycleCount();
for (int i = 0; i < 8; i++) { // Start bit;
digitalWrite(m_tx_pin, (b & 1) ? HIGH : LOW); digitalWrite(m_tx_pin, LOW);
TM_SERIAL_WAIT; 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 #ifdef TM_SERIAL_USE_IRAM

View File

@ -37,9 +37,10 @@
class TasmotaSerial : public Stream { class TasmotaSerial : public Stream {
public: 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(long speed);
bool begin(); bool begin();
bool hardwareSerial();
int peek(); int peek();
virtual size_t write(uint8_t byte); virtual size_t write(uint8_t byte);
@ -57,6 +58,7 @@ class TasmotaSerial : public Stream {
// Member variables // Member variables
bool m_valid; bool m_valid;
bool m_hardserial;
bool m_high_speed; bool m_high_speed;
int m_rx_pin; int m_rx_pin;
int m_tx_pin; int m_tx_pin;

View File

@ -10,6 +10,7 @@
* Add rule state test for On/Off in addition to 0/1 (#2613) * Add rule state test for On/Off in addition to 0/1 (#2613)
* Add hardware serial option to MHZ-19 sensor (#2659) * Add hardware serial option to MHZ-19 sensor (#2659)
* Updated Italian language file (#2618) * Updated Italian language file (#2618)
* Update TasmotaSerial to 2.0.0 allowing Hardware Serial Fallback when correct connection are configured
* Optimize command handling * Optimize command handling
* *
* 5.13.1 20180501 * 5.13.1 20180501

View File

@ -486,12 +486,13 @@ void SetSerialBaudrate(int baudrate)
} }
} }
void SetSerialLocal(bool slocal) void ClaimSerial()
{ {
serial_local = slocal; serial_local = 1;
if (slocal) { AddLog_P(LOG_LEVEL_INFO, PSTR("SNS: Hardware Serial"));
SetSeriallog(LOG_LEVEL_NONE); SetSeriallog(LOG_LEVEL_NONE);
} baudrate = Serial.baudRate();
Settings.baudrate = baudrate / 1200;
} }
uint32_t GetHash(const char *buffer, size_t size) uint32_t GetHash(const char *buffer, size_t size)

View File

@ -408,6 +408,8 @@ void CseEverySecond()
* *
* Source: Victor Ferrer https://github.com/vicfergar/Sonoff-MQTT-OTA-Arduino * Source: Victor Ferrer https://github.com/vicfergar/Sonoff-MQTT-OTA-Arduino
* Based on: PZEM004T library https://github.com/olehs/PZEM004T * Based on: PZEM004T library https://github.com/olehs/PZEM004T
*
* Hardware Serial will be selected if GPIO1 = [PZEM Rx] and [GPIO3 = PZEM Tx]
\*********************************************************************************************/ \*********************************************************************************************/
#include <TasmotaSerial.h> #include <TasmotaSerial.h>
@ -434,6 +436,8 @@ TasmotaSerial *PzemSerial;
#define PZEM_DEFAULT_READ_TIMEOUT 500 #define PZEM_DEFAULT_READ_TIMEOUT 500
/*********************************************************************************************/
struct PZEMCommand { struct PZEMCommand {
uint8_t command; uint8_t command;
uint8_t addr[4]; 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 #endif // USE_PZEM004T
@ -1033,7 +1031,7 @@ void EnergyDrvInit()
serial_config = SERIAL_8E1; serial_config = SERIAL_8E1;
energy_flg = ENERGY_CSE7766; energy_flg = ENERGY_CSE7766;
#ifdef USE_PZEM004T #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; energy_flg = ENERGY_PZEM004T;
#endif // USE_PZEM004T #endif // USE_PZEM004T
} }
@ -1044,8 +1042,13 @@ void EnergySnsInit()
if (ENERGY_HLW8012 == energy_flg) HlwInit(); if (ENERGY_HLW8012 == energy_flg) HlwInit();
#ifdef USE_PZEM004T #ifdef USE_PZEM004T
if ((ENERGY_PZEM004T == energy_flg) && !PzemInit()) { // PzemInit needs to be done here as earlier (serial) interrupts may lead to Exceptions if (ENERGY_PZEM004T == energy_flg) { // Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions
energy_flg = ENERGY_NONE; 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 #endif // USE_PZEM004T

View File

@ -25,6 +25,8 @@
* MH-Z19 - CO2 sensor * MH-Z19 - CO2 sensor
* *
* Adapted from EspEasy plugin P049 by Dmitry (rel22 ___ inbox.ru) * 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 * Filter usage
* *
@ -91,46 +93,6 @@ uint8_t mhz_retry = MHZ19_RETRY_COUNT;
uint8_t mhz_received = 0; uint8_t mhz_received = 0;
uint8_t mhz_state = 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) byte MhzCalculateChecksum(byte *array)
@ -158,7 +120,7 @@ size_t MhzSendCmd(byte command_id)
*/ */
mhz_send[8] = MhzCalculateChecksum(mhz_send); 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); MhzSendCmd(MHZ_CMND_READPPM);
mhz_received = 0; mhz_received = 0;
} }
@ -223,8 +185,8 @@ void MhzEverySecond()
unsigned long start = millis(); unsigned long start = millis();
uint8_t counter = 0; uint8_t counter = 0;
while (((millis() - start) < MHZ19_READ_TIMEOUT) && (counter < 9)) { while (((millis() - start) < MHZ19_READ_TIMEOUT) && (counter < 9)) {
if (MhzSerialAvailable() > 0) { if (MhzSerial->available() > 0) {
mhz_response[counter++] = MhzSerialRead(); mhz_response[counter++] = MhzSerial->read();
} else { } else {
delay(5); delay(5);
} }
@ -322,20 +284,12 @@ void MhzInit()
{ {
mhz_type = 0; mhz_type = 0;
if ((pin[GPIO_MHZ_RXD] < 99) && (pin[GPIO_MHZ_TXD] < 99)) { if ((pin[GPIO_MHZ_RXD] < 99) && (pin[GPIO_MHZ_TXD] < 99)) {
if ((1 == pin[GPIO_MHZ_RXD]) && (3 == pin[GPIO_MHZ_TXD])) { MhzSerial = new TasmotaSerial(pin[GPIO_MHZ_RXD], pin[GPIO_MHZ_TXD], 1);
AddLog_P(LOG_LEVEL_DEBUG, PSTR("MHZ: Hardware serial")); if (MhzSerial->begin(9600)) {
baudrate = 9600; if (MhzSerial->hardwareSerial()) { ClaimSerial(); }
SetSerialBaudrate(baudrate);
SetSerialLocal(true);
mhz_hard_serial = 1;
mhz_type = 1; 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;
}
} }
} }
} }

View File

@ -22,6 +22,8 @@
* SenseAir K30, K70 and S8 - CO2 sensor * SenseAir K30, K70 and S8 - CO2 sensor
* *
* Adapted from EspEasy plugin P052 by Mikael Trieb (mikael__AT__triebconsulting.se) * 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 <TasmotaSerial.h> #include <TasmotaSerial.h>
@ -191,8 +193,9 @@ void SenseairInit()
{ {
senseair_type = 0; senseair_type = 0;
if ((pin[GPIO_SAIR_RX] < 99) && (pin[GPIO_SAIR_TX] < 99)) { if ((pin[GPIO_SAIR_RX] < 99) && (pin[GPIO_SAIR_TX] < 99)) {
SensairSerial = new TasmotaSerial(pin[GPIO_SAIR_RX], pin[GPIO_SAIR_TX]); SensairSerial = new TasmotaSerial(pin[GPIO_SAIR_RX], pin[GPIO_SAIR_TX], 1);
if (SensairSerial->begin()) { if (SensairSerial->begin(9600)) {
if (SensairSerial->hardwareSerial()) { ClaimSerial(); }
senseair_type = 1; senseair_type = 1;
} }
} }

View File

@ -21,6 +21,8 @@
/*********************************************************************************************\ /*********************************************************************************************\
* PlanTower PMS5003 and PMS7003 particle concentration sensor * PlanTower PMS5003 and PMS7003 particle concentration sensor
* For background information see http://aqicn.org/sensor/pms5003-7003/ * For background information see http://aqicn.org/sensor/pms5003-7003/
*
* Hardware Serial will be selected if GPIO3 = [PMS5003]
\*********************************************************************************************/ \*********************************************************************************************/
#include <TasmotaSerial.h> #include <TasmotaSerial.h>
@ -39,6 +41,8 @@ struct pms5003data {
uint16_t checksum; uint16_t checksum;
} pms_data; } pms_data;
/*********************************************************************************************/
boolean PmsReadData() boolean PmsReadData()
{ {
if (! PmsSerial->available()) { if (! PmsSerial->available()) {
@ -97,10 +101,10 @@ void PmsSecond() // Every second
void PmsInit() void PmsInit()
{ {
pms_type = 0; pms_type = 0;
if (pin[GPIO_PMS5003] < 99) { if (pin[GPIO_PMS5003] < 99) {
PmsSerial = new TasmotaSerial(pin[GPIO_PMS5003], -1); PmsSerial = new TasmotaSerial(pin[GPIO_PMS5003], -1, 1);
if (PmsSerial->begin()) { if (PmsSerial->begin(9600)) {
if (PmsSerial->hardwareSerial()) { ClaimSerial(); }
pms_type = 1; pms_type = 1;
} }
} }

View File

@ -21,6 +21,8 @@
/*********************************************************************************************\ /*********************************************************************************************\
* Nova Fitness SDS011 (and possibly SDS021) particle concentration sensor * Nova Fitness SDS011 (and possibly SDS021) particle concentration sensor
* For background information see http://aqicn.org/sensor/sds011/ * For background information see http://aqicn.org/sensor/sds011/
*
* Hardware Serial will be selected if GPIO3 = [SDS0X01]
\*********************************************************************************************/ \*********************************************************************************************/
#include <TasmotaSerial.h> #include <TasmotaSerial.h>
@ -81,10 +83,10 @@ void NovaSdsSecond() // Every second
void NovaSdsInit() void NovaSdsInit()
{ {
novasds_type = 0; novasds_type = 0;
if (pin[GPIO_SDS0X1] < 99) { if (pin[GPIO_SDS0X1] < 99) {
NovaSdsSerial = new TasmotaSerial(pin[GPIO_SDS0X1], -1); NovaSdsSerial = new TasmotaSerial(pin[GPIO_SDS0X1], -1, 1);
if (NovaSdsSerial->begin()) { if (NovaSdsSerial->begin(9600)) {
if (NovaSdsSerial->hardwareSerial()) { ClaimSerial(); }
novasds_type = 1; novasds_type = 1;
} }
} }