Improvements to RF receiver for Drayton Digistat heating controller (#5504)

This commit is contained in:
marshn 2023-12-21 07:17:01 +00:00 committed by GitHub
parent d73ad39aed
commit 222bb9b495
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -13,7 +13,8 @@ static const uint8_t NBITS_SYNC = 4;
static const uint8_t NBITS_ADDRESS = 16; static const uint8_t NBITS_ADDRESS = 16;
static const uint8_t NBITS_CHANNEL = 5; static const uint8_t NBITS_CHANNEL = 5;
static const uint8_t NBITS_COMMAND = 7; static const uint8_t NBITS_COMMAND = 7;
static const uint8_t NBITS = NBITS_ADDRESS + NBITS_CHANNEL + NBITS_COMMAND; static const uint8_t NDATABITS = NBITS_ADDRESS + NBITS_CHANNEL + NBITS_COMMAND;
static const uint8_t MIN_RX_SRC = (NDATABITS * 2 + NBITS_SYNC / 2);
static const uint8_t CMD_ON = 0x41; static const uint8_t CMD_ON = 0x41;
static const uint8_t CMD_OFF = 0x02; static const uint8_t CMD_OFF = 0x02;
@ -116,7 +117,7 @@ void DraytonProtocol::encode(RemoteTransmitData *dst, const DraytonData &data) {
ESP_LOGV(TAG, "Send Drayton: out_data %08" PRIx32, out_data); ESP_LOGV(TAG, "Send Drayton: out_data %08" PRIx32, out_data);
for (uint32_t mask = 1UL << (NBITS - 1); mask != 0; mask >>= 1) { for (uint32_t mask = 1UL << (NDATABITS - 1); mask != 0; mask >>= 1) {
if (out_data & mask) { if (out_data & mask) {
dst->mark(BIT_TIME_US); dst->mark(BIT_TIME_US);
dst->space(BIT_TIME_US); dst->space(BIT_TIME_US);
@ -134,79 +135,96 @@ optional<DraytonData> DraytonProtocol::decode(RemoteReceiveData src) {
.command = 0, .command = 0,
}; };
if (src.size() < 45) { while (src.size() - src.get_index() > MIN_RX_SRC) {
return {}; ESP_LOGVV(TAG,
} "Decode Drayton: %" PRId32 ", %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32
" %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32
" %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 "",
src.size() - src.get_index(), src.peek(0), src.peek(1), src.peek(2), src.peek(3), src.peek(4),
src.peek(5), src.peek(6), src.peek(7), src.peek(8), src.peek(9), src.peek(10), src.peek(11), src.peek(12),
src.peek(13), src.peek(14), src.peek(15), src.peek(16), src.peek(17), src.peek(18), src.peek(19));
ESP_LOGVV(TAG, // If first preamble item is a space, skip it
"Decode Drayton: %" PRId32 ", %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 if (src.peek_space_at_least(1)) {
" %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 src.advance(1);
" %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 " %" PRId32 "", }
src.size(), src.peek(0), src.peek(1), src.peek(2), src.peek(3), src.peek(4), src.peek(5), src.peek(6),
src.peek(7), src.peek(8), src.peek(9), src.peek(10), src.peek(11), src.peek(12), src.peek(13), src.peek(14),
src.peek(15), src.peek(16), src.peek(17), src.peek(18), src.peek(19));
// If first preamble item is a space, skip it // Look for sync pulse, after. If sucessful index points to space of sync symbol
if (src.peek_space_at_least(1)) { while (src.size() - src.get_index() >= NDATABITS) {
src.advance(1); ESP_LOGVV(TAG, "Decode Drayton: sync search %d, %" PRId32 " %" PRId32, src.size() - src.get_index(), src.peek(),
} src.peek(1));
if (src.peek_mark(2 * BIT_TIME_US) &&
(src.peek_space(2 * BIT_TIME_US, 1) || src.peek_space(3 * BIT_TIME_US, 1))) {
src.advance(1);
ESP_LOGVV(TAG, "Decode Drayton: Found SYNC, - %d", src.get_index());
break;
} else {
src.advance(2);
}
}
// Look for sync pulse, after. If sucessful index points to space of sync symbol // No point continuing if not enough samples remaining to complete a packet
for (uint16_t preamble = 0; preamble <= NBITS_PREAMBLE * 2; preamble += 2) { if (src.size() - src.get_index() < NDATABITS) {
ESP_LOGVV(TAG, "Decode Drayton: preamble %d %" PRId32 " %" PRId32, preamble, src.peek(preamble), ESP_LOGV(TAG, "Decode Drayton: Fail 1, - %" PRIu32, src.get_index());
src.peek(preamble + 1));
if (src.peek_mark(2 * BIT_TIME_US, preamble) &&
(src.peek_space(2 * BIT_TIME_US, preamble + 1) || src.peek_space(3 * BIT_TIME_US, preamble + 1))) {
src.advance(preamble + 1);
break; break;
} }
}
// Read data. Index points to space of sync symbol // Read data. Index points to space of sync symbol
// Extract first bit // Extract first bit
// Checks next bit to leave index pointing correctly // Checks next bit to leave index pointing correctly
uint32_t out_data = 0; uint32_t out_data = 0;
uint8_t bit = NBITS_ADDRESS + NBITS_COMMAND + NBITS_CHANNEL - 1; uint8_t bit = NDATABITS - 1;
if (src.expect_space(3 * BIT_TIME_US) && (src.expect_mark(BIT_TIME_US) || src.peek_mark(2 * BIT_TIME_US))) { ESP_LOGVV(TAG, "Decode Drayton: first bit %d %" PRId32 ", %" PRId32, src.peek(0), src.peek(1), src.peek(2));
out_data |= 0 << bit; if (src.expect_space(3 * BIT_TIME_US) && (src.expect_mark(BIT_TIME_US) || src.peek_mark(2 * BIT_TIME_US))) {
} else if (src.expect_space(2 * BIT_TIME_US) && src.expect_mark(BIT_TIME_US) &&
(src.expect_space(BIT_TIME_US) || src.peek_space(2 * BIT_TIME_US))) {
out_data |= 1 << bit;
} else {
ESP_LOGV(TAG, "Decode Drayton: Fail 1, - %" PRIu32, src.get_index());
return {};
}
// Before/after each bit is read the index points to the transition at the start of the bit period or,
// if there is no transition at the start of the bit period, then the transition in the middle of
// the previous bit period.
while (--bit >= 1) {
ESP_LOGVV(TAG, "Decode Drayton: Data, %2d %08" PRIx32, bit, out_data);
if ((src.expect_space(BIT_TIME_US) || src.expect_space(2 * BIT_TIME_US)) &&
(src.expect_mark(BIT_TIME_US) || src.peek_mark(2 * BIT_TIME_US))) {
out_data |= 0 << bit; out_data |= 0 << bit;
} else if ((src.expect_mark(BIT_TIME_US) || src.expect_mark(2 * BIT_TIME_US)) && } else if (src.expect_space(2 * BIT_TIME_US) && src.expect_mark(BIT_TIME_US) &&
(src.expect_space(BIT_TIME_US) || src.peek_space(2 * BIT_TIME_US))) { (src.expect_space(BIT_TIME_US) || src.peek_space(2 * BIT_TIME_US))) {
out_data |= 1 << bit; out_data |= 1 << bit;
} else { } else {
ESP_LOGVV(TAG, "Decode Drayton: Fail 2, %2d %08" PRIx32, bit, out_data); ESP_LOGV(TAG, "Decode Drayton: Fail 2, - %d %d %d", src.peek(-1), src.peek(0), src.peek(1));
return {}; continue;
} }
}
if (src.expect_space(BIT_TIME_US) || src.expect_space(2 * BIT_TIME_US)) {
out_data |= 0;
} else if (src.expect_mark(BIT_TIME_US) || src.expect_mark(2 * BIT_TIME_US)) {
out_data |= 1;
}
ESP_LOGV(TAG, "Decode Drayton: Data, %2d %08" PRIx32, bit, out_data);
out.channel = (uint8_t) (out_data & 0x1F); // Before/after each bit is read the index points to the transition at the start of the bit period or,
out_data >>= NBITS_CHANNEL; // if there is no transition at the start of the bit period, then the transition in the middle of
out.command = (uint8_t) (out_data & 0x7F); // the previous bit period.
out_data >>= NBITS_COMMAND; while (--bit >= 1) {
out.address = (uint16_t) (out_data & 0xFFFF); ESP_LOGVV(TAG, "Decode Drayton: Data, %2d %08" PRIx32, bit, out_data);
if ((src.expect_space(BIT_TIME_US) || src.expect_space(2 * BIT_TIME_US)) &&
(src.expect_mark(BIT_TIME_US) || src.peek_mark(2 * BIT_TIME_US))) {
out_data |= 0 << bit;
} else if ((src.expect_mark(BIT_TIME_US) || src.expect_mark(2 * BIT_TIME_US)) &&
(src.expect_space(BIT_TIME_US) || src.peek_space(2 * BIT_TIME_US))) {
out_data |= 1 << bit;
} else {
break;
}
}
return out; if (bit > 0) {
ESP_LOGVV(TAG, "Decode Drayton: Fail 3, %d %" PRId32 " %" PRId32, src.peek(-1), src.peek(0), src.peek(1));
continue;
}
if (src.expect_space(BIT_TIME_US) || src.expect_space(2 * BIT_TIME_US)) {
out_data |= 0;
} else if (src.expect_mark(BIT_TIME_US) || src.expect_mark(2 * BIT_TIME_US)) {
out_data |= 1;
} else {
continue;
}
ESP_LOGV(TAG, "Decode Drayton: Data, %2d %08x", bit, out_data);
out.channel = (uint8_t) (out_data & 0x1F);
out_data >>= NBITS_CHANNEL;
out.command = (uint8_t) (out_data & 0x7F);
out_data >>= NBITS_COMMAND;
out.address = (uint16_t) (out_data & 0xFFFF);
return out;
}
return {};
} }
void DraytonProtocol::dump(const DraytonData &data) { void DraytonProtocol::dump(const DraytonData &data) {
ESP_LOGI(TAG, "Received Drayton: address=0x%04X (0x%04x), channel=0x%03x command=0x%03X", data.address, ESP_LOGI(TAG, "Received Drayton: address=0x%04X (0x%04x), channel=0x%03x command=0x%03X", data.address,