ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
remote_transmitter.h
Go to the documentation of this file.
1#pragma once
2
5
6#include <vector>
7
8#if defined(USE_ESP32)
9#include <soc/soc_caps.h>
10#if SOC_RMT_SUPPORTED
11#include <driver/rmt_tx.h>
12#endif // SOC_RMT_SUPPORTED
13#endif // USE_ESP32
14
15// Enables the ISR-driven transmitter on Beken. Gated on BK7238 alone: the shadow-load PWM
16// block is shared with BK7231N, but LibreTiny builds that family against an older BDK whose
17// PWM driver has no pwm_init_param()/pwm_start(). See remote_transmitter_bk72xx.cpp.
18// Keep in sync with _NON_BLOCKING_LIBRETINY_FAMILIES in __init__.py.
19#ifdef USE_LIBRETINY_VARIANT_BK7238
20#define REMOTE_TRANSMITTER_BK_PWM
21#endif
22
24
25#if defined(USE_ESP32) && SOC_RMT_SUPPORTED
26#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 1)
27// IDF version 5.5.1 and above is required because of a bug in
28// the RMT encoder: https://github.com/espressif/esp-idf/issues/17244
29typedef union { // NOLINT(modernize-use-using)
30 struct {
31 uint16_t duration : 15;
32 uint16_t level : 1;
33 };
34 uint16_t val;
36
41#endif
42#endif
43
45 public Component
46#if defined(USE_ESP32) && SOC_RMT_SUPPORTED
47 ,
49#endif
50{
51 public:
53 void setup() override;
54
55 void dump_config() override;
56
57 // transmitter setup must run after receiver setup to allow the same GPIO to be used by both
58 float get_setup_priority() const override { return setup_priority::DATA - 1; }
59
60 void set_carrier_duty_percent(uint8_t carrier_duty_percent) { this->carrier_duty_percent_ = carrier_duty_percent; }
61
62 void digital_write(bool value);
63
64#if defined(USE_ESP32) && SOC_RMT_SUPPORTED
65 void set_with_dma(bool with_dma) { this->with_dma_ = with_dma; }
66 void set_eot_level(bool eot_level) { this->eot_level_ = eot_level; }
67#endif
68#if (defined(USE_ESP32) && SOC_RMT_SUPPORTED) || defined(USE_LIBRETINY_VARIANT_RTL8720C) || \
69 defined(REMOTE_TRANSMITTER_BK_PWM)
70 void set_non_blocking(bool non_blocking) { this->non_blocking_ = non_blocking; }
71#endif
72#if defined(USE_LIBRETINY_VARIANT_RTL8720C) || defined(REMOTE_TRANSMITTER_BK_PWM)
73 void loop() override;
74 // called from the envelope timer ISR trampoline; not part of the public API
76 // same, for trampolines whose SDK callback carries no user argument
77 static void advance_active_isr();
78#endif
79
82
83 protected:
84 void send_internal(uint32_t send_times, uint32_t send_wait) override;
85 // the API reply is answered before the user's on_complete automation; sent is false on a
86 // bail-out that never put the frame on the wire, on_complete fires either way
87 void fire_complete_(bool sent = true) {
88 this->notify_complete_(sent);
90 }
91#if (defined(USE_ESP32) && SOC_RMT_SUPPORTED) || defined(USE_LIBRETINY_VARIANT_RTL8720C) || \
92 defined(REMOTE_TRANSMITTER_BK_PWM)
93 void flush_pending_completion() override;
94#endif
95#if defined(USE_ESP8266) || \
96 (defined(USE_LIBRETINY) && !defined(USE_LIBRETINY_VARIANT_RTL8720C) && !defined(REMOTE_TRANSMITTER_BK_PWM)) || \
97 defined(USE_RP2) || (defined(USE_ESP32) && !SOC_RMT_SUPPORTED)
98 void await_target_time_();
100#endif
101#if defined(USE_ESP8266) || \
102 (defined(USE_LIBRETINY) && !defined(USE_RTL87XX) && !defined(REMOTE_TRANSMITTER_BK_PWM)) || defined(USE_RP2) || \
103 (defined(USE_ESP32) && !SOC_RMT_SUPPORTED)
104 void calculate_on_off_time_(uint32_t carrier_frequency, uint32_t *on_time_period, uint32_t *off_time_period);
105
106 void mark_(uint32_t on_time, uint32_t off_time, uint32_t usec);
107
108 void space_(uint32_t usec);
109#endif
110#ifdef USE_RTL87XX
111 // Carrier frequency the PWM is currently configured for; 0 = not yet configured
113 void *pwm_{nullptr}; // pwmout_t*, opaque here to keep the SDK header out of this shared header
114#endif
115#if defined(USE_LIBRETINY_VARIANT_RTL8720C) || defined(REMOTE_TRANSMITTER_BK_PWM)
116 // Envelope chain, shared by every family that paces transmission from a hardware timer
117 // (remote_transmitter_libretiny_isr.cpp)
118 void start_isr_item_(size_t index);
119 void arm_envelope_timer_(uint32_t duration_us);
121 void deliver_completion_();
122 void wait_until_idle_();
123 void arm_chain_(uint32_t send_times, uint32_t send_wait);
124 // Hooks implemented per family: everything the chain needs from the hardware
125 bool envelope_ready_() const; // PWM claimed successfully in setup()
126 void prepare_carrier_(uint32_t carrier_frequency); // retune period, stage mark/space levels
127 void write_envelope_level_(bool mark); // drive carrier (mark) or idle (space)
128 void arm_one_shot_(uint32_t duration_us); // fire advance_envelope_isr after duration_us
130 std::vector<int32_t> isr_data_; // owned copy of the frame; temp_ may be re-encoded mid-flight
131 volatile size_t isr_index_{0};
134 volatile uint32_t isr_wait_remaining_{0}; // remainder of a duration chained across one-shots
135 volatile bool isr_in_gap_{false};
136 volatile bool transmitting_{false};
137 bool non_blocking_{false};
138 bool complete_pending_{false};
139 bool stall_aborted_{false}; // this transmission ended via abort; blocks warning clear
140#endif
141#ifdef USE_LIBRETINY_VARIANT_RTL8720C
142 float isr_mark_duty_{0.0f};
143 float isr_space_duty_{0.0f};
144#endif
145#ifdef REMOTE_TRANSMITTER_BK_PWM
146 void write_pwm_t1_(uint32_t t1_counts);
149 uint32_t isr_period_t4_{684}; // 26MHz counts; ~38kHz default until a send sets the real carrier
150 int8_t pwm_channel_{-1};
151#endif
152
153#if defined(USE_ESP32) && SOC_RMT_SUPPORTED
154 // log the failed RMT call and mark the component failed
155 void fail_(esp_err_t error, const LogString *reason);
156 void configure_rmt_();
157 void wait_for_rmt_();
158
159#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 1)
161 std::vector<rmt_symbol_half_t> rmt_temp_;
162#else
163 std::vector<rmt_symbol_word_t> rmt_temp_;
164#endif
166 bool initialized_{false};
167 bool with_dma_{false};
168 bool eot_level_{false};
169 rmt_channel_handle_t channel_{NULL};
170 rmt_encoder_handle_t encoder_{NULL};
171 bool inverted_{false};
172 bool non_blocking_{false};
173#endif
175
178};
179
180} // namespace esphome::remote_transmitter
void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE
Inform the parent automation that the event has triggered.
Definition automation.h:556
void notify_complete_(bool sent)
Reports the frame handed to the platform last, after its final repeat and before the on_complete trig...
void send_internal(uint32_t send_times, uint32_t send_wait) override
void fail_(esp_err_t error, const LogString *reason)
void calculate_on_off_time_(uint32_t carrier_frequency, uint32_t *on_time_period, uint32_t *off_time_period)
void mark_(uint32_t on_time, uint32_t off_time, uint32_t usec)
void set_carrier_duty_percent(uint8_t carrier_duty_percent)
constexpr float DATA
For components that import data from directly connected sensors like DHT.
Definition component.h:45
static void uint32_t