From b7cd501cc1033b0a9c6af8fe2cd39f87e5bcf1b6 Mon Sep 17 00:00:00 2001 From: lwvmobile Date: Thu, 19 Feb 2026 21:07:44 -0500 Subject: [PATCH] RTL: Add input gain adjustments during ncurses session using g/G and update example usage (credit: ki4hyf); Group trunking shortcut key changed from g to T; --- examples/Example_Usage.md | 8 +++++++- include/dsd.h | 1 + src/dsd_main.c | 1 + src/dsd_ncurses_handler.c | 22 +++++++++++++++++++++- src/dsd_ncurses_printer.c | 10 +++++----- src/rtl_sdr_fm.cpp | 23 ++++++++++++++++++++++- 6 files changed, 57 insertions(+), 8 deletions(-) diff --git a/examples/Example_Usage.md b/examples/Example_Usage.md index 412fe97..5d38bbc 100644 --- a/examples/Example_Usage.md +++ b/examples/Example_Usage.md @@ -190,7 +190,7 @@ y - toggle scanner (needs either rtl input, or rigctl connection) 1 - Toggle Voice Synthesis in TDMA Slot 1 or FDMA Conventional Voice 2 - Toggle Voice Synthesis in TDMA Slot 2 w - Toggle Trunking/Playback White List (Allow A Groups Only) / Black List (Block B or DE groups only) Mode -g - Toggle Trunking Tuning to Group Calls (DMR T3, Con+, Cap+, P25, NXDN) +T - Toggle Trunking Tuning to Group Calls (DMR T3, Con+, Cap+, P25, NXDN) u - Toggle Trunking Tuning to Private Calls (DMR T3, Cap+, P25) d - Toggle Trunking Tuning to Data Calls (DMR T3, NXDN) e - Toggle Trunking Tuning to Encrypted Calls (P25) @@ -222,6 +222,12 @@ N - Toggle Passband Filter on Analog Voice or Raw Signal Monitoring v - Cycle RTL Input Volume Multiplier 1X, 2X, 3X (lower v) +g - Manually decrease RTL gain +G - Manually increase RTL gain + +{ - Manually decrease PPM +} - Manually increase PPM + ``` ## Sending Audio to a Icecast 2 Server via FFmpeg (Windows) diff --git a/include/dsd.h b/include/dsd.h index 8a8c26e..eb1307f 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -364,6 +364,7 @@ typedef struct int unmute_encrypted_p25; int rtl_dev_index; int rtl_gain_value; + int rtl_gain_actual; int rtl_squelch_level; int rtl_volume_multiplier; int rtl_udp_port; diff --git a/src/dsd_main.c b/src/dsd_main.c index 7ffc2d4..eeb693c 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -689,6 +689,7 @@ //all RTL user options -- enabled AGC by default due to weak signal related issues opts->rtl_dev_index = 0; //choose which device we want by index number opts->rtl_gain_value = 0; //mid value, 0 - AGC - 0 to 49 acceptable values + opts->rtl_gain_actual = -100; //mirror dongle.gain actual values -100 is AUTO_GAIN, else nearest_gain(dongle.dev, dongle.gain); opts->rtl_squelch_level = 100; //100 by default, but only affects NXDN and dPMR during framesync test, compared to RMS value opts->rtl_volume_multiplier = 2; //sample multiplier; This multiplies the sample value to produce a higher 'inlvl' for the demodulator opts->rtl_udp_port = 0; //set UDP port for RTL remote -- 0 by default, will be making this optional for some external/legacy use cases (edacs-fm, etc) diff --git a/src/dsd_ncurses_handler.c b/src/dsd_ncurses_handler.c index f42edc0..fb88dff 100644 --- a/src/dsd_ncurses_handler.c +++ b/src/dsd_ncurses_handler.c @@ -594,7 +594,7 @@ uint8_t ncurses_input_handler(dsd_opts * opts, dsd_state * state, int c) else opts->trunk_tune_enc_calls = 1; } - if (opts->p25_trunk == 1 && c == 103) //'g' key, toggle tune group calls + if (opts->p25_trunk == 1 && c == 84) //'T' key, toggle tune group calls { if (opts->trunk_tune_group_calls == 1) opts->trunk_tune_group_calls = 0; else opts->trunk_tune_group_calls = 1; @@ -918,6 +918,26 @@ uint8_t ncurses_input_handler(dsd_opts * opts, dsd_state * state, int c) if (c == 123) opts->rtlsdr_ppm_error--; + //RTL Gain Manual Adjustment + if (c == 103) + { + if (opts->rtl_gain_value > 0) + { + opts->rtl_gain_value--; + opts->rtl_gain_actual = 0; + } + } + + if (c == 71) + { + if (opts->rtl_gain_value < 49) + { + opts->rtl_gain_value++; + opts->rtl_gain_actual = 0; + } + } + + //anything with an entry box will need the inputs and outputs stopped first //so probably just write a function to handle c input, and when c = certain values //needing an entry box, then stop all of those diff --git a/src/dsd_ncurses_printer.c b/src/dsd_ncurses_printer.c index f1384dc..7dee2a0 100644 --- a/src/dsd_ncurses_printer.c +++ b/src/dsd_ncurses_printer.c @@ -245,10 +245,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (opts->audio_in_type == 3) { printw ("| RTL: %d;", opts->rtl_dev_index); - if (opts->rtl_gain_value == 0) + if (opts->rtl_gain_actual == -100) printw (" G: AGC;"); else - printw (" G: %idB;", opts->rtl_gain_value); + printw (" G: %i/%i;", opts->rtl_gain_value, opts->rtl_gain_actual); printw (" V: %iX;", opts->rtl_volume_multiplier); printw (" PPM: %i;", opts->rtlsdr_ppm_error); //Adjust manually now with { and } printw (" SQ: %i;", opts->rtl_squelch_level); @@ -363,7 +363,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) { printw ("| Trunking -"); if (opts->trunk_tune_group_calls == 0) attron(COLOR_PAIR(2)); - printw (" Group(g)"); + printw (" Group(T)"); attron(COLOR_PAIR(4)); if (opts->trunk_tune_private_calls == 0) attron(COLOR_PAIR(2)); printw (" Private(u)"); @@ -382,8 +382,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (opts->p25_trunk == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3) ) { printw ("| Trunking -"); - if (opts->trunk_tune_group_calls == 0) printw (" group(g)"); - else printw (" GROUP(g)"); + if (opts->trunk_tune_group_calls == 0) printw (" group(T)"); + else printw (" GROUP(T)"); if (opts->trunk_tune_private_calls == 0) printw (" private(u)"); else printw (" PRIVATE(u)"); if (opts->trunk_tune_data_calls == 0) printw (" data(d)"); diff --git a/src/rtl_sdr_fm.cpp b/src/rtl_sdr_fm.cpp index 269bde5..4e5c2f4 100644 --- a/src/rtl_sdr_fm.cpp +++ b/src/rtl_sdr_fm.cpp @@ -1031,6 +1031,7 @@ void open_rtlsdr_stream(dsd_opts *opts) //this needs to be initted first, then we set the parameters dongle_init(&dongle); + //init with low pass if decoding P25 or EDACS/Provoice if (opts->frame_p25p1 == 1 || opts->frame_p25p2 == 1 || opts->frame_provoice == 1) demod_init_ro2(&demod); @@ -1089,7 +1090,7 @@ void open_rtlsdr_stream(dsd_opts *opts) verbose_auto_gain(dongle.dev); fprintf (stderr, "Setting RTL Autogain. \n"); } else { - dongle.gain = nearest_gain(dongle.dev, dongle.gain); + opts->rtl_gain_actual = dongle.gain = nearest_gain(dongle.dev, dongle.gain); verbose_gain_set(dongle.dev, dongle.gain); // fprintf (stderr, "Setting RTL Nearest Gain to %d. \n", dongle.gain); //seems to be working now } @@ -1151,6 +1152,26 @@ int get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state) verbose_ppm_set(dongle.dev, dongle.ppm_error); } + //if Gain or AGC Value is Manually Changed, Change it here now + if (opts->rtl_gain_actual != dongle.gain && opts->rtl_gain_value != 0) + { + dongle.gain = (opts->rtl_gain_value * 10); + opts->rtl_gain_actual = dongle.gain = nearest_gain(dongle.dev, dongle.gain); + verbose_gain_set(dongle.dev, dongle.gain); + + //debug + // fprintf (stderr, "\n Dongle Gain Set: %d; \n", dongle.gain); + } + + else if (opts->rtl_gain_value == 0 && dongle.gain != AUTO_GAIN) + { + opts->rtl_gain_actual = dongle.gain = AUTO_GAIN; + verbose_auto_gain(dongle.dev); + + //debug + // fprintf (stderr, "\n AGC Set; \n"); + } + while (output.queue.empty()) { struct timespec ts;