예제 #1
0
    def __init__(self, options):
        gr.top_block.__init__(self, "mhp")

        self.lfsr = lfsr.p25p2_lfsr(options.nac, options.sysid, options.wacn)
        xor_mask = ''
        for c in self.lfsr.xorsyms:
            xor_mask += chr(c)

        IN = blocks.file_source(gr.sizeof_char, options.input_file)

        slotid = options.tdma_slotid
        msgq = gr.msg_queue(2)
        do_msgq  = False

        wireshark_host = ''
        udp_port = 0
        verbosity = 100
        do_imbe = 1
        do_output = 1
        do_msgq = 0
        rx_q = gr.msg_queue(1)
        do_audio_output = 1
        phase2_tdma = 1
        
        FRAMER = op25_repeater.p25_frame_assembler(wireshark_host, udp_port, verbosity, do_imbe, do_output, do_msgq, rx_q, do_audio_output, phase2_tdma)
        FRAMER.set_xormask(xor_mask)

        S2F = blocks.short_to_float()
        M = blocks.multiply_const_ff(1.0 / 32767.0)

        SINK = audio.sink(8000, 'plughw:0,0')
        
        self.connect(IN, FRAMER, S2F, M, SINK)
예제 #2
0
    def __init__(self, input_rate=48000):
        gr.hier_block2.__init__(
            self,
            "CQPSK Receiver",
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
            gr.io_signature(1, 1, gr.sizeof_float * 1),
        )

        ##################################################
        # Parameters
        ##################################################
        self.input_rate = input_rate

        ##################################################
        # Variables
        ##################################################
        self.fa = fa = 6250
        self.fb = fb = fa + 0.1 * fa

        ##################################################
        # Blocks
        ##################################################
        self.short_to_float = blocks.short_to_float(1, 32768)
        self.p25_symbol_mapper_fb_0 = p25_symbol_mapper_fb(
            threshold1=-2.0,
            threshold2=0.0,
            threshold3=2.0,
            threshold4=4.0,
        )
        self.p25_cqpsk_demodulator_cf_0 = p25_cqpsk_demodulator_cf(
            costas_alpha=0.04,
            gain_mu=0.025,
            input_rate=48000,
            output_rate=4800,
        )
        self.op25_frame_assembler_0 = op25_repeater.p25_frame_assembler(
            "127.0.01", 0, True, True, True, False, gr.msg_queue(1), True,
            False)
        self.cutoff = filter.fir_filter_ccc(1, (filter.firdes.low_pass(
            1.0, 48000, (fa + fb) / 2, fb - fa, filter.firdes.WIN_HANN)))
        self.cutoff.declare_sample_delay(0)
        self.arb_resampler = p25_arb_resampler_cc(
            input_rate=input_rate,
            output_rate=48000,
        )

        ##################################################
        # Connections
        ##################################################
        self.connect((self.arb_resampler, 0), (self.cutoff, 0))
        self.connect((self.cutoff, 0), (self.p25_cqpsk_demodulator_cf_0, 0))
        self.connect((self.op25_frame_assembler_0, 0),
                     (self.short_to_float, 0))
        self.connect((self.p25_cqpsk_demodulator_cf_0, 0),
                     (self.p25_symbol_mapper_fb_0, 0))
        self.connect((self.p25_symbol_mapper_fb_0, 0),
                     (self.op25_frame_assembler_0, 0))
        self.connect((self, 0), (self.arb_resampler, 0))
        self.connect((self.short_to_float, 0), (self, 0))
예제 #3
0
    def __init__(self,
                 dest           = _def_dest,
                 do_imbe	= _def_do_imbe,
                 num_ambe	= _def_num_ambe,
                 wireshark_host	= _def_wireshark_host,
                 udp_port	= _def_udp_port,
                 do_msgq	= False,
                 msgq		= None,
                 audio_output	= _def_audio_output,
                 debug		= _def_debug):
        """
	Hierarchical block for P25 decoding.

        @param debug: debug level
        @type debug: int
	"""

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

        assert 0 <= num_ambe <= _def_max_tdma_timeslots
        assert not (num_ambe > 1 and dest != 'wav')

        self.debug = debug
        self.dest = dest
        do_output = 1
        do_audio_output = True

        if msgq is None:
            msgq = gr.msg_queue(1)

        self.p25_decoders = []
        self.audio_s2f = []
        self.scaler = []
        self.audio_sink = []
        self.xorhash = []
        num_decoders = 1
        if num_ambe > 1:
           num_decoders += num_ambe - 1
        for slot in xrange(num_decoders):
            self.p25_decoders.append(op25_repeater.p25_frame_assembler(wireshark_host, udp_port, debug, do_imbe, do_output, do_msgq, msgq, do_audio_output, True))
            self.p25_decoders[slot].set_slotid(slot)

            self.audio_s2f.append(blocks.short_to_float()) # another ridiculous conversion
            self.scaler.append(blocks.multiply_const_ff(1 / 32768.0))
            self.xorhash.append('')

            if dest == 'wav':
                filename = 'default-%f-%d.wav' % (time.time(), slot)
                n_channels = 1
                sample_rate = 8000
                bits_per_sample = 16
                self.audio_sink.append(blocks.wavfile_sink(filename, n_channels, sample_rate, bits_per_sample))
            elif dest == 'audio':
                self.audio_sink.append(audio.sink(_def_audio_rate, audio_output, True))

            self.connect(self, self.p25_decoders[slot], self.audio_s2f[slot], self.scaler[slot], self.audio_sink[slot])
