kopia lustrzana https://github.com/projecthorus/radiosonde_auto_rx
Added ability to temporary block the frequency of non-decodable (encrypted) sondes.
rodzic
e6aa3a043c
commit
f24fab881a
|
|
@ -61,6 +61,10 @@ exporter_objects = [] # This list will hold references to each exporter instan
|
|||
exporter_functions = [] # This list will hold references to the exporter add functions, which will be passed onto the decoders.
|
||||
|
||||
|
||||
# Temporary frequency block list
|
||||
# This contains frequncies that should be blocked for a short amount of time.
|
||||
temporary_block_list = {}
|
||||
|
||||
|
||||
# Scan Result Queue
|
||||
# Scan results are processed asynchronously from the main scanner object.
|
||||
|
|
@ -96,7 +100,7 @@ def allocate_sdr(check_only = False, task_description = ""):
|
|||
|
||||
def start_scanner():
|
||||
""" Start a scanner thread on the first available SDR """
|
||||
global config, scan_results, RS_PATH
|
||||
global config, scan_results, RS_PATH, temporary_block_list
|
||||
|
||||
if 'SCAN' in autorx.task_list:
|
||||
# Already a scanner running! Return.
|
||||
|
|
@ -136,7 +140,9 @@ def start_scanner():
|
|||
gain = autorx.sdr_list[_device_idx]['gain'],
|
||||
ppm = autorx.sdr_list[_device_idx]['ppm'],
|
||||
bias = autorx.sdr_list[_device_idx]['bias'],
|
||||
save_detection_audio = config['save_detection_audio']
|
||||
save_detection_audio = config['save_detection_audio'],
|
||||
temporary_block_list = temporary_block_list,
|
||||
temporary_block_time = config['temporary_block_time']
|
||||
)
|
||||
|
||||
# Add a reference into the sdr_list entry
|
||||
|
|
@ -174,7 +180,19 @@ def start_decoder(freq, sonde_type):
|
|||
sonde_type (str): The radiosonde type ('RS41', 'RS92', 'DFM', 'M10, 'iMet')
|
||||
|
||||
"""
|
||||
global config, RS_PATH, exporter_functions, rs92_ephemeris
|
||||
global config, RS_PATH, exporter_functions, rs92_ephemeris, temporary_block_list
|
||||
|
||||
# Check the frequency is not in our temporary block list
|
||||
# (This may happen from time-to-time depending on the timing of the scan thread)
|
||||
if freq in temporary_block_list.keys():
|
||||
if temporary_block_list[freq] > (time.time()-config['temporary_block_time']*60):
|
||||
logging.error("Task Manager - Attempted to start a decoder on a temporarily blocked frequency (%.3f MHz)" % (freq/1e6))
|
||||
return
|
||||
else:
|
||||
# This frequency should not be blocked any more, remove it from the block list.
|
||||
logging.info("Task Manager - Removed %.3f MHz from temporary block list." % (freq/1e6))
|
||||
temporary_block_list.pop(freq)
|
||||
|
||||
|
||||
# Allocate a SDR.
|
||||
_device_idx = allocate_sdr(task_description="Decoder (%s, %.3f MHz)" % (sonde_type, freq/1e6))
|
||||
|
|
@ -250,6 +268,7 @@ def handle_scan_results():
|
|||
# Break if we don't support this sonde type.
|
||||
if (_check_type not in VALID_SONDE_TYPES):
|
||||
logging.error("Unsupported sonde type: %s" % _check_type)
|
||||
# TODO - Potentially add the frequency of the unsupported sonde to the temporary block list?
|
||||
continue
|
||||
|
||||
if allocate_sdr(check_only=True) is not None :
|
||||
|
|
@ -277,19 +296,40 @@ def clean_task_list():
|
|||
try:
|
||||
_running = autorx.task_list[_key]['task'].running()
|
||||
_task_sdr = autorx.task_list[_key]['device_idx']
|
||||
_exit_state = autorx.task_list[_key]['task'].exit_state
|
||||
except Exception as e:
|
||||
logging.error("Task Manager - Error getting task %s state - %s" % (str(_key),str(e)))
|
||||
continue
|
||||
|
||||
if _running == False:
|
||||
# This task has stopped. Release its associated SDR.
|
||||
# This task has stopped.
|
||||
# Check the exit state of the task for any abnormalities:
|
||||
if _exit_state == "Encrypted":
|
||||
# This task was a decoder, and it has encountered an encrypted sonde.
|
||||
logging.info("Task Manager - Adding temporary block for frequency %.3f MHz" % (_key/1e6))
|
||||
# Add the sonde's frequency to the global temporary block-list
|
||||
temporary_block_list[_key] = time.time()
|
||||
# If there is a scanner currently running, add it to the scanners internal block list.
|
||||
if 'SCAN' in autorx.task_list:
|
||||
auto_rx.task_list['SCAN']['task'].add_temporary_block(_key)
|
||||
|
||||
|
||||
# Release its associated SDR.
|
||||
autorx.sdr_list[_task_sdr]['in_use'] = False
|
||||
autorx.sdr_list[_task_sdr]['task'] = None
|
||||
|
||||
# Pop the task from the task list.
|
||||
autorx.task_list.pop(_key)
|
||||
# Indicate to the web client that the task list has been updated.
|
||||
flask_emit_event('task_event')
|
||||
|
||||
# Clean out the temporary block list of old entries.
|
||||
for _freq in temporary_block_list.keys():
|
||||
if temporary_block_list[_freq] < (time.time() - config['temporary_block_time']*60):
|
||||
temporary_block_list.pop(_freq)
|
||||
logging.info("Task Manager - Removed %.3f MHz from temporary block list." % (_freq/1e6))
|
||||
|
||||
|
||||
# Check if there is a scanner thread still running. If not, and if there is a SDR free, start one up again.
|
||||
if ('SCAN' not in autorx.task_list) and (allocate_sdr(check_only=True) is not None):
|
||||
# We have a SDR free, and we are not running a scan thread. Start one.
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ def read_auto_rx_config(filename):
|
|||
'detect_dwell_time' : 5,
|
||||
'scan_delay' : 10,
|
||||
'payload_id_valid' : 5,
|
||||
'temporary_block_time' : 60,
|
||||
# Rotator Settings
|
||||
'enable_rotator': False,
|
||||
'rotator_update_rate': 30,
|
||||
|
|
@ -245,6 +246,12 @@ def read_auto_rx_config(filename):
|
|||
except:
|
||||
logging.error("Config - Could not find station_code field, using default.")
|
||||
|
||||
# New temporary block time - added 2019-04-14
|
||||
try:
|
||||
auto_rx_config['temporary_block_time'] = config.getint('advanced', 'temporary_block_time')
|
||||
except:
|
||||
logging.error("Config - New advanced settings missing, using defaults.")
|
||||
|
||||
|
||||
# Now we attempt to read in the individual SDR parameters.
|
||||
auto_rx_config['sdr_settings'] = {}
|
||||
|
|
|
|||
|
|
@ -142,6 +142,8 @@ class SondeDecoder(object):
|
|||
# This will become our decoder thread.
|
||||
self.decoder = None
|
||||
|
||||
self.exit_state = "OK"
|
||||
|
||||
# Detect if we have an 'inverted' sonde.
|
||||
if self.sonde_type.startswith('-'):
|
||||
self.inverted = True
|
||||
|
|
@ -363,6 +365,7 @@ class SondeDecoder(object):
|
|||
if time.time() > (_last_packet + self.timeout):
|
||||
# If we have not seen data for a while, break.
|
||||
self.log_error("RX Timed out.")
|
||||
self.exit_state = "Timeout"
|
||||
break
|
||||
else:
|
||||
# Otherwise, sleep for a short time.
|
||||
|
|
@ -442,9 +445,12 @@ class SondeDecoder(object):
|
|||
if _field not in _telemetry:
|
||||
_telemetry[_field] = self.DECODER_OPTIONAL_FIELDS[_field]
|
||||
|
||||
_telemetry['encrypted'] = True
|
||||
|
||||
# Check for an encrypted flag (this indicates a sonde that we cannot decode telemetry from.)
|
||||
if 'encrypted' in _telemetry:
|
||||
self.log_error("Radiosonde %s has encrypted telemetry (possible RS41-SGM)! We cannot decode this, closing decoder." % _telemetry['id'])
|
||||
self.exit_state = "Encrypted"
|
||||
self.decoder_running = False
|
||||
return False
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import platform
|
|||
import subprocess
|
||||
import time
|
||||
import traceback
|
||||
from threading import Thread
|
||||
from threading import Thread, Lock
|
||||
from types import FunctionType, MethodType
|
||||
from .utils import detect_peaks, rtlsdr_test, reset_rtlsdr_by_serial, reset_all_rtlsdrs, peak_decimation
|
||||
try:
|
||||
|
|
@ -358,7 +358,9 @@ class SondeScanner(object):
|
|||
gain = -1,
|
||||
ppm = 0,
|
||||
bias = False,
|
||||
save_detection_audio = False):
|
||||
save_detection_audio = False,
|
||||
temporary_block_list = {},
|
||||
temporary_block_time = 60):
|
||||
""" Initialise a Sonde Scanner Object.
|
||||
|
||||
Apologies for the huge number of args...
|
||||
|
|
@ -390,6 +392,8 @@ class SondeScanner(object):
|
|||
gain (int): SDR Gain setting, in dB. A gain setting of -1 enables the RTLSDR AGC.
|
||||
bias (bool): If True, enable the bias tee on the SDR.
|
||||
save_detection_audio (bool): Save the audio used in each detecton to detect_<device_idx>.wav
|
||||
temporary_block_list (dict): A dictionary where each attribute represents a frequency that should be blacklisted for a set time.
|
||||
temporary_block_time (int): How long (minutes) frequencies in the temporary block list should remain blocked for.
|
||||
"""
|
||||
|
||||
# Thread flag. This is set to True when a scan is running.
|
||||
|
|
@ -420,6 +424,14 @@ class SondeScanner(object):
|
|||
self.callback = callback
|
||||
self.save_detection_audio = save_detection_audio
|
||||
|
||||
# Temporary block list.
|
||||
self.temporary_block_list = temporary_block_list.copy()
|
||||
self.temporary_block_list_lock = Lock()
|
||||
self.temporary_block_time = temporary_block_time
|
||||
|
||||
# Alert the user if there are temporary blocks in place.
|
||||
if len(self.temporary_block_list.keys())>0:
|
||||
self.log_info("Temporary blocks in place for frequencies: %s" % str(self.temporary_block_list.keys()))
|
||||
|
||||
# Error counter.
|
||||
self.error_retries = 0
|
||||
|
|
@ -439,8 +451,11 @@ class SondeScanner(object):
|
|||
if not _rtlsdr_ok:
|
||||
self.log_error("RTLSDR #%s non-functional - exiting." % device_idx)
|
||||
self.sonde_scanner_running = False
|
||||
self.exit_state = "Failed SDR"
|
||||
return
|
||||
|
||||
self.exit_state = "OK"
|
||||
|
||||
if auto_start:
|
||||
self.start()
|
||||
|
||||
|
|
@ -611,6 +626,7 @@ class SondeScanner(object):
|
|||
_, peak_idx = np.unique(peak_frequencies, return_index=True)
|
||||
peak_frequencies = peak_frequencies[np.sort(peak_idx)]
|
||||
|
||||
|
||||
# Remove any frequencies in the blacklist.
|
||||
for _frequency in np.array(self.blacklist)*1e6:
|
||||
_index = np.argwhere(peak_frequencies==_frequency)
|
||||
|
|
@ -623,6 +639,25 @@ class SondeScanner(object):
|
|||
# Append on any frequencies in the supplied greylist
|
||||
peak_frequencies = np.append(np.array(self.greylist)*1e6, peak_frequencies)
|
||||
|
||||
|
||||
# Remove any frequencies in the temporary block list
|
||||
self.temporary_block_list_lock.acquire()
|
||||
for _frequency in self.temporary_block_list.keys():
|
||||
# Check the time the block was added.
|
||||
if self.temporary_block_list[_frequency] > (time.time()-self.temporary_block_time*60):
|
||||
# We should still be blocking this frequency, so remove any peaks with this frequency.
|
||||
_index = np.argwhere(peak_frequencies==_frequency)
|
||||
peak_frequencies = np.delete(peak_frequencies, _index)
|
||||
if len(_index) > 0:
|
||||
self.log_debug("Peak on %.3f MHz was removed due to temporary block." % (_frequency/1e6))
|
||||
|
||||
else:
|
||||
# This frequency doesn't need to be blocked any more, remove it from the block list.
|
||||
self.temporary_block_list.pop(_frequency)
|
||||
self.log_info("Removed %.3f MHz from temporary block list." % (_frequency/1e6))
|
||||
|
||||
self.temporary_block_list_lock.release()
|
||||
|
||||
# Get the level of our peak search results, to send to the web client.
|
||||
# This is actually a bit of a pain to do...
|
||||
_peak_freq = []
|
||||
|
|
@ -734,6 +769,20 @@ class SondeScanner(object):
|
|||
return self.sonde_scanner_running
|
||||
|
||||
|
||||
def add_temporary_block(self, frequency):
|
||||
""" Add a frequency to the temporary block list.
|
||||
|
||||
Args:
|
||||
frequency (float): Frequency to be blocked, in Hz
|
||||
"""
|
||||
# Acquire a lock on the block list, so we don't accidentally modify it
|
||||
# while it is being used in a scan.
|
||||
self.temporary_block_list_lock.acquire()
|
||||
self.temporary_block_list[frequency] = time.time()
|
||||
self.temporary_block_list_lock.release()
|
||||
self.log_info("Adding temporary block for frequency %.3f MHz." % (frequency/1e6))
|
||||
|
||||
|
||||
def log_debug(self, line):
|
||||
""" Helper function to log a debug message with a descriptive heading.
|
||||
Args:
|
||||
|
|
|
|||
|
|
@ -335,6 +335,8 @@ detect_dwell_time = 5
|
|||
scan_delay = 10
|
||||
# Quantize search results to x Hz steps. Useful as most sondes are on 10 kHz frequency steps.
|
||||
quantization = 10000
|
||||
# Temporary Block Time (minutes) - How long to block encrypted or otherwise non-decodable sondes for.
|
||||
temporary_block_time = 60
|
||||
# Upload when (seconds_since_utc_epoch%upload_rate) == 0. Otherwise just delay upload_rate seconds between uploads.
|
||||
# Setting this to True with multple uploaders should give a higher chance of all uploaders uploading the same frame,
|
||||
# however the upload_rate should not be set too low, else there may be a chance of missing upload slots.
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue