mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-09 15:27:22 -05:00
Add rtl_tcp input: -i rtltcp:host:port:freq:gain:ppm:bw:sq:vol
This commit is contained in:
@@ -134,6 +134,7 @@ FILE(GLOB HEADERS include/*.h include/*.hpp)
|
|||||||
|
|
||||||
if(NOT RTLSDR_FOUND)
|
if(NOT RTLSDR_FOUND)
|
||||||
list(REMOVE_ITEM SRCS ${CMAKE_CURRENT_SOURCE_DIR}/src/rtl_sdr_fm.cpp)
|
list(REMOVE_ITEM SRCS ${CMAKE_CURRENT_SOURCE_DIR}/src/rtl_sdr_fm.cpp)
|
||||||
|
list(REMOVE_ITEM SRCS ${CMAKE_CURRENT_SOURCE_DIR}/src/rtl_sdr_tcp.c)
|
||||||
endif(NOT RTLSDR_FOUND)
|
endif(NOT RTLSDR_FOUND)
|
||||||
|
|
||||||
configure_file("src/git_ver.c.in" "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c" @ONLY)
|
configure_file("src/git_ver.c.in" "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c" @ONLY)
|
||||||
|
|||||||
@@ -372,6 +372,9 @@ typedef struct
|
|||||||
int rtl_bandwidth;
|
int rtl_bandwidth;
|
||||||
int rtl_started;
|
int rtl_started;
|
||||||
long int rtl_rms;
|
long int rtl_rms;
|
||||||
|
int rtltcp_enabled;
|
||||||
|
char rtltcp_hostname[1024];
|
||||||
|
int rtltcp_portno;
|
||||||
int monitor_input_audio;
|
int monitor_input_audio;
|
||||||
int analog_only;
|
int analog_only;
|
||||||
int pulse_raw_rate_in;
|
int pulse_raw_rate_in;
|
||||||
@@ -1707,6 +1710,21 @@ void rtlsdr_sighandler();
|
|||||||
void rtl_dev_tune(dsd_opts * opts, long int frequency);
|
void rtl_dev_tune(dsd_opts * opts, long int frequency);
|
||||||
long int rtl_return_rms();
|
long int rtl_return_rms();
|
||||||
void rtl_clean_queue();
|
void rtl_clean_queue();
|
||||||
|
|
||||||
|
//rtl_tcp client (rtl_sdr_tcp.c)
|
||||||
|
int rtltcp_open(const char *hostname, int portno);
|
||||||
|
int rtlsdr_or_tcp_close(rtlsdr_dev_t *dev);
|
||||||
|
int rtlsdr_or_tcp_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx, uint32_t buf_num, uint32_t buf_len);
|
||||||
|
int rtlsdr_or_tcp_cancel_async(rtlsdr_dev_t *dev);
|
||||||
|
int rtlsdr_or_tcp_reset_buffer(rtlsdr_dev_t *dev);
|
||||||
|
int rtlsdr_or_tcp_get_tuner_gains(rtlsdr_dev_t *dev, int *gains);
|
||||||
|
int rtlsdr_or_tcp_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq);
|
||||||
|
int rtlsdr_or_tcp_set_sample_rate(rtlsdr_dev_t *dev, uint32_t rate);
|
||||||
|
int rtlsdr_or_tcp_set_direct_sampling(rtlsdr_dev_t *dev, int on);
|
||||||
|
int rtlsdr_or_tcp_set_offset_tuning(rtlsdr_dev_t *dev, int on);
|
||||||
|
int rtlsdr_or_tcp_set_tuner_gain_mode(rtlsdr_dev_t *dev, int manual);
|
||||||
|
int rtlsdr_or_tcp_set_tuner_gain(rtlsdr_dev_t *dev, int gain);
|
||||||
|
int rtlsdr_or_tcp_set_freq_correction(rtlsdr_dev_t *dev, int ppm);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -695,6 +695,9 @@
|
|||||||
opts->rtlsdr_center_freq = 850000000; //set to an initial value (if user is using a channel map, then they won't need to specify anything other than -i rtl if desired)
|
opts->rtlsdr_center_freq = 850000000; //set to an initial value (if user is using a channel map, then they won't need to specify anything other than -i rtl if desired)
|
||||||
opts->rtl_started = 0;
|
opts->rtl_started = 0;
|
||||||
opts->rtl_rms = 0; //root means square power level on rtl input signal
|
opts->rtl_rms = 0; //root means square power level on rtl input signal
|
||||||
|
opts->rtltcp_enabled = 0; //1 when the rtl input is an rtl_tcp server instead of a local dongle
|
||||||
|
sprintf (opts->rtltcp_hostname, "%s", "localhost");
|
||||||
|
opts->rtltcp_portno = 1234; //rtl_tcp default port
|
||||||
//end RTL user options
|
//end RTL user options
|
||||||
opts->pulse_raw_rate_in = 48000;
|
opts->pulse_raw_rate_in = 48000;
|
||||||
opts->pulse_raw_rate_out = 48000;//
|
opts->pulse_raw_rate_out = 48000;//
|
||||||
@@ -1406,6 +1409,7 @@
|
|||||||
printf (" pulse:6 or pulse:virtual_sink2.monitor for pulse audio signal input on virtual_sink2 (see -O) \n");
|
printf (" pulse:6 or pulse:virtual_sink2.monitor for pulse audio signal input on virtual_sink2 (see -O) \n");
|
||||||
printf (" rtl for rtl dongle (Default Values -- see below)\n");
|
printf (" rtl for rtl dongle (Default Values -- see below)\n");
|
||||||
printf (" rtl:dev:freq:gain:ppm:bw:sq:vol for rtl dongle (see below)\n");
|
printf (" rtl:dev:freq:gain:ppm:bw:sq:vol for rtl dongle (see below)\n");
|
||||||
|
printf (" rtltcp:host:port:freq:gain:ppm:bw:sq:vol for rtl dongle on an rtl_tcp server (see below)\n");
|
||||||
printf (" tcp for tcp client SDR++/GNURadio Companion/Other (Port 7355)\n");
|
printf (" tcp for tcp client SDR++/GNURadio Companion/Other (Port 7355)\n");
|
||||||
printf (" tcp:192.168.7.5:7355 for custom address and port \n");
|
printf (" tcp:192.168.7.5:7355 for custom address and port \n");
|
||||||
printf (" filename.bin for OP25/FME capture bin files\n");
|
printf (" filename.bin for OP25/FME capture bin files\n");
|
||||||
@@ -1477,6 +1481,11 @@
|
|||||||
printf (" vol <num> RTL-SDR Sample 'Volume' Multiplier (default = 2)(1,2,3)\n");
|
printf (" vol <num> RTL-SDR Sample 'Volume' Multiplier (default = 2)(1,2,3)\n");
|
||||||
printf (" Example: dsd-fme -fs -i rtl -C cap_plus_channel.csv -T\n");
|
printf (" Example: dsd-fme -fs -i rtl -C cap_plus_channel.csv -T\n");
|
||||||
printf (" Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:24:0:2\n");
|
printf (" Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:24:0:2\n");
|
||||||
|
printf (" Usage: rtltcp:host:port:freq:gain:ppm:bw:sq:vol\n");
|
||||||
|
printf (" host <name> rtl_tcp Server Hostname or IP Address (default = localhost)\n");
|
||||||
|
printf (" port <num> rtl_tcp Server Port (default = 1234)\n");
|
||||||
|
printf (" freq, gain, ppm, bw, sq, vol as above\n");
|
||||||
|
printf (" Example: dsd-fme -fs -i rtltcp:192.168.1.10:1234:450M:26:-2:8 -C connect_plus_chan.csv -T\n");
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
printf ("Decoder options:\n");
|
printf ("Decoder options:\n");
|
||||||
printf (" -fa Auto Detection\n");
|
printf (" -fa Auto Detection\n");
|
||||||
@@ -3281,9 +3290,24 @@
|
|||||||
if (curr != NULL) ; //continue
|
if (curr != NULL) ; //continue
|
||||||
else goto RTLEND; //end early with preset values
|
else goto RTLEND; //end early with preset values
|
||||||
|
|
||||||
curr = strtok(NULL, ":"); //rtl device number "-D"
|
if (strcmp (curr, "rtltcp") == 0) //rtl_tcp server instead of a local dongle
|
||||||
if (curr != NULL) opts.rtl_dev_index = atoi (curr);
|
{
|
||||||
else goto RTLEND;
|
opts.rtltcp_enabled = 1;
|
||||||
|
|
||||||
|
curr = strtok(NULL, ":"); //rtl_tcp hostname
|
||||||
|
if (curr != NULL) snprintf (opts.rtltcp_hostname, sizeof(opts.rtltcp_hostname), "%s", curr);
|
||||||
|
else goto RTLEND;
|
||||||
|
|
||||||
|
curr = strtok(NULL, ":"); //rtl_tcp port
|
||||||
|
if (curr != NULL) opts.rtltcp_portno = atoi (curr);
|
||||||
|
else goto RTLEND;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curr = strtok(NULL, ":"); //rtl device number "-D"
|
||||||
|
if (curr != NULL) opts.rtl_dev_index = atoi (curr);
|
||||||
|
else goto RTLEND;
|
||||||
|
}
|
||||||
|
|
||||||
curr = strtok(NULL, ":"); //rtl freq "-c"
|
curr = strtok(NULL, ":"); //rtl freq "-c"
|
||||||
if (curr != NULL) opts.rtlsdr_center_freq = (uint32_t)atofs(curr);
|
if (curr != NULL) opts.rtlsdr_center_freq = (uint32_t)atofs(curr);
|
||||||
@@ -3326,6 +3350,8 @@
|
|||||||
|
|
||||||
RTLEND:
|
RTLEND:
|
||||||
|
|
||||||
|
if (opts.rtltcp_enabled == 1) goto RTLTCPEND; //no local dongle to look for
|
||||||
|
|
||||||
device_count = rtlsdr_get_device_count();
|
device_count = rtlsdr_get_device_count();
|
||||||
if (!device_count)
|
if (!device_count)
|
||||||
{
|
{
|
||||||
@@ -3353,10 +3379,15 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RTLTCPEND:
|
||||||
|
|
||||||
if (opts.rtl_volume_multiplier > 3 || opts.rtl_volume_multiplier < 0)
|
if (opts.rtl_volume_multiplier > 3 || opts.rtl_volume_multiplier < 0)
|
||||||
opts.rtl_volume_multiplier = 1; //I wonder if you could flip polarity by using -1
|
opts.rtl_volume_multiplier = 1; //I wonder if you could flip polarity by using -1
|
||||||
|
|
||||||
fprintf (stderr, "Dev %d ", opts.rtl_dev_index);
|
if (opts.rtltcp_enabled == 1)
|
||||||
|
fprintf (stderr, "rtl_tcp %s:%d ", opts.rtltcp_hostname, opts.rtltcp_portno);
|
||||||
|
else
|
||||||
|
fprintf (stderr, "Dev %d ", opts.rtl_dev_index);
|
||||||
fprintf (stderr, "Freq %d ", opts.rtlsdr_center_freq);
|
fprintf (stderr, "Freq %d ", opts.rtlsdr_center_freq);
|
||||||
fprintf (stderr, "Gain %d ", opts.rtl_gain_value);
|
fprintf (stderr, "Gain %d ", opts.rtl_gain_value);
|
||||||
fprintf (stderr, "PPM %d ", opts.rtlsdr_ppm_error);
|
fprintf (stderr, "PPM %d ", opts.rtlsdr_ppm_error);
|
||||||
|
|||||||
@@ -567,7 +567,7 @@ static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
|
|||||||
static void *dongle_thread_fn(void *arg)
|
static void *dongle_thread_fn(void *arg)
|
||||||
{
|
{
|
||||||
struct dongle_state *s = static_cast<dongle_state*>(arg);
|
struct dongle_state *s = static_cast<dongle_state*>(arg);
|
||||||
rtlsdr_read_async(s->dev, rtlsdr_callback, s, 0, s->buf_len);
|
rtlsdr_or_tcp_read_async(s->dev, rtlsdr_callback, s, 0, s->buf_len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,17 +604,17 @@ int nearest_gain(rtlsdr_dev_t *dev, int target_gain)
|
|||||||
{
|
{
|
||||||
int i, r, err1, err2, count, nearest;
|
int i, r, err1, err2, count, nearest;
|
||||||
int* gains;
|
int* gains;
|
||||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
r = rtlsdr_or_tcp_set_tuner_gain_mode(dev, 1);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to enable manual gain.\n");
|
fprintf (stderr, "WARNING: Failed to enable manual gain.\n");
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
count = rtlsdr_get_tuner_gains(dev, NULL);
|
count = rtlsdr_or_tcp_get_tuner_gains(dev, NULL);
|
||||||
if (count <= 0) {
|
if (count <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
gains = static_cast<int*>(malloc(sizeof(int) * count));
|
gains = static_cast<int*>(malloc(sizeof(int) * count));
|
||||||
count = rtlsdr_get_tuner_gains(dev, gains);
|
count = rtlsdr_or_tcp_get_tuner_gains(dev, gains);
|
||||||
nearest = gains[0];
|
nearest = gains[0];
|
||||||
for (i=0; i<count; i++) {
|
for (i=0; i<count; i++) {
|
||||||
err1 = abs(target_gain - nearest);
|
err1 = abs(target_gain - nearest);
|
||||||
@@ -634,7 +634,7 @@ int verbose_set_frequency(rtlsdr_dev_t *dev, uint32_t frequency)
|
|||||||
//spam tuning
|
//spam tuning
|
||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 20; i++)
|
||||||
{
|
{
|
||||||
r = rtlsdr_set_center_freq(dev, frequency);
|
r = rtlsdr_or_tcp_set_center_freq(dev, frequency);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
fprintf (stderr, " (RETRY: Failed to set Center Frequency %u). \n", dongle.freq);
|
fprintf (stderr, " (RETRY: Failed to set Center Frequency %u). \n", dongle.freq);
|
||||||
else
|
else
|
||||||
@@ -650,7 +650,7 @@ int verbose_set_frequency(rtlsdr_dev_t *dev, uint32_t frequency)
|
|||||||
int verbose_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate)
|
int verbose_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = rtlsdr_set_sample_rate(dev, samp_rate);
|
r = rtlsdr_or_tcp_set_sample_rate(dev, samp_rate);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to set sample rate.\n");
|
fprintf (stderr, "WARNING: Failed to set sample rate.\n");
|
||||||
} else {
|
} else {
|
||||||
@@ -662,7 +662,7 @@ int verbose_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate)
|
|||||||
int verbose_direct_sampling(rtlsdr_dev_t *dev, int on)
|
int verbose_direct_sampling(rtlsdr_dev_t *dev, int on)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = rtlsdr_set_direct_sampling(dev, on);
|
r = rtlsdr_or_tcp_set_direct_sampling(dev, on);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to set direct sampling mode.\n");
|
fprintf (stderr, "WARNING: Failed to set direct sampling mode.\n");
|
||||||
return r;
|
return r;
|
||||||
@@ -679,7 +679,7 @@ int verbose_direct_sampling(rtlsdr_dev_t *dev, int on)
|
|||||||
int verbose_offset_tuning(rtlsdr_dev_t *dev)
|
int verbose_offset_tuning(rtlsdr_dev_t *dev)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = rtlsdr_set_offset_tuning(dev, 1);
|
r = rtlsdr_or_tcp_set_offset_tuning(dev, 1);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to set offset tuning.\n");
|
fprintf (stderr, "WARNING: Failed to set offset tuning.\n");
|
||||||
} else {
|
} else {
|
||||||
@@ -691,7 +691,7 @@ int verbose_offset_tuning(rtlsdr_dev_t *dev)
|
|||||||
int verbose_auto_gain(rtlsdr_dev_t *dev)
|
int verbose_auto_gain(rtlsdr_dev_t *dev)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = rtlsdr_set_tuner_gain_mode(dev, 0);
|
r = rtlsdr_or_tcp_set_tuner_gain_mode(dev, 0);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to set tuner gain.\n");
|
fprintf (stderr, "WARNING: Failed to set tuner gain.\n");
|
||||||
} else {
|
} else {
|
||||||
@@ -703,12 +703,12 @@ int verbose_auto_gain(rtlsdr_dev_t *dev)
|
|||||||
int verbose_gain_set(rtlsdr_dev_t *dev, int gain)
|
int verbose_gain_set(rtlsdr_dev_t *dev, int gain)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
r = rtlsdr_or_tcp_set_tuner_gain_mode(dev, 1);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to enable manual gain.\n");
|
fprintf (stderr, "WARNING: Failed to enable manual gain.\n");
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
r = rtlsdr_set_tuner_gain(dev, gain);
|
r = rtlsdr_or_tcp_set_tuner_gain(dev, gain);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to set tuner gain.\n");
|
fprintf (stderr, "WARNING: Failed to set tuner gain.\n");
|
||||||
} else {
|
} else {
|
||||||
@@ -722,7 +722,7 @@ int verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error)
|
|||||||
int r;
|
int r;
|
||||||
// if (ppm_error == 0) {
|
// if (ppm_error == 0) {
|
||||||
// return 0;}
|
// return 0;}
|
||||||
r = rtlsdr_set_freq_correction(dev, ppm_error);
|
r = rtlsdr_or_tcp_set_freq_correction(dev, ppm_error);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to set ppm error.\n");
|
fprintf (stderr, "WARNING: Failed to set ppm error.\n");
|
||||||
} else {
|
} else {
|
||||||
@@ -734,7 +734,7 @@ int verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error)
|
|||||||
int verbose_reset_buffer(rtlsdr_dev_t *dev)
|
int verbose_reset_buffer(rtlsdr_dev_t *dev)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = rtlsdr_reset_buffer(dev);
|
r = rtlsdr_or_tcp_reset_buffer(dev);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf (stderr, "WARNING: Failed to reset buffers.\n");}
|
fprintf (stderr, "WARNING: Failed to reset buffers.\n");}
|
||||||
return r;
|
return r;
|
||||||
@@ -807,7 +807,7 @@ static void *controller_thread_fn(void *arg)
|
|||||||
/* hacky hopping */
|
/* hacky hopping */
|
||||||
s->freq_now = (s->freq_now + 1) % s->freq_len;
|
s->freq_now = (s->freq_now + 1) % s->freq_len;
|
||||||
optimal_settings(s->freqs[s->freq_now], demod.rate_in);
|
optimal_settings(s->freqs[s->freq_now], demod.rate_in);
|
||||||
rtlsdr_set_center_freq(dongle.dev, dongle.freq);
|
rtlsdr_or_tcp_set_center_freq(dongle.dev, dongle.freq);
|
||||||
dongle.mute = BUFFER_DUMP;
|
dongle.mute = BUFFER_DUMP;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1012,7 +1012,7 @@ static void *socket_thread_fn(void *arg) {
|
|||||||
new_freq = chars_to_int(buffer);
|
new_freq = chars_to_int(buffer);
|
||||||
dongle.freq = new_freq;
|
dongle.freq = new_freq;
|
||||||
optimal_settings(new_freq, demod.rate_in);
|
optimal_settings(new_freq, demod.rate_in);
|
||||||
rtlsdr_set_center_freq(dongle.dev, dongle.freq);
|
rtlsdr_or_tcp_set_center_freq(dongle.dev, dongle.freq);
|
||||||
fprintf (stderr, "\nTuning to: %d [Hz] \n", new_freq);
|
fprintf (stderr, "\nTuning to: %d [Hz] \n", new_freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1027,7 +1027,7 @@ static void *socket_thread_fn(void *arg) {
|
|||||||
void rtlsdr_sighandler()
|
void rtlsdr_sighandler()
|
||||||
{
|
{
|
||||||
fprintf (stderr, "Signal caught, exiting!\n");
|
fprintf (stderr, "Signal caught, exiting!\n");
|
||||||
rtlsdr_cancel_async(dongle.dev);
|
rtlsdr_or_tcp_cancel_async(dongle.dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_rtlsdr_stream(dsd_opts *opts)
|
void open_rtlsdr_stream(dsd_opts *opts)
|
||||||
@@ -1080,14 +1080,23 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
|||||||
|
|
||||||
ACTUAL_BUF_LENGTH = lcm_post[demod.post_downsample] * DEFAULT_BUF_LENGTH;
|
ACTUAL_BUF_LENGTH = lcm_post[demod.post_downsample] * DEFAULT_BUF_LENGTH;
|
||||||
|
|
||||||
r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index);
|
if (opts->rtltcp_enabled == 1)
|
||||||
if (r < 0)
|
|
||||||
{
|
{
|
||||||
fprintf (stderr, "Failed to open rtlsdr device %d.\n", dongle.dev_index);
|
if (rtltcp_open(opts->rtltcp_hostname, opts->rtltcp_portno) < 0)
|
||||||
exit(1);
|
//rtltcp_open prints its own error messages
|
||||||
} else {
|
exit(1);
|
||||||
fprintf (stderr, "Using RTLSDR Device Index: %d. \n", dongle.dev_index);
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index);
|
||||||
|
if (r < 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Failed to open rtlsdr device %d.\n", dongle.dev_index);
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
fprintf (stderr, "Using RTLSDR Device Index: %d. \n", dongle.dev_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (demod.deemph) {
|
if (demod.deemph) {
|
||||||
demod.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(demod.rate_out * 75e-6)))));
|
demod.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(demod.rate_out * 75e-6)))));
|
||||||
@@ -1119,7 +1128,7 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
|||||||
void cleanup_rtlsdr_stream()
|
void cleanup_rtlsdr_stream()
|
||||||
{
|
{
|
||||||
fprintf (stderr, "cleaning up...\n");
|
fprintf (stderr, "cleaning up...\n");
|
||||||
rtlsdr_cancel_async(dongle.dev);
|
rtlsdr_or_tcp_cancel_async(dongle.dev);
|
||||||
pthread_join(dongle.thread, NULL);
|
pthread_join(dongle.thread, NULL);
|
||||||
safe_cond_signal(&demod.ready, &demod.ready_m);
|
safe_cond_signal(&demod.ready, &demod.ready_m);
|
||||||
pthread_join(demod.thread, NULL);
|
pthread_join(demod.thread, NULL);
|
||||||
@@ -1132,7 +1141,7 @@ void cleanup_rtlsdr_stream()
|
|||||||
output_cleanup(&output);
|
output_cleanup(&output);
|
||||||
controller_cleanup(&controller);
|
controller_cleanup(&controller);
|
||||||
|
|
||||||
rtlsdr_close(dongle.dev);
|
rtlsdr_or_tcp_close(dongle.dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
//original for safe keeping
|
//original for safe keeping
|
||||||
@@ -1241,7 +1250,7 @@ void rtl_dev_tune(dsd_opts * opts, long int frequency)
|
|||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 20; i++)
|
||||||
{
|
{
|
||||||
int r = -1;
|
int r = -1;
|
||||||
r = rtlsdr_set_center_freq(dongle.dev, dongle.freq);
|
r = rtlsdr_or_tcp_set_center_freq(dongle.dev, dongle.freq);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
fprintf (stderr, " (RETRY: Failed to set Center Frequency %u). \n", dongle.freq);
|
fprintf (stderr, " (RETRY: Failed to set Center Frequency %u). \n", dongle.freq);
|
||||||
else break;
|
else break;
|
||||||
|
|||||||
247
src/rtl_sdr_tcp.c
Normal file
247
src/rtl_sdr_tcp.c
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
/*-------------------------------------------------------------------------------
|
||||||
|
* rtl_sdr_tcp.c
|
||||||
|
* rtl_tcp client for the RTL-SDR input: samples arrive on a TCP socket, and tuner commands are sent back on it
|
||||||
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "dsd.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
//MSG_NOSIGNAL is missing before macOS 11; SO_NOSIGPIPE in rtltcp_open keeps send from raising SIGPIPE there
|
||||||
|
#ifndef MSG_NOSIGNAL
|
||||||
|
#define MSG_NOSIGNAL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//rtlsdr_read_async's default block size, in bytes
|
||||||
|
#define RTLTCP_BUF_LENGTH (16 * 32 * 512)
|
||||||
|
|
||||||
|
//rtl_tcp state: socket, tuner type, and a mutex that keeps commands from different threads from interleaving
|
||||||
|
//NOTE: Keeping these as static global is not great. They really should be in some kind of opaque handle
|
||||||
|
// like rtl_tcp_dev_t or something. For applications that only use one device at a time, this is fine.
|
||||||
|
// But if we ever move to supporting multiple simultaneous RTL tuners, this will need to change.
|
||||||
|
static int rtltcp_sock = -1;
|
||||||
|
static int rtltcp_tuner_type = RTLSDR_TUNER_UNKNOWN; //from the server's greeting
|
||||||
|
static pthread_mutex_t rtltcp_m = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
//rtl_tcp command bytes, each named after the librtlsdr function the server calls with the parameter
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
RTLTCP_SET_CENTER_FREQ = 0x01,
|
||||||
|
RTLTCP_SET_SAMPLE_RATE = 0x02,
|
||||||
|
RTLTCP_SET_TUNER_GAIN_MODE = 0x03,
|
||||||
|
RTLTCP_SET_TUNER_GAIN = 0x04,
|
||||||
|
RTLTCP_SET_FREQ_CORRECTION = 0x05,
|
||||||
|
RTLTCP_SET_DIRECT_SAMPLING = 0x09,
|
||||||
|
RTLTCP_SET_OFFSET_TUNING = 0x0a
|
||||||
|
};
|
||||||
|
|
||||||
|
//send one rtl_tcp command: a command byte followed by a 32-bit big-endian parameter.
|
||||||
|
//A partly sent command would misalign every later one, so a failed send ends the connection.
|
||||||
|
static int rtltcp_command(uint8_t cmd, uint32_t param)
|
||||||
|
{
|
||||||
|
//encode command and parameter to send to rtl_tcp
|
||||||
|
unsigned char buf[5] = {cmd, (unsigned char)(param >> 24), (unsigned char)(param >> 16), (unsigned char)(param >> 8), (unsigned char)param};
|
||||||
|
|
||||||
|
size_t sent = 0;
|
||||||
|
pthread_mutex_lock(&rtltcp_m);
|
||||||
|
while (sent < 5) {
|
||||||
|
ssize_t n = send(rtltcp_sock, buf + sent, 5 - sent, MSG_NOSIGNAL);
|
||||||
|
if (n < 0 && errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (n <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sent += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
//a failed or partial send ends the connection
|
||||||
|
if (sent < 5) {
|
||||||
|
shutdown(rtltcp_sock, SHUT_RDWR);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&rtltcp_m);
|
||||||
|
return sent < 5 ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//connect to an rtl_tcp server over IPv4 or IPv6, read its greeting, and store the socket in rtltcp_sock; prints the outcome and returns 0, or -1 on failure
|
||||||
|
int rtltcp_open(const char *hostname, int portno)
|
||||||
|
{
|
||||||
|
struct addrinfo hints, *res, *ai;
|
||||||
|
char portstr[16];
|
||||||
|
unsigned char header[12];
|
||||||
|
int sock = -1;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
snprintf(portstr, sizeof(portstr), "%d", portno);
|
||||||
|
if (getaddrinfo(hostname, portstr, &hints, &res) != 0) {
|
||||||
|
fprintf (stderr, "Failed to resolve rtl_tcp server %s.\n", hostname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//try each resolved address in turn until one connects
|
||||||
|
for (ai = res; ai != NULL; ai = ai->ai_next) {
|
||||||
|
//socket creation
|
||||||
|
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||||
|
if (sock < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//connect
|
||||||
|
if (connect(sock, ai->ai_addr, ai->ai_addrlen) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//close socket and retry with different address
|
||||||
|
close(sock);
|
||||||
|
sock = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(res);
|
||||||
|
if (sock < 0) {
|
||||||
|
fprintf (stderr, "Failed to connect to rtl_tcp server %s:%d.\n", hostname, portno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SO_NOSIGPIPE
|
||||||
|
//macOS and the BSDs: a send to a closed connection returns an error instead of raising SIGPIPE
|
||||||
|
int one = 1;
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//the greeting is "RTL0", the tuner type, and the number of tuner gain steps
|
||||||
|
if (recv(sock, header, 12, MSG_WAITALL) != 12 || memcmp(header, "RTL0", 4) != 0) {
|
||||||
|
fprintf (stderr, "%s:%d did not send an rtl_tcp greeting.\n", hostname, portno);
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//socket is valid and ready to use
|
||||||
|
rtltcp_sock = sock;
|
||||||
|
|
||||||
|
//store tuner type for later use in rtltcp_get_tuner_gains
|
||||||
|
rtltcp_tuner_type = ((uint32_t)header[4] << 24) | ((uint32_t)header[5] << 16) | ((uint32_t)header[6] << 8) | header[7];
|
||||||
|
fprintf (stderr, "Using rtl_tcp server %s:%d. \n", hostname, portno);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//rtlsdr_get_tuner_gains for the server's tuner: copies its gain steps, in tenths of a dB, into gains unless gains is NULL, and returns the number of steps
|
||||||
|
static int rtltcp_get_tuner_gains(int *gains)
|
||||||
|
{
|
||||||
|
//rtl_tcp advertises only the gain count, not the values; librtlsdr's gain query requires a local device.
|
||||||
|
//Unfortunately this means we have to copy librtlsdr's tables here to select the nearest valid gain given the remote device.
|
||||||
|
//It would be better if rtl_tcp told us the actual list of supported gains, but it doesn't.
|
||||||
|
static const int e4k[] = { -10, 15, 40, 65, 90, 115, 140, 165, 190, 215, 240, 290, 340, 420 };
|
||||||
|
static const int fc0012[] = { -99, -40, 71, 179, 192 };
|
||||||
|
static const int fc0013[] = { -99, -73, -65, -63, -60, -58, -54, 58, 61, 63, 65, 67, 68, 70, 71, 179, 181, 182, 184, 186, 188, 191, 197 };
|
||||||
|
static const int r82xx[] = { 0, 9, 14, 27, 37, 77, 87, 125, 144, 157, 166, 197, 207, 229, 254, 280, 297, 328, 338, 364, 372, 386, 402, 421, 434, 439, 445, 480, 496 };
|
||||||
|
static const int none[] = { 0 };
|
||||||
|
const int *table = none;
|
||||||
|
int count = 1;
|
||||||
|
|
||||||
|
//different tuners have different possible gains
|
||||||
|
switch (rtltcp_tuner_type) {
|
||||||
|
case RTLSDR_TUNER_E4000: table = e4k; count = sizeof(e4k) / sizeof(int); break;
|
||||||
|
case RTLSDR_TUNER_FC0012: table = fc0012; count = sizeof(fc0012) / sizeof(int); break;
|
||||||
|
case RTLSDR_TUNER_FC0013: table = fc0013; count = sizeof(fc0013) / sizeof(int); break;
|
||||||
|
case RTLSDR_TUNER_R820T:
|
||||||
|
case RTLSDR_TUNER_R828D: table = r82xx; count = sizeof(r82xx) / sizeof(int); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gains != NULL) {
|
||||||
|
memcpy(gains, table, count * sizeof(int));
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
//close the rtl_tcp connection; returns close's result
|
||||||
|
static int rtltcp_close(void)
|
||||||
|
{
|
||||||
|
int r = close(rtltcp_sock);
|
||||||
|
rtltcp_sock = -1;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//pass rtl_tcp samples to cb until the connection closes or exitflag is set, in the same block size that rtlsdr_read_async delivers by default
|
||||||
|
static int rtltcp_read_async(rtlsdr_read_async_cb_t cb, void *ctx)
|
||||||
|
{
|
||||||
|
static unsigned char buf[RTLTCP_BUF_LENGTH];
|
||||||
|
while (!exitflag && recv(rtltcp_sock, buf, RTLTCP_BUF_LENGTH, MSG_WAITALL) == RTLTCP_BUF_LENGTH) {
|
||||||
|
cb(buf, RTLTCP_BUF_LENGTH, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
//we are finished (for a variety of reasons). ensure exitflag is set
|
||||||
|
if (!exitflag) {
|
||||||
|
fprintf (stderr, "rtl_tcp server closed the connection.\n");
|
||||||
|
exitflag = 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Each rtlsdr_or_tcp_* function takes the arguments of the librtlsdr function it is named after.
|
||||||
|
//While an rtl_tcp server is connected, the call goes to the server; otherwise it goes to librtlsdr.
|
||||||
|
int rtlsdr_or_tcp_close(rtlsdr_dev_t *dev)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_close() : rtlsdr_close(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx, uint32_t buf_num, uint32_t buf_len)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_read_async(cb, ctx) : rtlsdr_read_async(dev, cb, ctx, buf_num, buf_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_cancel_async(rtlsdr_dev_t *dev)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? shutdown(rtltcp_sock, SHUT_RDWR) : rtlsdr_cancel_async(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_reset_buffer(rtlsdr_dev_t *dev)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? 0 : rtlsdr_reset_buffer(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_get_tuner_gains(rtlsdr_dev_t *dev, int *gains)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_get_tuner_gains(gains) : rtlsdr_get_tuner_gains(dev, gains);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_command(RTLTCP_SET_CENTER_FREQ, freq) : rtlsdr_set_center_freq(dev, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_set_sample_rate(rtlsdr_dev_t *dev, uint32_t rate)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_command(RTLTCP_SET_SAMPLE_RATE, rate) : rtlsdr_set_sample_rate(dev, rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_set_direct_sampling(rtlsdr_dev_t *dev, int on)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_command(RTLTCP_SET_DIRECT_SAMPLING, on) : rtlsdr_set_direct_sampling(dev, on);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_set_offset_tuning(rtlsdr_dev_t *dev, int on)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_command(RTLTCP_SET_OFFSET_TUNING, on) : rtlsdr_set_offset_tuning(dev, on);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_set_tuner_gain_mode(rtlsdr_dev_t *dev, int manual)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_command(RTLTCP_SET_TUNER_GAIN_MODE, manual) : rtlsdr_set_tuner_gain_mode(dev, manual);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_set_tuner_gain(rtlsdr_dev_t *dev, int gain)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_command(RTLTCP_SET_TUNER_GAIN, gain) : rtlsdr_set_tuner_gain(dev, gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtlsdr_or_tcp_set_freq_correction(rtlsdr_dev_t *dev, int ppm)
|
||||||
|
{
|
||||||
|
return rtltcp_sock >= 0 ? rtltcp_command(RTLTCP_SET_FREQ_CORRECTION, ppm) : rtlsdr_set_freq_correction(dev, ppm);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user