parallel talkgroup logging support
This commit is contained in:
parent
d6807f5575
commit
dd5c8b6d7e
|
@ -58,6 +58,9 @@ import gnuradio.wxgui.plot as plot
|
|||
|
||||
import trunking
|
||||
|
||||
import p25_demodulator
|
||||
import p25_decoder
|
||||
|
||||
sys.path.append('tdma')
|
||||
import lfsr
|
||||
|
||||
|
@ -107,6 +110,7 @@ class p25_rx_block (stdgui2.std_top_block):
|
|||
parser.add_option("-F", "--ifile", type="string", default=None, help="read input from complex capture file")
|
||||
parser.add_option("-H", "--hamlib-model", type="int", default=None, help="specify model for hamlib")
|
||||
parser.add_option("-s", "--seek", type="int", default=0, help="ifile seek in K")
|
||||
parser.add_option("-L", "--logfile-workers", type="int", default=None, help="number of demodulators to instantiate")
|
||||
parser.add_option("-S", "--sample-rate", type="int", default=320e3, help="source samp rate")
|
||||
parser.add_option("-t", "--tone-detect", action="store_true", default=False, help="use experimental tone detect algorithm")
|
||||
parser.add_option("-T", "--trunk-conf-file", type="string", default=None, help="trunking config file name")
|
||||
|
@ -258,8 +262,6 @@ class p25_rx_block (stdgui2.std_top_block):
|
|||
|
||||
self.rx_q = gr.msg_queue(100)
|
||||
msg_EVT_DATA_EVENT(self.frame, self.msg_data)
|
||||
self.trunk_rx = trunking.rx_ctl(frequency_set = self.change_freq, debug = self.options.verbosity, conf_file = self.options.trunk_conf_file)
|
||||
self.du_watcher = du_queue_watcher(self.rx_q, self.trunk_rx.process_qmsg)
|
||||
udp_port = 0
|
||||
if self.options.wireshark:
|
||||
udp_port = WIRESHARK_PORT
|
||||
|
@ -368,7 +370,7 @@ class p25_rx_block (stdgui2.std_top_block):
|
|||
|
||||
alpha = self.options.costas_alpha
|
||||
beta = 0.125 * alpha * alpha
|
||||
fmax = 1200 # Hz
|
||||
fmax = 2400 # Hz
|
||||
fmax = 2*pi * fmax / self.basic_rate
|
||||
|
||||
self.clock = op25_repeater.gardner_costas_cc(omega, gain_mu, gain_omega, alpha, beta, fmax, -fmax)
|
||||
|
@ -391,6 +393,18 @@ class p25_rx_block (stdgui2.std_top_block):
|
|||
self.set_connection(fft=1)
|
||||
self.connect_demods()
|
||||
|
||||
logfile_workers = []
|
||||
if self.options.logfile_workers:
|
||||
for i in xrange(self.options.logfile_workers):
|
||||
demod = p25_demodulator.p25_demod_cb(input_rate=capture_rate, demod_type='cqpsk', offset=self.options.offset)
|
||||
decoder = p25_decoder.p25_decoder_c(debug = self.options.verbosity, do_imbe = self.options.vocoder, do_ambe=self.options.phase2_tdma)
|
||||
logfile_workers.append({'demod': demod, 'decoder': decoder, 'active': False})
|
||||
self.connect(source, demod, decoder)
|
||||
|
||||
self.trunk_rx = trunking.rx_ctl(frequency_set = self.change_freq, debug = self.options.verbosity, conf_file = self.options.trunk_conf_file, logfile_workers=logfile_workers)
|
||||
|
||||
self.du_watcher = du_queue_watcher(self.rx_q, self.trunk_rx.process_qmsg)
|
||||
|
||||
# Connect up the flow graph
|
||||
#
|
||||
def __connect(self, cnxns):
|
||||
|
@ -432,6 +446,10 @@ class p25_rx_block (stdgui2.std_top_block):
|
|||
nac = params['nac']
|
||||
system = params['system']
|
||||
self.myform['system'].set_value('%X:%s' % (nac, system))
|
||||
if 'tdma' in params and params['tdma'] is not None:
|
||||
self.myform['tdma'].set_value('TDMA Slot %d' % (params['tdma']))
|
||||
else:
|
||||
self.myform['tdma'].set_value('')
|
||||
|
||||
def set_speed(self, new_speed):
|
||||
# assumes that lock is held, or that we are in init
|
||||
|
@ -661,7 +679,14 @@ class p25_rx_block (stdgui2.std_top_block):
|
|||
parent=self.panel, sizer=vbox_form, label="Talkgroup", weight=0)
|
||||
myform['talkgroup'].set_value("........................................")
|
||||
|
||||
if not self.baseband_input:
|
||||
if self.baseband_input:
|
||||
min_gain = 0
|
||||
max_gain = 200
|
||||
initial_val = 50
|
||||
else:
|
||||
min_gain = 0
|
||||
max_gain = 25
|
||||
initial_val = 10
|
||||
if self.options.trunk_conf_file:
|
||||
myform['freq'] = form.static_text_field(
|
||||
parent=self.panel, sizer=vbox_form, label="Frequency", weight=0)
|
||||
|
@ -671,14 +696,9 @@ class p25_rx_block (stdgui2.std_top_block):
|
|||
parent=self.panel, sizer=vbox_form, label="Frequency", weight=0,
|
||||
callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg))
|
||||
myform['freq'].set_value(self.options.frequency)
|
||||
if self.baseband_input:
|
||||
min_gain = 0
|
||||
max_gain = 200
|
||||
initial_val = 50
|
||||
else:
|
||||
min_gain = 0
|
||||
max_gain = 25
|
||||
initial_val = 10
|
||||
myform['tdma'] = form.static_text_field(
|
||||
parent=self.panel, sizer=vbox_form, label=None, weight=0)
|
||||
myform['tdma'].set_value("")
|
||||
|
||||
hbox.Add(vbox_form, 0, 0)
|
||||
|
||||
|
@ -749,7 +769,7 @@ class p25_rx_block (stdgui2.std_top_block):
|
|||
self.hamlib.set_freq(freq)
|
||||
elif params['center_frequency']:
|
||||
relative_freq = center_freq - freq
|
||||
if relative_freq + self.options.offset > self.channel_rate / 2:
|
||||
if abs(relative_freq + self.options.offset) > self.channel_rate / 2:
|
||||
print '***unable to tune Local Oscillator to offset %d Hz' % (relative_freq + self.options.offset)
|
||||
print '***limit is one half of sample-rate %d = %d' % (self.channel_rate, self.channel_rate / 2)
|
||||
print '***request for frequency %d rejected' % freq
|
||||
|
@ -1126,10 +1146,10 @@ class p25_rx_block (stdgui2.std_top_block):
|
|||
"source-dev": "AUDIO",
|
||||
"source-decim": 1 }
|
||||
self.audio_source = audio.source(capture_rate, audio_input_filename)
|
||||
self.audio_cvt = gr.float_to_complex()
|
||||
self.audio_cvt = blocks.float_to_complex()
|
||||
self.connect((self.audio_source, 0), (self.audio_cvt, 0))
|
||||
self.connect((self.audio_source, 1), (self.audio_cvt, 1))
|
||||
self.source = gr.multiply_const_cc(gain)
|
||||
self.source = blocks.multiply_const_cc(gain)
|
||||
self.connect(self.audio_cvt, self.source)
|
||||
self.__set_rx_from_audio(capture_rate)
|
||||
self._set_titlebar("Capturing")
|
||||
|
|
|
@ -140,6 +140,19 @@ class trunked_system (object):
|
|||
self.voice_frequencies[frequency]['time'] = time.time()
|
||||
self.voice_frequencies[frequency]['slot'] = tdma_slot
|
||||
|
||||
def get_updated_talkgroup_frequencies(self, start_time):
|
||||
updated_talkgroup_frequencies = []
|
||||
for frequency in self.voice_frequencies:
|
||||
if self.voice_frequencies[frequency]['time'] < start_time:
|
||||
continue
|
||||
active_tgid = self.voice_frequencies[frequency]['tgid']
|
||||
if active_tgid in self.blacklist:
|
||||
continue
|
||||
if self.whitelist and active_tgid not in self.whitelist:
|
||||
continue
|
||||
updated_talkgroup_frequencies.append(frequency)
|
||||
return updated_talkgroup_frequencies
|
||||
|
||||
def find_voice_frequency(self, start_time, tgid=None):
|
||||
for frequency in self.voice_frequencies:
|
||||
if self.voice_frequencies[frequency]['time'] < start_time:
|
||||
|
@ -376,7 +389,7 @@ class trunked_system (object):
|
|||
|
||||
|
||||
class rx_ctl (object):
|
||||
def __init__(self, debug=0, frequency_set=None, conf_file=None):
|
||||
def __init__(self, debug=0, frequency_set=None, conf_file=None, logfile_workers=None):
|
||||
class _states(object):
|
||||
ACQ = 0
|
||||
CC = 1
|
||||
|
@ -398,6 +411,8 @@ class rx_ctl (object):
|
|||
self.configs = {}
|
||||
self.last_tdma_vf = 0
|
||||
self.P2_GRACE_TIME = 1.0 # TODO: make more configurable
|
||||
self.logfile_workers = logfile_workers
|
||||
self.active_talkgroups = {}
|
||||
|
||||
if conf_file:
|
||||
if conf_file.endswith('.tsv'):
|
||||
|
@ -408,6 +423,19 @@ class rx_ctl (object):
|
|||
self.current_nac = self.nacs[0]
|
||||
self.current_state = self.states.CC
|
||||
|
||||
tsys = self.trunked_systems[self.current_nac]
|
||||
self.set_frequency({
|
||||
'freq': tsys.trunk_cc,
|
||||
'tgid': None,
|
||||
'offset': tsys.offset,
|
||||
'tag': "",
|
||||
'nac': self.current_nac,
|
||||
'system': tsys.sysname,
|
||||
'center_frequency': tsys.center_frequency,
|
||||
'tdma': None,
|
||||
'wacn': None,
|
||||
'sysid': None})
|
||||
|
||||
def set_frequency(self, params):
|
||||
frequency = params['freq']
|
||||
if frequency and self.frequency_set:
|
||||
|
@ -558,11 +586,68 @@ class rx_ctl (object):
|
|||
if nac != self.current_nac:
|
||||
return
|
||||
|
||||
if self.logfile_workers:
|
||||
self.update_logging_state(curr_time)
|
||||
return
|
||||
|
||||
if updated:
|
||||
self.update_state('update', curr_time)
|
||||
else:
|
||||
self.update_state('duid%d' % type, curr_time)
|
||||
|
||||
def find_available_worker(self):
|
||||
for worker in self.logfile_workers:
|
||||
if not worker['active']:
|
||||
worker['active'] = True
|
||||
return worker
|
||||
return None
|
||||
|
||||
def update_logging_state(self, curr_time):
|
||||
tsys = self.trunked_systems[self.current_nac]
|
||||
freqs = tsys.get_updated_talkgroup_frequencies(curr_time)
|
||||
for frequency in freqs:
|
||||
tgid = tsys.voice_frequencies[frequency]['tgid']
|
||||
relative_freq = tsys.center_frequency - frequency
|
||||
|
||||
if tgid in self.active_talkgroups:
|
||||
self.active_talkgroups[tgid]['updated'] = curr_time
|
||||
self.active_talkgroups[tgid]['worker']['demod'].set_relative_frequency(relative_freq)
|
||||
continue
|
||||
|
||||
worker = self.find_available_worker()
|
||||
if worker is None:
|
||||
print '*** error, no free demodulators, freq %d tgid %d' % (frequency, tgid)
|
||||
continue
|
||||
|
||||
self.active_talkgroups[tgid] = {}
|
||||
self.active_talkgroups[tgid]['updated'] = curr_time
|
||||
self.active_talkgroups[tgid]['worker'] = worker
|
||||
demod = worker['demod']
|
||||
decoder = worker['decoder']
|
||||
demod.set_relative_frequency(relative_freq)
|
||||
symbol_rate = 4800
|
||||
|
||||
if tsys.voice_frequencies[frequency]['slot'] is not None:
|
||||
symbol_rate = 6000
|
||||
demod.set_tdma_slotid(tsys.voice_frequencies[frequency]['slot'])
|
||||
demod.set_tdma_parameters(self.current_nac, tsys.ns_syid, tsys.ns_wacn)
|
||||
|
||||
demod.set_omega(symbol_rate)
|
||||
|
||||
filename = 'tgid-%d-%f.wav' % (tgid, curr_time)
|
||||
decoder.set_output(tsys.voice_frequencies[frequency]['slot'], filename)
|
||||
|
||||
# look for inactive talkgroups
|
||||
timeout_groups = []
|
||||
for tgid in self.active_talkgroups:
|
||||
if self.active_talkgroups[tgid]['updated'] + self.TGID_HOLD_TIME < curr_time:
|
||||
timeout_groups.append(tgid)
|
||||
for tgid in timeout_groups:
|
||||
print '%f release %d' % (time.time(), tgid)
|
||||
self.active_talkgroups[tgid]['worker']['decoder'].close_file()
|
||||
self.active_talkgroups[tgid]['worker']['active'] = False
|
||||
self.active_talkgroups.pop(tgid)
|
||||
|
||||
def update_state(self, command, curr_time):
|
||||
if not self.configs:
|
||||
return # run in "manual mode" if no conf
|
||||
|
|
Loading…
Reference in New Issue