kopia lustrzana https://github.com/xaelsouth/rtl-wmbus
- run length algorithm for picking datagrams out of the bit stream implemented.
- L(ength) field fixed for C1 Mode B datagrams. - Allow to redefine CFLAGS and OUTPUT directory.pull/18/head
rodzic
f213753a98
commit
355ba64a57
32
README.md
32
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 <xael.south@yandex.com>
|
||||
Copyright (c) 2021 <xael.south@yandex.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
|
331
rtl_wmbus.c
331
rtl_wmbus.c
|
@ -1,5 +1,5 @@
|
|||
/*-
|
||||
* Copyright (c) 2017 <xael.south@yandex.com>
|
||||
* Copyright (c) 2021 <xael.south@yandex.com>
|
||||
*
|
||||
* 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 <getopt.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -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 <immintrin.h>
|
||||
#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<<PACKET_PREAMBLE_DETECTED_SHIFT); // packet detected; mark the bit similar to "Access Code"-Block in GNU Radio
|
||||
}
|
||||
|
||||
t1_c1_packet_decoder(bit, rssi, &algo->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<<PACKET_PREAMBLE_DETECTED_SHIFT); // packet detected; mark the bit similar to "Access Code"-Block in GNU Radio
|
||||
}
|
||||
|
||||
t1_c1_packet_decoder(bit, rssi, &algo->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<<PACKET_DATABIT_SHIFT) : (0u<<PACKET_DATABIT_SHIFT);
|
||||
//int16_t u = bit ? (INT16_MAX-1) : 0;
|
||||
//fwrite(&u, sizeof(u), 1, rawbits_out);
|
||||
|
||||
// --- rssi filtering section begin ---
|
||||
// We are using one simple filter to rssi value in order to
|
||||
// prevent unexpected "splashes" in signal power.
|
||||
float rssi = sqrtf(i*i + q*q);
|
||||
rssi = rssi_filter(rssi); // comment out, if rssi filtering is unwanted
|
||||
#if defined(USE_MOVING_AVERAGE)
|
||||
// If using moving average, we would have doubles of each of i- and q- signal components.
|
||||
rssi /= DECIMATION_RATE;
|
||||
#endif
|
||||
// --- rssi filtering section end ---
|
||||
|
||||
// --- runlength algorithm section begin ---
|
||||
if (opts_run_length_algorithm_enabled) runlength_algorithm(bit, rssi, &rl_algo);
|
||||
// --- runlength algorithm section end ---
|
||||
|
||||
// --- clock recovery section begin ---
|
||||
// The time-2 method is implemented: push squared signal through a bandpass
|
||||
// tuned close to the symbol rate. Saturating band-pass output produces a
|
||||
|
@ -453,26 +618,9 @@ int main(int argc, char *argv[])
|
|||
const int16_t clock = (bp_iir_cheb1_800kHz_90kHz_98kHz_102kHz_110kHz(delta_phi * delta_phi) >= 0) ? INT16_MAX : INT16_MIN;
|
||||
//fwrite(&clock, sizeof(clock), 1, clock_out);
|
||||
|
||||
unsigned bit = (delta_phi >= 0) ? (1u<<PACKET_DATABIT_SHIFT) : (0u<<PACKET_DATABIT_SHIFT);
|
||||
|
||||
#if defined(USING_BITFILTER)
|
||||
unfilt_bitstream = (unfilt_bitstream << 1) | bit;
|
||||
bits_in_unfilt_bitstream = (bits_in_unfilt_bitstream << 1) | 1;
|
||||
#endif
|
||||
|
||||
// We are using one simple filter to rssi value in order to
|
||||
// prevent unexpected "splashes" in signal power.
|
||||
float rssi = sqrtf(i*i + q*q);
|
||||
rssi = rssi_filter(rssi); // comment out, if rssi filtering is unwanted
|
||||
|
||||
if (clock > 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<<PACKET_PREAMBLE_DETECTED_SHIFT); // packet detected; mark the bit similar to "Access Code"-Block in GNU Radio
|
||||
}
|
||||
|
||||
//fwrite(&bit, sizeof(bit), 1, bits_out);
|
||||
out_function(bit, rssi);
|
||||
if (opts_time2_algorithm_enabled) time2_algorithm(bit, rssi, &t2_algo);
|
||||
}
|
||||
old_clock = clock;
|
||||
// --- clock recovery section end ---
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define T1_C1_PACKET_DECODER_H
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2017 <xael.south@yandex.com>
|
||||
* Copyright (c) 2021 <xael.south@yandex.com>
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue