Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
150 lines
7.3 KiB
Diff
150 lines
7.3 KiB
Diff
diff --git a/src/config.cpp b/src/config.cpp
|
|
index 84be9dd..609eb71 100644
|
|
--- a/src/config.cpp
|
|
+++ b/src/config.cpp
|
|
@@ -301,6 +301,7 @@ static struct freq_t* mk_freqlist(int n) {
|
|
fl[i].squelch = Squelch();
|
|
fl[i].active_counter = 0;
|
|
fl[i].modulation = MOD_AM;
|
|
+ fl[i].hold_ms = 0;
|
|
}
|
|
return fl;
|
|
}
|
|
@@ -425,7 +426,19 @@ static int parse_channels(libconfig::Setting& chans, device_t* dev, int i) {
|
|
error();
|
|
}
|
|
|
|
+ if (chans[j].exists("hold_ms") && (libconfig::Setting::TypeList != chans[j]["hold_ms"].getType() || chans[j]["hold_ms"].getLength() < channel->freq_count)) {
|
|
+ cerr << "Configuration error: devices.[" << i << "] channels.[" << j << "]: hold_ms should be a list of ints with at least " << channel->freq_count << " elements\n";
|
|
+ error();
|
|
+ }
|
|
for (int f = 0; f < channel->freq_count; f++) {
|
|
+ if (chans[j].exists("hold_ms")) {
|
|
+ int h = (int)chans[j]["hold_ms"][f];
|
|
+ if (h < 0 || h > 60000) {
|
|
+ cerr << "Configuration error: devices.[" << i << "] channels.[" << j << "]: hold_ms must be 0..60000\n";
|
|
+ error();
|
|
+ }
|
|
+ channel->freqlist[f].hold_ms = h;
|
|
+ }
|
|
channel->freqlist[f].frequency = parse_anynum2int((chans[j]["freqs"][f]));
|
|
if (chans[j].exists("labels")) {
|
|
channel->freqlist[f].label = strdup(chans[j]["labels"][f]);
|
|
diff --git a/src/helper_functions.cpp b/src/helper_functions.cpp
|
|
index 8a33130..d04fce4 100644
|
|
--- a/src/helper_functions.cpp
|
|
+++ b/src/helper_functions.cpp
|
|
@@ -74,7 +74,7 @@ bool make_subdirs(const string& basedir, const string& subdirs) {
|
|
string make_dated_subdirs(const string& basedir, const struct tm* time) {
|
|
// use the time to build the date subdirectories
|
|
char date_path[11];
|
|
- strftime(date_path, sizeof(date_path), "%Y/%m/%d", time);
|
|
+ strftime(date_path, sizeof(date_path), "%Y-%m-%d", time);
|
|
const string date_path_str = string(date_path);
|
|
|
|
// make all the subdirectories, and return the full path if successful
|
|
diff --git a/src/rtl_airband.cpp b/src/rtl_airband.cpp
|
|
index 8993356..3d10d03 100644
|
|
--- a/src/rtl_airband.cpp
|
|
+++ b/src/rtl_airband.cpp
|
|
@@ -83,6 +83,10 @@ bool use_localtime = false;
|
|
bool multiple_demod_threads = false;
|
|
bool multiple_output_threads = false;
|
|
bool log_scan_activity = false;
|
|
+// LOCAL PATCH (2026-10-20): configurable scan dwell / hold (upstream hardcodes 200 ms and 10 steps = 2 s)
|
|
+int scan_dwell_ms = 200;
|
|
+int scan_hold_ms = 2000;
|
|
+int scan_long_hold_min_ms = 800; // per-frequency hold_ms applies only after >= this much open squelch
|
|
char* stats_filepath = NULL;
|
|
double stats_update_interval = 15.0;
|
|
double global_split_min_file_time = 1.0;
|
|
@@ -110,38 +114,50 @@ void sighandler(int sig) {
|
|
void* controller_thread(void* params) {
|
|
device_t* dev = (device_t*)params;
|
|
int i = 0;
|
|
- int consecutive_squelch_off = 0;
|
|
+ int off_ticks = 0; // consecutive dwell ticks without signal on the current frequency
|
|
+ int on_ticks = 0; // dwell ticks with signal since the scanner stopped on this frequency
|
|
+ bool stepping = false; // true while hopping (hold expired); false while holding after activity
|
|
int new_centerfreq = 0;
|
|
struct timeval tv;
|
|
|
|
if (dev->channels[0].freq_count < 2)
|
|
return 0;
|
|
+ // LOCAL PATCH: dwell = scan_dwell_ms, hold after activity = per-frequency hold_ms (or scan_hold_ms)
|
|
while (!do_exit) {
|
|
- SLEEP(200);
|
|
+ SLEEP(scan_dwell_ms);
|
|
+ freq_t* fl = dev->channels[0].freqlist;
|
|
if (dev->channels[0].axcindicate == NO_SIGNAL) {
|
|
- if (consecutive_squelch_off < 10) {
|
|
- consecutive_squelch_off++;
|
|
+ // long per-frequency hold only after a real transmission, not after a noise blip
|
|
+ const bool real_tx = on_ticks * scan_dwell_ms >= scan_long_hold_min_ms;
|
|
+ const int hold = (fl[i].hold_ms > 0 && real_tx) ? fl[i].hold_ms : scan_hold_ms;
|
|
+ const int hold_steps = hold / scan_dwell_ms > 0 ? hold / scan_dwell_ms : 1;
|
|
+ if (!stepping && off_ticks < hold_steps) {
|
|
+ off_ticks++;
|
|
} else {
|
|
+ stepping = true;
|
|
+ on_ticks = 0;
|
|
i++;
|
|
i %= dev->channels[0].freq_count;
|
|
dev->channels[0].freq_idx = i;
|
|
- new_centerfreq = dev->channels[0].freqlist[i].frequency + 20 * (double)(dev->input->sample_rate / fft_size);
|
|
+ new_centerfreq = fl[i].frequency + 20 * (double)(dev->input->sample_rate / fft_size);
|
|
if (input_set_centerfreq(dev->input, new_centerfreq) < 0) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
- if (consecutive_squelch_off == 10) {
|
|
+ if (stepping) {
|
|
if (log_scan_activity)
|
|
- log(LOG_INFO, "Activity on %7.3f MHz (%s)\n", dev->channels[0].freqlist[i].frequency / 1000000.0, dev->channels[0].freqlist[i].label);
|
|
+ log(LOG_INFO, "Activity on %7.3f MHz (%s)\n", fl[i].frequency / 1000000.0, fl[i].label);
|
|
if (i != dev->last_frequency) {
|
|
- // squelch has just opened on a new frequency - we might need to update outputs' metadata
|
|
+ // squelch just opened on a new frequency: outputs may need new metadata
|
|
gettimeofday(&tv, NULL);
|
|
tag_queue_put(dev, i, tv);
|
|
dev->last_frequency = i;
|
|
}
|
|
}
|
|
- consecutive_squelch_off = 0;
|
|
+ stepping = false;
|
|
+ off_ticks = 0;
|
|
+ on_ticks++;
|
|
}
|
|
}
|
|
return 0;
|
|
@@ -858,6 +874,16 @@ int main(int argc, char* argv[]) {
|
|
}
|
|
if (root.exists("log_scan_activity") && (bool)root["log_scan_activity"] == true)
|
|
log_scan_activity = true;
|
|
+ if (root.exists("scan_dwell_ms"))
|
|
+ scan_dwell_ms = (int)root["scan_dwell_ms"];
|
|
+ if (root.exists("scan_hold_ms"))
|
|
+ scan_hold_ms = (int)root["scan_hold_ms"];
|
|
+ if (root.exists("scan_long_hold_min_ms"))
|
|
+ scan_long_hold_min_ms = (int)root["scan_long_hold_min_ms"];
|
|
+ if (scan_dwell_ms < 20 || scan_dwell_ms > 5000 || scan_hold_ms < 0 || scan_hold_ms > 60000) {
|
|
+ cerr << "Configuration error: scan_dwell_ms must be 20..5000, scan_hold_ms 0..60000\n";
|
|
+ error();
|
|
+ }
|
|
if (root.exists("stats_filepath"))
|
|
stats_filepath = strdup(root["stats_filepath"]);
|
|
parse_global_double(root, "stats_update_interval", &stats_update_interval);
|
|
diff --git a/src/rtl_airband.h b/src/rtl_airband.h
|
|
index 2029fce..a1c27b4 100644
|
|
--- a/src/rtl_airband.h
|
|
+++ b/src/rtl_airband.h
|
|
@@ -256,6 +256,7 @@ struct freq_t {
|
|
NotchFilter notch_filter; // notch filter - good to remove CTCSS tones
|
|
LowpassFilter lowpass_filter; // lowpass filter, applied to I/Q after derotation, set at bandwidth/2 to remove out of band noise
|
|
enum modulations modulation;
|
|
+ int hold_ms; // LOCAL PATCH: per-frequency scan hold after activity (0 = global scan_hold_ms)
|
|
};
|
|
struct channel_t {
|
|
float wavein[WAVE_LEN]; // FFT output waveform
|