예제 #4
0
	def __init__(self,infile, outfile, input_rate, channel_rate, codec_provoice, codec_p25, sslevel, svlevel):
		gr.top_block.__init__(self, "Top Block")
		
		self.input_rate = input_rate
		self.channel_rate = channel_rate
		
		self.source = blocks.file_source(gr.sizeof_gr_complex*1, infile, False)
		self.lp1_decim = int(input_rate/(channel_rate*1.6))
		print self.lp1_decim
		self.lp1 = filter.fir_filter_ccc(self.lp1_decim,firdes.low_pass( 1.0, self.input_rate, (self.channel_rate/2), ((self.channel_rate/2)*0.6), firdes.WIN_HAMMING))

		#self.audiodemod =  gr.quadrature_demod_cf(1)

		audio_pass = (input_rate/self.lp1_decim)*0.25
		audio_stop = audio_pass+2000
		self.audiodemod = analog.fm_demod_cf(channel_rate=(input_rate/self.lp1_decim), audio_decim=1, deviation=15000, audio_pass=audio_pass, audio_stop=audio_stop, gain=8, tau=75e-6)
		
		self.throttle = blocks.throttle(gr.sizeof_gr_complex*1, self.input_rate)

		self.signal_squelch = analog.pwr_squelch_cc(sslevel,0.01, 0, True)
		self.vox_squelch = analog.pwr_squelch_ff(svlevel, 0.0005, 0, True)
		
		self.audiosink = blocks.wavfile_sink(outfile, 1, 8000)

		if codec_provoice:
			self.dsd = dsd.block_ff(dsd.dsd_FRAME_PROVOICE,dsd.dsd_MOD_AUTO_SELECT,1,0,False)
			channel_rate = input_rate/self.lp1_decim
			self.resampler_in = filter.rational_resampler_fff(interpolation=48000, decimation=channel_rate, taps=None, fractional_bw=None, )
			output_rate = 8000
			resampler = filter.rational_resampler_fff(
                                        interpolation=(input_rate/self.lp1_decim),
                                        decimation=output_rate,
                                        taps=None,
                                        fractional_bw=None,
                                )
		elif codec_p25:
			symbol_deviation = 600.0
			symbol_rate = 4800
			channel_rate = input_rate/self.lp1_decim
			
		        fm_demod_gain = channel_rate / (2.0 * pi * symbol_deviation)
		        fm_demod = analog.quadrature_demod_cf(fm_demod_gain)

		        symbol_decim = 1
		        samples_per_symbol = channel_rate // symbol_rate
		        symbol_coeffs = (1.0/samples_per_symbol,) * samples_per_symbol
		        symbol_filter = filter.fir_filter_fff(symbol_decim, symbol_coeffs)

		        autotuneq = gr.msg_queue(2)
		        demod_fsk4 = op25.fsk4_demod_ff(autotuneq, channel_rate, symbol_rate)


		        # symbol slicer
		        levels = [ -2.0, 0.0, 2.0, 4.0 ]
		        slicer = op25.fsk4_slicer_fb(levels)

			imbe = repeater.vocoder(False, True, 0, "", 0, False)
			self.decodequeue = decodequeue = gr.msg_queue(10000)
			decoder = repeater.p25_frame_assembler('', 0, 0, True, True, False, decodequeue)
	
		        float_conversion = blocks.short_to_float(1, 8192)
		        resampler = filter.rational_resampler_fff(
		                        interpolation=8000,
		                        decimation=8000,
		                        taps=None,
		                        fractional_bw=None,
		                )
	
					
		#Tone squelch, custom GRC block that rips off CTCSS squelch to detect 4800 hz tone and latch squelch after that
		if not codec_provoice and not codec_p25:
			#self.tone_squelch = gr.tone_squelch_ff(audiorate, 4800.0, 0.05, 300, 0, True)
			#tone squelch is EDACS ONLY
			self.high_pass = filter.fir_filter_fff(1, firdes.high_pass(1, (input_rate/self.lp1_decim), 300, 30, firdes.WIN_HAMMING, 6.76))
			#output_rate = channel_rate
			resampler = filter.rational_resampler_fff(
                                        interpolation=8000,
                                        decimation=(input_rate/self.lp1_decim),
                                        taps=None,
                                        fractional_bw=None,
			)
		if(codec_provoice):
			self.connect(self.source, self.throttle, self.lp1, self.audiodemod, self.resampler_in, self.dsd, self.audiosink)
		elif(codec_p25):
			self.connect(self.source, self.throttle, self.lp1, fm_demod, symbol_filter, demod_fsk4, slicer, decoder, imbe, float_conversion, resampler, self.audiosink)
		else:
			self.connect(self.source, self.throttle, self.lp1, self.signal_squelch, self.audiodemod, self.high_pass, self.vox_squelch, resampler, self.audiosink)

		self.time_open = time.time()
		self.time_tone = 0
		self.time_activity = 0
