Add CS16 input and output (#773)

This commit is contained in:
Christian W. Zuckschwerdt
2018-07-25 10:26:17 +02:00
committed by GitHub
parent 5b098cea03
commit eb02ef4bab
3 changed files with 74 additions and 35 deletions

View File

@@ -82,9 +82,9 @@ Usage: = Tuner options =
[-m <mode>] Data file mode for input / output file (default: 0)
0 = Raw I/Q samples (uint8, 2 channel)
1 = AM demodulated samples (int16 pcm, 1 channel)
2 = FM demodulated samples (int16) (experimental)
2 = FM demodulated samples (int16) (output only)
3 = Raw I/Q samples (cf32, 2 channel)
Note: If output file is specified, input will always be I/Q
4 = Raw I/Q samples (cs16, 2 channel)
[-F] kv|json|csv|syslog Produce decoded output in given format. Not yet supported by all drivers.
append output to file with :<filename> (e.g. -F csv:log.csv), defaults to stdout.
specify host/port for syslog with e.g. -F syslog:127.0.0.1:1514

View File

@@ -72,6 +72,7 @@ struct dm_state {
int16_t fm[MAXIMAL_BUF_LENGTH]; // FM demodulated signal (for FSK decoding)
uint16_t temp[MAXIMAL_BUF_LENGTH]; // Temporary buffer (to be optimized out..)
} buf;
int sample_size; // CU8: 1, CS16: 2
FilterState lowpass_filter_state;
DemodFM_State demod_FM_state;
int enable_FM_demod;
@@ -141,9 +142,9 @@ void usage(r_device *devices) {
"\t[-m <mode>] Data file mode for input / output file (default: 0)\n"
"\t\t 0 = Raw I/Q samples (uint8, 2 channel)\n"
"\t\t 1 = AM demodulated samples (int16 pcm, 1 channel)\n"
"\t\t 2 = FM demodulated samples (int16) (experimental)\n"
"\t\t 2 = FM demodulated samples (int16) (output only)\n"
"\t\t 3 = Raw I/Q samples (cf32, 2 channel)\n"
"\t\t Note: If output file is specified, input will always be I/Q\n"
"\t\t 4 = Raw I/Q samples (cs16, 2 channel)\n"
"\t[-F] kv|json|csv|syslog Produce decoded output in given format. Not yet supported by all drivers.\n"
"\t\t append output to file with :<filename> (e.g. -F csv:log.csv), defaults to stdout.\n"
"\t\t specify host/port for syslog with e.g. -F syslog:127.0.0.1:1514\n"
@@ -690,6 +691,7 @@ static void rtlsdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) {
struct dm_state *demod = ctx;
int i;
char time_str[LOCAL_TIME_BUFLEN];
unsigned long n_samples;
if (do_exit || do_exit_async)
return;
@@ -700,6 +702,8 @@ static void rtlsdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) {
rtlsdr_cancel_async(dev);
}
n_samples = len / 2 / demod->sample_size;
#ifndef _WIN32
alarm(3); // require callback to run every 3 second, abort otherwise
#endif
@@ -714,29 +718,41 @@ static void rtlsdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) {
}
// AM demodulation
envelope_detect(iq_buf, demod->buf.temp, len/2);
baseband_low_pass_filter(demod->buf.temp, demod->am_buf, len/2, &demod->lowpass_filter_state);
if (demod->sample_size == 1) { // CU8
envelope_detect(iq_buf, demod->buf.temp, n_samples);
//magnitude_true_cu8(iq_buf, demod->buf.temp, n_samples);
//magnitude_est_cu8(iq_buf, demod->buf.temp, n_samples);
} else { // CS16
//magnitude_true_cs16((int16_t *)iq_buf, demod->buf.temp, n_samples);
magnitude_est_cs16((int16_t *)iq_buf, demod->buf.temp, n_samples);
}
baseband_low_pass_filter(demod->buf.temp, demod->am_buf, n_samples, &demod->lowpass_filter_state);
// FM demodulation
if (demod->enable_FM_demod) {
baseband_demod_FM(iq_buf, demod->buf.fm, len/2, &demod->demod_FM_state);
if (demod->sample_size == 1) { // CU8
baseband_demod_FM(iq_buf, demod->buf.fm, n_samples, &demod->demod_FM_state);
} else { // CS16
baseband_demod_FM_cs16((int16_t *)iq_buf, demod->buf.fm, n_samples, &demod->demod_FM_state);
}
}
// Handle special input formats
if (demod->load_mode == 1) { // The IQ buffer is really AM demodulated data
memcpy(demod->am_buf, iq_buf, len);
} else if (demod->load_mode == 2) { // The IQ buffer is really FM demodulated data
// we would need AM for the envelope too
memcpy(demod->buf.fm, iq_buf, len);
}
if (demod->analyze || (demod->out_file == stdout)) { // We don't want to decode devices when outputting to stdout
pwm_analyze(demod, demod->am_buf, len / 2);
pwm_analyze(demod, demod->am_buf, n_samples);
} else {
// Detect a package and loop through demodulators with pulse data
int package_type = 1; // Just to get us started
int p_events = 0; // Sensor events successfully detected per package
while (package_type) {
package_type = pulse_detect_package(demod->am_buf, demod->buf.fm, len/2, demod->level_limit, samp_rate, &demod->pulse_data, &demod->fsk_pulse_data);
package_type = pulse_detect_package(demod->am_buf, demod->buf.fm, n_samples, demod->level_limit, samp_rate, &demod->pulse_data, &demod->fsk_pulse_data);
if (package_type == 1) {
if (demod->analyze_pulses) fprintf(stderr, "Detected OOK package\t@ %s\n", local_time_str(0, time_str));
for (i = 0; i < demod->r_dev_num; i++) {
@@ -824,12 +840,15 @@ static void rtlsdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) {
if (demod->out_file) {
uint8_t *out_buf = iq_buf; // Default is to dump IQ samples
unsigned long out_len = n_samples * 2 * demod->sample_size;
if (demod->dump_mode == 1) { // AM data
out_buf = (uint8_t*)demod->am_buf;
out_len = n_samples * sizeof(int16_t);
} else if (demod->dump_mode == 2) { // FM data
out_buf = (uint8_t*)demod->buf.fm;
out_len = n_samples * sizeof(int16_t);
}
if (fwrite(out_buf, 1, len, demod->out_file) != len) {
if (fwrite(out_buf, 1, out_len, demod->out_file) != out_len) {
fprintf(stderr, "Short write, samples lost, exiting!\n");
rtlsdr_cancel_async(dev);
}
@@ -1072,6 +1091,10 @@ int main(int argc, char **argv) {
break;
case 'r':
in_filename = optarg;
if (loaddump_mode == 2) {
fprintf(stderr, "FM input not supported\n");
usage(devices);
}
demod->load_mode = loaddump_mode;
break;
case 't':
@@ -1079,7 +1102,7 @@ int main(int argc, char **argv) {
break;
case 'm':
loaddump_mode = atoi(optarg);
if (loaddump_mode < 0 || loaddump_mode > 3) {
if (loaddump_mode < 0 || loaddump_mode > 4) {
fprintf(stderr, "Invalid sample mode %s\n", optarg);
usage(devices);
}
@@ -1275,6 +1298,7 @@ int main(int argc, char **argv) {
} else {
if (!quiet_mode) fprintf(stderr, "Using device %d: %s\n",
i, rtlsdr_get_device_name(i));
demod->sample_size = sizeof(uint8_t); // CU8
break;
}
}
@@ -1352,9 +1376,8 @@ int main(int argc, char **argv) {
demod->sg_buf = malloc(SIGNAL_GRABBER_BUFFER);
if (in_filename) {
int i = 0;
unsigned char *test_mode_buf = malloc(DEFAULT_BUF_LENGTH * sizeof(unsigned char));
float *test_mode_float_buf = malloc(DEFAULT_BUF_LENGTH * sizeof(float));
float *test_mode_float_buf = malloc(DEFAULT_BUF_LENGTH / sizeof(int16_t) * sizeof(float));
if (!test_mode_buf || !test_mode_float_buf)
{
fprintf(stderr, "Couldn't allocate read buffers!\n");
@@ -1371,30 +1394,45 @@ int main(int argc, char **argv) {
}
}
fprintf(stderr, "Test mode active. Reading samples from file: %s\n", in_filename); // Essential information (not quiet)
if (demod->load_mode < 3) {
demod->sample_size = sizeof(uint8_t); // CU8, AM, FM
} else {
demod->sample_size = sizeof(int16_t); // CF32, CS16
}
if (!quiet_mode) {
fprintf(stderr, "Input format: %s\n", (demod->load_mode == 3) ? "2ch cf32" : "2ch uint8 / 1ch uint16");
char *load_mode_str;
switch (demod->load_mode) {
case 0: load_mode_str = "CU8 (2ch uint8)"; break;
case 1: load_mode_str = "S16 AM (1ch int16)"; break;
case 2: load_mode_str = "S16 FM (1ch int16)"; break;
case 3: load_mode_str = "CF32 (2ch Float32)"; break;
case 4: load_mode_str = "CS16 (2ch int16)"; break;
}
fprintf(stderr, "Input format: %s\n", load_mode_str);
}
sample_file_pos = 0.0;
int n_read, cf32_tmp;
int n_blocks = 0;
unsigned long n_read;
do {
if (demod->load_mode == 3) {
n_read = fread(test_mode_float_buf, sizeof(float), DEFAULT_BUF_LENGTH, in_file);
for(int n = 0; n < n_read; n++) {
cf32_tmp = test_mode_float_buf[n]*127 + 127;
if (cf32_tmp < 0)
cf32_tmp = 0;
else if (cf32_tmp > 255)
cf32_tmp = 255;
test_mode_buf[n] = (uint8_t)cf32_tmp;
n_read = fread(test_mode_float_buf, sizeof(float), DEFAULT_BUF_LENGTH / 2, in_file);
// clamp float to [-1,1] and scale to Q0.15
for(unsigned long n = 0; n < n_read; n++) {
int s_tmp = test_mode_float_buf[n] * INT16_MAX;
if (s_tmp < -INT16_MAX)
s_tmp = -INT16_MAX;
else if (s_tmp > INT16_MAX)
s_tmp = INT16_MAX;
test_mode_buf[n] = (int16_t)s_tmp;
}
} else {
n_read = fread(test_mode_buf, 1, DEFAULT_BUF_LENGTH, in_file);
}
if (n_read == 0) break; // rtlsdr_callback() will Segmentation Fault with len=0
rtlsdr_callback(test_mode_buf, n_read, demod);
i++;
sample_file_pos = (float)i * n_read / samp_rate / 2;
n_blocks++;
sample_file_pos = (float)n_blocks * n_read / samp_rate / 2 / demod->sample_size;
} while (n_read != 0);
// Call a last time with cleared samples to ensure EOP detection

View File

@@ -66,7 +66,6 @@ int main(int argc, char *argv[])
uint32_t *u32_buf;
int16_t *s16_buf;
int32_t *s32_buf;
int fd;
char *filename;
long n_read;
unsigned long n_samples;
@@ -95,6 +94,8 @@ int main(int argc, char *argv[])
n_samples = n_read / (sizeof(uint8_t) * 2);
for (unsigned long i = 0; i < n_samples * 2; i++) {
//cs16_buf[i] = 127 - cu8_buf[i];
//cs16_buf[i] = (int16_t)cu8_buf[i] * 16 - 2040;
cs16_buf[i] = (int16_t)cu8_buf[i] * 128 - 16320;
//cs16_buf[i] = (int16_t)cu8_buf[i] * 256 - 32640;
}
@@ -111,21 +112,21 @@ int main(int argc, char *argv[])
MEASURE("magnitude_true_cu8",
magnitude_true_cu8(cu8_buf, y16_buf, n_samples);
);
write_buf("bb_am.u16", y16_buf, sizeof(uint16_t) * n_samples);
write_buf("bb.am.s16", y16_buf, sizeof(uint16_t) * n_samples);
MEASURE("baseband_low_pass_filter",
baseband_low_pass_filter(y16_buf, (int16_t *)u16_buf, n_samples, &state);
);
write_buf("bb_am.lp.u16", u16_buf, sizeof(int16_t) * n_samples);
write_buf("bb.lp.am.s16", u16_buf, sizeof(int16_t) * n_samples);
MEASURE("baseband_demod_FM",
baseband_demod_FM(cu8_buf, s16_buf, n_samples, &fm_state);
);
write_buf("bb_fm.s16", s16_buf, sizeof(int16_t) * n_samples);
write_buf("bb.fm.s16", s16_buf, sizeof(int16_t) * n_samples);
write_buf("bb.cs16", cs16_buf, sizeof(int16_t) * 2 * n_samples);
//envelope_detect_cs16(cs16_buf, y32_buf, n_samples);
//write_buf("bb_am.u32", y32_buf, sizeof(uint32_t) * n_samples);
//write_buf("bb.am.u32", y32_buf, sizeof(uint32_t) * n_samples);
//baseband_low_pass_filter_u32(y32_buf, u32_buf, n_samples, &state);
//write_buf("bb_am.lp.u32", u32_buf, sizeof(uint32_t) * n_samples);
//write_buf("bb.lp.am.u32", u32_buf, sizeof(uint32_t) * n_samples);
MEASURE("magnitude_est_cs16",
magnitude_est_cs16(cs16_buf, y16_buf, n_samples);
@@ -133,17 +134,17 @@ int main(int argc, char *argv[])
MEASURE("magnitude_true_cs16",
magnitude_true_cs16(cs16_buf, y16_buf, n_samples);
);
write_buf("bb_m.u16", y16_buf, sizeof(uint16_t) * n_samples);
write_buf("bb.mag.s16", y16_buf, sizeof(uint16_t) * n_samples);
MEASURE("baseband_low_pass_filter",
baseband_low_pass_filter(y16_buf, (int16_t *)u16_buf, n_samples, &state);
);
write_buf("bb_m.lp.u16", u16_buf, sizeof(int16_t) * n_samples);
write_buf("bb.mag.lp.s16", u16_buf, sizeof(int16_t) * n_samples);
//baseband_demod_FM_cs16(cs16_buf, s32_buf, n_samples, &fm_state);
//write_buf("bb_fm.s32", s32_buf, sizeof(int32_t) * n_samples);
//write_buf("bb.fm.s32", s32_buf, sizeof(int32_t) * n_samples);
MEASURE("baseband_demod_FM_cs16",
baseband_demod_FM_cs16(cs16_buf, s16_buf, n_samples, &fm_state);
);
write_buf("bb_fm.cs16.s16", s16_buf, sizeof(int16_t) * n_samples);
write_buf("bb.cs16.fm.s16", s16_buf, sizeof(int16_t) * n_samples);
}