kopia lustrzana https://github.com/xaelsouth/rtl-wmbus
clock recovering for time2 method only if latter selected
rodzic
6d92d1b3f1
commit
cec199312e
94
rtl_wmbus.c
94
rtl_wmbus.c
|
@ -43,7 +43,7 @@ static const uint32_t ACCESS_CODE = 0b0101010101010000111101u;
|
||||||
static const uint32_t ACCESS_CODE_BITMASK = 0x3FFFFFu;
|
static const uint32_t ACCESS_CODE_BITMASK = 0x3FFFFFu;
|
||||||
static const unsigned ACCESS_CODE_ERRORS = 1u; // 0 if no errors allowed
|
static const unsigned ACCESS_CODE_ERRORS = 1u; // 0 if no errors allowed
|
||||||
|
|
||||||
/* deglitch_filter has been calculated by Python script as follows.
|
/* deglitch_filter has been calculated by a Python script as follows.
|
||||||
The filter is counting "1" among 7 bits and saying "1" if count("1") >= 3 else "0".
|
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.)
|
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
|
That forces the filter to put more "1" than "0" on the output, because RTL-SDR streams
|
||||||
|
@ -83,6 +83,7 @@ static const uint8_t deglitch_filter[128] =
|
||||||
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)
|
static float lp_1600kHz_56kHz(int sample, size_t i_or_q)
|
||||||
{
|
{
|
||||||
static float moving_average[2];
|
static float moving_average[2];
|
||||||
|
@ -334,6 +335,7 @@ struct runlength_algorithm
|
||||||
struct t1_c1_packet_decoder_work decoder;
|
struct t1_c1_packet_decoder_work decoder;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void runlength_algorithm_reset(struct runlength_algorithm *algo)
|
static void runlength_algorithm_reset(struct runlength_algorithm *algo)
|
||||||
{
|
{
|
||||||
algo->run_length = 0;
|
algo->run_length = 0;
|
||||||
|
@ -345,6 +347,7 @@ static void runlength_algorithm_reset(struct runlength_algorithm *algo)
|
||||||
reset_t1_c1_packet_decoder(&algo->decoder);
|
reset_t1_c1_packet_decoder(&algo->decoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void runlength_algorithm(unsigned raw_bit, unsigned rssi, struct runlength_algorithm *algo)
|
static void runlength_algorithm(unsigned raw_bit, unsigned rssi, struct runlength_algorithm *algo)
|
||||||
{
|
{
|
||||||
algo->raw_bitstream = (algo->raw_bitstream << 1) | raw_bit;
|
algo->raw_bitstream = (algo->raw_bitstream << 1) | raw_bit;
|
||||||
|
@ -406,7 +409,7 @@ static void runlength_algorithm(unsigned raw_bit, unsigned rssi, struct runlengt
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Some kind of PI controller is implemented below: u[n] = u[n-1] + Kp * e[n] + Ki * sum(e[0..n]).
|
// 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
|
// Kp and Ki were found by experiment; e[n] := algo->run_length; u[[n] is the new bit length; u[n-1] is the last known bit length
|
||||||
algo->cum_run_length_error += algo->run_length; // sum(e[0..n])
|
algo->cum_run_length_error += algo->run_length; // sum(e[0..n])
|
||||||
#define PI_KP 32
|
#define PI_KP 32
|
||||||
#define PI_KI 16
|
#define PI_KI 16
|
||||||
|
@ -420,18 +423,21 @@ static void runlength_algorithm(unsigned raw_bit, unsigned rssi, struct runlengt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct time2_algorithm
|
struct time2_algorithm
|
||||||
{
|
{
|
||||||
uint32_t bitstream;
|
uint32_t bitstream;
|
||||||
struct t1_c1_packet_decoder_work decoder;
|
struct t1_c1_packet_decoder_work decoder;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void time2_algorithm_reset(struct time2_algorithm *algo)
|
static void time2_algorithm_reset(struct time2_algorithm *algo)
|
||||||
{
|
{
|
||||||
algo->bitstream = 0;
|
algo->bitstream = 0;
|
||||||
reset_t1_c1_packet_decoder(&algo->decoder);
|
reset_t1_c1_packet_decoder(&algo->decoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void time2_algorithm(unsigned bit, unsigned rssi, struct time2_algorithm *algo)
|
static void time2_algorithm(unsigned bit, unsigned rssi, struct time2_algorithm *algo)
|
||||||
{
|
{
|
||||||
algo->bitstream = (algo->bitstream << 1) | bit;
|
algo->bitstream = (algo->bitstream << 1) | bit;
|
||||||
|
@ -444,10 +450,13 @@ static void time2_algorithm(unsigned bit, unsigned rssi, struct time2_algorithm
|
||||||
t1_c1_packet_decoder(bit, rssi, &algo->decoder, "t2a;");
|
t1_c1_packet_decoder(bit, rssi, &algo->decoder, "t2a;");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int opts_run_length_algorithm_enabled = 1;
|
static int opts_run_length_algorithm_enabled = 1;
|
||||||
static int opts_time2_algorithm_enabled = 1;
|
static int opts_time2_algorithm_enabled = 1;
|
||||||
static unsigned decimation_rate = 2u;
|
static unsigned opts_decimation_rate = 2u;
|
||||||
int show_used_algorithm = 0;
|
int opts_show_used_algorithm = 0;
|
||||||
|
static const unsigned opts_CLOCK_LOCK_THRESHOLD = 2;
|
||||||
|
|
||||||
|
|
||||||
static void print_usage(const char *program_name)
|
static void print_usage(const char *program_name)
|
||||||
{
|
{
|
||||||
|
@ -458,6 +467,7 @@ static void print_usage(const char *program_name)
|
||||||
fprintf(stdout, "\t-s show used algorithm in the output\n");
|
fprintf(stdout, "\t-s show used algorithm in the output\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void process_options(int argc, char *argv[])
|
static void process_options(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int option;
|
int option;
|
||||||
|
@ -489,10 +499,10 @@ static void process_options(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
decimation_rate = strtoul(optarg, NULL, 10);
|
opts_decimation_rate = strtoul(optarg, NULL, 10);
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
show_used_algorithm = 1;
|
opts_show_used_algorithm = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
print_usage(argv[0]);
|
print_usage(argv[0]);
|
||||||
|
@ -505,14 +515,6 @@ int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
process_options(argc, argv);
|
process_options(argc, argv);
|
||||||
|
|
||||||
// --- parameter section begin ---
|
|
||||||
// The idea behind the variables in the section is to make parameters
|
|
||||||
// configurable via command line.
|
|
||||||
const unsigned CLOCK_LOCK_THRESHOLD = 2;
|
|
||||||
|
|
||||||
|
|
||||||
// --- parameter section end ---
|
|
||||||
|
|
||||||
__attribute__((__aligned__(16))) uint8_t samples[4096];
|
__attribute__((__aligned__(16))) uint8_t samples[4096];
|
||||||
float i = 0, q = 0;
|
float i = 0, q = 0;
|
||||||
unsigned decimation_rate_index = 0;
|
unsigned decimation_rate_index = 0;
|
||||||
|
@ -587,7 +589,7 @@ int main(int argc, char *argv[])
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
++decimation_rate_index;
|
++decimation_rate_index;
|
||||||
if (decimation_rate_index < decimation_rate) continue;
|
if (decimation_rate_index < opts_decimation_rate) continue;
|
||||||
decimation_rate_index = 0;
|
decimation_rate_index = 0;
|
||||||
|
|
||||||
// Demodulate.
|
// Demodulate.
|
||||||
|
@ -605,46 +607,60 @@ int main(int argc, char *argv[])
|
||||||
//int16_t u = bit ? (INT16_MAX-1) : 0;
|
//int16_t u = bit ? (INT16_MAX-1) : 0;
|
||||||
//fwrite(&u, sizeof(u), 1, rawbits_out);
|
//fwrite(&u, sizeof(u), 1, rawbits_out);
|
||||||
|
|
||||||
|
|
||||||
// --- rssi filtering section begin ---
|
// --- rssi filtering section begin ---
|
||||||
// We are using one simple filter to rssi value in order to
|
// We are using one simple filter to rssi value in order to
|
||||||
// prevent unexpected "splashes" in signal power.
|
// prevent unexpected "splashes" in signal power.
|
||||||
float rssi = sqrtf(i*i + q*q);
|
float rssi = sqrtf(i*i + q*q);
|
||||||
rssi = rssi_filter(rssi); // comment out, if rssi filtering is unwanted
|
rssi = rssi_filter(rssi); // comment out, if rssi filtering is unwanted
|
||||||
#if defined(USE_MOVING_AVERAGE)
|
#if defined(USE_MOVING_AVERAGE)
|
||||||
// If using moving average, we would have doubles of each of i- and q- signal components.
|
// If using moving average, we would have multiples of I- and Q- signal components.
|
||||||
rssi /= decimation_rate;
|
rssi /= opts_decimation_rate;
|
||||||
#endif
|
#endif
|
||||||
// --- rssi filtering section end ---
|
// --- rssi filtering section end ---
|
||||||
|
|
||||||
|
|
||||||
// --- runlength algorithm section begin ---
|
// --- runlength algorithm section begin ---
|
||||||
if (opts_run_length_algorithm_enabled) runlength_algorithm(bit, rssi, &rl_algo);
|
if (opts_run_length_algorithm_enabled)
|
||||||
|
{
|
||||||
|
runlength_algorithm(bit, rssi, &rl_algo);
|
||||||
|
}
|
||||||
// --- runlength algorithm section end ---
|
// --- 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
|
|
||||||
// rectangular pulses with the required timing information.
|
|
||||||
// Clock-Signal is crossing zero in half period.
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (clock > old_clock) // rising edge
|
// --- time2 algorithm section begin ---
|
||||||
|
if (opts_time2_algorithm_enabled)
|
||||||
{
|
{
|
||||||
clock_lock = 1;
|
// --- clock recovery section begin ---
|
||||||
}
|
// The time-2 method is implemented: push squared signal through a bandpass
|
||||||
else if (old_clock == clock && clock_lock < CLOCK_LOCK_THRESHOLD)
|
// tuned close to the symbol rate. Saturating band-pass output produces a
|
||||||
{
|
// rectangular pulses with the required timing information.
|
||||||
clock_lock++;
|
// Clock-Signal is crossing zero in half period.
|
||||||
}
|
const int16_t clock = (bp_iir_cheb1_800kHz_90kHz_98kHz_102kHz_110kHz(delta_phi * delta_phi) >= 0) ? INT16_MAX : INT16_MIN;
|
||||||
else if (clock_lock == CLOCK_LOCK_THRESHOLD) // sample data bit on CLOCK_LOCK_THRESHOLD after rose up
|
//fwrite(&clock, sizeof(clock), 1, clock_out);
|
||||||
{
|
|
||||||
clock_lock++;
|
|
||||||
|
|
||||||
//fwrite(&bit, sizeof(bit), 1, bits_out);
|
if (clock > old_clock)
|
||||||
if (opts_time2_algorithm_enabled) time2_algorithm(bit, rssi, &t2_algo);
|
{ // Clock signal rising edge detected.
|
||||||
|
clock_lock = 1;
|
||||||
|
}
|
||||||
|
else if (clock == INT16_MAX)
|
||||||
|
{ // Clock signal is still high.
|
||||||
|
if (clock_lock < opts_CLOCK_LOCK_THRESHOLD)
|
||||||
|
{ // Skip up to (opts_CLOCK_LOCK_THRESHOLD - 1) clock bits
|
||||||
|
// to get closer to the middle of the data bit.
|
||||||
|
clock_lock++;
|
||||||
|
}
|
||||||
|
else if (clock_lock == opts_CLOCK_LOCK_THRESHOLD)
|
||||||
|
{ // Sample data bit at CLOCK_LOCK_THRESHOLD clock bit position.
|
||||||
|
clock_lock++;
|
||||||
|
time2_algorithm(bit, rssi, &t2_algo);
|
||||||
|
//fwrite(&bit, sizeof(bit), 1, bits_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
old_clock = clock;
|
||||||
|
// --- clock recovery section end ---
|
||||||
}
|
}
|
||||||
old_clock = clock;
|
// --- time2 algorithm section end ---
|
||||||
// --- clock recovery section end ---
|
|
||||||
|
|
||||||
#if defined(USE_MOVING_AVERAGE)
|
#if defined(USE_MOVING_AVERAGE)
|
||||||
i = q = 0;
|
i = q = 0;
|
||||||
|
|
|
@ -661,7 +661,7 @@ static inline uint32_t get_serial(const uint8_t *const packet)
|
||||||
return serial;
|
return serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int show_used_algorithm;
|
extern int opts_show_used_algorithm;
|
||||||
|
|
||||||
static void t1_c1_packet_decoder(unsigned bit, unsigned rssi, struct t1_c1_packet_decoder_work *decoder, const char *algorithm)
|
static void t1_c1_packet_decoder(unsigned bit, unsigned rssi, struct t1_c1_packet_decoder_work *decoder, const char *algorithm)
|
||||||
{
|
{
|
||||||
|
@ -684,7 +684,7 @@ static void t1_c1_packet_decoder(unsigned bit, unsigned rssi, struct t1_c1_packe
|
||||||
decoder->crc_ok = check_calc_crc_wmbus(decoder->packet, decoder->L) ? 1 : 0;
|
decoder->crc_ok = check_calc_crc_wmbus(decoder->packet, decoder->L) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!show_used_algorithm) algorithm = "";
|
if (!opts_show_used_algorithm) algorithm = "";
|
||||||
fprintf(stdout, "%s%s;%u;%u;%s;%u;%u;%08X;", algorithm, decoder->c1_packet ? "C1": "T1",
|
fprintf(stdout, "%s%s;%u;%u;%s;%u;%u;%08X;", algorithm, decoder->c1_packet ? "C1": "T1",
|
||||||
decoder->crc_ok,
|
decoder->crc_ok,
|
||||||
decoder->err_3outof^1,
|
decoder->err_3outof^1,
|
||||||
|
|
Ładowanie…
Reference in New Issue