예제 #5
0
    def __init__(self,
                 dest=_def_dest,
                 do_imbe=_def_do_imbe,
                 num_ambe=_def_num_ambe,
                 wireshark_host=_def_wireshark_host,
                 udp_port=_def_udp_port,
                 do_msgq=False,
                 msgq=None,
                 audio_output=_def_audio_output,
                 debug=_def_debug):
        """
	Hierarchical block for P25 decoding.

        @param debug: debug level
        @type debug: int
	"""

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

        assert 0 <= num_ambe <= _def_max_tdma_timeslots
        assert not (num_ambe > 1 and dest != 'wav')

        self.debug = debug
        self.dest = dest
        do_output = False
        if dest == 'wav':
            do_output = True
        do_audio_output = True

        if msgq is None:
            msgq = gr.msg_queue(1)

        self.p25_decoders = []
        self.audio_s2f = []
        self.scaler = []
        self.audio_sink = []
        self.xorhash = []
        num_decoders = 1
        if num_ambe > 1:
            num_decoders += num_ambe - 1
        for slot in xrange(num_decoders):
            self.p25_decoders.append(
                op25_repeater.p25_frame_assembler(wireshark_host, udp_port,
                                                  debug, do_imbe, do_output,
                                                  do_msgq, msgq,
                                                  do_audio_output, True))
            self.p25_decoders[slot].set_slotid(slot)

            self.xorhash.append('')

            if dest == 'wav':
                filename = 'default-%f-%d.wav' % (time.time(), slot)
                n_channels = 1
                sample_rate = 8000
                bits_per_sample = 16
                self.audio_s2f.append(
                    blocks.short_to_float())  # another ridiculous conversion
                self.scaler.append(blocks.multiply_const_ff(1 / 32768.0))
                self.audio_sink.append(
                    blocks.wavfile_sink(filename, n_channels, sample_rate,
                                        bits_per_sample))
                self.connect(self, self.p25_decoders[slot],
                             self.audio_s2f[slot], self.scaler[slot],
                             self.audio_sink[slot])
            elif dest == 'audio':
                self.connect(self, self.p25_decoders[slot])
예제 #6
0
    def __init__(self, input_rate=48000):
        gr.hier_block2.__init__(
            self,
            "C4FM Receiver",
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
            gr.io_signaturev(
                3, 3,
                [gr.sizeof_float * 1, gr.sizeof_float * 1, gr.sizeof_char * 1
                 ]),
        )

        ##################################################
        # Parameters
        ##################################################
        self.input_rate = input_rate

        ##################################################
        # Variables
        ##################################################
        self.if_rate = if_rate = 48000

        ##################################################
        # Blocks
        ##################################################
        self.short_to_float = blocks.short_to_float(1, 32768)
        self.p25_symbol_mapper_fb_0 = p25_symbol_mapper_fb(
            threshold1=-2,
            threshold2=0,
            threshold3=2.0,
            threshold4=4.0,
        )
        self.p25_fm_demodulator_cf_0 = p25_fm_demodulator_cf(
            max_deviation=2500,
            samp_rate=if_rate,
        )
        self.p25_c4fm_demodulator_ff_0 = p25_c4fm_demodulator_ff(
            input_rate=if_rate,
            output_rate=4800,
        )
        self.op25_frame_assembler_0 = op25_repeater.p25_frame_assembler(
            "127.0.01", 0, True, True, True, False, gr.msg_queue(1), True,
            False)
        self.cutoff = filter.fir_filter_ccf(
            input_rate / if_rate, (filter.firdes.low_pass(
                1.0, input_rate, 12500 / 2, 625, filter.firdes.WIN_HANN)))
        self.cutoff.declare_sample_delay(0)
        self.baseband_amp = blocks.multiply_const_vff((6.0, ))

        ##################################################
        # Connections
        ##################################################
        self.connect((self.baseband_amp, 0),
                     (self.p25_c4fm_demodulator_ff_0, 0))
        self.connect((self.baseband_amp, 0), (self, 1))
        self.connect((self.cutoff, 0), (self.p25_fm_demodulator_cf_0, 0))
        self.connect((self.op25_frame_assembler_0, 0),
                     (self.short_to_float, 0))
        self.connect((self.p25_c4fm_demodulator_ff_0, 0),
                     (self.p25_symbol_mapper_fb_0, 0))
        self.connect((self.p25_fm_demodulator_cf_0, 0), (self.baseband_amp, 0))
        self.connect((self.p25_symbol_mapper_fb_0, 0),
                     (self.op25_frame_assembler_0, 0))
        self.connect((self.p25_symbol_mapper_fb_0, 0), (self, 2))
        self.connect((self, 0), (self.cutoff, 0))
        self.connect((self.short_to_float, 0), (self, 0))
