diff --git a/README.md b/README.md index 2ce1e2a..fd9f10c 100644 --- a/README.md +++ b/README.md @@ -55,19 +55,41 @@ Before building Android version the SDK and NDK have to be installed. See androi Carrier-frequency given at "-f" must be set properly. With my DVB-T-Receiver I had to choose carrier 50kHz under the standard of 868.95MHz. Sample rate at 1.6Ms/s is hardcoded and cannot be changed. -samples2.bin is a "live" example with two devices received. +samples/samples2.bin is a live example with two devices received. On Android first the driver must be started with options given above. IQ-data goes to a port which is would be already set by driver settings. Use get_net to get IQ-data into rtl_wmbus. Bugfixing ----- -Mode C1 datagram type B is supported now - thanks to Fredrik Öhrström for spotting this bug and for providing raw datagram samples. -An another thanks to Kjell Braden (afflux) and to carlos62 for the idea how to fix this. - +Mode C1 datagram type B is supported now - thanks to Fredrik Öhrström for spotting this and for providing raw datagram samples. +An another thanks goes to Kjell Braden (afflux) and to carlos62 for the idea how to implement this. + +Redefining CFLAGS and OUTPUT directory is allowed now (patch sent by dwrobel). + +L(ength) field from C1 mode B datagrams does not include CRC bytes anymore: L field will now be printed as if the datagram +would be received from a T1 or C1 mode A meter. + + Improvements + ----- +A new method for picking datagrams out of the bit stream that _could_ probably better perform in C1 mode has been implemented. +I called that "run length algorithm". I don't know if any similar term already exists in the literature. +The new method is very sensitive to the bit glitches, which have to be filtered out of the bit stream with an asymmetrical glitch filter. +The glitch filter _must_ be implemented asymmetrical in this case, because RTL-SDR produces more "0" bits than "1" bits on it's output. +The latter seems more to be a hardware feature rather than a bug. + +Run length algorithm is running in parallel (and fully independantly) to the time2 method. You will eventually get two +identical datagrams - each of them decoded by one of the both methods. If you really want avoiding duplicates, then start +rtl_wmbus with "-r 0" or "-t 0" argument to prevent executing of run length or time2 method respectively. +You can play with arguments and check which method performs better for you. Please note, that both method are active by default. + +An additional method introduces more calculation steps, so I'm not sure if Raspberry Pi 1 will still do. + +Run length algorithm works well with a few mode C1 devices I had around me, but can still be improved with your help. + License ------- -Copyright (c) 2017 +Copyright (c) 2021 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/rtl_wmbus.c b/rtl_wmbus.c index e4e409e..01848b8 100644 --- a/rtl_wmbus.c +++ b/rtl_wmbus.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017 + * Copyright (c) 2021 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,6 +23,7 @@ * SUCH DAMAGE. */ +#include #include #include #include @@ -38,11 +39,49 @@ #include "net_support.h" #include "t1_c1_packet_decoder.h" +static const uint32_t ACCESS_CODE = 0b0101010101010000111101u; +static const uint32_t ACCESS_CODE_BITMASK = 0x3FFFFFu; +static const unsigned ACCESS_CODE_ERRORS = 1u; // 0 if no errors allowed -#if defined(__SSE4_2__) -#include -#endif +/* deglitch_filter has been calculated by Python script as follows. + The filter is counting "1" among 7 bits and saying "1" if count("1") >= 3 else "0". + Notice here count("1") >= 3. (More intuitive in that case would be count("1") >= 3.5.) + That forces the filter to put more "1" than "0" on the output, because RTL-SDR streams + more "0" than "1" - i don't know why RTL-SDR do this. +x = 'static const uint8_t deglitch_filter[128] = {' +mod8 = 8 +for i in range(2**7): + s = '{0:07b};'.format(i) + val = '1' if bin(i).count("1") >= 3 else '0' + print(s[0] + ";" + s[1] + ";" + s[2] + ";" + s[3] + ";" + s[4] + ";" + s[5] + ";" + s[6] + ";;%d;;%s" % (bin(i).count("1"), val)) + + if i % 8 == 0: x += '\n\t' + x += val + ',' + +x += '};\n' + +print(x) +*/ +static const uint8_t deglitch_filter[128] = +{ + 0,0,0,0,0,0,0,1, + 0,0,0,1,0,1,1,1, + 0,0,0,1,0,1,1,1, + 0,1,1,1,1,1,1,1, + 0,0,0,1,0,1,1,1, + 0,1,1,1,1,1,1,1, + 0,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, + 0,0,0,1,0,1,1,1, + 0,1,1,1,1,1,1,1, + 0,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, + 0,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1 +}; static float lp_1600kHz_56kHz(int sample, size_t i_or_q) { @@ -284,46 +323,177 @@ static inline unsigned count_set_bits(uint32_t n) } -static inline int majority_votes_bitfilter(uint32_t unfilt_bitstream, uint32_t bits_in_unfilt_bitstream) +struct runlength_algorithm { - const unsigned ones = count_set_bits(unfilt_bitstream & bits_in_unfilt_bitstream); - const bool odd = (ones & 1) > 0; - const uint32_t bits_in_unfilt_bitstream_half = count_set_bits(bits_in_unfilt_bitstream)/2; + int run_length; + int bit_length; + int cum_run_length_error; + unsigned state; + uint32_t raw_bitstream; + uint32_t bitstream; + struct t1_c1_packet_decoder_work decoder; +}; - if (odd) - return (ones <= bits_in_unfilt_bitstream_half) ? 0 : 1; - - if (ones < bits_in_unfilt_bitstream_half) - return 0; - - if (ones > bits_in_unfilt_bitstream_half) - return 1; - - return unfilt_bitstream & 1; +static void runlength_algorithm_reset(struct runlength_algorithm *algo) +{ + algo->run_length = 0; + algo->bit_length = 8 * 256; + algo->cum_run_length_error = 0; + algo->state = 0u; + algo->raw_bitstream = 0; + algo->bitstream = 0; + reset_t1_c1_packet_decoder(&algo->decoder); } - -typedef void (*OutFunction)(unsigned bit, unsigned rssi); - - -static inline void to_stdout(unsigned bit, unsigned rssi) +static void runlength_algorithm(unsigned raw_bit, unsigned rssi, struct runlength_algorithm *algo) { - (void)rssi; + algo->raw_bitstream = (algo->raw_bitstream << 1) | raw_bit; - const uint8_t tmp = bit; + const unsigned state = deglitch_filter[algo->raw_bitstream & 0x3Fu]; - fwrite(&tmp, sizeof(tmp), 1, stdout); + if (algo->state == state) + { + algo->run_length++; + } + else + { + if (algo->run_length < 5) + { + runlength_algorithm_reset(algo); + algo->state = state; + algo->run_length = 1; + return; + } + + const int unscaled_run_length = algo->run_length; + + algo->run_length *= 256; // resolution scaling up for fixed point calculation + + const int half_bit_length = algo->bit_length / 2; + + if (algo->run_length <= half_bit_length) + { + runlength_algorithm_reset(algo); + algo->state = state; + algo->run_length = 1; + return; + } + + int num_of_bits_rx; + for (num_of_bits_rx = 0; algo->run_length > half_bit_length; num_of_bits_rx++) + { + algo->run_length -= algo->bit_length; + + unsigned bit = algo->state; + + algo->bitstream = (algo->bitstream << 1) | bit; + + if (count_set_bits((algo->bitstream & ACCESS_CODE_BITMASK) ^ ACCESS_CODE) <= ACCESS_CODE_ERRORS) + { + bit |= (1u<decoder, "rla;"); + } + + #if 0 + const int bit_error_length = algo->run_length / num_of_bits_rx; + if (in_rx_t1_c1_packet_decoder(&algo->decoder)) + { + fprintf(stdout, "rl = %d, num_of_bits_rx = %d, bit_length = %d, old_bit_error_length = %d, new_bit_error_length = %d\n", + unscaled_run_length, num_of_bits_rx, algo->bit_length, algo->bit_error_length, bit_error_length); + } + #endif + + // Some kind of PI controller is implemented below: u[n] = u[n-1] + Kp * e[n] + Ki * sum(e[0..n]). + // Kp and Ki were found by experiment; e[n] := algo->run_length + algo->cum_run_length_error += algo->run_length; // sum(e[0..n]) + #define PI_KP 32 + #define PI_KI 16 + //algo->bit_length += (algo->run_length / PI_KP + algo->cum_run_length_error / PI_KI) / num_of_bits_rx; + algo->bit_length += (algo->run_length + algo->cum_run_length_error / PI_KI) / (PI_KP * num_of_bits_rx); + #undef PI_KI + #undef PI_KP + + algo->state = state; + algo->run_length = 1; + } } +struct time2_algorithm +{ + uint32_t bitstream; + struct t1_c1_packet_decoder_work decoder; +}; -static const OutFunction out_functions[] = { to_stdout, t1_c1_packet_decoder }; +static void time2_algorithm_reset(struct time2_algorithm *algo) +{ + algo->bitstream = 0; + reset_t1_c1_packet_decoder(&algo->decoder); +} +static void time2_algorithm(unsigned bit, unsigned rssi, struct time2_algorithm *algo) +{ + algo->bitstream = (algo->bitstream << 1) | bit; + + if (count_set_bits((algo->bitstream & ACCESS_CODE_BITMASK) ^ ACCESS_CODE) <= ACCESS_CODE_ERRORS) + { + bit |= (1u<decoder, "t2a;"); +} + +static int opts_run_length_algorithm_enabled = 1; +static int opts_time2_algorithm_enabled = 1; + +static void print_usage(const char *program_name) +{ + fprintf(stdout, "Usage %s:\n", program_name); + fprintf(stdout, "\t-r 0 to disable run length algorithm\n"); + fprintf(stdout, "\t-t 0 to disable time2 algorithm\n"); +} + +static void process_options(int argc, char *argv[]) +{ + int option; + + while ((option = getopt(argc, argv, "r:t:")) != -1) + { + switch (option) + { + case 'r': + if (strcmp(optarg, "0") == 0) + { + opts_run_length_algorithm_enabled = 0; + } + else + { + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + break; + case 't': + if (strcmp(optarg, "0") == 0) + { + opts_time2_algorithm_enabled = 0; + } + else + { + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + break; + default: + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + } +} int main(int argc, char *argv[]) { - (void)argc; - (void)argv; - + process_options(argc, argv); // --- parameter section begin --- // The idea behind the variables in the section is to make parameters @@ -331,37 +501,26 @@ int main(int argc, char *argv[]) const unsigned CLOCK_LOCK_THRESHOLD = 2; const unsigned DECIMATION_RATE = 2; - - //#define USING_BITFILTER - - const uint32_t ACCESS_CODE = 0b0101010101010000111101u; - const uint32_t ACCESS_CODE_BITMASK = 0x3FFFFFu; - const unsigned ACCESS_CODE_ERRORS = 1u; // 0 if no errors allowed // --- parameter section end --- - // Select function for output - OutFunction out_function = out_functions[1]; - __attribute__((__aligned__(16))) uint8_t samples[4096]; float i = 0, q = 0; unsigned decimation_rate_index = 0; int16_t old_clock = INT16_MIN; - uint32_t bitstream = 0; unsigned clock_lock = 0; -#if defined(USING_BITFILTER) - uint32_t unfilt_bitstream = 0; - uint32_t bits_in_unfilt_bitstream = 0; -#endif + struct time2_algorithm t2_algo; + time2_algorithm_reset(&t2_algo); -#if defined (__SSE4_2__) - __attribute__((__aligned__(16))) int16_t iq_samples[sizeof(samples)]; - const __m128i dc_offset = _mm_set_epi16(-127, -127, -127, -127, -127, -127, -127, -127); -#endif + struct runlength_algorithm rl_algo; + runlength_algorithm_reset(&rl_algo); - //FILE *input = fopen("samples.bin", "rb"); + //FILE *input = fopen("samples/samples2.bin", "rb"); + //FILE *input = fopen("samples/kamstrup.bin", "rb"); + //FILE *input = fopen("samples/c1_mode_b.bin", "rb"); + //FILE *input = fopen("samples/t1_c1a_mixed.bin", "rb"); //FILE *input = get_net("localhost", 14423); - FILE *input= stdin; + FILE *input = stdin; if (input == NULL) { @@ -373,6 +532,7 @@ int main(int argc, char *argv[]) //FILE *demod_out2 = fopen("demod.bin", "wb"); //FILE *clock_out = fopen("clock.bin", "wb"); //FILE *bits_out= fopen("bits.bin", "wb"); + //FILE *rawbits_out = fopen("rawbits.bin", "wb"); while (!feof(input)) { @@ -383,24 +543,10 @@ int main(int argc, char *argv[]) return 2; } -#if defined (__SSE4_2__) - for (size_t k = 0; k < sizeof(samples)/sizeof(samples[0]); k += 8) // +2 : i and q interleaved - { - __m128i tmp = _mm_loadu_si128((__m128i const*)&samples[k]); // Hmmm, loading 8 byte besides of upper boundary?.. - __m128i cvt = _mm_add_epi16(_mm_cvtepu8_epi16(tmp), dc_offset); - _mm_store_si128((__m128i *)&iq_samples[k], cvt); - } -#endif - for (size_t k = 0; k < sizeof(samples)/sizeof(samples[0]); k += 2) // +2 : i and q interleaved { -#if defined (__SSE4_2__) - const int i_unfilt = iq_samples[k]; - const int q_unfilt = iq_samples[k+1]; -#else const int i_unfilt = ((int)samples[k] - 127); const int q_unfilt = ((int)samples[k + 1] - 127); -#endif // Low-Pass-Filtering before decimation is necessary, to ensure // that i and q signals don't contain frequencies above new sample @@ -436,7 +582,6 @@ int main(int argc, char *argv[]) // Demodulate. float delta_phi = polar_discriminator(i, q); - //int16_t demodulated_signal = (INT16_MAX-1)*delta_phi; //fwrite(&demodulated_signal, sizeof(demodulated_signal), 1, demod_out); @@ -445,6 +590,26 @@ int main(int argc, char *argv[]) //int16_t demodulated_signal = (INT16_MAX-1)*delta_phi; //fwrite(&demodulated_signal, sizeof(demodulated_signal), 1, demod_out2); + // Get the bit! + unsigned bit = (delta_phi >= 0) ? (1u<= 0) ? INT16_MAX : INT16_MIN; //fwrite(&clock, sizeof(clock), 1, clock_out); - unsigned bit = (delta_phi >= 0) ? (1u< old_clock) // rising edge { clock_lock = 1; - -#if defined(USING_BITFILTER) - unfilt_bitstream = bit; - bits_in_unfilt_bitstream = 1; -#endif } else if (old_clock == clock && clock_lock < CLOCK_LOCK_THRESHOLD) { @@ -482,25 +630,8 @@ int main(int argc, char *argv[]) { clock_lock++; -#if defined(USE_MOVING_AVERAGE) - // If using moving average, we would habe doubles of each of i- and q- signal components. - rssi /= DECIMATION_RATE; -#endif - -#if defined(USING_BITFILTER) - // Bitfilter can be used to remove unwanted spikes in the demodulated signal. - bit = majority_votes_bitfilter(unfilt_bitstream, bits_in_unfilt_bitstream); -#endif - - bitstream = (bitstream << 1) | bit; - - if (count_set_bits((bitstream & ACCESS_CODE_BITMASK) ^ ACCESS_CODE) <= ACCESS_CODE_ERRORS) - { - bit |= (1u< + * Copyright (c) 2021 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -134,34 +134,35 @@ static const uint16_t CRC16_DNP_TABLE[] = }; -typedef void (*t1_c1_packet_decoder_state)(unsigned bit); +struct t1_c1_packet_decoder_work; +typedef void (*t1_c1_packet_decoder_state)(unsigned bit, struct t1_c1_packet_decoder_work *decoder); -static void idle(unsigned bit); -static void done(unsigned bit); -static void rx_bit(unsigned bit); +static void idle(unsigned bit, struct t1_c1_packet_decoder_work *decoder); +static void done(unsigned bit, struct t1_c1_packet_decoder_work *decoder); +static void rx_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); -static void rx_high_nibble_first_lfield_bit(unsigned bit); -static void rx_high_nibble_last_lfield_bit(unsigned bit); +static void rx_high_nibble_first_lfield_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); +static void rx_high_nibble_last_lfield_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); -static void rx_low_nibble_first_lfield_bit(unsigned bit); -static void rx_low_nibble_last_lfield_bit(unsigned bit); +static void rx_low_nibble_first_lfield_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); +static void rx_low_nibble_last_lfield_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); -static void rx_high_nibble_first_data_bit(unsigned bit); -static void rx_high_nibble_last_data_bit(unsigned bit); +static void rx_high_nibble_first_data_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); +static void rx_high_nibble_last_data_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); -static void rx_low_nibble_first_data_bit(unsigned bit); -static void rx_low_nibble_last_data_bit(unsigned bit); +static void rx_low_nibble_first_data_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); +static void rx_low_nibble_last_data_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); -static void c1_rx_bit(unsigned bit); +static void c1_rx_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); -static void c1_rx_first_mode_bit(unsigned bit); -static void c1_rx_last_mode_bit(unsigned bit); +static void c1_rx_first_mode_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); +static void c1_rx_last_mode_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); -static void c1_rx_first_lfield_bit(unsigned bit); -static void c1_rx_last_lfield_bit(unsigned bit); +static void c1_rx_first_lfield_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); +static void c1_rx_last_lfield_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); -static void c1_rx_first_data_bit(unsigned bit); -static void c1_rx_last_data_bit(unsigned bit); +static void c1_rx_first_data_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); +static void c1_rx_last_data_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder); static const t1_c1_packet_decoder_state states[] = @@ -225,7 +226,7 @@ static const t1_c1_packet_decoder_state states[] = }; -static struct +struct t1_c1_packet_decoder_work { const t1_c1_packet_decoder_state *state; unsigned current_rssi; @@ -247,7 +248,7 @@ static struct unsigned byte; uint8_t packet[290]; // max. packet length with L- and all CRC-Fields char timestamp[64]; -} t1_c1_packet_decoder_work = {.state = &states[0]}; // idle +}; int get_mode_a_tlg_length(uint8_t lfield) { @@ -260,126 +261,131 @@ int get_mode_b_tlg_length(uint8_t lfield) return 1 + (int)lfield; } -static void reset_t1_c1_packet_decoder(void) +static int in_rx_t1_c1_packet_decoder(struct t1_c1_packet_decoder_work *decoder) { - memset(&t1_c1_packet_decoder_work, 0, sizeof(t1_c1_packet_decoder_work)); - t1_c1_packet_decoder_work.state = &states[0]; + return (decoder->state == &states[0]) ? 0 : 1; } -static void idle(unsigned bit) +static void reset_t1_c1_packet_decoder(struct t1_c1_packet_decoder_work *decoder) +{ + memset(decoder, 0, sizeof(*decoder)); + decoder->state = &states[0]; +} + +static void idle(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { if (!(bit & PACKET_PREAMBLE_DETECTED_MASK)) { - reset_t1_c1_packet_decoder(); + reset_t1_c1_packet_decoder(decoder); } } -static void done(unsigned bit) +static void done(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { (void)bit; } -static void rx_bit(unsigned bit) +static void rx_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte <<= 1; - t1_c1_packet_decoder_work.byte |= (bit & PACKET_DATABIT_MASK); + decoder->byte <<= 1; + decoder->byte |= (bit & PACKET_DATABIT_MASK); } -static void rx_high_nibble_first_lfield_bit(unsigned bit) +static void rx_high_nibble_first_lfield_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte = (bit & PACKET_DATABIT_MASK); - t1_c1_packet_decoder_work.packet_rssi = t1_c1_packet_decoder_work.current_rssi; + decoder->byte = (bit & PACKET_DATABIT_MASK); + decoder->packet_rssi = decoder->current_rssi; } -static void rx_high_nibble_last_lfield_bit(unsigned bit) +static void rx_high_nibble_last_lfield_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte <<= 1; - t1_c1_packet_decoder_work.byte |= (bit & PACKET_DATABIT_MASK); - t1_c1_packet_decoder_work.mode = t1_c1_packet_decoder_work.byte; + decoder->byte <<= 1; + decoder->byte |= (bit & PACKET_DATABIT_MASK); + decoder->mode = decoder->byte; - t1_c1_packet_decoder_work.L = HIGH_NIBBLE_3OUTOF6[t1_c1_packet_decoder_work.byte]; - t1_c1_packet_decoder_work.flags = 0; + decoder->L = HIGH_NIBBLE_3OUTOF6[decoder->byte]; + decoder->flags = 0; } -static void rx_low_nibble_first_lfield_bit(unsigned bit) +static void rx_low_nibble_first_lfield_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte = (bit & PACKET_DATABIT_MASK); + decoder->byte = (bit & PACKET_DATABIT_MASK); } -static void rx_low_nibble_last_lfield_bit(unsigned bit) +static void rx_low_nibble_last_lfield_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte <<= 1; - t1_c1_packet_decoder_work.byte |= (bit & PACKET_DATABIT_MASK); - t1_c1_packet_decoder_work.mode <<= 6; - t1_c1_packet_decoder_work.mode |= t1_c1_packet_decoder_work.byte; + decoder->byte <<= 1; + decoder->byte |= (bit & PACKET_DATABIT_MASK); + decoder->mode <<= 6; + decoder->mode |= decoder->byte; - const unsigned byte = LOW_NIBBLE_3OUTOF6[t1_c1_packet_decoder_work.byte]; + const unsigned byte = LOW_NIBBLE_3OUTOF6[decoder->byte]; - if (t1_c1_packet_decoder_work.L == 0xFFu || byte == 0xFFu) + if (decoder->L == 0xFFu || byte == 0xFFu) { - if (t1_c1_packet_decoder_work.mode == C1_MODE_A) + if (decoder->mode == C1_MODE_A) { - t1_c1_packet_decoder_work.b_frame_type = 0; - t1_c1_packet_decoder_work.state = &states[26]; // c1_rx_first_mode_bit + decoder->b_frame_type = 0; + decoder->state = &states[26]; // c1_rx_first_mode_bit } - else if (t1_c1_packet_decoder_work.mode == C1_MODE_B) + else if (decoder->mode == C1_MODE_B) { - t1_c1_packet_decoder_work.b_frame_type = 1; - t1_c1_packet_decoder_work.state = &states[26]; // c1_rx_first_mode_bit + decoder->b_frame_type = 1; + decoder->state = &states[26]; // c1_rx_first_mode_bit } else { - reset_t1_c1_packet_decoder(); + reset_t1_c1_packet_decoder(decoder); } } else { - t1_c1_packet_decoder_work.b_frame_type = 0; - t1_c1_packet_decoder_work.c1_packet = 0; + decoder->b_frame_type = 0; + decoder->c1_packet = 0; - t1_c1_packet_decoder_work.L |= byte; - t1_c1_packet_decoder_work.l = 0; - t1_c1_packet_decoder_work.packet[t1_c1_packet_decoder_work.l++] = t1_c1_packet_decoder_work.L; - t1_c1_packet_decoder_work.L = FULL_TLG_LENGTH_FROM_L_FIELD[t1_c1_packet_decoder_work.L]; + decoder->L |= byte; + decoder->l = 0; + decoder->packet[decoder->l++] = decoder->L; + decoder->L = FULL_TLG_LENGTH_FROM_L_FIELD[decoder->L]; } } -static void rx_high_nibble_first_data_bit(unsigned bit) +static void rx_high_nibble_first_data_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte = (bit & PACKET_DATABIT_MASK); + decoder->byte = (bit & PACKET_DATABIT_MASK); } -static void rx_high_nibble_last_data_bit(unsigned bit) +static void rx_high_nibble_last_data_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte <<= 1; - t1_c1_packet_decoder_work.byte |= (bit & PACKET_DATABIT_MASK); + decoder->byte <<= 1; + decoder->byte |= (bit & PACKET_DATABIT_MASK); - const unsigned byte = HIGH_NIBBLE_3OUTOF6[t1_c1_packet_decoder_work.byte]; + const unsigned byte = HIGH_NIBBLE_3OUTOF6[decoder->byte]; - if (byte == 0xFFu) t1_c1_packet_decoder_work.err_3outof = 1; + if (byte == 0xFFu) decoder->err_3outof = 1; - t1_c1_packet_decoder_work.packet[t1_c1_packet_decoder_work.l] = byte; + decoder->packet[decoder->l] = byte; } -static void rx_low_nibble_first_data_bit(unsigned bit) +static void rx_low_nibble_first_data_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte = (bit & PACKET_DATABIT_MASK); + decoder->byte = (bit & PACKET_DATABIT_MASK); } -static void rx_low_nibble_last_data_bit(unsigned bit) +static void rx_low_nibble_last_data_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte <<= 1; - t1_c1_packet_decoder_work.byte |= (bit & PACKET_DATABIT_MASK); + decoder->byte <<= 1; + decoder->byte |= (bit & PACKET_DATABIT_MASK); - const unsigned byte = LOW_NIBBLE_3OUTOF6[t1_c1_packet_decoder_work.byte]; + const unsigned byte = LOW_NIBBLE_3OUTOF6[decoder->byte]; - if (byte == 0xFFu) t1_c1_packet_decoder_work.err_3outof = 1; + if (byte == 0xFFu) decoder->err_3outof = 1; - t1_c1_packet_decoder_work.packet[t1_c1_packet_decoder_work.l++] |= byte; + decoder->packet[decoder->l++] |= byte; - if (t1_c1_packet_decoder_work.l < t1_c1_packet_decoder_work.L) + if (decoder->l < decoder->L) { - t1_c1_packet_decoder_work.state = &states[13]; // rx_high_nibble_first_data_bit + decoder->state = &states[13]; // rx_high_nibble_first_data_bit } else { @@ -387,77 +393,77 @@ static void rx_low_nibble_last_data_bit(unsigned bit) time(&now); struct tm *timeinfo = gmtime(&now); - strftime(t1_c1_packet_decoder_work.timestamp, sizeof(t1_c1_packet_decoder_work.timestamp), "%Y-%m-%d %H:%M:%S.000", timeinfo); + strftime(decoder->timestamp, sizeof(decoder->timestamp), "%Y-%m-%d %H:%M:%S.000", timeinfo); } } -static void c1_rx_bit(unsigned bit) +static void c1_rx_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte <<= 1; - t1_c1_packet_decoder_work.byte |= (bit & PACKET_DATABIT_MASK); + decoder->byte <<= 1; + decoder->byte |= (bit & PACKET_DATABIT_MASK); } -static void c1_rx_first_mode_bit(unsigned bit) +static void c1_rx_first_mode_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte = (bit & PACKET_DATABIT_MASK); + decoder->byte = (bit & PACKET_DATABIT_MASK); } -static void c1_rx_last_mode_bit(unsigned bit) +static void c1_rx_last_mode_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte <<= 1; - t1_c1_packet_decoder_work.byte |= (bit & PACKET_DATABIT_MASK); + decoder->byte <<= 1; + decoder->byte |= (bit & PACKET_DATABIT_MASK); - t1_c1_packet_decoder_work.mode <<= 4; - t1_c1_packet_decoder_work.mode |= t1_c1_packet_decoder_work.byte; + decoder->mode <<= 4; + decoder->mode |= decoder->byte; - if (t1_c1_packet_decoder_work.byte == C1_MODE_AB_TRAILER) + if (decoder->byte == C1_MODE_AB_TRAILER) { - t1_c1_packet_decoder_work.c1_packet = 1; + decoder->c1_packet = 1; } else { - reset_t1_c1_packet_decoder(); + reset_t1_c1_packet_decoder(decoder); } } -static void c1_rx_first_lfield_bit(unsigned bit) +static void c1_rx_first_lfield_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte = (bit & PACKET_DATABIT_MASK); + decoder->byte = (bit & PACKET_DATABIT_MASK); } -static void c1_rx_last_lfield_bit(unsigned bit) +static void c1_rx_last_lfield_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte <<= 1; - t1_c1_packet_decoder_work.byte |= (bit & PACKET_DATABIT_MASK); + decoder->byte <<= 1; + decoder->byte |= (bit & PACKET_DATABIT_MASK); - t1_c1_packet_decoder_work.L = t1_c1_packet_decoder_work.byte; - t1_c1_packet_decoder_work.l = 0; - t1_c1_packet_decoder_work.packet[t1_c1_packet_decoder_work.l++] = t1_c1_packet_decoder_work.L; - if (t1_c1_packet_decoder_work.b_frame_type) + decoder->L = decoder->byte; + decoder->l = 0; + decoder->packet[decoder->l++] = decoder->L; + if (decoder->b_frame_type) { - t1_c1_packet_decoder_work.L = get_mode_b_tlg_length(t1_c1_packet_decoder_work.L); + decoder->L = get_mode_b_tlg_length(decoder->L); } else { - t1_c1_packet_decoder_work.L = FULL_TLG_LENGTH_FROM_L_FIELD[t1_c1_packet_decoder_work.L]; + decoder->L = FULL_TLG_LENGTH_FROM_L_FIELD[decoder->L]; } } -static void c1_rx_first_data_bit(unsigned bit) +static void c1_rx_first_data_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte = (bit & PACKET_DATABIT_MASK); + decoder->byte = (bit & PACKET_DATABIT_MASK); } -static void c1_rx_last_data_bit(unsigned bit) +static void c1_rx_last_data_bit(unsigned bit, struct t1_c1_packet_decoder_work *decoder) { - t1_c1_packet_decoder_work.byte <<= 1; - t1_c1_packet_decoder_work.byte |= (bit & PACKET_DATABIT_MASK); + decoder->byte <<= 1; + decoder->byte |= (bit & PACKET_DATABIT_MASK); - t1_c1_packet_decoder_work.packet[t1_c1_packet_decoder_work.l++] = t1_c1_packet_decoder_work.byte; + decoder->packet[decoder->l++] = decoder->byte; - if (t1_c1_packet_decoder_work.l < t1_c1_packet_decoder_work.L) + if (decoder->l < decoder->L) { - t1_c1_packet_decoder_work.state = &states[38]; // c1_rx_first_data_bit + decoder->state = &states[38]; // c1_rx_first_data_bit } else { @@ -465,7 +471,7 @@ static void c1_rx_last_data_bit(unsigned bit) time(&now); struct tm *timeinfo = gmtime(&now); - strftime(t1_c1_packet_decoder_work.timestamp, sizeof(t1_c1_packet_decoder_work.timestamp), "%Y-%m-%d %H:%M:%S.000", timeinfo); + strftime(decoder->timestamp, sizeof(decoder->timestamp), "%Y-%m-%d %H:%M:%S.000", timeinfo); } } @@ -590,6 +596,7 @@ static unsigned cook_pkt(uint8_t *data, unsigned datalen) /** @brief Strip CRCs in place. */ static unsigned cook_pkt_b_frame_type(uint8_t *data, unsigned datalen) { + uint8_t *const L = data; uint8_t *dst = data; unsigned dstlen = 0; @@ -620,6 +627,11 @@ static unsigned cook_pkt_b_frame_type(uint8_t *data, unsigned datalen) datalen -= datalen; } } + + // L field has to be a number of data bytes in the datagram without CRC bytes. + // dstlen is this "number of data bytes" already but has an add-on of L field itself, + // which is going to be subtracted in the next step. + *L = dstlen - 1; } return dstlen; @@ -634,58 +646,59 @@ static inline uint32_t get_serial(const uint8_t *const packet) return serial; } -static void t1_c1_packet_decoder(unsigned bit, unsigned rssi) +static void t1_c1_packet_decoder(unsigned bit, unsigned rssi, struct t1_c1_packet_decoder_work *decoder, const char *algorithm) { - t1_c1_packet_decoder_work.current_rssi = rssi; + decoder->current_rssi = rssi; - (*t1_c1_packet_decoder_work.state++)(bit); + (*decoder->state++)(bit, decoder); - if (*t1_c1_packet_decoder_work.state == idle) + if (*decoder->state == idle) { // nothing } - else if (*t1_c1_packet_decoder_work.state == done) + else if (*decoder->state == done) { - if (t1_c1_packet_decoder_work.b_frame_type) + if (decoder->b_frame_type) { - t1_c1_packet_decoder_work.crc_ok = check_calc_crc_wmbus_b_frame_type(t1_c1_packet_decoder_work.packet, t1_c1_packet_decoder_work.L) ? 1 : 0; + decoder->crc_ok = check_calc_crc_wmbus_b_frame_type(decoder->packet, decoder->L) ? 1 : 0; } else { - t1_c1_packet_decoder_work.crc_ok = check_calc_crc_wmbus(t1_c1_packet_decoder_work.packet, t1_c1_packet_decoder_work.L) ? 1 : 0; + decoder->crc_ok = check_calc_crc_wmbus(decoder->packet, decoder->L) ? 1 : 0; } - fprintf(stdout, "%s;%u;%u;%s;%u;%u;%08X;", t1_c1_packet_decoder_work.c1_packet ? "C1": "T1", - t1_c1_packet_decoder_work.crc_ok, - t1_c1_packet_decoder_work.err_3outof^1, - t1_c1_packet_decoder_work.timestamp, - t1_c1_packet_decoder_work.packet_rssi, + algorithm = ""; // uncomment of want to see which algorithm is executed right now + fprintf(stdout, "%s%s;%u;%u;%s;%u;%u;%08X;", algorithm, decoder->c1_packet ? "C1": "T1", + decoder->crc_ok, + decoder->err_3outof^1, + decoder->timestamp, + decoder->packet_rssi, rssi, - get_serial(t1_c1_packet_decoder_work.packet)); + get_serial(decoder->packet)); #if 0 fprintf(stdout, "0x"); - for (size_t l = 0; l < t1_c1_packet_decoder_work.L; l++) fprintf(stdout, "%02x", t1_c1_packet_decoder_work.packet[l]); + for (size_t l = 0; l < decoder->L; l++) fprintf(stdout, "%02x", decoder->packet[l]); fprintf(stdout, ";"); #endif #if 1 - if (t1_c1_packet_decoder_work.b_frame_type) + if (decoder->b_frame_type) { - t1_c1_packet_decoder_work.L = cook_pkt_b_frame_type(t1_c1_packet_decoder_work.packet, t1_c1_packet_decoder_work.L); + decoder->L = cook_pkt_b_frame_type(decoder->packet, decoder->L); } else { - t1_c1_packet_decoder_work.L = cook_pkt(t1_c1_packet_decoder_work.packet, t1_c1_packet_decoder_work.L); + decoder->L = cook_pkt(decoder->packet, decoder->L); } fprintf(stdout, "0x"); - for (size_t l = 0; l < t1_c1_packet_decoder_work.L; l++) fprintf(stdout, "%02x", t1_c1_packet_decoder_work.packet[l]); + for (size_t l = 0; l < decoder->L; l++) fprintf(stdout, "%02x", decoder->packet[l]); #endif fprintf(stdout, "\n"); fflush(stdout); - reset_t1_c1_packet_decoder(); + reset_t1_c1_packet_decoder(decoder); } else { @@ -693,7 +706,7 @@ static void t1_c1_packet_decoder(unsigned bit, unsigned rssi) // The current packet seems to be collided with an another one. if (rssi < PACKET_CAPTURE_THRESHOLD) { - reset_t1_c1_packet_decoder(); + reset_t1_c1_packet_decoder(decoder); } } }