ESPHome  2024.5.0
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 ([email protected])
6 #ifdef USE_ESP8266
7 
8 #include "LwTx.h"
9 #include <cstring>
10 #include <Arduino.h>
11 #include "esphome/core/log.h"
12 #include "esphome/core/helpers.h"
13 
14 namespace esphome {
15 namespace lightwaverf {
16 
17 static const uint8_t TX_NIBBLE[] = {0xF6, 0xEE, 0xED, 0xEB, 0xDE, 0xDD, 0xDB, 0xBE,
18  0xBD, 0xBB, 0xB7, 0x7E, 0x7D, 0x7B, 0x77, 0x6F};
19 
20 static const uint8_t TX_STATE_IDLE = 0;
21 static const uint8_t TX_STATE_MSGSTART = 1;
22 static const uint8_t TX_STATE_BYTESTART = 2;
23 static const uint8_t TX_STATE_SENDBYTE = 3;
24 static const uint8_t TX_STATE_MSGEND = 4;
25 static const uint8_t TX_STATE_GAPSTART = 5;
26 static const uint8_t TX_STATE_GAPEND = 6;
30 void LwTx::lwtx_settranslate(bool txtranslate) { tx_translate = txtranslate; }
31 
32 static void IRAM_ATTR isr_t_xtimer(LwTx *arg) {
33  // Set low after toggle count interrupts
34  arg->tx_toggle_count--;
35  if (arg->tx_toggle_count == arg->tx_trail_count) {
36  // ESP_LOGD("lightwaverf.sensor", "timer")
37  arg->tx_pin->digital_write(arg->txoff);
38  } else if (arg->tx_toggle_count == 0) {
39  arg->tx_toggle_count = arg->tx_high_count; // default high pulse duration
40  switch (arg->tx_state) {
41  case TX_STATE_IDLE:
42  if (arg->tx_msg_active) {
43  arg->tx_repeat = 0;
44  arg->tx_state = TX_STATE_MSGSTART;
45  }
46  break;
47  case TX_STATE_MSGSTART:
48  arg->tx_pin->digital_write(arg->txon);
49  arg->tx_num_bytes = 0;
50  arg->tx_state = TX_STATE_BYTESTART;
51  break;
52  case TX_STATE_BYTESTART:
53  arg->tx_pin->digital_write(arg->txon);
54  arg->tx_bit_mask = 0x80;
55  arg->tx_state = TX_STATE_SENDBYTE;
56  break;
57  case TX_STATE_SENDBYTE:
58  if (arg->tx_buf[arg->tx_num_bytes] & arg->tx_bit_mask) {
59  arg->tx_pin->digital_write(arg->txon);
60  } else {
61  // toggle count for the 0 pulse
62  arg->tx_toggle_count = arg->tx_low_count;
63  }
64  arg->tx_bit_mask >>= 1;
65  if (arg->tx_bit_mask == 0) {
66  arg->tx_num_bytes++;
68  arg->tx_state = TX_STATE_MSGEND;
69  } else {
70  arg->tx_state = TX_STATE_BYTESTART;
71  }
72  }
73  break;
74  case TX_STATE_MSGEND:
75  arg->tx_pin->digital_write(arg->txon);
76  arg->tx_state = TX_STATE_GAPSTART;
77  arg->tx_gap_repeat = arg->tx_gap_multiplier;
78  break;
79  case TX_STATE_GAPSTART:
80  arg->tx_toggle_count = arg->tx_gap_count;
81  if (arg->tx_gap_repeat == 0) {
82  arg->tx_state = TX_STATE_GAPEND;
83  } else {
84  arg->tx_gap_repeat--;
85  }
86  break;
87  case TX_STATE_GAPEND:
88  arg->tx_repeat++;
89  if (arg->tx_repeat >= arg->tx_repeats) {
90  // disable timer nterrupt
91  arg->lw_timer_stop();
92  arg->tx_msg_active = false;
93  arg->tx_state = TX_STATE_IDLE;
94  } else {
95  arg->tx_state = TX_STATE_MSGSTART;
96  }
97  break;
98  }
99  }
100 }
101 
105 bool LwTx::lwtx_free() { return !this->tx_msg_active; }
106 
110 void LwTx::lwtx_send(const std::vector<uint8_t> &msg) {
111  if (this->tx_translate) {
112  for (uint8_t i = 0; i < TX_MSGLEN; i++) {
113  this->tx_buf[i] = TX_NIBBLE[msg[i] & 0xF];
114  ESP_LOGD("lightwaverf.sensor", "%x ", msg[i]);
115  }
116  } else {
117  // memcpy(tx_buf, msg, tx_msglen);
118  }
119  this->lw_timer_start();
120  this->tx_msg_active = true;
121 }
122 
126 void LwTx::lwtx_setaddr(const uint8_t *addr) {
127  for (uint8_t i = 0; i < 5; i++) {
128  this->tx_buf[i + 4] = TX_NIBBLE[addr[i] & 0xF];
129  }
130 }
131 
135 void LwTx::lwtx_cmd(uint8_t command, uint8_t parameter, uint8_t room, uint8_t device) {
136  // enable timer 2 interrupts
137  this->tx_buf[0] = TX_NIBBLE[parameter >> 4];
138  this->tx_buf[1] = TX_NIBBLE[parameter & 0xF];
139  this->tx_buf[2] = TX_NIBBLE[device & 0xF];
140  this->tx_buf[3] = TX_NIBBLE[command & 0xF];
141  this->tx_buf[9] = TX_NIBBLE[room & 0xF];
142  this->lw_timer_start();
143  this->tx_msg_active = true;
144 }
145 
149 void LwTx::lwtx_setup(InternalGPIOPin *pin, uint8_t repeats, bool inverted, int u_sec) {
150  pin->setup();
151  tx_pin = pin;
152 
155 
156  if (repeats > 0 && repeats < 40) {
157  this->tx_repeats = repeats;
158  }
159  if (inverted) {
160  this->txon = 0;
161  this->txoff = 1;
162  } else {
163  this->txon = 1;
164  this->txoff = 0;
165  }
166 
167  int period1 = 330;
168  /*
169  if (period > 32 && period < 1000) {
170  period1 = period;
171  } else {
172  // default 330 uSec
173  period1 = 330;
174  }*/
175  this->espPeriod = 5 * period1;
176  timer1_isr_init();
177 }
178 
179 void LwTx::lwtx_set_tick_counts(uint8_t low_count, uint8_t high_count, uint8_t trail_count, uint8_t gap_count) {
180  this->tx_low_count = low_count;
181  this->tx_high_count = high_count;
182  this->tx_trail_count = trail_count;
183  this->tx_gap_count = gap_count;
184 }
185 
186 void LwTx::lwtx_set_gap_multiplier(uint8_t gap_multiplier) { this->tx_gap_multiplier = gap_multiplier; }
187 
189  {
190  InterruptLock lock;
191  static LwTx *arg = this; // NOLINT
192  timer1_attachInterrupt([] { isr_t_xtimer(arg); });
193  timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP);
194  timer1_write(this->espPeriod);
195  }
196 }
197 
199  {
200  InterruptLock lock;
201  timer1_disable();
202  timer1_detachInterrupt();
203  }
204 }
205 
206 } // namespace lightwaverf
207 } // namespace esphome
208 #endif
virtual void digital_write(bool value)=0
virtual void pin_mode(gpio::Flags flags)=0
uint8_t tx_trail_count
Definition: LwTx.h:55
static const uint8_t TX_MSGLEN
Definition: LwTx.h:59
virtual void setup()=0
void lwtx_settranslate(bool txtranslate)
Set translate mode.
Definition: LwTx.cpp:30
void lwtx_set_gap_multiplier(uint8_t gap_multiplier)
Definition: LwTx.cpp:186
void lwtx_set_tick_counts(uint8_t low_count, uint8_t high_count, uint8_t trail_count, uint8_t gap_count)
Definition: LwTx.cpp:179
uint8_t tx_gap_multiplier
Definition: LwTx.h:81
uint8_t tx_buf[TX_MSGLEN]
Definition: LwTx.h:68
void lwtx_setaddr(const uint8_t *addr)
Set 5 char address for future messages.
Definition: LwTx.cpp:126
uint8_t tx_toggle_count
Definition: LwTx.h:57
Helper class to disable interrupts.
Definition: helpers.h:597
uint16_t tx_gap_repeat
Definition: LwTx.h:71
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
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:135
void lwtx_setup(InternalGPIOPin *pin, uint8_t repeats, bool inverted, int u_sec)
Set things up to transmit LightWaveRF 434Mhz messages.
Definition: LwTx.cpp:149
InternalGPIOPin * tx_pin
Definition: LwTx.h:86
bool lwtx_free()
Check for send free.
Definition: LwTx.cpp:105
void lwtx_send(const std::vector< uint8_t > &msg)
Send a LightwaveRF message (10 nibbles in bytes)
Definition: LwTx.cpp:110