예제 #7
0
    def __init__(self):
        gr.top_block.__init__(self)
        parser = OptionParser(option_class=eng_option)

        parser.add_option("-1",
                          "--one-channel",
                          action="store_true",
                          default=False,
                          help="software synthesized Q channel")
        parser.add_option("-a",
                          "--agc",
                          action="store_true",
                          default=False,
                          help="automatic gain control (overrides --gain)")
        parser.add_option("-c",
                          "--calibration",
                          type="eng_float",
                          default=0,
                          help="freq offset")
        parser.add_option("-d",
                          "--debug",
                          action="store_true",
                          default=False,
                          help="allow time at init to attach gdb")
        parser.add_option("-C",
                          "--costas-alpha",
                          type="eng_float",
                          default=0.125,
                          help="Costas alpha")
        parser.add_option("-g", "--gain", type="eng_float", default=1.0)
        parser.add_option("-i",
                          "--input-file",
                          type="string",
                          default="in.dat",
                          help="specify the input file")
        parser.add_option("-I",
                          "--imbe",
                          action="store_true",
                          default=False,
                          help="output IMBE codewords")
        parser.add_option("-L",
                          "--low-pass",
                          type="eng_float",
                          default=6.5e3,
                          help="low pass cut-off",
                          metavar="Hz")
        parser.add_option("-o",
                          "--output-file",
                          type="string",
                          default="out.dat",
                          help="specify the output file")
        parser.add_option("-p",
                          "--polarity",
                          action="store_true",
                          default=False,
                          help="use reversed polarity")
        parser.add_option("-r",
                          "--raw-symbols",
                          type="string",
                          default=None,
                          help="dump decoded symbols to file")
        parser.add_option("-s",
                          "--sample-rate",
                          type="int",
                          default=96000,
                          help="input sample rate")
        parser.add_option("-t",
                          "--tone-detect",
                          action="store_true",
                          default=False,
                          help="use experimental tone detect algorithm")
        parser.add_option("-v",
                          "--verbose",
                          action="store_true",
                          default=False,
                          help="additional output")
        parser.add_option("-6",
                          "--k6k",
                          action="store_true",
                          default=False,
                          help="use 6K symbol rate")
        (options, args) = parser.parse_args()

        sample_rate = options.sample_rate
        if options.k6k:
            symbol_rate = 6000
        else:
            symbol_rate = 4800
        samples_per_symbol = sample_rate // symbol_rate

        IN = blocks.file_source(gr.sizeof_gr_complex, options.input_file)

        if options.one_channel:
            C2F = blocks.complex_to_float()
            F2C = blocks.float_to_complex()

        # osc./mixer for mixing signal down to approx. zero IF
        LO = analog.sig_source_c(sample_rate, analog.GR_COS_WAVE,
                                 options.calibration, 1.0, 0)
        MIXER = blocks.multiply_cc()

        # get signal into normalized range (-1.0 - +1.0)
        if options.agc:
            AMP = analog.feedforward_agc_cc(16, 1.0)
        else:
            AMP = blocks.multiply_const_cc(options.gain)

        lpf_taps = filter.firdes.low_pass(1.0, sample_rate, options.low_pass,
                                          options.low_pass * 0.1,
                                          filter.firdes.WIN_HANN)

        decim_amt = 1
        if options.tone_detect:
            if sample_rate != 96000:
                print "warning, only 96K has been tested."
                print "other rates may require theta to be reviewed/adjusted."
            step_size = 7.5e-8
            theta = -4  # optimum timing sampling point
            cic_length = 48
            DEMOD = op25_repeater.tdetect_cc(samples_per_symbol, step_size,
                                             theta, cic_length)
        else:
            # decim by 2 to get 48k rate
            samples_per_symbol /= 2  # for DECIM
            sample_rate /= 2  # for DECIM
            decim_amt = 2
            # create Gardner/Costas loop
            # the loop will not work if the sample levels aren't normalized (above)
            timing_error_gain = 0.025  # loop error gain
            gain_omega = 0.25 * timing_error_gain * timing_error_gain
            alpha = options.costas_alpha
            beta = 0.125 * alpha * alpha
            fmin = -0.025  # fmin and fmax are in radians/s
            fmax = 0.025
            DEMOD = op25_repeater.gardner_costas_cc(samples_per_symbol,
                                                    timing_error_gain,
                                                    gain_omega, alpha, beta,
                                                    fmax, fmin)
        DECIM = filter.fir_filter_ccf(decim_amt, lpf_taps)

        # probably too much phase noise etc to attempt coherent demodulation
        # so we use differential
        DIFF = digital.diff_phasor_cc()

        # take angle of the phase difference (in radians)
        TOFLOAT = blocks.complex_to_arg()

        # convert from radians such that signal is in [-3, -1, +1, +3]
        RESCALE = blocks.multiply_const_ff(1 / (pi / 4.0))

        # optional polarity reversal (should be unnec. - now autodetected)
        p = 1.0
        if options.polarity:
            p = -1.0
        POLARITY = blocks.multiply_const_ff(p)

        # hard decision at specified points
        levels = [-2.0, 0.0, 2.0, 4.0]
        SLICER = op25_repeater.fsk4_slicer_fb(levels)

        # assemble received frames and route to Wireshark via UDP
        hostname = "127.0.0.1"
        port = 23456
        debug = 0
        if options.verbose:
            debug = 255
        do_imbe = False
        if options.imbe:
            do_imbe = True
        do_output = True  # enable block's output stream
        do_msgq = False  # msgq output not yet implemented
        msgq = gr.msg_queue(2)
        DECODER = op25_repeater.p25_frame_assembler(hostname, port, debug,
                                                    do_imbe, do_output,
                                                    do_msgq, msgq, False,
                                                    False)

        OUT = blocks.file_sink(gr.sizeof_char, options.output_file)

        if options.one_channel:
            self.connect(IN, C2F, F2C, (MIXER, 0))
        else:
            self.connect(IN, (MIXER, 0))
        self.connect(LO, (MIXER, 1))
        self.connect(MIXER, AMP, DECIM, DEMOD, DIFF, TOFLOAT, RESCALE,
                     POLARITY, SLICER, DECODER, OUT)

        if options.raw_symbols:
            SINKC = blocks.file_sink(gr.sizeof_char, options.raw_symbols)
            self.connect(SLICER, SINKC)

        if options.debug:
            print 'Ready for GDB to attach (pid = %d)' % (os.getpid(), )
            raw_input("Press 'Enter' to continue...")
    def __init__(self, system, site_uuid, overseer_uuid):

        gr.top_block.__init__(self, "p25 receiver")

        #set globals
        self.is_locked = False
        self.system = system
        self.instance_uuid = '%s' % uuid.uuid4()

        self.log = logging.getLogger('overseer.p25_control_demod.%s' %
                                     self.instance_uuid)
        self.protocol_log = logging.getLogger('protocol.%s' %
                                              self.instance_uuid)
        self.log.info('Initializing instance: %s site: %s overseer: %s' %
                      (self.instance_uuid, site_uuid, overseer_uuid))

        self.site_uuid = site_uuid
        self.overseer_uuid = overseer_uuid

        self.control_channel = system['channels'][
            system['default_control_channel']]
        self.control_channel_i = system['default_control_channel']

        self.channel_identifier_table = {}

        try:
            self.modulation = system['modulation']
        except:
            self.modulation = 'C4FM'

        self.channel_rate = 12500
        symbol_rate = 4800

        self.site_detail = {}
        self.site_detail['WACN ID'] = None
        self.site_detail['System ID'] = None
        self.site_detail['Control Channel'] = None
        self.site_detail['System Service Class'] = None
        self.site_detail['Site ID'] = None
        self.site_detail['RF Sub-system ID'] = None
        self.site_detail['RFSS Network Connection'] = None

        self.bad_messages = 0
        self.total_messages = 0
        self.quality = []

        self.keep_running = True

        self.source = None

        # channel filter
        channel_rate = self.channel_rate * 2
        self.control_prefilter = filter.freq_xlating_fir_filter_ccc(
            1, (1, ), 0, channel_rate)

        # power squelch
        #power_squelch = gr.pwr_squelch_cc(squelch, 1e-3, 0, True)
        #self.connect(self.channel_filter, power_squelch)

        autotuneq = gr.msg_queue(2)
        self.demod_watcher = demod_watcher(self)
        self.symbol_deviation = 600.0

        if self.modulation == 'C4FM':
            # FM demodulator
            fm_demod_gain = channel_rate / (2.0 * pi * self.symbol_deviation)
            self.fm_demod = fm_demod = analog.quadrature_demod_cf(
                fm_demod_gain)

            moving_sum = blocks.moving_average_ff(10000, 1, 40000)
            subtract = blocks.sub_ff(1)
            divide_const = blocks.multiply_const_vff((0.0001, ))
            self.probe = blocks.probe_signal_f()
            self.connect(self.fm_demod, moving_sum, divide_const, self.probe)

            # symbol filter
            symbol_decim = 1
            samples_per_symbol = channel_rate // symbol_rate
            symbol_coeffs = (1.0 / samples_per_symbol, ) * samples_per_symbol
            symbol_filter = filter.fir_filter_fff(symbol_decim, symbol_coeffs)

            demod_fsk4 = op25.fsk4_demod_ff(autotuneq, channel_rate,
                                            symbol_rate)
        elif self.modulation == 'CQPSK':
            # FM demodulator
            fm_demod_gain = channel_rate / (2.0 * pi * self.symbol_deviation)
            self.fm_demod = fm_demod = analog.quadrature_demod_cf(
                fm_demod_gain)

            moving_sum = blocks.moving_average_ff(10000, 1, 40000)
            subtract = blocks.sub_ff(1)
            divide_const = blocks.multiply_const_vff((0.0001, ))
            self.probe = blocks.probe_signal_f()
            self.connect(fm_demod, moving_sum, divide_const, self.probe)

            #self.resampler = filter.pfb.arb_resampler_ccf(float(48000)/float(channel_rate))
            self.resampler = blocks.multiply_const_cc(1.0)
            self.agc = analog.feedforward_agc_cc(1024, 1.0)
            self.symbol_filter_c = blocks.multiply_const_cc(1.0)

            gain_mu = 0.025
            omega = float(channel_rate) / float(symbol_rate)
            gain_omega = 0.1 * gain_mu * gain_mu

            alpha = 0.04
            beta = 0.125 * alpha * alpha
            fmax = 1200  # Hz
            fmax = 2 * pi * fmax / float(channel_rate)

            self.clock = repeater.gardner_costas_cc(omega, gain_mu, gain_omega,
                                                    alpha, beta, fmax, -fmax)
            self.diffdec = digital.diff_phasor_cc()
            self.to_float = blocks.complex_to_arg()
            self.rescale = blocks.multiply_const_ff((1 / (pi / 4)))

    # symbol slicer
        levels = [-2.0, 0.0, 2.0, 4.0]
        slicer = op25.fsk4_slicer_fb(levels)

        # frame decoder
        self.decodequeue = decodequeue = gr.msg_queue(1000)
        qsink = blocks.message_sink(gr.sizeof_char, self.decodequeue, False)
        self.decoder = decoder = repeater.p25_frame_assembler(
            '', 0, 0, False, True, True, autotuneq, False, False)

        if self.modulation == 'C4FM':
            self.connect(self.control_prefilter, fm_demod, symbol_filter,
                         demod_fsk4, slicer, decoder, qsink)
        elif self.modulation == 'CQPSK':
            self.connect(self.resampler, self.agc, self.symbol_filter_c,
                         self.clock, self.diffdec, self.to_float, self.rescale,
                         slicer, decoder, qsink)

