ESPHome  2024.6.1
byronsx_protocol.cpp
Go to the documentation of this file.
1 #include "byronsx_protocol.h"
2 #include "esphome/core/log.h"
3 
4 #include <cinttypes>
5 
6 namespace esphome {
7 namespace remote_base {
8 
9 static const char *const TAG = "remote.byronsx";
10 
11 static const uint32_t BIT_TIME_US = 333;
12 static const uint8_t NBITS_ADDRESS = 8;
13 static const uint8_t NBITS_COMMAND = 4;
14 static const uint8_t NBITS_START_BIT = 1;
15 static const uint8_t NBITS_DATA = NBITS_ADDRESS + NBITS_COMMAND /*+ NBITS_COMMAND*/;
16 
17 /*
18 ByronSX Protocol
19 Each transmitted packet appears to consist of thirteen bits of PWM encoded
20 data. Each bit period of aprox 1ms consists of a transmitter OFF period
21 followed by a transmitter ON period. The 'on' and 'off' periods are either
22 short (approx 332us) or long (664us).
23 
24 A short 'off' followed by a long 'on' represents a '1' bit.
25 A long 'off' followed by a short 'on' represents a '0' bit.
26 
27 A the beginning of each packet is and initial 'off' period of approx 5.6ms
28 followed by a short 'on'.
29 
30 The data payload consists of twelve bits which appear to be an eight bit
31 address floowied by a 4 bit chime number.
32 
33 SAAAAAAAACCCC
34 
35 Whese:
36 S = the initial short start pulse
37 A = The eight address bits
38 C - The four chime bits
39 
40 --------------------
41 
42 I have also used 'RFLink' software (RLink Firmware Version: 1.1 Revision: 48)
43 to capture these packets, eg:
44 
45 20;19;Byron;ID=004f;SWITCH=02;CMD=ON;CHIME=02;
46 
47 This module transmits and interprets packets in the same way as RFLink.
48 
49 marshn
50 
51 */
52 
54  uint32_t out_data = 0x0;
55 
56  ESP_LOGD(TAG, "Send ByronSX: address=%04x command=%03x", data.address, data.command);
57 
58  out_data = data.address;
59  out_data <<= NBITS_COMMAND;
60  out_data |= data.command;
61 
62  ESP_LOGV(TAG, "Send ByronSX: out_data %03" PRIx32, out_data);
63 
64  // Initial Mark start bit
65  dst->mark(1 * BIT_TIME_US);
66 
67  for (uint32_t mask = 1UL << (NBITS_DATA - 1); mask != 0; mask >>= 1) {
68  if (out_data & mask) {
69  dst->space(2 * BIT_TIME_US);
70  dst->mark(1 * BIT_TIME_US);
71  } else {
72  dst->space(1 * BIT_TIME_US);
73  dst->mark(2 * BIT_TIME_US);
74  }
75  }
76  // final space at end of packet
77  dst->space(17 * BIT_TIME_US);
78 }
79 
81  ByronSXData out{
82  .address = 0,
83  .command = 0,
84  };
85 
86  if (src.size() != (NBITS_DATA + NBITS_START_BIT) * 2) {
87  return {};
88  }
89 
90  // Skip start bit
91  if (!src.expect_mark(BIT_TIME_US)) {
92  return {};
93  }
94 
95  ESP_LOGVV(TAG,
96  "%3" PRId32 ": %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32
97  " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32
98  " %" PRId32 " %" PRId32 " %" PRId32,
99  src.size(), src.peek(0), src.peek(1), src.peek(2), src.peek(3), src.peek(4), src.peek(5), src.peek(6),
100  src.peek(7), src.peek(8), src.peek(9), src.peek(10), src.peek(11), src.peek(12), src.peek(13), src.peek(14),
101  src.peek(15), src.peek(16), src.peek(17), src.peek(18), src.peek(19));
102 
103  ESP_LOGVV(TAG, " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32, src.peek(20),
104  src.peek(21), src.peek(22), src.peek(23), src.peek(24), src.peek(25));
105 
106  // Read data bits
107  uint32_t out_data = 0;
108  int8_t bit = NBITS_DATA;
109  while (--bit >= 0) {
110  if (src.expect_space(2 * BIT_TIME_US) && src.expect_mark(BIT_TIME_US)) {
111  out_data |= 1 << bit;
112  } else if (src.expect_space(BIT_TIME_US) && src.expect_mark(2 * BIT_TIME_US)) {
113  out_data |= 0 << bit;
114  } else {
115  ESP_LOGV(TAG, "Decode ByronSX: Fail 2, %2d %08" PRIx32, bit, out_data);
116  return {};
117  }
118  ESP_LOGVV(TAG, "Decode ByronSX: Data, %2d %08" PRIx32, bit, out_data);
119  }
120 
121  // last bit followed by a long space
122  if (!src.peek_space_at_least(BIT_TIME_US)) {
123  ESP_LOGV(TAG, "Decode ByronSX: Fail 4 ");
124  return {};
125  }
126 
127  out.command = (uint8_t) (out_data & 0xF);
128  out_data >>= NBITS_COMMAND;
129  out.address = (uint16_t) (out_data & 0xFF);
130 
131  return out;
132 }
133 
135  ESP_LOGD(TAG, "Received ByronSX: address=0x%08X, command=0x%02x", data.address, data.command);
136 }
137 
138 } // namespace remote_base
139 } // namespace esphome
void dump(const ByronSXData &data) override
optional< ByronSXData > decode(RemoteReceiveData src) override
int32_t peek(uint32_t offset=0) const
Definition: remote_base.h:58
void encode(RemoteTransmitData *dst, const ByronSXData &data) override
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
bool peek_space_at_least(uint32_t length, uint32_t offset=0) const
Definition: remote_base.cpp:52