1
0
mirror of https://github.com/esphome/esphome.git synced 2025-03-24 03:28:20 +00:00
Christian 76ebbfefd2
Integration LightwaveRF switches (#4812)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2023-09-06 10:33:49 +12:00

209 lines
5.6 KiB
C++

// LwTx.cpp
//
// LightwaveRF 434MHz tx interface for Arduino
//
// Author: Bob Tidey (robert@tideys.net)
#ifdef USE_ESP8266
#include "LwTx.h"
#include <cstring>
#include <Arduino.h>
#include "esphome/core/log.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace lightwaverf {
static const uint8_t TX_NIBBLE[] = {0xF6, 0xEE, 0xED, 0xEB, 0xDE, 0xDD, 0xDB, 0xBE,
0xBD, 0xBB, 0xB7, 0x7E, 0x7D, 0x7B, 0x77, 0x6F};
static const uint8_t TX_STATE_IDLE = 0;
static const uint8_t TX_STATE_MSGSTART = 1;
static const uint8_t TX_STATE_BYTESTART = 2;
static const uint8_t TX_STATE_SENDBYTE = 3;
static const uint8_t TX_STATE_MSGEND = 4;
static const uint8_t TX_STATE_GAPSTART = 5;
static const uint8_t TX_STATE_GAPEND = 6;
/**
Set translate mode
**/
void LwTx::lwtx_settranslate(bool txtranslate) { tx_translate = txtranslate; }
static void IRAM_ATTR isr_t_xtimer(LwTx *arg) {
// Set low after toggle count interrupts
arg->tx_toggle_count--;
if (arg->tx_toggle_count == arg->tx_trail_count) {
// ESP_LOGD("lightwaverf.sensor", "timer")
arg->tx_pin->digital_write(arg->txoff);
} else if (arg->tx_toggle_count == 0) {
arg->tx_toggle_count = arg->tx_high_count; // default high pulse duration
switch (arg->tx_state) {
case TX_STATE_IDLE:
if (arg->tx_msg_active) {
arg->tx_repeat = 0;
arg->tx_state = TX_STATE_MSGSTART;
}
break;
case TX_STATE_MSGSTART:
arg->tx_pin->digital_write(arg->txon);
arg->tx_num_bytes = 0;
arg->tx_state = TX_STATE_BYTESTART;
break;
case TX_STATE_BYTESTART:
arg->tx_pin->digital_write(arg->txon);
arg->tx_bit_mask = 0x80;
arg->tx_state = TX_STATE_SENDBYTE;
break;
case TX_STATE_SENDBYTE:
if (arg->tx_buf[arg->tx_num_bytes] & arg->tx_bit_mask) {
arg->tx_pin->digital_write(arg->txon);
} else {
// toggle count for the 0 pulse
arg->tx_toggle_count = arg->tx_low_count;
}
arg->tx_bit_mask >>= 1;
if (arg->tx_bit_mask == 0) {
arg->tx_num_bytes++;
if (arg->tx_num_bytes >= esphome::lightwaverf::LwTx::TX_MSGLEN) {
arg->tx_state = TX_STATE_MSGEND;
} else {
arg->tx_state = TX_STATE_BYTESTART;
}
}
break;
case TX_STATE_MSGEND:
arg->tx_pin->digital_write(arg->txon);
arg->tx_state = TX_STATE_GAPSTART;
arg->tx_gap_repeat = arg->tx_gap_multiplier;
break;
case TX_STATE_GAPSTART:
arg->tx_toggle_count = arg->tx_gap_count;
if (arg->tx_gap_repeat == 0) {
arg->tx_state = TX_STATE_GAPEND;
} else {
arg->tx_gap_repeat--;
}
break;
case TX_STATE_GAPEND:
arg->tx_repeat++;
if (arg->tx_repeat >= arg->tx_repeats) {
// disable timer nterrupt
arg->lw_timer_stop();
arg->tx_msg_active = false;
arg->tx_state = TX_STATE_IDLE;
} else {
arg->tx_state = TX_STATE_MSGSTART;
}
break;
}
}
}
/**
Check for send free
**/
bool LwTx::lwtx_free() { return !this->tx_msg_active; }
/**
Send a LightwaveRF message (10 nibbles in bytes)
**/
void LwTx::lwtx_send(const std::vector<uint8_t> &msg) {
if (this->tx_translate) {
for (uint8_t i = 0; i < TX_MSGLEN; i++) {
this->tx_buf[i] = TX_NIBBLE[msg[i] & 0xF];
ESP_LOGD("lightwaverf.sensor", "%x ", msg[i]);
}
} else {
// memcpy(tx_buf, msg, tx_msglen);
}
this->lw_timer_start();
this->tx_msg_active = true;
}
/**
Set 5 char address for future messages
**/
void LwTx::lwtx_setaddr(const uint8_t *addr) {
for (uint8_t i = 0; i < 5; i++) {
this->tx_buf[i + 4] = TX_NIBBLE[addr[i] & 0xF];
}
}
/**
Send a LightwaveRF message (10 nibbles in bytes)
**/
void LwTx::lwtx_cmd(uint8_t command, uint8_t parameter, uint8_t room, uint8_t device) {
// enable timer 2 interrupts
this->tx_buf[0] = TX_NIBBLE[parameter >> 4];
this->tx_buf[1] = TX_NIBBLE[parameter & 0xF];
this->tx_buf[2] = TX_NIBBLE[device & 0xF];
this->tx_buf[3] = TX_NIBBLE[command & 0xF];
this->tx_buf[9] = TX_NIBBLE[room & 0xF];
this->lw_timer_start();
this->tx_msg_active = true;
}
/**
Set things up to transmit LightWaveRF 434Mhz messages
**/
void LwTx::lwtx_setup(InternalGPIOPin *pin, uint8_t repeats, bool inverted, int u_sec) {
pin->setup();
tx_pin = pin;
tx_pin->pin_mode(gpio::FLAG_OUTPUT);
tx_pin->digital_write(txoff);
if (repeats > 0 && repeats < 40) {
this->tx_repeats = repeats;
}
if (inverted) {
this->txon = 0;
this->txoff = 1;
} else {
this->txon = 1;
this->txoff = 0;
}
int period1 = 330;
/*
if (period > 32 && period < 1000) {
period1 = period;
} else {
// default 330 uSec
period1 = 330;
}*/
this->espPeriod = 5 * period1;
timer1_isr_init();
}
void LwTx::lwtx_set_tick_counts(uint8_t low_count, uint8_t high_count, uint8_t trail_count, uint8_t gap_count) {
this->tx_low_count = low_count;
this->tx_high_count = high_count;
this->tx_trail_count = trail_count;
this->tx_gap_count = gap_count;
}
void LwTx::lwtx_set_gap_multiplier(uint8_t gap_multiplier) { this->tx_gap_multiplier = gap_multiplier; }
void LwTx::lw_timer_start() {
{
InterruptLock lock;
static LwTx *arg = this; // NOLINT
timer1_attachInterrupt([] { isr_t_xtimer(arg); });
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP);
timer1_write(this->espPeriod);
}
}
void LwTx::lw_timer_stop() {
{
InterruptLock lock;
timer1_disable();
timer1_detachInterrupt();
}
}
} // namespace lightwaverf
} // namespace esphome
#endif