ESPHome 2026.10.2
Loading...
Searching...
No Matches
canbus.h
Go to the documentation of this file.
1#pragma once
2
6
7#include <cinttypes>
8#include <vector>
9
10namespace esphome::canbus {
11
20
44
45class CanbusTrigger;
46template<typename... Ts> class CanbusSendAction;
47
48/* CAN payload length definitions according to ISO 11898-1 */
49static const uint8_t CAN_MAX_DATA_LENGTH = 8;
50
51/*
52Can Frame describes a normative CAN Frame
53The RTR = Remote Transmission Request is implemented in every CAN controller but rarely used
54So currently the flag is passed to and from the hardware but currently ignored to the user application.
55*/
56struct CanFrame {
57 bool use_extended_id = false;
59 uint32_t can_id; /* 29 or 11 bit CAN_ID */
60 uint8_t can_data_length_code; /* frame payload length in byte (0 .. CAN_MAX_DATA_LENGTH) */
61 uint8_t data[CAN_MAX_DATA_LENGTH] __attribute__((aligned(8)));
62};
63
64class Canbus : public Component {
65 public:
66 Canbus(){};
67 void setup() override;
68 void dump_config() override;
69 float get_setup_priority() const override { return setup_priority::HARDWARE; }
70 void loop() override;
71
72 canbus::Error send_data(uint32_t can_id, bool use_extended_id, bool remote_transmission_request,
73 const std::vector<uint8_t> &data);
74 canbus::Error send_data(uint32_t can_id, bool use_extended_id, const std::vector<uint8_t> &data) {
75 // for backwards compatibility only
76 return this->send_data(can_id, use_extended_id, false, data);
77 }
78 void set_can_id(uint32_t can_id) { this->can_id_ = can_id; }
79 void set_use_extended_id(bool use_extended_id) { this->use_extended_id_ = use_extended_id; }
80 void set_bitrate(CanSpeed bit_rate) { this->bit_rate_ = bit_rate; }
81 void set_max_frames_per_loop(uint32_t max_frames_per_loop) { this->max_frames_per_loop_ = max_frames_per_loop; }
82
83 void add_trigger(CanbusTrigger *trigger);
94 template<typename F> void add_callback(F &&callback) { this->callback_manager_.add(std::forward<F>(callback)); }
95
96 protected:
97 template<typename... Ts> friend class CanbusSendAction;
98 std::vector<CanbusTrigger *> triggers_{};
100 uint32_t max_frames_per_loop_{50}; // Keep in sync with DEFAULT_MAX_FRAMES_PER_LOOP in __init__.py
101 CanSpeed bit_rate_{CAN_125KBPS}; // Keep in sync with DEFAULT_BIT_RATE in __init__.py
102 bool use_extended_id_{false};
103 CallbackManager<void(uint32_t can_id, bool extended_id, bool rtr, const std::vector<uint8_t> &data)>
105
106 virtual bool setup_internal() = 0;
107 virtual Error send_message(struct CanFrame *frame) = 0;
108 virtual Error read_message(struct CanFrame *frame) = 0;
109};
110
111template<typename... Ts> class CanbusSendAction final : public Action<Ts...>, public Parented<Canbus> {
112 public:
113 void set_data_template(std::vector<uint8_t> (*func)(Ts...)) {
114 // Stateless lambdas (generated by ESPHome) implicitly convert to function pointers
115 this->data_.func = func;
116 this->len_ = -1; // Sentinel value indicates template mode
117 }
118
119 // Store pointer to static data in flash (no RAM copy)
120 void set_data_static(const uint8_t *data, size_t len) {
121 this->data_.data = data;
122 this->len_ = len; // Length >= 0 indicates static mode
123 }
124
125 void set_can_id(uint32_t can_id) { this->can_id_ = can_id; }
126
127 void set_use_extended_id(bool use_extended_id) { this->use_extended_id_ = use_extended_id; }
128
129 void set_remote_transmission_request(bool remote_transmission_request) {
130 this->remote_transmission_request_ = remote_transmission_request;
131 }
132
133 void play(const Ts &...x) override {
134 auto can_id = this->can_id_.has_value() ? *this->can_id_ : this->parent_->can_id_;
135 auto use_extended_id =
136 this->use_extended_id_.has_value() ? *this->use_extended_id_ : this->parent_->use_extended_id_;
137 std::vector<uint8_t> data;
138 if (this->len_ >= 0) {
139 // Static mode: copy from flash to vector
140 data.assign(this->data_.data, this->data_.data + this->len_);
141 } else {
142 // Template mode: call function
143 data = this->data_.func(x...);
144 }
145 this->parent_->send_data(can_id, use_extended_id, this->remote_transmission_request_, data);
146 }
147
148 protected:
149 optional<uint32_t> can_id_{};
150 optional<bool> use_extended_id_{};
152 ssize_t len_{-1}; // -1 = template mode, >=0 = static mode with length
153 union Data {
154 std::vector<uint8_t> (*func)(Ts...); // Function pointer (stateless lambdas)
155 const uint8_t *data; // Pointer to static data in flash
157};
158
159class CanbusTrigger final : public Trigger<std::vector<uint8_t>, uint32_t, bool>, public Component {
160 friend class Canbus;
161
162 public:
163 explicit CanbusTrigger(Canbus *parent, const std::uint32_t can_id, const std::uint32_t can_id_mask,
164 const bool use_extended_id)
165 : parent_(parent), can_id_(can_id), can_id_mask_(can_id_mask), use_extended_id_(use_extended_id){};
166
167 void set_remote_transmission_request(bool remote_transmission_request) {
168 this->remote_transmission_request_ = remote_transmission_request;
169 }
170
171 void setup() override { this->parent_->add_trigger(this); }
172
173 protected:
179};
180
181} // namespace esphome::canbus
Helper class to easily give an object a parent of type T.
Definition helpers.h:2004
CallbackManager< void(uint32_t can_id, bool extended_id, bool rtr, const std::vector< uint8_t > &data)> callback_manager_
Definition canbus.h:104
void loop() override
Definition canbus.cpp:68
void set_max_frames_per_loop(uint32_t max_frames_per_loop)
Definition canbus.h:81
void set_use_extended_id(bool use_extended_id)
Definition canbus.h:79
canbus::Error send_data(uint32_t can_id, bool use_extended_id, bool remote_transmission_request, const std::vector< uint8_t > &data)
Definition canbus.cpp:24
void add_callback(F &&callback)
Add a callback to be called when a CAN message is received.
Definition canbus.h:94
void setup() override
Definition canbus.cpp:9
void add_trigger(CanbusTrigger *trigger)
Definition canbus.cpp:59
uint32_t max_frames_per_loop_
Definition canbus.h:100
canbus::Error send_data(uint32_t can_id, bool use_extended_id, const std::vector< uint8_t > &data)
Definition canbus.h:74
void set_bitrate(CanSpeed bit_rate)
Definition canbus.h:80
void set_can_id(uint32_t can_id)
Definition canbus.h:78
float get_setup_priority() const override
Definition canbus.h:69
void dump_config() override
Definition canbus.cpp:16
virtual Error send_message(struct CanFrame *frame)=0
virtual bool setup_internal()=0
std::vector< CanbusTrigger * > triggers_
Definition canbus.h:98
virtual Error read_message(struct CanFrame *frame)=0
void set_data_template(std::vector< uint8_t >(*func)(Ts...))
Definition canbus.h:113
void set_remote_transmission_request(bool remote_transmission_request)
Definition canbus.h:129
void set_data_static(const uint8_t *data, size_t len)
Definition canbus.h:120
optional< uint32_t > can_id_
Definition canbus.h:149
void play(const Ts &...x) override
Definition canbus.h:133
void set_use_extended_id(bool use_extended_id)
Definition canbus.h:127
optional< bool > use_extended_id_
Definition canbus.h:150
void set_can_id(uint32_t can_id)
Definition canbus.h:125
union esphome::canbus::CanbusSendAction::Data data_
optional< bool > remote_transmission_request_
Definition canbus.h:178
CanbusTrigger(Canbus *parent, const std::uint32_t can_id, const std::uint32_t can_id_mask, const bool use_extended_id)
Definition canbus.h:163
void set_remote_transmission_request(bool remote_transmission_request)
Definition canbus.h:167
__int64 ssize_t
Definition httplib.h:178
constexpr float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Definition component.h:43
const void size_t len
Definition hal.h:64
static void uint32_t
uint8_t can_data_length_code
Definition canbus.h:60
uint8_t data[CAN_MAX_DATA_LENGTH] __attribute__((aligned(8)))
uint16_t x
Definition tt21100.cpp:5
std::vector< uint8_t >(* func)(Ts...)
Definition canbus.h:154