##################################################
# Threads
##################################################
        self.connector = frontend_connector()
        self.client_redis = client_redis()
        self.redis_demod_publisher = redis_demod_publisher(parent_demod=self)

        quality_check_0 = threading.Thread(target=self.quality_check)
        quality_check_0.daemon = True
        quality_check_0.start()
        # Adjust the channel offset
        #
        self.tune_next_control_channel()

        #self.receive_engine()

        receive_engine = threading.Thread(target=self.receive_engine)
        receive_engine.daemon = True
        receive_engine.start()
예제 #9
0
    def configure_blocks(self, protocol):
        if protocol == 'provoice' or protocol == 'analog_edacs':
            protocol = 'analog'
        self.log.debug('configure_blocks(%s)' % protocol)
        if not (protocol == 'p25' or protocol == 'p25_tdma'
                or protocol == 'p25_cqpsk' or protocol == 'p25_cqpsk_tdma'
                or protocol == 'provoice' or protocol == 'dsd_p25'
                or protocol == 'analog' or protocol == 'none'):
            raise Exception('Invalid protocol %s' % protocol)
        if self.protocol == protocol:
            return True
        self.lock()
        if self.protocol == 'analog':
            self.disconnect(self.source, self.signal_squelch, self.audiodemod,
                            self.high_pass, self.resampler, self.sink)
            self.signal_squelch = None
            self.audiodemod = None
            self.high_pass = None
            self.resampler = None

        elif self.protocol == 'p25' or 'p25_tdma':
            try:
                self.disconnect(self.source, self.prefilter,
                                self.fm_demod)  #, (self.subtract,0))
                self.disconnect(self.fm_demod, self.symbol_filter,
                                self.demod_fsk4, self.slicer, self.decoder,
                                self.float_conversion, self.sink)
                self.disconnect(self.slicer, self.decoder2, self.qsink)
                self.demod_watcher.keep_running = False

            except:
                pass
            #self.disconnect(self.fm_demod, self.avg, self.mult, (self.subtract,1))

            self.prefilter = None
            self.fm_demod = None
            #self.avg = None
            #self.mult = None
            #self.subtract = None
            self.symbol_filter = None
            self.demod_fsk4 = None
            self.slicer = None
            self.decoder = None
            self.decoder2 = None
            self.qsink = None
            self.imbe = None
            self.float_conversion = None
            self.resampler = None
        elif self.protocol == 'p25_cqpsk' or self.protocol == 'p25_cqpsk_tdma':
            self.disconnect(self.source, self.resampler, self.agc,
                            self.symbol_filter_c, self.clock, self.diffdec,
                            self.to_float, self.rescale, self.slicer,
                            self.decoder2, self.qsink)  #, (self.subtract,0))
            self.disconnect(self.slicer, self.decoder, self.float_conversion,
                            self.sink)

            self.prefilter = None
            self.resampler = None
            self.agc = None
            self.symbol_filter_c = None
            self.clock = None
            self.diffdec = None
            self.to_float = None
            self.rescale = None
            self.slicer = None

            self.imbe = None
            self.decodequeue3 = None
            self.decodequeue2 = None
            self.decodequeue = None

            self.demod_watcher = None
            self.decoder = None
            self.decoder2 = None
            self.qsink = None
            self.float_conversion = None

        elif self.protocol == 'provoice':
            self.disconnect(self.source, self.fm_demod, self.resampler_in,
                            self.dsd, self.out_squelch, self.sink)
            self.fm_demod = None
            self.resampler_in = None
            self.dsd = None
            self.out_squelch = None
        elif self.protocol == 'dsd_p25':
            self.disconnect(self.source, self.fm_demod, self.resampler_in,
                            self.dsd, self.sink)
            self.fm_demod = None
            self.resampler_in = None
            self.dsd = None
        self.protocol = protocol

        if protocol == 'analog':
            self.signal_squelch = analog.pwr_squelch_cc(-100, 0.01, 0, True)
            #self.tone_squelch = gr.tone_squelch_ff(audiorate, 4800.0, 0.05, 300, 0, True)
            #tone squelch is EDACS ONLY
            self.audiodemod = analog.fm_demod_cf(
                channel_rate=self.input_rate,
                audio_decim=1,
                deviation=15000,
                audio_pass=(self.input_rate * 0.25),
                audio_stop=((self.input_rate * 0.25) + 2000),
                gain=8,
                tau=75e-6)
            self.high_pass = filter.fir_filter_fff(
                1,
                firdes.high_pass(1, self.input_rate, 300, 30,
                                 firdes.WIN_HAMMING, 6.76))
            self.resampler = filter.rational_resampler_fff(
                interpolation=8000,
                decimation=self.input_rate,
                taps=None,
                fractional_bw=None,
            )
            self.connect(self.source, self.signal_squelch, self.audiodemod,
                         self.high_pass, self.resampler, self.sink)
        elif protocol == 'p25' or protocol == 'p25_tdma':
            self.symbol_deviation = symbol_deviation = 600.0
            if protocol == 'p25_tdma':
                symbol_rate = 6000
            else:
                symbol_rate = 4800
            channel_rate = self.input_rate

            self.prefilter = filter.freq_xlating_fir_filter_ccc(
                1, (1, ), 0, self.input_rate)

            fm_demod_gain = channel_rate / (2.0 * pi * symbol_deviation)
            self.fm_demod = analog.quadrature_demod_cf(fm_demod_gain)

            #self.avg = blocks.moving_average_ff(1000, 1, 4000)
            #self.mult = blocks.multiply_const_vff((0.001, ))
            #self.subtract = blocks.sub_ff(1)

            symbol_decim = 1
            samples_per_symbol = channel_rate // symbol_rate
            symbol_coeffs = (1.0 / samples_per_symbol, ) * samples_per_symbol
            self.symbol_filter = filter.fir_filter_fff(symbol_decim,
                                                       symbol_coeffs)

            autotuneq = gr.msg_queue(2)
            self.demod_fsk4 = op25.fsk4_demod_ff(autotuneq, channel_rate,
                                                 symbol_rate)

            # symbol slicer
            levels = [-2.0, 0.0, 2.0, 4.0]
            self.slicer = op25.fsk4_slicer_fb(levels)

            self.imbe = repeater.vocoder(False, True, 0, "", 0, False)
            self.decodequeue3 = decodequeue3 = gr.msg_queue(10000)
            self.decodequeue2 = decodequeue2 = gr.msg_queue(10000)
            self.decodequeue = decodequeue = gr.msg_queue(10000)

            self.demod_watcher = None  #demod_watcher(decodequeue2, self.adjust_channel_offset)

            self.decoder = repeater.p25_frame_assembler(
                '', 0, 0, True, True, False, decodequeue2, True,
                (True if protocol == 'p25_tdma' else False))
            self.decoder2 = repeater.p25_frame_assembler(
                '', 0, 0, False, True, False, decodequeue3, False, False)

            self.qsink = blocks.message_sink(gr.sizeof_char, self.decodequeue,
                                             False)

            self.float_conversion = blocks.short_to_float(1, 8192)

            self.connect(self.source, self.prefilter,
                         self.fm_demod)  #, (self.subtract,0))
            #self.connect(self.fm_demod, self.symbol_filter, self.demod_fsk4, self.slicer, self.decoder, self.imbe, self.float_conversion, self.sink)
            self.connect(self.fm_demod, self.symbol_filter, self.demod_fsk4,
                         self.slicer, self.decoder, self.float_conversion,
                         self.sink)
            self.connect(self.slicer, self.decoder2, self.qsink)
            #self.connect(self.fm_demod, self.avg, self.mult, (self.subtract,1))
        elif protocol == 'p25_cqpsk' or protocol == 'p25_cqpsk_tdma':
            self.symbol_deviation = symbol_deviation = 600.0
            self.resampler = blocks.multiply_const_cc(1.0)
            self.agc = analog.feedforward_agc_cc(1024, 1.0)
            self.symbol_filter_c = blocks.multiply_const_cc(1.0)

            gain_mu = 0.025
            if protocol == 'p25_cqpsk_tdma':
                symbol_rate = 6000
            else:
                symbol_rate = 4800
            omega = float(self.input_rate) / float(symbol_rate)
            gain_omega = 0.1 * gain_mu * gain_mu

            alpha = 0.04
            beta = 0.125 * alpha * alpha
            fmax = 1200  # Hz
            fmax = 2 * pi * fmax / float(self.input_rate)

            self.clock = repeater.gardner_costas_cc(omega, gain_mu, gain_omega,
                                                    alpha, beta, fmax, -fmax)
            self.diffdec = digital.diff_phasor_cc()
            self.to_float = blocks.complex_to_arg()
            self.rescale = blocks.multiply_const_ff((1 / (pi / 4)))

            # symbol slicer
            levels = [-2.0, 0.0, 2.0, 4.0]
            self.slicer = op25.fsk4_slicer_fb(levels)

            #self.imbe = repeater.vocoder(False, True, 0, "", 0, False)
            self.decodequeue3 = decodequeue3 = gr.msg_queue(2)
            self.decodequeue2 = decodequeue2 = gr.msg_queue(2)
            self.decodequeue = decodequeue = gr.msg_queue(10000)

            #self.demod_watcher = demod_watcher(decodequeue2, self.adjust_channel_offset)
            self.decoder = repeater.p25_frame_assembler(
                '', 0, 0, True, True, False, decodequeue2, True,
                (False if protocol == 'p25_cqpsk' else True))
            self.decoder2 = repeater.p25_frame_assembler(
                '', 0, 0, False, True, True, decodequeue3, False, False)

            #temp for debug
            #self.debug_sink = blocks.file_sink(1, '/dev/null')
            #self.connect(self.slicer, self.debug_sink)

            self.qsink = blocks.message_sink(gr.sizeof_char, self.decodequeue,
                                             False)

            self.float_conversion = blocks.short_to_float(1, 8192)

            self.connect(self.source, self.resampler, self.agc,
                         self.symbol_filter_c, self.clock, self.diffdec,
                         self.to_float, self.rescale, self.slicer,
                         self.decoder2, self.qsink)  #, (self.subtract,0))
            self.connect(self.slicer, self.decoder, self.float_conversion,
                         self.sink)
        elif protocol == 'provoice':
            fm_demod_gain = 0.6
            self.fm_demod = analog.quadrature_demod_cf(fm_demod_gain)

            self.resampler_in = filter.rational_resampler_fff(
                interpolation=48000,
                decimation=self.input_rate,
                taps=None,
                fractional_bw=None,
            )
            self.dsd = dsd.block_ff(dsd.dsd_FRAME_PROVOICE,
                                    dsd.dsd_MOD_AUTO_SELECT, 3, 0, False)
            self.out_squelch = analog.pwr_squelch_ff(-100, 0.01, 0, True)

            self.connect(self.source, self.fm_demod, self.resampler_in,
                         self.dsd, self.out_squelch, self.sink)
        elif protocol == 'dsd_p25':
            symbol_deviation = 600.0
            fm_demod_gain = 0.4  #self.input_rate / (2.0 * pi * symbol_deviation)
            self.fm_demod = analog.quadrature_demod_cf(fm_demod_gain)

            self.resampler_in = filter.rational_resampler_fff(
                interpolation=48000,
                decimation=self.input_rate,
                taps=None,
                fractional_bw=None,
            )
            self.dsd = dsd.block_ff(dsd.dsd_FRAME_P25_PHASE_1,
                                    dsd.dsd_MOD_AUTO_SELECT, 3, 3, False)

            self.connect(self.source, self.fm_demod, self.resampler_in,
                         self.dsd, self.sink)
        self.unlock()
