コード例 #1
0
ファイル: multi_rx.py プロジェクト: legitosaurus/op25
    def __init__(self, config, dev, verbosity):
        sys.stderr.write('channel (dev %s): %s\n' % (dev.name, config))
        self.device = dev
        self.name = config['name']
        self.symbol_rate = _def_symbol_rate
        if 'symbol_rate' in config.keys():
            self.symbol_rate = config['symbol_rate']
        self.config = config
        self.demod = p25_demodulator.p25_demod_cb(
                         input_rate = dev.sample_rate,
                         demod_type = config['demod_type'],
                         filter_type = config['filter_type'],
                         excess_bw = config['excess_bw'],
                         relative_freq = dev.frequency + dev.offset - config['frequency'],
                         offset = dev.offset,
                         if_rate = config['if_rate'],
                         symbol_rate = self.symbol_rate)
        q = gr.msg_queue(1)
        self.decoder = op25_repeater.frame_assembler(config['destination'], verbosity, q)

        self.kill_sink = []

        if 'plot' not in config.keys():
            return

        self.sinks = []
        for plot in config['plot'].split(','):
            # fixme: allow multiple complex consumers (fft and constellation currently mutually exclusive)
            if plot == 'datascope':
                assert config['demod_type'] == 'fsk4'   ## datascope plot requires fsk4 demod type
                sink = eye_sink_f(sps=config['if_rate'] / self.symbol_rate)
                self.demod.connect_bb('symbol_filter', sink)
                self.kill_sink.append(sink)
            elif plot == 'symbol':
                sink = symbol_sink_f()
                self.demod.connect_float(sink)
                self.kill_sink.append(sink)
            elif plot == 'fft':
                i = len(self.sinks)
                self.sinks.append(fft_sink_c())
                self.demod.connect_complex('src', self.sinks[i])
                self.kill_sink.append(self.sinks[i])
                self.sinks[i].set_offset(self.device.offset)
                self.sinks[i].set_center_freq(self.device.frequency)
                self.sinks[i].set_relative_freq(self.device.frequency + self.device.offset - self.config['frequency'])
                self.sinks[i].set_width(self.device.sample_rate)
            elif plot == 'constellation':
                i = len(self.sinks)
                assert config['demod_type'] == 'cqpsk'   ## constellation plot requires cqpsk demod type
                self.sinks.append(constellation_sink_c())
                self.demod.connect_complex('diffdec', self.sinks[i])
                self.kill_sink.append(self.sinks[i])
            elif plot == 'mixer':
                i = len(self.sinks)
                self.sinks.append(mixer_sink_c())
                self.demod.connect_complex('mixer', self.sinks[i])
                self.kill_sink.append(self.sinks[i])
            else:
                sys.stderr.write('unrecognized plot type %s\n' % plot)
                return
