From 4736276bd456f02668abd7013a5b60ed7cc90f86 Mon Sep 17 00:00:00 2001 From: "Christian W. Zuckschwerdt" Date: Wed, 16 Oct 2024 03:40:41 +0200 Subject: [PATCH] Add extract_bytes_uart_parity utility function --- include/bit_util.h | 15 +++++++-- src/bit_util.c | 42 +++++++++++++++++++++++--- src/devices/rosstech_dcu706.c | 57 ++++++++++++----------------------- 3 files changed, 68 insertions(+), 46 deletions(-) diff --git a/include/bit_util.h b/include/bit_util.h index c1924d115..550967c14 100644 --- a/include/bit_util.h +++ b/include/bit_util.h @@ -52,7 +52,7 @@ void reflect_nibbles(uint8_t message[], unsigned num_bytes); /// @param num_bits message length in bits /// @param dst target buffer for extracted nibbles, at least num_bits/5 size /// @return number of successfully unstuffed nibbles. -unsigned extract_nibbles_4b1s(uint8_t *message, unsigned offset_bits, unsigned num_bits, uint8_t *dst); +unsigned extract_nibbles_4b1s(uint8_t const *message, unsigned offset_bits, unsigned num_bits, uint8_t *dst); /// UART "8n1" (10-to-8) decoder with 1 start bit (0), no parity, 1 stop bit (1), LSB-first bit-order. /// @@ -61,7 +61,16 @@ unsigned extract_nibbles_4b1s(uint8_t *message, unsigned offset_bits, unsigned n /// @param num_bits message length in bits /// @param dst target buffer for extracted bytes, at least num_bits/10 size /// @return number of successful decoded bytes -unsigned extract_bytes_uart(uint8_t *message, unsigned offset_bits, unsigned num_bits, uint8_t *dst); +unsigned extract_bytes_uart(uint8_t const *message, unsigned offset_bits, unsigned num_bits, uint8_t *dst); + +/// UART "8o1" (11-to-8) decoder with 1 start bit (1), odd parity, 1 stop bit (0), MSB-first bit-order. +/// +/// @param message bytes of message data +/// @param offset_bits start offset of message in bits +/// @param num_bits message length in bits +/// @param dst target buffer for extracted bytes, at least num_bits/11 size +/// @return number of successful decoded bytes +unsigned extract_bytes_uart_parity(uint8_t const *message, unsigned offset_bits, unsigned num_bits, uint8_t *dst); /// Decode symbols to bits. /// @@ -73,7 +82,7 @@ unsigned extract_bytes_uart(uint8_t *message, unsigned offset_bits, unsigned num /// @param sync symbol for sync bit, ignored at start, terminates at end /// @param dst target buffer for extracted bits, at least num_bits/symbol_x_len size /// @return number of successful decoded bits -unsigned extract_bits_symbols(uint8_t *message, unsigned offset_bits, unsigned num_bits, uint32_t zero, uint32_t one, uint32_t sync, uint8_t *dst); +unsigned extract_bits_symbols(uint8_t const *message, unsigned offset_bits, unsigned num_bits, uint32_t zero, uint32_t one, uint32_t sync, uint8_t *dst); /// CRC-4. /// diff --git a/src/bit_util.c b/src/bit_util.c index 5200fe558..fad3b4af3 100644 --- a/src/bit_util.c +++ b/src/bit_util.c @@ -26,7 +26,7 @@ uint8_t reverse8(uint8_t x) uint32_t reverse32(uint32_t x) { uint32_t ret; - uint8_t* xp = (uint8_t*)&x; + uint8_t const* xp = (uint8_t*)&x; ret = (uint32_t) reverse8(xp[0]) << 24 | reverse8(xp[1]) << 16 | reverse8(xp[2]) << 8 | reverse8(xp[3]); return ret; } @@ -52,7 +52,7 @@ void reflect_nibbles(uint8_t message[], unsigned num_bytes) } } -unsigned extract_nibbles_4b1s(uint8_t *message, unsigned offset_bits, unsigned num_bits, uint8_t *dst) +unsigned extract_nibbles_4b1s(uint8_t const *message, unsigned offset_bits, unsigned num_bits, uint8_t *dst) { unsigned ret = 0; @@ -70,7 +70,7 @@ unsigned extract_nibbles_4b1s(uint8_t *message, unsigned offset_bits, unsigned n return ret; } -unsigned extract_bytes_uart(uint8_t *message, unsigned offset_bits, unsigned num_bits, uint8_t *dst) +unsigned extract_bytes_uart(uint8_t const *message, unsigned offset_bits, unsigned num_bits, uint8_t *dst) { unsigned ret = 0; @@ -97,7 +97,39 @@ unsigned extract_bytes_uart(uint8_t *message, unsigned offset_bits, unsigned num return ret; } -static unsigned symbol_match(uint8_t *message, unsigned offset_bits, unsigned num_bits, uint32_t symbol) +unsigned extract_bytes_uart_parity(uint8_t const *message, unsigned offset_bits, unsigned num_bits, uint8_t *dst) +{ + unsigned ret = 0; + + while (num_bits >= 11) { + int startb = message[offset_bits / 8] >> (7 - (offset_bits % 8)); + offset_bits += 1; + int datab = message[offset_bits / 8]; + if (offset_bits % 8) { + datab = (message[offset_bits / 8] << 8) | message[offset_bits / 8 + 1]; + datab >>= 8 - (offset_bits % 8); + } + offset_bits += 8; + int parityb = message[offset_bits / 8] >> (7 - (offset_bits % 8)); + offset_bits += 1; + int stopb = message[offset_bits / 8] >> (7 - (offset_bits % 8)); + offset_bits += 1; + int data_parity = parity8(datab); + if ((startb & 1) != 1) + break; // start-bit error + if ((parityb & 1) != data_parity) + break; // parity-bit error + if ((stopb & 1) != 0) + break; // stop-bit error + *dst++ = (datab & 0xff); + ret += 1; + num_bits -= 11; + } + + return ret; +} + +static unsigned symbol_match(uint8_t const *message, unsigned offset_bits, unsigned num_bits, uint32_t symbol) { unsigned symbol_len = symbol & 0x1f; @@ -119,7 +151,7 @@ static unsigned symbol_match(uint8_t *message, unsigned offset_bits, unsigned nu return symbol_len; } -unsigned extract_bits_symbols(uint8_t *message, unsigned offset_bits, unsigned num_bits, uint32_t zero, uint32_t one, uint32_t sync, uint8_t *dst) +unsigned extract_bits_symbols(uint8_t const *message, unsigned offset_bits, unsigned num_bits, uint32_t zero, uint32_t one, uint32_t sync, uint8_t *dst) { unsigned zero_len = zero & 0x1f; unsigned one_len = one & 0x1f; diff --git a/src/devices/rosstech_dcu706.c b/src/devices/rosstech_dcu706.c index 0ff306870..29261c6f1 100644 --- a/src/devices/rosstech_dcu706.c +++ b/src/devices/rosstech_dcu706.c @@ -18,6 +18,10 @@ Supported Models: Sundance DCU-6560-131, SD-880 Series, PN 6560-131 Jacuzzi DCU-2560-131, Jac-J300/J400 and SD-780 series, PN 6560-132/2560-131 +Data coding: + +UART 8o1: 11 bits/byte: 1 start bit (1), odd parity, 1 stop bit (0). + Data layout: SS IIII TT CC @@ -28,29 +32,8 @@ Data layout: - C: 8 bit Checksum: Count 1s for each bit of each element: Set bit to 1 if number is even 0 if odd -11 bits/byte: 1 start bit, 0 stop bits and odd parity - */ -static uint8_t calculateChecksum(const uint8_t *data, size_t size) -{ - uint8_t checksum = 0; - - for (int bit = 0; bit < 8; bit++) { - int count = 0; - - for (size_t i = 0; i < size; i++) { - count += (data[i] >> bit) & 1; - } - - if (count % 2 == 0) { - checksum |= (1 << bit); - } - } - - return checksum; -} - static int rosstech_dcu706_decode(r_device *decoder, bitbuffer_t *bitbuffer) { uint8_t const preamble_data_transmission[] = {0xDD, 0x40}; @@ -85,23 +68,21 @@ static int rosstech_dcu706_decode(r_device *decoder, bitbuffer_t *bitbuffer) bitbuffer_extract_bytes(bitbuffer, 0, start_pos, msg, sizeof(msg) * 8); - uint8_t msg_type = (msg[0] << 1) | (msg[1] >> 7); // S - uint8_t id_high = (msg[1] << 4) | (msg[2] >> 4); - uint8_t id_low = (msg[2] << 7) | (msg[3] >> 1); - uint16_t id = (id_high << 8) | id_low; // I - uint8_t temp_f = (msg[4] << 2) | (msg[5] >> 6); // T - uint8_t checksum = (msg[5] << 5) | (msg[6] >> 3); // C - - // Create a uint8_t array to hold the extracted values - uint8_t extracted_data[4]; - extracted_data[0] = msg_type; - extracted_data[1] = id_high; - extracted_data[2] = id_low; - extracted_data[3] = temp_f; - - uint8_t calculated_checksum = calculateChecksum(extracted_data, sizeof(extracted_data) / sizeof(extracted_data[0])); - if (calculated_checksum != checksum) { - decoder_logf(decoder, 2, __func__, "Checksum failed. Expected: %02x, Calculated: %02x.", checksum, calculated_checksum); + uint8_t b[5] = {0}; + unsigned r = extract_bytes_uart_parity(msg, 0, 55, b); + if (r != 5) { + decoder_logf(decoder, 2, __func__, "UART decoding failed. Got %d of 5 bytes", r); + return DECODE_ABORT_LENGTH; + } + + int msg_type = b[0]; // S + int id = (b[1] << 8) | (b[2]); // I + int temp_f = b[3]; // T + int checksum = b[4]; // C + + uint8_t calculated = 0xff ^ xor_bytes(b, 4); + if (calculated != checksum) { + decoder_logf(decoder, 2, __func__, "Checksum failed. Expected: %02x, Calculated: %02x", checksum, calculated); return DECODE_FAIL_MIC; }