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
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.

View File

@ -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",

View File

@ -1,8 +1,8 @@
name=TasmotaSerial
version=1.3.0
version=2.0.0
author=Theo Arends
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=
category=Signal Input/Output
url=

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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 <TasmotaSerial.h>
@ -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

View File

@ -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;
}
}
}
}

View File

@ -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 <TasmotaSerial.h>
@ -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;
}
}

View File

@ -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 <TasmotaSerial.h>
@ -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;
}
}

View File

@ -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 <TasmotaSerial.h>
@ -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;
}
}