コード例 #2
0
    def __init__(self, config, dev, verbosity, msgq_id, rx_q, tb):
        sys.stderr.write('channel (dev %s): %s\n' % (dev.name, config))
        self.verbosity = verbosity
        ch_name = str(from_dict(config, 'name', ""))
        self.name = ("[%d] %s" % (msgq_id, ch_name)) if ch_name != "" else ("[%d]" % msgq_id) 
        self.device = dev
        if 'frequency' in config and (config['frequency'] != ""):
            self.frequency = config['frequency']
        else:
            self.frequency = self.device.frequency
        self.msgq_id = msgq_id
        self.tb = tb
        self.raw_sink = None
        self.raw_file = None
        self.throttle = None
        self.nbfm = None
        self.nbfm_mode = 0
        self.sinks = {}
        self.tdma_state = False
        self.xor_cache = {}
        self.symbol_rate = _def_symbol_rate
        if 'symbol_rate' in list(config.keys()):
            self.symbol_rate = config['symbol_rate']
        self.config = config
        if config['demod_type'] == "fsk": # Motorola 3600bps
            filter_type = from_dict(config, 'filter_type', 'fsk2mm')
            if filter_type[:4] != 'fsk2':   # has to be 'fsk2' or derivative such as 'fsk2mm'
                filter_type = 'fsk2mm'
            self.demod = p25_demodulator.p25_demod_cb(
                             input_rate = dev.sample_rate,
                             demod_type = 'fsk4',
                             filter_type = filter_type,
                             excess_bw = config['excess_bw'],
                             relative_freq = (dev.frequency + dev.offset + dev.fractional_corr) - self.frequency,
                             offset = dev.offset,
                             if_rate = config['if_rate'],
                             symbol_rate = self.symbol_rate)
            self.decoder = op25_repeater.frame_assembler(str(config['destination']), verbosity, msgq_id, rx_q)

        else:                             # P25, DMR, NXDN and everything else
            self.demod = p25_demodulator.p25_demod_cb(
                             input_rate = dev.sample_rate,
                             demod_type = config['demod_type'],
                             filter_type = config['filter_type'],
                             excess_bw = config['excess_bw'],
                             relative_freq = (dev.frequency + dev.offset + dev.fractional_corr) - self.frequency,
                             offset = dev.offset,
                             if_rate = config['if_rate'],
                             symbol_rate = self.symbol_rate)
            self.decoder = op25_repeater.frame_assembler(str(config['destination']), verbosity, msgq_id, rx_q)

        if 'key' in config and (config['key'] != ""):
            self.set_key(int(config['key'], 0))

        enable_analog = str(from_dict(config, 'enable_analog', "auto")).lower()
        if enable_analog == "off":
            self.nbfm_mode = 0;
        elif enable_analog == "on":
            self.nbfm_mode = 2;
        else:
            self.nbfm_mode = 1;
        
        if self.nbfm_mode > 0:
            self.nbfm = op25_nbfm.op25_nbfm_c(str(config['destination']), verbosity, config, msgq_id, rx_q)
            if self.demod.connect_nbfm(self.nbfm):
                if self.nbfm_mode == 2:
                    self.nbfm.control(True)
            else:
                self.nbfm = None

        if ('plot' not in list(config.keys())) or (config['plot'] == ""):
            return

        for plot in config['plot'].split(','):
            if plot == 'datascope':
                self.toggle_eye_plot()
            elif plot == 'symbol':
                self.toggle_symbol_plot()
            elif plot == 'fft':
                self.toggle_fft_plot()
            elif plot == 'constellation':
                self.toggle_constellation_plot()
            elif plot == 'mixer':
                self.toggle_mixer_plot()
            elif plot == 'tuner':
                self.toggle_tuner_plot()
            else:
                sys.stderr.write('unrecognized plot type %s\n' % plot)
                return
