6 bool OOKwiz::serial_cli_disable =
false;
7 int OOKwiz::first_pulse_min_len;
8 int OOKwiz::pulse_gap_min_len;
11 int OOKwiz::pulse_gap_len_new_packet;
13 int OOKwiz::noise_threshold;
15 bool OOKwiz::no_noise_fix =
false;
16 int OOKwiz::lost_packets = 0;
17 int64_t
OOKwiz::last_transition;
18 hw_timer_t*
OOKwiz::transitionTimer =
nullptr;
19 int64_t
OOKwiz::repeat_time_start = 0;
20 long OOKwiz::repeat_timeout;
21 bool OOKwiz::rx_active_high;
22 bool OOKwiz::tx_active_high;
28 int64_t
OOKwiz::last_periodic = 0;
52 INFO(
"\n\nOOKwiz version %s (built %s %s) initializing.\n",
OOKWIZ_VERSION, __DATE__, __TIME__);
55 if (skip_saved_defaults ==
true) {
56 INFO(
"OOKwiz::setup(true) called: not loading user defaults, factory settings only.\n");
59 if (!Settings::fileExists(
"default") || !Settings::load(
"default")) {
60 INFO(
"No saved settings found, using factory settings.\n");
67 if (pin_rescue != -1) {
69 if (digitalRead(pin_rescue) == Settings::isSet(
"rescue_active_high")) {
70 INFO(
"Rescue button pressed at boot, skipping initialization.\n");
71 Settings::unset(
"serial_cli_disable");
77 ERROR(
"ERROR: Your radio doesn't set up correctly. Make sure you set the correct\n radio and pins, save settings and reboot.\n");
92 no_noise_fix = Settings::isSet(
"no_noise_fix");
93 rx_active_high = Settings::isSet(
"rx_active_high");
94 tx_active_high = Settings::isSet(
"tx_active_high");
97 transitionTimer = timerBegin(0, 80,
true);
98 timerAttachInterrupt(transitionTimer, &ISR_transitionTimeout,
false);
99 timerAlarmWrite(transitionTimer, pulse_gap_len_new_packet,
true);
100 timerAlarmEnable(transitionTimer);
101 timerStart(transitionTimer);
104 attachInterrupt(Radio::pin_rx, ISR_transition, CHANGE);
106 if (Settings::isSet(
"start_in_standby")) {
124 if (!serial_cli_disable) {
128 if (transitionTimer ==
nullptr) {
132 if (esp_timer_get_time() - last_periodic > 1000000) {
140 no_noise_fix = Settings::isSet(
"no_noise_fix");
141 serial_cli_disable = Settings::isSet(
"serial_cli_disable");
143 int new_p_g_l_n_p = Settings::getInt(
"pulse_gap_len_new_packet", -1);
144 if (new_p_g_l_n_p != pulse_gap_len_new_packet) {
145 pulse_gap_len_new_packet = new_p_g_l_n_p;
146 timerAlarmWrite(transitionTimer, pulse_gap_len_new_packet,
true);
148 int new_r_t = Settings::getInt(
"repeat_timeout", -1);
149 last_periodic = esp_timer_get_time();
153 loop_compare.train &&
154 esp_timer_get_time() - repeat_time_start > repeat_timeout
156 loop_ready.raw = loop_compare.raw;
157 loop_ready.train = loop_compare.train;
159 }
else if (isr_out) {
162 loop_in.raw = isr_out;
165 if (loop_in.raw.intervals.size() < (min_nr_pulses * 2) + 1) {
170 if (loop_in.raw.intervals.size() % 2 == 0) {
171 loop_in.raw.intervals.pop_back();
178 for (
int n = 1; n < loop_in.raw.intervals.size() - 1; n++) {
179 if (loop_in.raw.intervals[n] < pulse_gap_min_len) {
180 int new_interval = loop_in.raw.intervals[n - 1] + loop_in.raw.intervals[n] + loop_in.raw.intervals[n + 1];
181 loop_in.raw.intervals.erase(loop_in.raw.intervals.begin() + n - 1, loop_in.raw.intervals.begin() + n + 2);
182 loop_in.raw.intervals.insert(loop_in.raw.intervals.begin() + n - 1, new_interval);
189 if (loop_in.raw.intervals.back() < pulse_gap_min_len) {
190 loop_in.raw.intervals.pop_back();
191 loop_in.raw.intervals.pop_back();
194 if (loop_in.raw.intervals.size() < (min_nr_pulses * 2) + 1) {
199 loop_in.raw.intervals.shrink_to_fit();
201 loop_in.train.fromRawTimings(loop_in.raw);
206 if (!loop_compare.train) {
207 loop_compare = loop_in;
210 repeat_time_start = esp_timer_get_time();
212 }
else if (loop_in.train && loop_in.train.sameAs(loop_compare.train)) {
214 loop_compare.train.repeats++;
216 int64_t gap = (esp_timer_get_time() - loop_compare.train.last_at) - loop_compare.train.duration;
217 if (gap < loop_compare.train.gap || loop_compare.train.gap == 0) {
218 loop_compare.train.gap = gap;
220 loop_compare.train.last_at = esp_timer_get_time();
223 repeat_time_start = esp_timer_get_time();
226 loop_ready.raw = loop_compare.raw;
227 loop_ready.train = loop_compare.train;
228 loop_compare = loop_in;
230 repeat_time_start = esp_timer_get_time();
234 if (loop_ready.train) {
237 ERROR(
"\n\nWARNING: %i packets lost because loop() was not fast enough.\n", lost_packets);
241 if (Settings::isSet(
"print_raw") ||
242 Settings::isSet(
"print_visualizer") ||
243 Settings::isSet(
"print_summary") ||
244 Settings::isSet(
"print_pulsetrain") ||
245 Settings::isSet(
"print_binlist") ||
246 Settings::isSet(
"print_meaning")
250 if (Settings::isSet(
"print_raw") && loop_ready.raw) {
251 INFO(
"%s\n", loop_ready.raw.toString().c_str());
253 if (Settings::isSet(
"print_visualizer")) {
256 if (loop_ready.raw) {
257 INFO(
"%s\n", loop_ready.raw.visualizer().c_str());
259 INFO(
"%s\n", loop_ready.train.visualizer().c_str());
262 if (Settings::isSet(
"print_summary")) {
263 INFO(
"%s\n", loop_ready.train.summary().c_str());
265 if (Settings::isSet(
"print_pulsetrain")) {
266 INFO(
"%s\n", loop_ready.train.toString().c_str());
268 if (Settings::isSet(
"print_binlist")) {
269 INFO(
"%s\n", loop_ready.train.binList().c_str());
273 loop_ready.meaning.fromPulsetrain(loop_ready.train);
274 if (loop_ready.meaning && Settings::isSet(
"print_meaning")) {
275 INFO(
"%s\n", loop_ready.meaning.toString().c_str());
281 if (callback !=
nullptr) {
282 callback(loop_ready.raw, loop_ready.train, loop_ready.meaning);
289 void IRAM_ATTR OOKwiz::ISR_transition() {
290 int64_t t = esp_timer_get_time() - last_transition;
291 last_transition = esp_timer_get_time();
292 if (rx_state == RX_WAIT_PREAMBLE) {
294 if (t > first_pulse_min_len && digitalRead(Radio::pin_rx) != rx_active_high) {
297 isr_in.intervals.reserve((max_nr_pulses * 2) + 1);
298 rx_state = RX_RECEIVING_DATA;
301 if (rx_state == RX_RECEIVING_DATA) {
303 if (t < pulse_gap_min_len) {
304 noise_score += noise_penalty;
305 if (noise_score >= noise_threshold) {
310 noise_score -= noise_score > 0;
312 isr_in.intervals.push_back(t);
314 if (isr_in.intervals.size() == (max_nr_pulses * 2) + 1) {
319 timerRestart(transitionTimer);
322 void IRAM_ATTR OOKwiz::ISR_transitionTimeout() {
323 if (rx_state != RX_OFF) {
328 void IRAM_ATTR OOKwiz::process_raw() {
335 rx_state = RX_WAIT_PREAMBLE;
364 bool OOKwiz::onReceive(
void (*callback_function)(RawTimings, Pulsetrain, Meaning)) {
365 callback = callback_function;
376 bool OOKwiz::receive() {
377 if (!Radio::radio_rx()) {
381 rx_state = RX_WAIT_PREAMBLE;
385 bool OOKwiz::tryToBeNice(
int ms) {
388 long start = millis();
389 while (millis() - start < ms) {
390 if (rx_state == RX_WAIT_PREAMBLE) {
400 bool OOKwiz::simulate(String &str) {
401 if (RawTimings::maybe(str)) {
403 if (raw.fromString(str)) {
404 return simulate(raw);
406 }
else if (Pulsetrain::maybe(str)) {
408 if (train.fromString(str)) {
409 return simulate(train);
411 }
else if (Meaning::maybe(str)) {
413 if (meaning.fromString(str)) {
414 return simulate(meaning);
417 ERROR(
"ERROR: string does not look like RawTimings, Pulsetrain or Meaning.\n");
425 bool OOKwiz::simulate(RawTimings &raw) {
434 bool OOKwiz::simulate(Pulsetrain &train) {
436 loop_ready.train = train;
443 bool OOKwiz::simulate(Meaning &meaning) {
445 if (train.fromMeaning(meaning)) {
446 return simulate(train);
454 bool OOKwiz::transmit(String &str) {
455 if (RawTimings::maybe(str)) {
457 if (raw.fromString(str)) {
458 return transmit(raw);
460 }
else if (Pulsetrain::maybe(str)) {
462 if (train.fromString(str)) {
463 return transmit(train);
465 }
else if (Meaning::maybe(str)) {
467 if (meaning.fromString(str)) {
468 return transmit(meaning);
470 }
else if (str.indexOf(
":") != -1) {
473 tools::split(str,
":", plugin_name, tx_str);
474 return Device::transmit(plugin_name, tx_str);
476 ERROR(
"ERROR: string does not look like RawTimings, Pulsetrain or Meaning.\n");
484 bool OOKwiz::transmit(RawTimings &raw) {
485 bool rx_was_on = (rx_state != RX_OFF);
492 if (!Radio::radio_tx()) {
493 ERROR(
"ERROR: Transceiver could not be set to transmit.\n");
496 INFO(
"Transmitting: %s\n", raw.toString().c_str());
497 INFO(
" %s\n", raw.visualizer().c_str());
499 int64_t tx_timer = esp_timer_get_time();
502 bool bit = tx_active_high;
504 for (uint16_t interval: raw.intervals) {
505 delayMicroseconds(interval);
509 PIN_WRITE(Radio::pin_tx, !tx_active_high);
512 tx_timer = esp_timer_get_time() - tx_timer;
513 INFO(
"Transmission done, took %i µs.\n", tx_timer);
514 delayMicroseconds(400);
527 bool OOKwiz::transmit(Pulsetrain &train) {
528 bool rx_was_on = (rx_state != RX_OFF);
535 if (!Radio::radio_tx()) {
536 ERROR(
"ERROR: Transceiver could not be set to transmit.\n");
539 INFO(
"Transmitting %s\n", train.toString().c_str());
540 INFO(
" %s\n", train.visualizer().c_str());
542 int64_t tx_timer = esp_timer_get_time();
543 for (
int repeat = 0; repeat < train.repeats; repeat++) {
546 bool bit = tx_active_high;
548 for (
int transition : train.transitions) {
549 uint16_t t = train.bins[transition].average;
550 delayMicroseconds(t);
554 PIN_WRITE(Radio::pin_tx, !tx_active_high);
557 delayMicroseconds(train.gap);
559 tx_timer = esp_timer_get_time() - tx_timer;
560 INFO(
"Transmission done, took %i µs.\n", tx_timer);
561 delayMicroseconds(400);
574 bool OOKwiz::transmit(Meaning &meaning) {
576 if (train.fromMeaning(meaning)) {
577 return transmit(train);
584 bool OOKwiz::standby() {
585 if (rx_state != RX_OFF) {
589 Radio::radio_standby();