ESPHome  2024.4.2
wiegand.cpp
Go to the documentation of this file.
1 #include "wiegand.h"
2 #include "esphome/core/log.h"
3 #include "esphome/core/helpers.h"
4 
5 namespace esphome {
6 namespace wiegand {
7 
8 static const char *const TAG = "wiegand";
9 static const char *const KEYS = "0123456789*#";
10 
11 void IRAM_ATTR HOT WiegandStore::d0_gpio_intr(WiegandStore *arg) {
12  if (arg->d0.digital_read())
13  return;
14  arg->count++;
15  arg->value <<= 1;
16  arg->last_bit_time = millis();
17  arg->done = false;
18 }
19 
20 void IRAM_ATTR HOT WiegandStore::d1_gpio_intr(WiegandStore *arg) {
21  if (arg->d1.digital_read())
22  return;
23  arg->count++;
24  arg->value = (arg->value << 1) | 1;
25  arg->last_bit_time = millis();
26  arg->done = false;
27 }
28 
30  this->d0_pin_->setup();
31  this->store_.d0 = this->d0_pin_->to_isr();
32  this->d1_pin_->setup();
33  this->store_.d1 = this->d1_pin_->to_isr();
34  this->d0_pin_->attach_interrupt(WiegandStore::d0_gpio_intr, &this->store_, gpio::INTERRUPT_FALLING_EDGE);
35  this->d1_pin_->attach_interrupt(WiegandStore::d1_gpio_intr, &this->store_, gpio::INTERRUPT_FALLING_EDGE);
36 }
37 
38 bool check_eparity(uint64_t value, int start, int length) {
39  int parity = 0;
40  uint64_t mask = 1LL << start;
41  for (int i = 0; i < length; i++, mask <<= 1) {
42  if (value & mask)
43  parity++;
44  }
45  return !(parity & 1);
46 }
47 
48 bool check_oparity(uint64_t value, int start, int length) {
49  int parity = 0;
50  uint64_t mask = 1LL << start;
51  for (int i = 0; i < length; i++, mask <<= 1) {
52  if (value & mask)
53  parity++;
54  }
55  return parity & 1;
56 }
57 
58 void Wiegand::loop() {
59  if (this->store_.done)
60  return;
61  if (millis() - this->store_.last_bit_time < 100)
62  return;
63  uint8_t count = this->store_.count;
64  uint64_t value = this->store_.value;
65  this->store_.count = 0;
66  this->store_.value = 0;
67  this->store_.done = true;
68  ESP_LOGV(TAG, "received %d-bit value: %llx", count, value);
69  for (auto *trigger : this->raw_triggers_)
70  trigger->trigger(count, value);
71  if (count == 26) {
72  std::string tag = to_string((value >> 1) & 0xffffff);
73  ESP_LOGD(TAG, "received 26-bit tag: %s", tag.c_str());
74  if (!check_eparity(value, 13, 13) || !check_oparity(value, 0, 13)) {
75  ESP_LOGW(TAG, "invalid parity");
76  return;
77  }
78  for (auto *trigger : this->tag_triggers_)
79  trigger->trigger(tag);
80  } else if (count == 34) {
81  std::string tag = to_string((value >> 1) & 0xffffffff);
82  ESP_LOGD(TAG, "received 34-bit tag: %s", tag.c_str());
83  if (!check_eparity(value, 17, 17) || !check_oparity(value, 0, 17)) {
84  ESP_LOGW(TAG, "invalid parity");
85  return;
86  }
87  for (auto *trigger : this->tag_triggers_)
88  trigger->trigger(tag);
89  } else if (count == 37) {
90  std::string tag = to_string((value >> 1) & 0x7ffffffff);
91  ESP_LOGD(TAG, "received 37-bit tag: %s", tag.c_str());
92  if (!check_eparity(value, 18, 19) || !check_oparity(value, 0, 19)) {
93  ESP_LOGW(TAG, "invalid parity");
94  return;
95  }
96  for (auto *trigger : this->tag_triggers_)
97  trigger->trigger(tag);
98  } else if (count == 4) {
99  for (auto *trigger : this->key_triggers_)
100  trigger->trigger(value);
101  if (value < 12) {
102  uint8_t key = KEYS[value];
103  this->send_key_(key);
104  }
105  } else if (count == 8) {
106  if ((value ^ 0xf0) >> 4 == (value & 0xf)) {
107  value &= 0xf;
108  for (auto *trigger : this->key_triggers_)
109  trigger->trigger(value);
110  if (value < 12) {
111  uint8_t key = KEYS[value];
112  this->send_key_(key);
113  }
114  }
115  } else {
116  ESP_LOGD(TAG, "received unknown %d-bit value: %llx", count, value);
117  }
118 }
119 
121  ESP_LOGCONFIG(TAG, "Wiegand reader:");
122  LOG_PIN(" D0 pin: ", this->d0_pin_);
123  LOG_PIN(" D1 pin: ", this->d1_pin_);
124 }
125 
126 } // namespace wiegand
127 } // namespace esphome
ISRInternalGPIOPin d0
Definition: wiegand.h:14
void setup() override
Definition: wiegand.cpp:29
volatile uint8_t count
Definition: wiegand.h:19
bool check_eparity(uint64_t value, int start, int length)
Definition: wiegand.cpp:38
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
void dump_config() override
Definition: wiegand.cpp:120
volatile uint64_t value
Definition: wiegand.h:16
static void d0_gpio_intr(WiegandStore *arg)
Definition: wiegand.cpp:11
std::string to_string(int value)
Definition: helpers.cpp:82
ISRInternalGPIOPin d1
Definition: wiegand.h:15
bool check_oparity(uint64_t value, int start, int length)
Definition: wiegand.cpp:48
uint16_t length
Definition: tt21100.cpp:12
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 loop() override
Definition: wiegand.cpp:58
static void d1_gpio_intr(WiegandStore *arg)
Definition: wiegand.cpp:20
volatile uint32_t last_bit_time
Definition: wiegand.h:17