140 lines
3.4 KiB
C++
140 lines
3.4 KiB
C++
#pragma once
|
|
#include <cstdint>
|
|
|
|
#ifdef USE_ESP32
|
|
#include "esphome/components/uart/uart_component_esp_idf.h"
|
|
#include "esphome/core/log.h"
|
|
#endif
|
|
|
|
#ifdef USE_ESP8266
|
|
#include "esphome/components/uart/uart_component_esp8266.h"
|
|
#endif
|
|
|
|
namespace esphome {
|
|
namespace xt211 {
|
|
|
|
static const uint32_t TIMEOUT = 20; // default value in uart implementation is 100ms
|
|
|
|
#ifdef USE_ESP8266
|
|
|
|
class XSoftSerial : public uart::ESP8266SoftwareSerial {
|
|
public:
|
|
void set_bit_time(uint32_t bt) { bit_time_ = bt; }
|
|
};
|
|
|
|
class XT211Uart final : public uart::ESP8266UartComponent {
|
|
public:
|
|
XT211Uart(uart::ESP8266UartComponent const &uart)
|
|
: uart_(uart), hw_(uart.*(&XT211Uart::hw_serial_)), sw_(uart.*(&XT211Uart::sw_serial_)) {}
|
|
|
|
void update_baudrate(uint32_t baudrate) {
|
|
if (this->hw_ != nullptr) {
|
|
this->hw_->updateBaudRate(baudrate);
|
|
} else if (baudrate > 0) {
|
|
((XSoftSerial *) sw_)->set_bit_time(F_CPU / baudrate);
|
|
}
|
|
}
|
|
|
|
bool read_one_byte(uint8_t *data) {
|
|
if (this->hw_ != nullptr) {
|
|
if (!this->check_read_timeout_quick_(1))
|
|
return false;
|
|
this->hw_->readBytes(data, 1);
|
|
} else {
|
|
if (sw_->available() < 1)
|
|
return false;
|
|
assert(this->sw_ != nullptr);
|
|
optional<uint8_t> b = this->sw_->read_byte();
|
|
if (b) {
|
|
*data = *b;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
protected:
|
|
bool check_read_timeout_quick_(size_t len) {
|
|
if (this->hw_->available() >= int(len))
|
|
return true;
|
|
|
|
uint32_t start_time = millis();
|
|
while (this->hw_->available() < int(len)) {
|
|
if (millis() - start_time > TIMEOUT) {
|
|
return false;
|
|
}
|
|
yield();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
uart::ESP8266UartComponent const &uart_;
|
|
HardwareSerial *const hw_; // hardware Serial
|
|
uart::ESP8266SoftwareSerial *const sw_; // software serial
|
|
};
|
|
#endif
|
|
|
|
#ifdef USE_ESP32
|
|
|
|
// backward compatibility with old IDF versions
|
|
#ifndef portTICK_PERIOD_MS
|
|
#define portTICK_PERIOD_MS portTICK_RATE_MS
|
|
#endif
|
|
|
|
class XT211Uart final : public uart::IDFUARTComponent {
|
|
public:
|
|
XT211Uart(uart::IDFUARTComponent &uart)
|
|
: uart_(uart), iuart_num_(uart.*(&XT211Uart::uart_num_)), ilock_(uart.*(&XT211Uart::lock_)) {}
|
|
|
|
// Reconfigure baudrate
|
|
void update_baudrate(uint32_t baudrate) {
|
|
xSemaphoreTake(ilock_, portMAX_DELAY);
|
|
uart_set_baudrate(iuart_num_, baudrate);
|
|
xSemaphoreGive(ilock_);
|
|
}
|
|
|
|
bool read_one_byte(uint8_t *data) { return read_array_quick_(data, 1); }
|
|
|
|
protected:
|
|
bool check_read_timeout_quick_(size_t len) {
|
|
if (uart_.available() >= int(len))
|
|
return true;
|
|
|
|
uint32_t start_time = millis();
|
|
while (uart_.available() < int(len)) {
|
|
if (millis() - start_time > TIMEOUT) {
|
|
return false;
|
|
}
|
|
yield();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool read_array_quick_(uint8_t *data, size_t len) {
|
|
size_t length_to_read = len;
|
|
if (!this->check_read_timeout_quick_(len))
|
|
return false;
|
|
xSemaphoreTake(this->ilock_, portMAX_DELAY);
|
|
if (this->has_peek_) {
|
|
length_to_read--;
|
|
*data = this->peek_byte_;
|
|
data++;
|
|
this->has_peek_ = false;
|
|
}
|
|
if (length_to_read > 0)
|
|
uart_read_bytes(this->iuart_num_, data, length_to_read, 20 / portTICK_PERIOD_MS);
|
|
xSemaphoreGive(this->ilock_);
|
|
|
|
return true;
|
|
}
|
|
|
|
uart::IDFUARTComponent &uart_;
|
|
uart_port_t iuart_num_;
|
|
SemaphoreHandle_t &ilock_;
|
|
};
|
|
#endif
|
|
|
|
} // namespace xt211
|
|
} // namespace esphome
|