ESPHome 2026.5.1
Loading...
Searching...
No Matches
beo4_protocol.cpp
Go to the documentation of this file.
1#include "beo4_protocol.h"
2#include "esphome/core/log.h"
3
4#include <cinttypes>
5
6namespace esphome::remote_base {
7
8static const char *const TAG = "remote.beo4";
9
10// beo4 pulse width, high=carrier_pulse low=data_pulse
11constexpr uint16_t PW_CARR_US = 200; // carrier pulse length
12constexpr uint16_t PW_ZERO_US = 2925; // + 200 = 3125 µs
13constexpr uint16_t PW_SAME_US = 6050; // + 200 = 6250 µs
14constexpr uint16_t PW_ONE_US = 9175; // + 200 = 9375 µs
15constexpr uint16_t PW_STOP_US = 12300; // + 200 = 12500 µs
16constexpr uint16_t PW_START_US = 15425; // + 200 = 15625 µs
17
18// beo4 pulse codes
19constexpr uint8_t PC_ZERO = (PW_CARR_US + PW_ZERO_US) / 3125; // =1
20constexpr uint8_t PC_SAME = (PW_CARR_US + PW_SAME_US) / 3125; // =2
21constexpr uint8_t PC_ONE = (PW_CARR_US + PW_ONE_US) / 3125; // =3
22constexpr uint8_t PC_STOP = (PW_CARR_US + PW_STOP_US) / 3125; // =4
23constexpr uint8_t PC_START = (PW_CARR_US + PW_START_US) / 3125; // =5
24
25// beo4 number of data bits = beoLink+beoSrc+beoCmd = 1+8+8 = 17
26constexpr uint32_t N_BITS = 1 + 8 + 8;
27
28// required symbols = 2*(start_sequence + n_bits + stop) = 2*(3+17+1) = 42
29constexpr uint32_t N_SYM = 2 + ((3 + 17 + 1) * 2u); // + 2 = 44
30
31// states finite-state-machine decoder
32enum class RxSt { RX_IDLE, RX_DATA, RX_STOP };
33
35 uint32_t beo_code = ((uint32_t) data.source << 8) + (uint32_t) data.command;
36 uint32_t jc = 0, ic = 0;
37 uint32_t cur_bit = 0;
38 uint32_t pre_bit = 0;
39 dst->set_carrier_frequency(455000);
40 dst->reserve(N_SYM);
41
42 // start sequence=zero,zero,start
46
47 // the data-bit BeoLink is always 0
49
50 // The B&O trick to avoid extra long and extra short
51 // code-frames by extracting the data-bits from left
52 // to right, then comparing current with previous bit
53 // and set pulse to "same" "one" or "zero"
54 for (jc = 15, ic = 0; ic < 16; ic++, jc--) {
55 cur_bit = ((beo_code) >> jc) & 1;
56 if (cur_bit == pre_bit) {
58 } else if (1 == cur_bit) {
60 } else {
62 }
63 pre_bit = cur_bit;
64 }
65 // complete the frame with stop-symbol and final carrier pulse
67 dst->mark(PW_CARR_US);
68}
69
70optional<Beo4Data> Beo4Protocol::decode(RemoteReceiveData src) {
71 int32_t n_sym = src.size();
72 Beo4Data data{
73 .source = 0,
74 .command = 0,
75 .repeats = 0,
76 };
77 // suppress dummy codes (TSO7000 hiccups)
78 if (n_sym > 42) {
79 static uint32_t beo_code = 0;
80 RxSt fsm = RxSt::RX_IDLE;
81 int32_t ic = 0;
82 int32_t jc = 0;
83 uint32_t pre_bit = 0;
84 uint32_t cnt_bit = 0;
85 ESP_LOGD(TAG, "Beo4: n_sym=%" PRId32, n_sym);
86 for (jc = 0, ic = 0; ic < (n_sym - 1); ic += 2, jc++) {
87 int32_t pulse_width = src[ic] - src[ic + 1];
88 // suppress TSOP7000 (dummy pulses)
89 if (pulse_width > 1500) {
90 int32_t pulse_code = (pulse_width + 1560) / 3125;
91 switch (fsm) {
92 case RxSt::RX_IDLE: {
93 beo_code = 0;
94 cnt_bit = 0;
95 pre_bit = 0;
96 if (PC_START == pulse_code) {
97 fsm = RxSt::RX_DATA;
98 }
99 break;
100 }
101 case RxSt::RX_DATA: {
102 uint32_t cur_bit = 0;
103 switch (pulse_code) {
104 case PC_ZERO: {
105 cur_bit = pre_bit = 0;
106 break;
107 }
108 case PC_SAME: {
109 cur_bit = pre_bit;
110 break;
111 }
112 case PC_ONE: {
113 cur_bit = pre_bit = 1;
114 break;
115 }
116 default: {
117 fsm = RxSt::RX_IDLE;
118 break;
119 }
120 }
121 beo_code = (beo_code << 1) + cur_bit;
122 if (++cnt_bit == N_BITS) {
123 fsm = RxSt::RX_STOP;
124 }
125 break;
126 }
127 case RxSt::RX_STOP: {
128 if (PC_STOP == pulse_code) {
129 data.source = (uint8_t) ((beo_code >> 8) & 0xff);
130 data.command = (uint8_t) ((beo_code) &0xff);
131 data.repeats++;
132 }
133 if ((n_sym - ic) < 42) {
134 return data;
135 } else {
136 fsm = RxSt::RX_IDLE;
137 }
138 break;
139 }
140 }
141 }
142 }
143 }
144 return {}; // decoding failed
145}
146
147void Beo4Protocol::dump(const Beo4Data &data) {
148 ESP_LOGI(TAG, "Beo4: source=0x%02x command=0x%02x repeats=%d ", data.source, data.command, data.repeats);
149}
150
151} // namespace esphome::remote_base
void dump(const Beo4Data &data) override
optional< Beo4Data > decode(RemoteReceiveData src) override
void encode(RemoteTransmitData *dst, const Beo4Data &data) override
void set_carrier_frequency(uint32_t carrier_frequency)
Definition remote_base.h:29
void item(uint32_t mark, uint32_t space)
Definition remote_base.h:24
constexpr uint32_t N_BITS
constexpr uint32_t N_SYM
constexpr uint8_t PC_ONE
constexpr uint16_t PW_ONE_US
constexpr uint16_t PW_CARR_US
constexpr uint8_t PC_START
constexpr uint16_t PW_ZERO_US
constexpr uint8_t PC_STOP
constexpr uint8_t PC_SAME
constexpr uint8_t PC_ZERO
constexpr uint16_t PW_STOP_US
constexpr uint16_t PW_SAME_US
constexpr uint16_t PW_START_US
static void uint32_t