コード例 #3
0
    def __init__(self,
                 config,
                 dev,
                 verbosity,
                 msgq=None,
                 process_msg=None,
                 msgq_id=-1,
                 role=''):
        sys.stderr.write('channel (dev %s): %s\n' % (dev.name, config))
        self.device = dev
        self.name = config['name']
        self.symbol_rate = _def_symbol_rate
        self.process_msg = process_msg
        self.role = role
        self.dev = ''
        self.sysid = []
        self.nac = []
        if 'symbol_rate' in config.keys():
            self.symbol_rate = config['symbol_rate']
        self.config = config
        self.verbosity = verbosity
        self.frequency = 0
        self.tdma_state = False
        self.xor_cache = {}

        self.tuning_error = 0
        self.freq_correction = 0
        self.error_band = 0
        self.last_error_update = 0
        self.last_set_freq_at = time.time()
        self.warned_frequencies = {}
        self.msgq_id = msgq_id
        self.next_band_change = time.time()

        self.audio_port = _def_audio_port
        self.audio_output = _def_audio_output
        self.audio_gain = 1.0
        if 'audio_gain' in config:
            self.audio_gain = float(config['audio_gain'])

        if dev.args.startswith('audio:'):
            self.demod = p25_demodulator.p25_demod_fb(
                input_rate=dev.sample_rate,
                filter_type=config['filter_type'],
                if_rate=config['if_rate'],
                symbol_rate=self.symbol_rate)
        else:
            self.demod = p25_demodulator.p25_demod_cb(
                input_rate=dev.sample_rate,
                demod_type=config['demod_type'],
                filter_type=config['filter_type'],
                excess_bw=config['excess_bw'],
                relative_freq=dev.frequency + dev.offset - config['frequency'],
                offset=dev.offset,
                if_rate=config['if_rate'],
                symbol_rate=self.symbol_rate)
        if msgq is not None:
            q = msgq
        else:
            q = gr.msg_queue(20)
        if 'decode' in config.keys() and config['decode'].startswith(
                'p25_decoder'):
            num_ambe = 1
            (proto, wireshark_host,
             udp_port) = config['destination'].split(':')
            assert proto == 'udp'
            wireshark_host = wireshark_host.replace('/', '')
            udp_port = int(udp_port)
            if role == 'vc':
                self.audio_port = udp_port
            if 'audio_output' in config.keys():
                self.audio_output = config['audio_output']

            self.decoder = p25_decoder.p25_decoder_sink_b(
                dest='audio',
                do_imbe=True,
                num_ambe=num_ambe,
                wireshark_host=wireshark_host,
                udp_port=udp_port,
                do_msgq=True,
                msgq=q,
                audio_output=self.audio_output,
                debug=verbosity,
                msgq_id=self.msgq_id)
        else:
            self.decoder = op25_repeater.frame_assembler(
                config['destination'], verbosity, q, self.msgq_id)

        if self.symbol_rate == 6000 and role == 'cc':
            sps = config['if_rate'] // self.symbol_rate
            self.demod.set_symbol_rate(
                self.symbol_rate)  # this and the foll. call should be merged?
            self.demod.clock.set_omega(float(sps))
            self.demod.clock.set_tdma(True)
            sys.stderr.write(
                'initializing TDMA control channel %s channel ID %d\n' %
                (self.name, self.msgq_id))

        if self.process_msg is not None and msgq is None:
            self.q_watcher = du_queue_watcher(
                q, lambda msg: self.process_msg(msg, sender=self))

        self.kill_sink = []

        if 'blacklist' in config.keys():
            for g in config['blacklist'].split(','):
                self.decoder.insert_blacklist(int(g))

        if 'whitelist' in config.keys():
            for g in config['whitelist'].split(','):
                self.decoder.insert_whitelist(int(g))

        self.sinks = []
        if 'plot' not in config.keys():
            return

        for plot in config['plot'].split(','):
            if plot == 'datascope':
                assert config[
                    'demod_type'] == 'fsk4'  ## datascope plot requires fsk4 demod type
                sink = eye_sink_f(sps=config['if_rate'] // self.symbol_rate)
                sink.set_title(self.name)
                self.sinks.append(sink)
                self.demod.connect_bb('symbol_filter', sink)
                self.kill_sink.append(sink)
            elif plot == 'symbol':
                sink = symbol_sink_f()
                sink.set_title(self.name)
                self.sinks.append(sink)
                self.demod.connect_float(sink)
                self.kill_sink.append(sink)
            elif plot == 'fft':
                assert config[
                    'demod_type'] == 'cqpsk'  ## fft plot requires cqpsk demod type
                i = len(self.sinks)
                sink = fft_sink_c()
                sink.set_title(self.name)
                self.sinks.append(sink)
                self.demod.connect_complex('src', self.sinks[i])
                self.kill_sink.append(self.sinks[i])
            elif plot == 'mixer':
                assert config[
                    'demod_type'] == 'cqpsk'  ## mixer plot requires cqpsk demod type
                i = len(self.sinks)
                sink = mixer_sink_c()
                sink.set_title(self.name)
                self.sinks.append(sink)
                self.demod.connect_complex('mixer', self.sinks[i])
                self.kill_sink.append(self.sinks[i])
            elif plot == 'constellation':
                i = len(self.sinks)
                assert config[
                    'demod_type'] == 'cqpsk'  ## constellation plot requires cqpsk demod type
                sink = constellation_sink_c()
                sink.set_title(self.name)
                self.sinks.append(sink)
                self.demod.connect_complex('diffdec', self.sinks[i])
                self.kill_sink.append(self.sinks[i])
            elif plot == 'correlation':
                assert config[
                    'demod_type'] == 'fsk4'  ## correlation plot requires fsk4 demod type
                assert config[
                    'symbol_rate'] == 4800  ## 4800 required for correlation plot
                sps = config['if_rate'] // self.symbol_rate
                sinks = setup_correlation(sps, self.name,
                                          self.demod.connect_bb)
                self.kill_sink += sinks
                self.sinks += sinks
            else:
                sys.stderr.write('unrecognized plot type %s\n' % plot)
                return
コード例 #4
0
    def __init__(self, dest, debug, config, msgq_id, msg_q):

        gr.hier_block2.__init__(
            self,
            "op25_nbfm_c",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature(0, 0, 0))  # Output signature

        self.debug = debug
        self.config = config
        self.msgq_id = msgq_id

        sys.stderr.write("%s [%d] Enabling nbfm analog audio\n" %
                         (log_ts.get(), msgq_id))

        # load config
        input_rate = int(from_dict(config, 'if_rate', 24000))
        deviation = int(from_dict(config, 'nbfm_deviation', 4000))
        squelch = int(from_dict(config, 'nbfm_squelch_threshold', -60))
        gain = float(from_dict(config, 'nbfm_squelch_gain', 0.0015))
        subchannel_enabled = bool(
            from_dict(config, 'nbfm_enable_subchannel', False))
        raw_in = str(from_dict(config, 'nbfm_raw_input', ""))
        raw_out = str(from_dict(config, 'nbfm_raw_output', ""))

        # 'switch' enables the analog decoding to be turned on/off
        self.switch = blocks.copy(gr.sizeof_gr_complex)
        self.switch.set_enabled(False)

        # power squelch
        self.squelch = analog.simple_squelch_cc(squelch, gain)

        # quadrature demod
        fm_demod_gain = input_rate / (4 * pi * deviation)
        self.fm_demod = analog.quadrature_demod_cf(fm_demod_gain)

        # fm deemphasis
        self.deemph = analog.fm_deemph(input_rate, 0.00075)

        # decimate and filter
        audio_decim = input_rate // _PCM_RATE
        lpf_taps = filter.firdes.low_pass(
            1.0,  # gain
            input_rate,  # sampling rate
            3000.0,  # Audio high cutoff (remove aliasing)
            200.0,  # transition
            filter.firdes.WIN_HAMMING)  # filter type
        hpf_taps = filter.firdes.high_pass(
            1.0,  # gain
            _PCM_RATE,  # sampling rate
            200.0,  # Audio low cutoff  (remove sub-audio signaling)
            10.0,  # Sharp transition band
            filter.firdes.WIN_HAMMING)  # filter type
        self.lp_filter = filter.fir_filter_fff(audio_decim, lpf_taps)
        self.hp_filter = filter.fir_filter_fff(1, hpf_taps)

        # analog_udp block converts +/-1.0 float samples to S16LE PCM and sends over UDP
        self.analog_udp = op25_repeater.analog_udp(dest, debug, msgq_id, msg_q)

        # raw playback
        if raw_in != "":
            self.null_sink = blocks.null_sink(gr.sizeof_gr_complex)
            self.connect(self, self.null_sink)  # dispose of regular input
            self.raw_file = blocks.file_source(gr.sizeof_float, raw_in, False)
            self.throttle = blocks.throttle(gr.sizeof_float, input_rate)
            self.throttle.set_max_noutput_items(input_rate / 50)
            self.fm_demod = self.throttle  # and replace fm_demod with throttled file source
            self.connect(self.raw_file, self.throttle)
            sys.stderr.write("%s [%d] Reading nbfm demod from file: %s\n" %
                             (log_ts.get(), msgq_id, raw_in))

        else:
            self.connect(self, self.switch, self.squelch, self.fm_demod)

        self.connect(self.fm_demod, self.deemph, self.lp_filter,
                     self.hp_filter, self.analog_udp)

        # raw capture
        if raw_in == "" and raw_out != "":
            sys.stderr.write("%s [%d] Saving nbfm demod to file: %s\n" %
                             (log_ts.get(), msgq_id, raw_out))
            self.raw_sink = blocks.file_sink(gr.sizeof_float, raw_out)
            self.connect(self.fm_demod, self.raw_sink)

        # subchannel signaling
        if subchannel_enabled:
            self.subchannel_decimation = 25
            self.subchannel_gain = 10
            self.subchannelfilttaps = filter.firdes.low_pass(
                self.subchannel_gain, input_rate, 200, 40,
                filter.firdes.WIN_HANN)
            self.subchannelfilt = filter.fir_filter_fff(
                self.subchannel_decimation, self.subchannelfilttaps)
            self.subchannel_syms_per_sec = 150
            self.subchannel_samples_per_symbol = (
                input_rate /
                self.subchannel_decimation) / self.subchannel_syms_per_sec
            sys.stderr.write(
                "%s [%d] Subchannel samples per symbol: %f\n" %
                (log_ts.get(), msgq_id, self.subchannel_samples_per_symbol))
            self.subchannel_clockrec = digital.clock_recovery_mm_ff(
                self.subchannel_samples_per_symbol, 0.25 * 0.01 * 0.01, 0.5,
                0.01, 0.3)
            self.subchannel_slicer = digital.binary_slicer_fb()
            #self.subchannel_correlator = digital.correlate_access_code_bb("01000", 0)
            self.subchannel_framer = op25_repeater.frame_assembler(
                "subchannel", debug, msgq_id, msg_q)
            self.connect(self.fm_demod, self.subchannelfilt,
                         self.subchannel_clockrec, self.subchannel_slicer,
                         self.subchannel_framer)
コード例 #5
0
    def __init__(self, config, dev, verbosity, msgq = None):
        sys.stderr.write('channel (dev %s): %s\n' % (dev.name, config))
        self.device = dev
        self.name = config['name']
        self.symbol_rate = _def_symbol_rate
        if 'symbol_rate' in config.keys():
            self.symbol_rate = config['symbol_rate']
        self.config = config
        if dev.args.startswith('audio:'):
            self.demod = p25_demodulator.p25_demod_fb(
                         input_rate = dev.sample_rate,
                         filter_type = config['filter_type'],
                         if_rate = config['if_rate'],
                         symbol_rate = self.symbol_rate)
        else:
            self.demod = p25_demodulator.p25_demod_cb(
                         input_rate = dev.sample_rate,
                         demod_type = config['demod_type'],
                         filter_type = config['filter_type'],
                         excess_bw = config['excess_bw'],
                         relative_freq = dev.frequency + dev.offset - config['frequency'],
                         offset = dev.offset,
                         if_rate = config['if_rate'],
                         symbol_rate = self.symbol_rate)
        if msgq is None:
            q = gr.msg_queue(1)
        else:
            q = msgq
        self.decoder = op25_repeater.frame_assembler(config['destination'], verbosity, q)

        self.kill_sink = []

        if 'blacklist' in config.keys():
            for g in config['blacklist'].split(','):
                self.decoder.insert_blacklist(int(g))

        if 'whitelist' in config.keys():
            for g in config['whitelist'].split(','):
                self.decoder.insert_whitelist(int(g))

        if 'plot' not in config.keys():
            return

        self.sinks = []
        for plot in config['plot'].split(','):
            if plot == 'datascope':
                assert config['demod_type'] == 'fsk4'   ## datascope plot requires fsk4 demod type
                sink = eye_sink_f(sps=config['if_rate'] // self.symbol_rate)
                self.demod.connect_bb('symbol_filter', sink)
                self.kill_sink.append(sink)
            elif plot == 'symbol':
                sink = symbol_sink_f()
                self.demod.connect_float(sink)
                self.kill_sink.append(sink)
            elif plot == 'fft':
                assert config['demod_type'] == 'cqpsk'   ## fft plot requires cqpsk demod type
                i = len(self.sinks)
                self.sinks.append(fft_sink_c())
                self.demod.connect_complex('src', self.sinks[i])
                self.kill_sink.append(self.sinks[i])
            elif plot == 'mixer':
                assert config['demod_type'] == 'cqpsk'   ## mixer plot requires cqpsk demod type
                i = len(self.sinks)
                self.sinks.append(mixer_sink_c())
                self.demod.connect_complex('mixer', self.sinks[i])
                self.kill_sink.append(self.sinks[i])
            elif plot == 'constellation':
                i = len(self.sinks)
                assert config['demod_type'] == 'cqpsk'   ## constellation plot requires cqpsk demod type
                self.sinks.append(constellation_sink_c())
                self.demod.connect_complex('diffdec', self.sinks[i])
                self.kill_sink.append(self.sinks[i])
            elif plot == 'correlation':
                assert config['demod_type'] == 'fsk4'   ## correlation plot requires fsk4 demod type
                assert config['symbol_rate'] == 4800	## 4800 required for correlation plot
                sps=config['if_rate'] // self.symbol_rate
                sinks = setup_correlation(sps, self.name, self.demod.connect_bb)
                self.kill_sink += sinks
                self.sinks += sinks
            else:
                sys.stderr.write('unrecognized plot type %s\n' % plot)
                return