ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
LwTx.cpp
Go to the documentation of this file.
1// LwTx.cpp
2//
3// LightwaveRF 434MHz tx interface for Arduino
4//
5// Author: Bob Tidey (robert@tideys.net)
6#ifdef USE_ESP8266
7
8#include "LwTx.h"
9#include <cstring>
10#include <Arduino.h>
12#include "esphome/core/log.h"
13
14namespace esphome::lightwaverf {
15
16static const uint8_t TX_NIBBLE[] = {0xF6, 0xEE, 0xED, 0xEB, 0xDE, 0xDD, 0xDB, 0xBE,
17 0xBD, 0xBB, 0xB7, 0x7E, 0x7D, 0x7B, 0x77, 0x6F};
18
19static const uint8_t TX_STATE_IDLE = 0;
20static const uint8_t TX_STATE_MSGSTART = 1;
21static const uint8_t TX_STATE_BYTESTART = 2;
22static const uint8_t TX_STATE_SENDBYTE = 3;
23static const uint8_t TX_STATE_MSGEND = 4;
24static const uint8_t TX_STATE_GAPSTART = 5;
25static const uint8_t TX_STATE_GAPEND = 6;
29void LwTx::lwtx_settranslate(bool txtranslate) { tx_translate = txtranslate; }
30
31static void IRAM_ATTR isr_t_xtimer(LwTx *arg) {
32 // Set low after toggle count interrupts
33 arg->tx_toggle_count--;
34 if (arg->tx_toggle_count == arg->tx_trail_count) {
35 // ESP_LOGD("lightwaverf.sensor", "timer")
36 arg->tx_pin->digital_write(arg->txoff);
37 } else if (arg->tx_toggle_count == 0) {
38 arg->tx_toggle_count = arg->tx_high_count; // default high pulse duration
39 switch (arg->tx_state) {
40 case TX_STATE_IDLE:
41 if (arg->tx_msg_active) {
42 arg->tx_repeat = 0;
43 arg->tx_state = TX_STATE_MSGSTART;
44 }
45 break;
46 case TX_STATE_MSGSTART:
47 arg->tx_pin->digital_write(arg->txon);
48 arg->tx_num_bytes = 0;
49 arg->tx_state = TX_STATE_BYTESTART;
50 break;
51 case TX_STATE_BYTESTART:
52 arg->tx_pin->digital_write(arg->txon);
53 arg->tx_bit_mask = 0x80;
54 arg->tx_state = TX_STATE_SENDBYTE;
55 break;
56 case TX_STATE_SENDBYTE:
57 if (arg->tx_buf[arg->tx_num_bytes] & arg->tx_bit_mask) {
58 arg->tx_pin->digital_write(arg->txon);
59 } else {
60 // toggle count for the 0 pulse
61 arg->tx_toggle_count = arg->tx_low_count;
62 }
63 arg->tx_bit_mask >>= 1;
64 if (arg->tx_bit_mask == 0) {
65 arg->tx_num_bytes++;
67 arg->tx_state = TX_STATE_MSGEND;
68 } else {
69 arg->tx_state = TX_STATE_BYTESTART;
70 }
71 }
72 break;
73 case TX_STATE_MSGEND:
74 arg->tx_pin->digital_write(arg->txon);
75 arg->tx_state = TX_STATE_GAPSTART;
77 break;
78 case TX_STATE_GAPSTART:
79 arg->tx_toggle_count = arg->tx_gap_count;
80 if (arg->tx_gap_repeat == 0) {
81 arg->tx_state = TX_STATE_GAPEND;
82 } else {
83 arg->tx_gap_repeat--;
84 }
85 break;
86 case TX_STATE_GAPEND:
87 arg->tx_repeat++;
88 if (arg->tx_repeat >= arg->tx_repeats) {
89 // disable timer nterrupt
90 arg->lw_timer_stop();
91 arg->tx_msg_active = false;
92 arg->tx_state = TX_STATE_IDLE;
93 } else {
94 arg->tx_state = TX_STATE_MSGSTART;
95 }
96 break;
97 }
98 }
99}
100
104bool LwTx::lwtx_free() { return !this->tx_msg_active; }
105
109void LwTx::lwtx_send(const std::vector<uint8_t> &msg) {
110 if (msg.size() < TX_MSGLEN) {
111 ESP_LOGW("lightwaverf.sensor", "Message too short: %zu < %u", msg.size(), static_cast<unsigned>(TX_MSGLEN));
112 return;
113 }
114 if (this->tx_translate) {
115 for (uint8_t i = 0; i < TX_MSGLEN; i++) {
116 this->tx_buf[i] = TX_NIBBLE[msg[i] & 0xF];
117 ESP_LOGD("lightwaverf.sensor", "%x ", msg[i]);
118 }
119 } else {
120 // memcpy(tx_buf, msg, tx_msglen);
121 }
122 this->lw_timer_start();
123 this->tx_msg_active = true;
124}
125
129void LwTx::lwtx_setaddr(const uint8_t *addr) {
130 for (uint8_t i = 0; i < 5; i++) {
131 this->tx_buf[i + 4] = TX_NIBBLE[addr[i] & 0xF];
132 }
133}
134
138void LwTx::lwtx_cmd(uint8_t command, uint8_t parameter, uint8_t room, uint8_t device) {
139 // enable timer 2 interrupts
140 this->tx_buf[0] = TX_NIBBLE[parameter >> 4];
141 this->tx_buf[1] = TX_NIBBLE[parameter & 0xF];
142 this->tx_buf[2] = TX_NIBBLE[device & 0xF];
143 this->tx_buf[3] = TX_NIBBLE[command & 0xF];
144 this->tx_buf[9] = TX_NIBBLE[room & 0xF];
145 this->lw_timer_start();
146 this->tx_msg_active = true;
147}
148
152void LwTx::lwtx_setup(InternalGPIOPin *pin, uint8_t repeats, bool inverted, int u_sec) {
153 pin->setup();
154 tx_pin = pin;
155
158
159 if (repeats > 0 && repeats < 40) {
160 this->tx_repeats = repeats;
161 }
162 if (inverted) {
163 this->txon = 0;
164 this->txoff = 1;
165 } else {
166 this->txon = 1;
167 this->txoff = 0;
168 }
169
170 int period1 = 330;
171 /*
172 if (period > 32 && period < 1000) {
173 period1 = period;
174 } else {
175 // default 330 uSec
176 period1 = 330;
177 }*/
178 this->espPeriod = 5 * period1;
179 timer1_isr_init();
180}
181
182void LwTx::lwtx_set_tick_counts(uint8_t low_count, uint8_t high_count, uint8_t trail_count, uint8_t gap_count) {
183 this->tx_low_count = low_count;
184 this->tx_high_count = high_count;
185 this->tx_trail_count = trail_count;
186 this->tx_gap_count = gap_count;
187}
188
189void LwTx::lwtx_set_gap_multiplier(uint8_t gap_multiplier) { this->tx_gap_multiplier = gap_multiplier; }
190
192 {
194 static LwTx *arg;
195 arg = this;
196 timer1_attachInterrupt([] { isr_t_xtimer(arg); });
197 timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP);
198 timer1_write(this->espPeriod);
199 }
200}
201
203 {
205 timer1_disable();
206 timer1_detachInterrupt();
207 }
208}
209
210} // namespace esphome::lightwaverf
211#endif
virtual void pin_mode(gpio::Flags flags)=0
virtual void setup()=0
virtual void digital_write(bool value)=0
Helper class to disable interrupts.
Definition helpers.h:1952
void lwtx_set_gap_multiplier(uint8_t gap_multiplier)
Definition LwTx.cpp:189
uint8_t tx_buf[TX_MSGLEN]
Definition LwTx.h:67
void lwtx_setup(InternalGPIOPin *pin, uint8_t repeats, bool inverted, int u_sec)
Set things up to transmit LightWaveRF 434Mhz messages.
Definition LwTx.cpp:152
void lwtx_set_tick_counts(uint8_t low_count, uint8_t high_count, uint8_t trail_count, uint8_t gap_count)
Definition LwTx.cpp:182
static const uint8_t TX_MSGLEN
Definition LwTx.h:58
InternalGPIOPin * tx_pin
Definition LwTx.h:85
volatile bool tx_msg_active
Definition LwTx.h:64
void lwtx_send(const std::vector< uint8_t > &msg)
Send a LightwaveRF message (10 nibbles in bytes)
Definition LwTx.cpp:109
void lwtx_settranslate(bool txtranslate)
Set translate mode.
Definition LwTx.cpp:29
void lwtx_cmd(uint8_t command, uint8_t parameter, uint8_t room, uint8_t device)
Send a LightwaveRF message (10 nibbles in bytes)
Definition LwTx.cpp:138
uint8_t tx_gap_multiplier
Definition LwTx.h:80
void lwtx_setaddr(const uint8_t *addr)
Set 5 char address for future messages.
Definition LwTx.cpp:129
bool lwtx_free()
Check for send free.
Definition LwTx.cpp:104
@ FLAG_OUTPUT
Definition gpio.h:28
SemaphoreHandle_t lock