mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 00:31:58 +00:00
[esp32_can] Add listen-only mode to esp32_can component (#13084)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,7 @@ from esphome.components.esp32 import (
|
|||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
|
CONF_MODE,
|
||||||
CONF_RX_PIN,
|
CONF_RX_PIN,
|
||||||
CONF_RX_QUEUE_LEN,
|
CONF_RX_QUEUE_LEN,
|
||||||
CONF_TX_PIN,
|
CONF_TX_PIN,
|
||||||
@@ -33,6 +34,13 @@ CONF_TX_ENQUEUE_TIMEOUT = "tx_enqueue_timeout"
|
|||||||
esp32_can_ns = cg.esphome_ns.namespace("esp32_can")
|
esp32_can_ns = cg.esphome_ns.namespace("esp32_can")
|
||||||
esp32_can = esp32_can_ns.class_("ESP32Can", CanbusComponent)
|
esp32_can = esp32_can_ns.class_("ESP32Can", CanbusComponent)
|
||||||
|
|
||||||
|
# Mode options - consistent with MCP2515 component
|
||||||
|
CanMode = esp32_can_ns.enum("CanMode")
|
||||||
|
CAN_MODES = {
|
||||||
|
"NORMAL": CanMode.CAN_MODE_NORMAL,
|
||||||
|
"LISTENONLY": CanMode.CAN_MODE_LISTEN_ONLY,
|
||||||
|
}
|
||||||
|
|
||||||
# Currently the driver only supports a subset of the bit rates defined in canbus
|
# Currently the driver only supports a subset of the bit rates defined in canbus
|
||||||
# The supported bit rates differ between ESP32 variants.
|
# The supported bit rates differ between ESP32 variants.
|
||||||
# See ESP-IDF Programming Guide --> API Reference --> Two-Wire Automotive Interface (TWAI)
|
# See ESP-IDF Programming Guide --> API Reference --> Two-Wire Automotive Interface (TWAI)
|
||||||
@@ -95,6 +103,7 @@ CONFIG_SCHEMA = canbus.CANBUS_SCHEMA.extend(
|
|||||||
cv.Optional(CONF_BIT_RATE, default="125KBPS"): validate_bit_rate,
|
cv.Optional(CONF_BIT_RATE, default="125KBPS"): validate_bit_rate,
|
||||||
cv.Required(CONF_RX_PIN): pins.internal_gpio_input_pin_number,
|
cv.Required(CONF_RX_PIN): pins.internal_gpio_input_pin_number,
|
||||||
cv.Required(CONF_TX_PIN): pins.internal_gpio_output_pin_number,
|
cv.Required(CONF_TX_PIN): pins.internal_gpio_output_pin_number,
|
||||||
|
cv.Optional(CONF_MODE, default="NORMAL"): cv.enum(CAN_MODES, upper=True),
|
||||||
cv.Optional(CONF_RX_QUEUE_LEN): cv.uint32_t,
|
cv.Optional(CONF_RX_QUEUE_LEN): cv.uint32_t,
|
||||||
cv.Optional(CONF_TX_QUEUE_LEN): cv.uint32_t,
|
cv.Optional(CONF_TX_QUEUE_LEN): cv.uint32_t,
|
||||||
cv.Optional(CONF_TX_ENQUEUE_TIMEOUT): cv.positive_time_period_milliseconds,
|
cv.Optional(CONF_TX_ENQUEUE_TIMEOUT): cv.positive_time_period_milliseconds,
|
||||||
@@ -117,6 +126,7 @@ async def to_code(config):
|
|||||||
|
|
||||||
cg.add(var.set_rx(config[CONF_RX_PIN]))
|
cg.add(var.set_rx(config[CONF_RX_PIN]))
|
||||||
cg.add(var.set_tx(config[CONF_TX_PIN]))
|
cg.add(var.set_tx(config[CONF_TX_PIN]))
|
||||||
|
cg.add(var.set_mode(config[CONF_MODE]))
|
||||||
if (rx_queue_len := config.get(CONF_RX_QUEUE_LEN)) is not None:
|
if (rx_queue_len := config.get(CONF_RX_QUEUE_LEN)) is not None:
|
||||||
cg.add(var.set_rx_queue_len(rx_queue_len))
|
cg.add(var.set_rx_queue_len(rx_queue_len))
|
||||||
if (tx_queue_len := config.get(CONF_TX_QUEUE_LEN)) is not None:
|
if (tx_queue_len := config.get(CONF_TX_QUEUE_LEN)) is not None:
|
||||||
|
|||||||
@@ -75,8 +75,15 @@ bool ESP32Can::setup_internal() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Select TWAI mode based on configuration
|
||||||
|
twai_mode_t twai_mode = (this->mode_ == CAN_MODE_LISTEN_ONLY) ? TWAI_MODE_LISTEN_ONLY : TWAI_MODE_NORMAL;
|
||||||
|
|
||||||
|
if (this->mode_ == CAN_MODE_LISTEN_ONLY) {
|
||||||
|
ESP_LOGI(TAG, "CAN bus configured in LISTEN_ONLY mode (passive, no ACKs)");
|
||||||
|
}
|
||||||
|
|
||||||
twai_general_config_t g_config =
|
twai_general_config_t g_config =
|
||||||
TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t) this->tx_, (gpio_num_t) this->rx_, TWAI_MODE_NORMAL);
|
TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t) this->tx_, (gpio_num_t) this->rx_, twai_mode);
|
||||||
g_config.controller_id = next_twai_ctrl_num++;
|
g_config.controller_id = next_twai_ctrl_num++;
|
||||||
if (this->tx_queue_len_.has_value()) {
|
if (this->tx_queue_len_.has_value()) {
|
||||||
g_config.tx_queue_len = this->tx_queue_len_.value();
|
g_config.tx_queue_len = this->tx_queue_len_.value();
|
||||||
@@ -111,6 +118,12 @@ bool ESP32Can::setup_internal() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
canbus::Error ESP32Can::send_message(struct canbus::CanFrame *frame) {
|
canbus::Error ESP32Can::send_message(struct canbus::CanFrame *frame) {
|
||||||
|
// In listen-only mode, we cannot transmit
|
||||||
|
if (this->mode_ == CAN_MODE_LISTEN_ONLY) {
|
||||||
|
ESP_LOGW(TAG, "Cannot send messages in LISTEN_ONLY mode");
|
||||||
|
return canbus::ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->twai_handle_ == nullptr) {
|
if (this->twai_handle_ == nullptr) {
|
||||||
// not setup yet or setup failed
|
// not setup yet or setup failed
|
||||||
return canbus::ERROR_FAIL;
|
return canbus::ERROR_FAIL;
|
||||||
|
|||||||
@@ -10,10 +10,16 @@
|
|||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace esp32_can {
|
namespace esp32_can {
|
||||||
|
|
||||||
|
enum CanMode : uint8_t {
|
||||||
|
CAN_MODE_NORMAL = 0,
|
||||||
|
CAN_MODE_LISTEN_ONLY = 1,
|
||||||
|
};
|
||||||
|
|
||||||
class ESP32Can : public canbus::Canbus {
|
class ESP32Can : public canbus::Canbus {
|
||||||
public:
|
public:
|
||||||
void set_rx(int rx) { rx_ = rx; }
|
void set_rx(int rx) { rx_ = rx; }
|
||||||
void set_tx(int tx) { tx_ = tx; }
|
void set_tx(int tx) { tx_ = tx; }
|
||||||
|
void set_mode(CanMode mode) { mode_ = mode; }
|
||||||
void set_tx_queue_len(uint32_t tx_queue_len) { this->tx_queue_len_ = tx_queue_len; }
|
void set_tx_queue_len(uint32_t tx_queue_len) { this->tx_queue_len_ = tx_queue_len; }
|
||||||
void set_rx_queue_len(uint32_t rx_queue_len) { this->rx_queue_len_ = rx_queue_len; }
|
void set_rx_queue_len(uint32_t rx_queue_len) { this->rx_queue_len_ = rx_queue_len; }
|
||||||
void set_tx_enqueue_timeout_ms(uint32_t tx_enqueue_timeout_ms) {
|
void set_tx_enqueue_timeout_ms(uint32_t tx_enqueue_timeout_ms) {
|
||||||
@@ -28,6 +34,7 @@ class ESP32Can : public canbus::Canbus {
|
|||||||
|
|
||||||
int rx_{-1};
|
int rx_{-1};
|
||||||
int tx_{-1};
|
int tx_{-1};
|
||||||
|
CanMode mode_{CAN_MODE_NORMAL};
|
||||||
TickType_t tx_enqueue_timeout_ticks_{};
|
TickType_t tx_enqueue_timeout_ticks_{};
|
||||||
optional<uint32_t> tx_queue_len_{};
|
optional<uint32_t> tx_queue_len_{};
|
||||||
optional<uint32_t> rx_queue_len_{};
|
optional<uint32_t> rx_queue_len_{};
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ canbus:
|
|||||||
tx_pin: ${tx_pin}
|
tx_pin: ${tx_pin}
|
||||||
can_id: 4
|
can_id: 4
|
||||||
bit_rate: 50kbps
|
bit_rate: 50kbps
|
||||||
|
mode: NORMAL
|
||||||
on_frame:
|
on_frame:
|
||||||
- can_id: 500
|
- can_id: 500
|
||||||
then:
|
then:
|
||||||
|
|||||||
@@ -12,17 +12,7 @@ esphome:
|
|||||||
canbus_id: esp32_internal_can
|
canbus_id: esp32_internal_can
|
||||||
can_id: 0x100
|
can_id: 0x100
|
||||||
data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
|
data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
|
||||||
- canbus.send:
|
# Note: esp32_internal_can_2 uses LISTENONLY mode, so no send actions
|
||||||
# Extended ID explicit
|
|
||||||
canbus_id: esp32_internal_can_2
|
|
||||||
use_extended_id: true
|
|
||||||
can_id: 0x100
|
|
||||||
data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
|
|
||||||
- canbus.send:
|
|
||||||
# Standard ID by default
|
|
||||||
canbus_id: esp32_internal_can_2
|
|
||||||
can_id: 0x100
|
|
||||||
data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
|
|
||||||
|
|
||||||
canbus:
|
canbus:
|
||||||
- platform: esp32_can
|
- platform: esp32_can
|
||||||
@@ -31,6 +21,7 @@ canbus:
|
|||||||
tx_pin: GPIO7
|
tx_pin: GPIO7
|
||||||
can_id: 4
|
can_id: 4
|
||||||
bit_rate: 50kbps
|
bit_rate: 50kbps
|
||||||
|
mode: NORMAL
|
||||||
on_frame:
|
on_frame:
|
||||||
- can_id: 500
|
- can_id: 500
|
||||||
then:
|
then:
|
||||||
@@ -62,6 +53,7 @@ canbus:
|
|||||||
tx_pin: GPIO9
|
tx_pin: GPIO9
|
||||||
can_id: 4
|
can_id: 4
|
||||||
bit_rate: 50kbps
|
bit_rate: 50kbps
|
||||||
|
mode: LISTENONLY
|
||||||
on_frame:
|
on_frame:
|
||||||
- can_id: 500
|
- can_id: 500
|
||||||
then:
|
then:
|
||||||
|
|||||||
Reference in New Issue
Block a user