[sx126x][sx127x] Fixes from code review

- Warn when a send goes ahead over a busy period at its limit, as that
  means a stuck busy indication or a jammed channel
- Log an empty packet at verbose level, and say why it counts as sent
- Name the radio id if code generation cannot find its configuration

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
clydebarrow
2026-10-20 09:35:06 +11:00
co-authored by Claude Opus 5.5
parent 9845bde08e
commit 69422272a4
4 changed files with 25 additions and 6 deletions
@@ -21,11 +21,17 @@ bool RadioLinkBase::may_send_(bool busy) {
if (!this->listen_before_talk_.may_send(busy, now))
return false;
if (busy) {
ESP_LOGD(TAG, "Radio busy for %" PRIu32 "ms, sending anyway", this->listen_before_talk_.busy_for(now));
// The limit is longer than any packet takes, so the radio's busy indication is stuck or the channel is jammed
ESP_LOGW(TAG, "Radio busy for %" PRIu32 "ms, sending anyway", this->listen_before_talk_.busy_for(now));
}
return true;
}
bool RadioLinkBase::skip_empty_() const {
ESP_LOGV(TAG, "Empty packet not sent");
return true;
}
void RadioLinkBase::radio_free_() {
this->listen_before_talk_.end_busy();
this->disable_loop();
@@ -18,6 +18,8 @@ class RadioLinkBase : public PacketInterface {
bool check_size_(size_t size) const;
/// False if sending must wait, as the radio is busy; starts loop() to watch the radio.
bool may_send_(bool busy);
/// Returns true for an empty packet, which the radios cannot send, so there is nothing to retry.
bool skip_empty_() const;
/// Ends the busy period when loop() finds the radio free.
void radio_free_();
void receive_(const std::vector<uint8_t> &packet, float rssi, float snr);
@@ -56,7 +58,7 @@ class RadioLink : public RadioLinkBase, public Listener {
return false;
size_t size = data.size();
if (size == 0)
return true;
return this->skip_empty_();
if (!this->check_size_(size) || !this->may_send_(this->radio_->is_receiving()))
return false;
if (data.is_contiguous()) {
@@ -7,7 +7,7 @@ import esphome.codegen as cg
from esphome.components.const import CONF_MAX_PACKET_SIZE
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.core import CORE
from esphome.core import CORE, EsphomeError
from esphome.cpp_generator import MockObjClass
import esphome.final_validate as fv
from esphome.types import ConfigType
@@ -126,8 +126,13 @@ async def new_radio_link(
radio = await cg.get_variable(config[radio_id_key])
var = await new_packet_interface(config, radio, config[CONF_MAX_PACKET_SIZE])
radio_config = next(
conf
for conf in CORE.config[radio_domain]
if conf[CONF_ID] == config[radio_id_key]
(
conf
for conf in CORE.config[radio_domain]
if conf[CONF_ID] == config[radio_id_key]
),
None,
)
if radio_config is None:
raise EsphomeError(f"No {radio_domain} radio with id '{config[radio_id_key]}'")
cg.add(var.set_max_busy(max_busy_ms(radio_config, config[CONF_MAX_PACKET_SIZE])))
@@ -91,6 +91,12 @@ TEST_F(RadioLinkTest, BusyFlagThatNeverClearsIsSentOver) {
EXPECT_EQ(this->radio_.sent[0], (Packet{1, 2, 3}));
}
TEST_F(RadioLinkTest, EmptyPacketCountsAsSentWithoutTransmitting) {
static const Packet EMPTY;
EXPECT_TRUE(this->link_.send_to_interface(PacketBuffer(EMPTY), {}));
EXPECT_TRUE(this->radio_.sent.empty());
}
TEST_F(RadioLinkTest, ReceivedPacketCarriesSignal) {
Packet received;
PacketMetaData meta;