mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 15:27:33 +00:00
Only re-wake the loop once the RX buffer is drained, reset the frame state in decoder setup, test reconfiguration
This commit is contained in:
@@ -22,6 +22,8 @@ class SoftwareSerialRxDecoder {
|
||||
public:
|
||||
static constexpr uint8_t RX_IDLE = 0xFF;
|
||||
|
||||
/// Configure the framing and buffer. Drops buffered bytes and any partial frame and
|
||||
/// assumes an idle high line; call reset() afterwards with the real line level.
|
||||
void setup(uint32_t bit_cycles, uint8_t data_bits, bool parity, uint8_t stop_bits, uint8_t *buffer,
|
||||
size_t buffer_size) {
|
||||
this->bit_cycles_ = bit_cycles;
|
||||
@@ -33,11 +35,13 @@ class SoftwareSerialRxDecoder {
|
||||
this->buffer_size_ = buffer_size;
|
||||
this->in_pos_ = 0;
|
||||
this->out_pos_ = 0;
|
||||
this->reset(0, true);
|
||||
}
|
||||
|
||||
/// Forget any partial frame; `level` is the current line level.
|
||||
void reset(uint32_t now, bool level) {
|
||||
this->bit_ = RX_IDLE;
|
||||
this->cur_byte_ = 0;
|
||||
this->last_level_ = level;
|
||||
this->last_edge_ = now;
|
||||
}
|
||||
|
||||
@@ -315,8 +315,10 @@ void IRAM_ATTR ESP8266SoftwareSerial::gpio_intr_edge(ESP8266SoftwareSerial *arg)
|
||||
void ESP8266SoftwareSerial::rx_finalize_pending_() {
|
||||
if (!this->rx_.finalize_due(arch_get_cpu_cycle_count())) {
|
||||
#ifdef USE_UART_WAKE_LOOP_ON_RX
|
||||
// Not old enough yet: run the loop again right away instead of after a full loop_interval_.
|
||||
wake_loop_threadsafe();
|
||||
// Not old enough yet: once the caller has drained what is there, run the loop
|
||||
// again right away instead of after a full loop_interval_.
|
||||
if (this->rx_.available() == 0)
|
||||
wake_loop_threadsafe();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -219,6 +219,59 @@ TEST(SoftwareSerialRxDecoder, DropsBytesWhenBufferIsFullAndKeepsOldest) {
|
||||
EXPECT_EQ(sim.received()[n], n);
|
||||
}
|
||||
|
||||
TEST(SoftwareSerialRxDecoder, SetupAgainDropsStaleStateAndUsesNewBufferAndFraming) {
|
||||
// Mirrors load_settings(): bytes buffered and a frame left open under 8N1 in a
|
||||
// 64 byte buffer, then setup() again with 5E2 in a 4 byte buffer.
|
||||
LineSim sim(9600, 8, false, false, 1);
|
||||
uint32_t t = 5000;
|
||||
for (int n = 0; n < 10; n++)
|
||||
t = sim.send(static_cast<uint8_t>(0x40 + n), t);
|
||||
sim.edge(t + 8 * sim.bit_cycles(), false); // open a frame, never closed
|
||||
SoftwareSerialRxDecoder &dec = sim.decoder();
|
||||
ASSERT_GE(dec.available(), 9u);
|
||||
|
||||
std::vector<uint8_t> small(4, 0xEE);
|
||||
const uint32_t bit = CPU_HZ / 2400;
|
||||
dec.setup(bit, 5, true, 2, small.data(), small.size());
|
||||
EXPECT_EQ(dec.available(), 0u);
|
||||
EXPECT_FALSE(dec.pending());
|
||||
EXPECT_EQ(dec.read_byte(), 0);
|
||||
|
||||
// 5E2 frames fed straight into the reconfigured decoder: capacity is 3, the
|
||||
// rest are dropped and nothing is written past the end of the new buffer.
|
||||
auto send_5e2 = [&](uint8_t value, uint32_t start) {
|
||||
bool line = true;
|
||||
uint32_t at = start;
|
||||
auto put = [&](bool b) {
|
||||
if (b != line) {
|
||||
dec.on_edge(at, b);
|
||||
line = b;
|
||||
}
|
||||
at += bit;
|
||||
};
|
||||
put(false);
|
||||
int ones = 0;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
bool b = (value >> i) & 1;
|
||||
ones += b;
|
||||
put(b);
|
||||
}
|
||||
put(ones & 1);
|
||||
put(true);
|
||||
put(true);
|
||||
return at;
|
||||
};
|
||||
uint32_t t2 = 5000;
|
||||
for (int n = 1; n <= 6; n++)
|
||||
t2 = send_5e2(static_cast<uint8_t>(n), t2);
|
||||
dec.finalize(t2 + 20 * bit);
|
||||
ASSERT_EQ(dec.available(), 3u);
|
||||
EXPECT_EQ(dec.read_byte(), 1);
|
||||
EXPECT_EQ(dec.read_byte(), 2);
|
||||
EXPECT_EQ(dec.read_byte(), 3);
|
||||
EXPECT_EQ(small[3], 0xEE); // capacity slot is never written
|
||||
}
|
||||
|
||||
TEST(SoftwareSerialRxDecoder, ResetDiscardsPartialFrame) {
|
||||
LineSim sim(9600, 8, false, false, 1);
|
||||
const uint32_t bit = sim.bit_cycles();
|
||||
|
||||
Reference in New Issue
Block a user