Files
ESPEasy/lib/ESPEasySerial/ESPeasySerial.cpp
T

799 lines
18 KiB
C++

#include <ESPeasySerial.h>
#define DETECT_BAUDATE_TIMEOUT 250
// ****************************************
// ESP8266 implementation wrapper
// ****************************************
#ifdef ESP8266
bool ESPeasySerial::_serial0_swap_active = false;
#endif
#if !defined(DISABLE_SOFTWARE_SERIAL) && defined(ESP8266)
ESPeasySerial::ESPeasySerial(int receivePin, int transmitPin, bool inverse_logic, unsigned int buffSize)
: _swserial(nullptr), _receivePin(receivePin), _transmitPin(transmitPin)
{
_serialtype = ESPeasySerialType::getSerialType(receivePin, transmitPin);
if (isSWserial()) {
_swserial = new SoftwareSerial(receivePin, transmitPin, inverse_logic, buffSize);
} else {
getHW()->pins(transmitPin, receivePin);
}
}
ESPeasySerial::~ESPeasySerial() {
end();
if (_swserial != nullptr) {
delete _swserial;
}
}
void ESPeasySerial::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin) {
_baud = baud;
if (_serialtype == ESPeasySerialType::serialtype::serial0_swap) {
// Serial.swap() should only be called here and only once.
if (!_serial0_swap_active) {
Serial.begin(baud, config, mode, tx_pin);
Serial.swap();
_serial0_swap_active = true;
return;
}
}
if (!isValid()) {
_baud = 0;
return;
}
if (isSWserial()) {
_swserial->begin(baud);
} else {
doHWbegin(baud, config, mode, tx_pin);
}
}
void ESPeasySerial::end() {
if (!isValid()) {
return;
}
if (isSWserial()) {
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
_swserial->end();
#endif
return;
} else {
if (_serialtype == ESPeasySerialType::serialtype::serial0_swap) {
if (_serial0_swap_active) {
Serial.end();
Serial.swap();
_serial0_swap_active = false;
return;
}
}
getHW()->end();
}
}
HardwareSerial* ESPeasySerial::getHW() {
switch (_serialtype) {
case ESPeasySerialType::serialtype::serial0:
case ESPeasySerialType::serialtype::serial0_swap: return &Serial;
case ESPeasySerialType::serialtype::serial1: return &Serial1;
case ESPeasySerialType::serialtype::software: break;
default: break;
}
return nullptr;
}
const HardwareSerial* ESPeasySerial::getHW() const {
switch (_serialtype) {
case ESPeasySerialType::serialtype::serial0:
case ESPeasySerialType::serialtype::serial0_swap: return &Serial;
case ESPeasySerialType::serialtype::serial1: return &Serial1;
case ESPeasySerialType::serialtype::software: break;
default: break;
}
return nullptr;
}
bool ESPeasySerial::isValid() const {
switch (_serialtype) {
case ESPeasySerialType::serialtype::serial0: return !_serial0_swap_active;
case ESPeasySerialType::serialtype::serial0_swap: return _serial0_swap_active;
case ESPeasySerialType::serialtype::serial1: return true; // Must also check RX pin?
case ESPeasySerialType::serialtype::software: return _swserial != nullptr;
default: break;
}
return false;
}
int ESPeasySerial::peek(void) {
if (!isValid()) {
return -1;
}
if (isSWserial()) {
return _swserial->peek();
} else {
return getHW()->peek();
}
}
size_t ESPeasySerial::write(uint8_t byte) {
if (!isValid()) {
return 0;
}
if (isSWserial()) {
return _swserial->write(byte);
} else {
return getHW()->write(byte);
}
}
size_t ESPeasySerial::write(const uint8_t *buffer, size_t size) {
if (!isValid() || !buffer) {
return 0;
}
if (isSWserial()) {
// Not implemented in SoftwareSerial
size_t count = 0;
for (size_t i = 0; i < size; ++i) {
size_t written = _swserial->write(buffer[i]);
if (written == 0) return count;
count += written;
}
return count;
} else {
return getHW()->write(buffer, size);
}
}
size_t ESPeasySerial::write(const char *buffer) {
if (!buffer) return 0;
return write(buffer, strlen(buffer));
}
int ESPeasySerial::read(void) {
if (!isValid()) {
return -1;
}
if (isSWserial()) {
return _swserial->read();
} else {
return getHW()->read();
}
}
size_t ESPeasySerial::readBytes(char* buffer, size_t size) {
if (!isValid() || !buffer) {
return 0;
}
if (isSWserial()) {
// Not implemented in SoftwareSerial
size_t count = 0;
for (size_t i = 0; i < size; ++i) {
int read = _swserial->read();
if (read < 0) return count;
buffer[i] = static_cast<char>(read & 0xFF);
++count;
}
return count;
} else {
return getHW()->readBytes(buffer, size);
}
}
size_t ESPeasySerial::readBytes(uint8_t* buffer, size_t size) {
return readBytes((char*)buffer, size);
}
int ESPeasySerial::available(void) {
if (!isValid()) {
return 0;
}
if (isSWserial()) {
return _swserial->available();
} else {
return getHW()->available();
}
}
void ESPeasySerial::flush(void) {
if (!isValid()) {
return;
}
if (isSWserial()) {
_swserial->flush();
} else {
getHW()->flush();
}
}
bool ESPeasySerial::overflow() { return hasOverrun(); }
bool ESPeasySerial::hasOverrun(void) {
if (!isValid()) {
return false;
}
#if defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1)
return false;
#else
if (isSWserial()) {
return _swserial->overflow();
} else {
return getHW()->hasOverrun();
}
#endif
}
// *****************************
// HardwareSerial specific
// *****************************
void ESPeasySerial::swap(uint8_t tx_pin) {
if (isValid() && !isSWserial()) {
switch (_serialtype) {
case ESPeasySerialType::serialtype::serial0:
case ESPeasySerialType::serialtype::serial0_swap:
// isValid() also checks for correct swap active state.
_serial0_swap_active = !_serial0_swap_active;
getHW()->swap(tx_pin);
if (_serialtype == ESPeasySerialType::serialtype::serial0) {
_serialtype = ESPeasySerialType::serialtype::serial0_swap;
} else {
_serialtype = ESPeasySerialType::serialtype::serial0;
}
break;
default:
return;
}
}
}
int ESPeasySerial::baudRate(void) {
if (!isValid() || isSWserial()) {
return _baud;
}
return getHW()->baudRate();
}
void ESPeasySerial::setDebugOutput(bool enable) {
if (!isValid() || isSWserial()) {
return;
}
getHW()->setDebugOutput(enable);
}
bool ESPeasySerial::isTxEnabled(void) {
if (!isValid() || isSWserial()) {
return false;
}
return getHW()->isTxEnabled();
}
bool ESPeasySerial::isRxEnabled(void) {
if (!isValid() || isSWserial()) {
return false;
}
return getHW()->isRxEnabled();
}
#ifdef CORE_2_5_0
bool ESPeasySerial::hasRxError(void) {
if (!isValid() || isSWserial()) {
return false;
}
return getHW()->hasRxError();
}
#endif
void ESPeasySerial::startDetectBaudrate() {
if (!isValid() || isSWserial()) {
return;
}
#if defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1)
return;
#else
getHW()->startDetectBaudrate();
#endif
}
unsigned long ESPeasySerial::testBaudrate() {
if (!isValid() || isSWserial()) {
return 0;
}
#if defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1)
return 0;
#else
return getHW()->testBaudrate();
#endif
}
unsigned long ESPeasySerial::detectBaudrate(time_t timeoutMillis) {
if (!isValid() || isSWserial()) {
return 0;
}
#if defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1)
return 0;
#else
return getHW()->detectBaudrate(timeoutMillis);
#endif
}
// *****************************
// SoftwareSerial specific
// *****************************
bool ESPeasySerial::listen() {
if (isValid() && isSWserial()) {
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
return _swserial->listen();
#endif
}
return false;
}
bool ESPeasySerial::isListening() {
if (isValid() && isSWserial()) {
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
return _swserial->isListening();
#endif
}
return false;
}
bool ESPeasySerial::stopListening() {
if (isValid() && isSWserial()) {
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
return _swserial->stopListening();
#endif
}
return false;
}
#endif // ESP8266
#ifdef ESP8266
// ****************************************
// ESP8266 implementation wrapper
// Shared functions for HW serial
// ****************************************
bool ESPeasySerial::doHWbegin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin) {
if (!isValid()) {
return false;
}
if (baud > 0) {
getHW()->begin(baud ? baud : 9600, config, mode, tx_pin);
return true;
}
startDetectBaudrate();
unsigned long detectedBaudRate = detectBaudrate(DETECT_BAUDATE_TIMEOUT);
if(detectedBaudRate > 0) {
delay(100); // Give some time...
getHW()->begin(detectedBaudRate, config, mode, tx_pin);
_baud = detectedBaudRate;
return true;
} else {
return false;
}
}
#endif
#if defined(DISABLE_SOFTWARE_SERIAL) && defined(ESP8266)
// ****************************************
// ESP8266 implementation wrapper
// No SoftwareSerial
// Only support HW serial on Serial 0 .. 1
// ****************************************
ESPeasySerial::ESPeasySerial(int receivePin, int transmitPin, bool inverse_logic, unsigned int buffSize)
: _receivePin(receivePin), _transmitPin(transmitPin)
{
_serialtype = ESPeasySerialType::getSerialType(receivePin, transmitPin);
if (isValid()) {
getHW()->pins(transmitPin, receivePin);
}
}
ESPeasySerial::~ESPeasySerial() {
end();
}
void ESPeasySerial::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin) {
_baud = baud;
if (_serialtype == ESPeasySerialType::serialtype::serial0_swap) {
// Serial.swap() should only be called here and only once.
if (!_serial0_swap_active) {
Serial.begin(baud, config, mode, tx_pin);
Serial.swap();
_serial0_swap_active = true;
return;
}
}
if (!isValid()) {
_baud = 0;
return;
}
doHWbegin(baud, config, mode, tx_pin);
}
void ESPeasySerial::end() {
if (!isValid()) {
return;
}
if (_serialtype == ESPeasySerialType::serialtype::serial0_swap) {
if (_serial0_swap_active) {
Serial.end();
Serial.swap();
_serial0_swap_active = false;
return;
}
}
getHW()->end();
}
HardwareSerial* ESPeasySerial::getHW() {
switch (_serialtype) {
case ESPeasySerialType::serialtype::serial0:
case ESPeasySerialType::serialtype::serial0_swap: return &Serial;
case ESPeasySerialType::serialtype::serial1: return &Serial1;
case ESPeasySerialType::serialtype::software: break;
default: break;
}
return nullptr;
}
const HardwareSerial* ESPeasySerial::getHW() const {
switch (_serialtype) {
case ESPeasySerialType::serialtype::serial0:
case ESPeasySerialType::serialtype::serial0_swap: return &Serial;
case ESPeasySerialType::serialtype::serial1: return &Serial1;
case ESPeasySerialType::serialtype::software: break;
default: break;
}
return nullptr;
}
bool ESPeasySerial::isValid() const {
switch (_serialtype) {
case ESPeasySerialType::serialtype::serial0: return !_serial0_swap_active;
case ESPeasySerialType::serialtype::serial0_swap: return _serial0_swap_active;
case ESPeasySerialType::serialtype::serial1: return true; // Must also check RX pin?
case ESPeasySerialType::serialtype::software: return false;
default: break;
}
return false;
}
int ESPeasySerial::peek(void) {
if (!isValid()) {
return -1;
}
return getHW()->peek();
}
size_t ESPeasySerial::write(uint8_t byte) {
if (!isValid()) {
return 0;
}
return getHW()->write(byte);
}
size_t ESPeasySerial::write(const uint8_t *buffer, size_t size) {
if (!isValid() || !buffer) {
return 0;
}
return getHW()->write(buffer, size);
}
size_t ESPeasySerial::write(const char *buffer) {
if (!buffer) return 0;
return write(buffer, strlen(buffer));
}
int ESPeasySerial::read(void) {
if (!isValid()) {
return -1;
}
return getHW()->read();
}
size_t ESPeasySerial::readBytes(char* buffer, size_t size) {
if (!isValid() || !buffer) {
return 0;
}
return getHW()->readBytes(buffer, size);
}
size_t ESPeasySerial::readBytes(uint8_t* buffer, size_t size) {
return readBytes((char*)buffer, size);
}
int ESPeasySerial::available(void) {
if (!isValid()) {
return 0;
}
return getHW()->available();
}
void ESPeasySerial::flush(void) {
if (!isValid()) {
return;
}
getHW()->flush();
}
bool ESPeasySerial::overflow() { return hasOverrun(); }
bool ESPeasySerial::hasOverrun(void) {
return false;
}
// *****************************
// HardwareSerial specific
// *****************************
void ESPeasySerial::swap(uint8_t tx_pin) {
if (isValid()) {
switch (_serialtype) {
case ESPeasySerialType::serialtype::serial0:
case ESPeasySerialType::serialtype::serial0_swap:
// isValid() also checks for correct swap active state.
_serial0_swap_active = !_serial0_swap_active;
getHW()->swap(tx_pin);
if (_serialtype == ESPeasySerialType::serialtype::serial0) {
_serialtype = ESPeasySerialType::serialtype::serial0_swap;
} else {
_serialtype = ESPeasySerialType::serialtype::serial0;
}
break;
default:
return;
}
}
}
int ESPeasySerial::baudRate(void) {
if (!isValid()) {
return _baud;
}
return getHW()->baudRate();
}
void ESPeasySerial::setDebugOutput(bool enable) {
if (!isValid()) {
return;
}
getHW()->setDebugOutput(enable);
}
bool ESPeasySerial::isTxEnabled(void) {
if (!isValid()) {
return false;
}
return getHW()->isTxEnabled();
}
bool ESPeasySerial::isRxEnabled(void) {
if (!isValid()) {
return false;
}
return getHW()->isRxEnabled();
}
#ifdef CORE_2_5_0
bool ESPeasySerial::hasRxError(void) {
if (!isValid()) {
return false;
}
return getHW()->hasRxError();
}
#endif
void ESPeasySerial::startDetectBaudrate() {
if (!isValid()) {
return;
}
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
getHW()->startDetectBaudrate();
#endif
}
unsigned long ESPeasySerial::testBaudrate() {
if (!isValid()) {
return 0;
}
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
return getHW()->testBaudrate();
#else
return 0;
#endif
}
unsigned long ESPeasySerial::detectBaudrate(time_t timeoutMillis) {
if (!isValid()) {
return 0;
}
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
return getHW()->detectBaudrate(timeoutMillis);
#else
return 0;
#endif
}
// *****************************
// SoftwareSerial specific
// *****************************
bool ESPeasySerial::listen() {
if (isValid()) {
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
return _swserial->listen();
#endif
}
return false;
}
#endif // DISABLE_SOFTWARE_SERIAL
// ****************************************
// ESP32 implementation wrapper
// Only support HW serial on Serial 0 .. 2
// ****************************************
#ifdef ESP32
ESPeasySerial::ESPeasySerial(int receivePin, int transmitPin, bool inverse_logic, int serialPort)
: _receivePin(receivePin), _transmitPin(transmitPin), _inverse_logic(inverse_logic)
{
switch (serialPort) {
case 0: _serialtype = ESPeasySerialType::serialtype::serial0;
case 1: _serialtype = ESPeasySerialType::serialtype::serial1;
case 2: _serialtype = ESPeasySerialType::serialtype::serial2;
default:
_serialtype = ESPeasySerialType::getSerialType(receivePin, transmitPin);
}
}
ESPeasySerial::~ESPeasySerial() {
end();
}
void ESPeasySerial::begin(unsigned long baud, uint32_t config
, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms) {
_baud = baud;
if (rxPin != -1) _receivePin = rxPin;
if (txPin != -1) _transmitPin = txPin;
if (invert) _inverse_logic = true;
if (!isValid()) {
_baud = 0;
return;
}
// Timeout added for 1.0.1
// See: https://github.com/espressif/arduino-esp32/commit/233d31bed22211e8c85f82bcf2492977604bbc78
// getHW()->begin(baud, config, _receivePin, _transmitPin, invert, timeout_ms);
getHW()->begin(baud, config, _receivePin, _transmitPin, _inverse_logic);
}
void ESPeasySerial::end() {
if (!isValid()) {
return;
}
getHW()->end();
}
HardwareSerial* ESPeasySerial::getHW() {
switch (_serialtype) {
case ESPeasySerialType::serialtype::serial0: return &Serial;
case ESPeasySerialType::serialtype::serial1: return &Serial1;
case ESPeasySerialType::serialtype::serial2: return &Serial2;
default: break;
}
return nullptr;
}
const HardwareSerial* ESPeasySerial::getHW() const {
switch (_serialtype) {
case ESPeasySerialType::serialtype::serial0: return &Serial;
case ESPeasySerialType::serialtype::serial1: return &Serial1;
case ESPeasySerialType::serialtype::serial2: return &Serial2;
default: break;
}
return nullptr;
}
bool ESPeasySerial::isValid() const {
switch (_serialtype) {
case ESPeasySerialType::serialtype::serial0:
case ESPeasySerialType::serialtype::serial2:
return true;
case ESPeasySerialType::serialtype::serial1:
return _transmitPin != -1 && _receivePin != -1;
// FIXME TD-er: Must perform proper check for GPIO pins here.
default: break;
}
return false;
}
int ESPeasySerial::peek(void) {
if (!isValid()) {
return -1;
}
return getHW()->peek();
}
size_t ESPeasySerial::write(uint8_t byte) {
if (!isValid()) {
return 0;
}
return getHW()->write(byte);
}
size_t ESPeasySerial::write(const uint8_t *buffer, size_t size) {
if (!isValid() || !buffer) {
return 0;
}
return getHW()->write(buffer, size);
}
size_t ESPeasySerial::write(const char *buffer) {
if (!buffer) return 0;
return write(buffer, strlen(buffer));
}
int ESPeasySerial::read(void) {
if (!isValid()) {
return -1;
}
return getHW()->read();
}
int ESPeasySerial::available(void) {
if (!isValid()) {
return 0;
}
return getHW()->available();
}
void ESPeasySerial::flush(void) {
if (!isValid()) {
return;
}
getHW()->flush();
}
int ESPeasySerial::baudRate(void) {
if (!isValid()) {
return 0;
}
return getHW()->baudRate();
}
// Not supported in ESP32, since only HW serial is used.
// Function included since it is used in some libraries.
bool ESPeasySerial::listen() {
return true;
}
#endif // ESP32