diff --git a/include/util.h b/include/util.h index a0e3b5415..857bf5f63 100644 --- a/include/util.h +++ b/include/util.h @@ -52,8 +52,18 @@ void reflect_nibbles(uint8_t message[], unsigned num_bytes); /// @param offset_bits start offset of message in bits /// @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); +/// UART "8n1" (10-to-8) decoder with 1 start bit (0), no parity, 1 stop bit (1), LSB-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/10 size +/// @return number of successful decoded bytes +unsigned extract_bytes_uart(uint8_t *message, unsigned offset_bits, unsigned num_bits, uint8_t *dst); + /// CRC-4. /// /// @param message array of bytes to check diff --git a/src/devices/flex.c b/src/devices/flex.c index 077699c4f..06f9f9474 100644 --- a/src/devices/flex.c +++ b/src/devices/flex.c @@ -91,6 +91,7 @@ struct flex_params { unsigned preamble_len; bitrow_t preamble_bits; struct flex_get getter[GETTER_SLOTS]; + unsigned decode_uart; }; static void print_row_bytes(char *row_bytes, uint8_t *bits, int num_bits) @@ -213,6 +214,14 @@ static int flex_callback(r_device *decoder, bitbuffer_t *bitbuffer) return DECODE_FAIL_SANITY; } + if (params->decode_uart) { + for (i = 0; i < bitbuffer->num_rows; i++) { + int len = extract_bytes_uart(bitbuffer->bb[i], 0, bitbuffer->bits_per_row[i], tmp); + memcpy(bitbuffer->bb[i], tmp, len); + bitbuffer->bits_per_row[i] = len * 8; + } + } + if (decoder->verbose) { fprintf(stderr, "%s: ", params->name); bitbuffer_print(bitbuffer); @@ -658,6 +667,9 @@ r_device *flex_create_device(char *spec) else if (!strcasecmp(key, "unique")) params->unique = val ? atoi(val) : 1; + else if (!strcasecmp(key, "decode_uart")) + params->decode_uart = val ? atoi(val) : 1; + else if (!strcasecmp(key, "get")) { if (get_count < GETTER_SLOTS) parse_getter(val, ¶ms->getter[get_count++]); diff --git a/src/util.c b/src/util.c index 33a9015aa..4ea3facb8 100644 --- a/src/util.c +++ b/src/util.c @@ -61,6 +61,33 @@ 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 ret = 0; + + while (num_bits >= 10) { + 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 stopb = message[offset_bits / 8] >> (7 - (offset_bits % 8)); + offset_bits += 1; + if ((startb & 1) != 0) + break; // start-bit error + if ((stopb & 1) != 1) + break; // stop-bit error + *dst++ = reverse8(datab & 0xff); + ret += 1; + num_bits -= 10; + } + + return ret; +} + uint8_t crc4(uint8_t const message[], unsigned nBytes, uint8_t polynomial, uint8_t init) { unsigned remainder = init << 4; // LSBs are unused @@ -316,14 +343,51 @@ int add_nibbles(uint8_t const message[], unsigned num_bytes) // Unit testing #ifdef _TEST +#define ASSERT_EQUALS(a, b) \ + do { \ + if ((a) == (b)) \ + ++passed; \ + else { \ + ++failed; \ + fprintf(stderr, "FAIL: %d <> %d\n", (a), (b)); \ + } \ + } while (0) + int main(int argc, char **argv) { + unsigned passed = 0; + unsigned failed = 0; + fprintf(stderr, "util:: test\n"); uint8_t msg[] = {0x08, 0x0a, 0xe8, 0x80}; - fprintf(stderr, "util::crc8(): odd parity: %02X\n", crc8(msg, 3, 0x80, 0x00)); - fprintf(stderr, "util::crc8(): even parity: %02X\n", crc8(msg, 4, 0x80, 0x00)); + fprintf(stderr, "util::crc8(): odd parity\n"); + ASSERT_EQUALS(crc8(msg, 3, 0x80, 0x00), 0x80); + + fprintf(stderr, "util::crc8(): even parity\n"); + ASSERT_EQUALS(crc8(msg, 4, 0x80, 0x00), 0x00); + + // sync-word 0b0 0xff 0b1 0b0 0x33 0b1 (i.e. 0x7fd99, note that 0x33 is 0xcc "on the wire") + uint8_t uart[] = {0x7f, 0xd9, 0x90}; + uint8_t bytes[6] = {0}; + + // y0 xff y1 y0 xcc y1 y0 x80 y1 y0 x40 y1 y0 xc0 y1 + uint8_t uart123[] = {0x07, 0xfd, 0x99, 0x40, 0x48, 0x16, 0x04, 0x00}; + + fprintf(stderr, "util::extract_bytes_uart():\n"); + ASSERT_EQUALS(extract_bytes_uart(uart, 0, 24, bytes), 2); + ASSERT_EQUALS(bytes[0], 0xff); + ASSERT_EQUALS(bytes[1], 0x33); + + ASSERT_EQUALS(extract_bytes_uart(uart123, 4, 60, bytes), 5); + ASSERT_EQUALS(bytes[0], 0xff); + ASSERT_EQUALS(bytes[1], 0x33); + ASSERT_EQUALS(bytes[2], 0x01); + ASSERT_EQUALS(bytes[3], 0x02); + ASSERT_EQUALS(bytes[4], 0x03); + + fprintf(stderr, "util:: test (%u/%u) passed, (%u) failed.\n", passed, passed + failed, failed); - return 0; + return failed; } #endif /* _TEST */