예제 #10
0
    def __init__(self):
        gr.top_block.__init__(self)
        parser = OptionParser(option_class=eng_option)

        parser.add_option("-1", "--one-channel", action="store_true", default=False, help="software synthesized Q channel")
        parser.add_option("-a", "--agc", action="store_true", default=False, help="automatic gain control (overrides --gain)")
        parser.add_option("-c", "--calibration", type="eng_float", default=0, help="freq offset")
        parser.add_option("-d", "--debug", action="store_true", default=False, help="allow time at init to attach gdb")
        parser.add_option("-C", "--costas-alpha", type="eng_float", default=0.125, help="Costas alpha")
        parser.add_option("-g", "--gain", type="eng_float", default=1.0)
        parser.add_option("-i", "--input-file", type="string", default="in.dat", help="specify the input file")
        parser.add_option("-I", "--imbe", action="store_true", default=False, help="output IMBE codewords")
        parser.add_option("-L", "--low-pass", type="eng_float", default=6.5e3, help="low pass cut-off", metavar="Hz")
        parser.add_option("-o", "--output-file", type="string", default="out.dat", help="specify the output file")
        parser.add_option("-p", "--polarity", action="store_true", default=False, help="use reversed polarity")
        parser.add_option("-r", "--raw-symbols", type="string", default=None, help="dump decoded symbols to file")
        parser.add_option("-s", "--sample-rate", type="int", default=96000, help="input sample rate")
        parser.add_option("-t", "--tone-detect", action="store_true", default=False, help="use experimental tone detect algorithm")
        parser.add_option("-v", "--verbose", action="store_true", default=False, help="additional output")
        parser.add_option("-6", "--k6k", action="store_true", default=False, help="use 6K symbol rate")
        (options, args) = parser.parse_args()
 
        sample_rate = options.sample_rate
        if options.k6k:
            symbol_rate = 6000
        else:
            symbol_rate = 4800
        samples_per_symbol = sample_rate // symbol_rate

        IN = blocks.file_source(gr.sizeof_gr_complex, options.input_file)

        if options.one_channel:
            C2F = blocks.complex_to_float()
            F2C = blocks.float_to_complex()

        # osc./mixer for mixing signal down to approx. zero IF
        LO = analog.sig_source_c (sample_rate, analog.GR_COS_WAVE, options.calibration, 1.0, 0)
        MIXER = blocks.multiply_cc()

        # get signal into normalized range (-1.0 - +1.0)
        if options.agc:
            AMP = analog.feedforward_agc_cc(16, 1.0)
        else:
            AMP = blocks.multiply_const_cc(options.gain)

        lpf_taps = filter.firdes.low_pass(1.0, sample_rate, options.low_pass, options.low_pass * 0.1, filter.firdes.WIN_HANN)

        decim_amt = 1
        if options.tone_detect:
            if sample_rate != 96000:
                print "warning, only 96K has been tested."
                print "other rates may require theta to be reviewed/adjusted."
            step_size = 7.5e-8
            theta = -4	# optimum timing sampling point
            cic_length = 48
            DEMOD = op25_repeater.tdetect_cc(samples_per_symbol, step_size, theta, cic_length)
        else:
            # decim by 2 to get 48k rate
            samples_per_symbol /= 2	# for DECIM
            sample_rate /= 2	# for DECIM
            decim_amt = 2
            # create Gardner/Costas loop
            # the loop will not work if the sample levels aren't normalized (above)
            timing_error_gain = 0.025   # loop error gain
            gain_omega = 0.25 * timing_error_gain * timing_error_gain
            alpha = options.costas_alpha
            beta = 0.125 * alpha * alpha
            fmin = -0.025   # fmin and fmax are in radians/s
            fmax =  0.025
            DEMOD = op25_repeater.gardner_costas_cc(samples_per_symbol, timing_error_gain, gain_omega, alpha, beta, fmax, fmin)
        DECIM = filter.fir_filter_ccf (decim_amt, lpf_taps)

        # probably too much phase noise etc to attempt coherent demodulation
        # so we use differential
        DIFF = digital.diff_phasor_cc()

        # take angle of the phase difference (in radians)
        TOFLOAT = blocks.complex_to_arg()

        # convert from radians such that signal is in [-3, -1, +1, +3]
        RESCALE = blocks.multiply_const_ff(1 / (pi / 4.0))

        # optional polarity reversal (should be unnec. - now autodetected)
        p = 1.0
        if options.polarity:
            p = -1.0
        POLARITY = blocks.multiply_const_ff(p)

        # hard decision at specified points
        levels = [-2.0, 0.0, 2.0, 4.0 ]
        SLICER = op25_repeater.fsk4_slicer_fb(levels)

        # assemble received frames and route to Wireshark via UDP
        hostname = "127.0.0.1"
        port = 23456
        debug = 0
	if options.verbose:
                debug = 255
        do_imbe = False
        if options.imbe:
                do_imbe = True
        do_output = True # enable block's output stream
        do_msgq = False  # msgq output not yet implemented
        msgq = gr.msg_queue(2)
        DECODER = op25_repeater.p25_frame_assembler(hostname, port, debug, do_imbe, do_output, do_msgq, msgq, False, False)

        OUT = blocks.file_sink(gr.sizeof_char, options.output_file)

        if options.one_channel:
            self.connect(IN, C2F, F2C, (MIXER, 0))
        else:
            self.connect(IN, (MIXER, 0))
        self.connect(LO, (MIXER, 1))
        self.connect(MIXER, AMP, DECIM, DEMOD, DIFF, TOFLOAT, RESCALE, POLARITY, SLICER, DECODER, OUT)

        if options.raw_symbols:
            SINKC = blocks.file_sink(gr.sizeof_char, options.raw_symbols)
            self.connect(SLICER, SINKC)

        if options.debug:
            print 'Ready for GDB to attach (pid = %d)' % (os.getpid(),)
            raw_input("Press 'Enter' to continue...")