Major simplification and some argument changes in grgsm_capture

grmgs_capture tried to do too many things for a simple recorder.
It was simplified by removing the receiver and ability to
save data to bursts files.

All other stuff that is not necessary for recording signal to disk was
also removed:
-setters/getters,
-storing of parameters that never will be changed.

The 'fc' parameter name was changed to 'freq' to follow GNU Radio
guidelines.

The 'shiftoff' parameter was removed.

'bb_gain' and 'if_gain' parameters were added.

Variables specific to some of SDR's like:
-gains at different stages,
-bandwidth (not all devices can set it),
-antennas (some devices have just one, some not),
were moved to separate options group.

What is left to be exposed is:
-dc_offset_mode,
-iq_balance_mode,
-gain_mode.

Change-Id: I092a43eaddb09a99c6cc05fde13f0ae94d9e0251
This commit is contained in:
Piotr Krysik 2018-09-20 14:49:27 +02:00
parent 8c30ba6687
commit e11b1d3710
1 changed files with 117 additions and 171 deletions

View File

@ -2,6 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# @file # @file
# @author (C) 2015 by Roman Khassraf <rkhassraf@gmail.com> # @author (C) 2015 by Roman Khassraf <rkhassraf@gmail.com>
# (C) 2019 by Piotr Krysik <ptrkrysik@gmail.com>
# @section LICENSE # @section LICENSE
# #
# Gr-gsm is free software; you can redistribute it and/or modify # Gr-gsm is free software; you can redistribute it and/or modify
@ -26,217 +27,162 @@ from gnuradio import eng_notation
from gnuradio import gr from gnuradio import gr
from gnuradio.eng_option import eng_option from gnuradio.eng_option import eng_option
from gnuradio.filter import firdes from gnuradio.filter import firdes
from math import pi from optparse import OptionParser, OptionGroup
from optparse import OptionParser
import grgsm
import osmosdr import osmosdr
import pmt import time
import grgsm
import signal import signal
import sys import sys
class grgsm_capture(gr.top_block): class grgsm_capture(gr.top_block):
def __init__(self,
def __init__(self, fc, gain, samp_rate, ppm, arfcn, cfile=None, burst_file=None, verbose=False, rec_length=None, args=""): freq,
gain=30,
samp_rate=1e6,
rec_length=float('Inf'),
freq_corr=0,
output_filename=None,
bandwidth=0,
bb_gain=20,
if_gain=20,
antenna="",
device_args=""):
gr.top_block.__init__(self, "Gr-gsm Capture") gr.top_block.__init__(self, "Gr-gsm Capture")
################################################## ##################################################
# Parameters # Setting up RF source
##################################################
self.fc = fc
self.gain = gain
self.samp_rate = samp_rate
self.ppm = ppm
self.arfcn = arfcn
self.cfile = cfile
self.burst_file = burst_file
self.verbose = verbose
self.shiftoff = shiftoff = 400e3
self.rec_length = rec_length
##################################################
# Processing Blocks
################################################## ##################################################
self.rtlsdr_source = osmosdr.source( args="numchan=" + str(1) + " " + args ) self.sdr_source = \
self.rtlsdr_source.set_sample_rate(samp_rate) osmosdr.source(args="numchan=1" + device_args )
self.rtlsdr_source.set_center_freq(fc - shiftoff, 0) self.sdr_source.set_sample_rate(samp_rate)
self.rtlsdr_source.set_freq_corr(ppm, 0) self.sdr_source.set_center_freq(freq, 0)
self.rtlsdr_source.set_dc_offset_mode(2, 0) self.sdr_source.set_freq_corr(freq_corr, 0)
self.rtlsdr_source.set_iq_balance_mode(2, 0) self.sdr_source.set_dc_offset_mode(2, 0)
self.rtlsdr_source.set_gain_mode(True, 0) self.sdr_source.set_iq_balance_mode(2, 0)
self.rtlsdr_source.set_gain(gain, 0) self.sdr_source.set_gain_mode(True, 0)
self.rtlsdr_source.set_if_gain(20, 0) self.sdr_source.set_gain(gain, 0)
self.rtlsdr_source.set_bb_gain(20, 0) self.sdr_source.set_if_gain(if_gain, 0)
self.rtlsdr_source.set_antenna("", 0) self.sdr_source.set_bb_gain(bb_gain, 0)
self.rtlsdr_source.set_bandwidth(250e3+abs(shiftoff), 0) self.sdr_source.set_antenna("", 0)
self.blocks_rotator = blocks.rotator_cc(-2*pi*shiftoff/samp_rate) if bandwidth != 0:
self.sdr_source.set_bandwidth(bandwidth, 0)
if self.rec_length is not None:
self.blocks_head_0 = blocks.head(gr.sizeof_gr_complex, int(samp_rate*rec_length))
if self.verbose or self.burst_file:
self.gsm_receiver = grgsm.receiver(4, ([self.arfcn]), ([]))
self.gsm_input = grgsm.gsm_input(
ppm=0,
osr=4,
fc=fc,
samp_rate_in=samp_rate,
)
self.gsm_clock_offset_control = grgsm.clock_offset_control(fc-shiftoff, samp_rate, osr=4)
if self.burst_file: ##################################################
self.gsm_burst_file_sink = grgsm.burst_file_sink(self.burst_file) # The rest of processing blocks
##################################################
if self.cfile: if rec_length != float('Inf'):
self.blocks_file_sink = blocks.file_sink(gr.sizeof_gr_complex*1, self.cfile, False) self.head = \
self.blocks_file_sink.set_unbuffered(False) blocks.head(gr.sizeof_gr_complex, int(samp_rate*rec_length))
if self.verbose: self.file_sink = blocks.file_sink(gr.sizeof_gr_complex*1, \
self.gsm_bursts_printer_0 = grgsm.bursts_printer(pmt.intern(""), output_filename, False)
False, False, False, False) self.file_sink.set_unbuffered(False)
################################################## ##################################################
# Connections # Connections
################################################## ##################################################
if self.rec_length is not None: #if recording length is defined connect head block after the source if rec_length != float('Inf'): #if recording length is not infinite
self.connect((self.rtlsdr_source, 0), (self.blocks_head_0, 0)) #connect head block after the source
self.connect((self.blocks_head_0, 0), (self.blocks_rotator, 0)) self.connect((self.sdr_source, 0), (self.head, 0))
self.connect((self.head, 0), (self.file_sink, 0))
else: else:
self.connect((self.rtlsdr_source, 0), (self.blocks_rotator, 0)) self.connect((self.sdr_source, 0), (self.file_sink, 0))
if self.cfile:
self.connect((self.blocks_rotator, 0), (self.blocks_file_sink, 0))
if self.verbose or self.burst_file:
self.connect((self.gsm_input, 0), (self.gsm_receiver, 0))
self.connect((self.blocks_rotator, 0), (self.gsm_input, 0))
self.msg_connect(self.gsm_clock_offset_control, "ctrl", self.gsm_input, "ctrl_in")
self.msg_connect(self.gsm_receiver, "measurements", self.gsm_clock_offset_control, "measurements")
if self.burst_file:
self.msg_connect(self.gsm_receiver, "C0", self.gsm_burst_file_sink, "in")
if self.verbose:
self.msg_connect(self.gsm_receiver, "C0", self.gsm_bursts_printer_0, "bursts")
def get_fc(self):
return self.fc
def set_fc(self, fc):
self.fc = fc
if self.verbose or self.burst_file:
self.gsm_input.set_fc(self.fc)
def get_arfcn(self):
return self.arfcn
def set_arfcn(self, arfcn):
self.arfcn = arfcn
if self.verbose or self.burst_file:
self.gsm_receiver.set_cell_allocation([self.arfcn])
new_freq = grgsm.arfcn.arfcn2downlink(self.arfcn)
self.set_fc(new_freq)
def get_gain(self):
return self.gain
def set_gain(self, gain):
self.gain = gain
def get_samp_rate(self):
return self.samp_rate
def set_samp_rate(self, samp_rate):
self.samp_rate = samp_rate
self.rtlsdr_source.set_sample_rate(self.samp_rate)
if self.verbose or self.burst_file:
self.gsm_input.set_samp_rate_in(self.samp_rate)
def get_ppm(self):
return self.ppm
def set_ppm(self, ppm):
self.ppm = ppm
self.set_ppm_slider(self.ppm)
def get_rec_length(self):
return self.rec_length
def set_rec_length(self, rec_length):
self.rec_length = rec_length
self.blocks_head_0.set_length(int(self.samp_rate*self.rec_length))
if __name__ == '__main__': if __name__ == '__main__':
parser = OptionParser(option_class=eng_option, usage="%prog [options]", parser = OptionParser(option_class=eng_option, usage="%prog [options] output_filename",
description="RTL-SDR capturing app of gr-gsm.") description="RTL-SDR capturing app of gr-gsm.")
parser.add_option("-f", "--fc", dest="fc", type="eng_float", parser.add_option("-f", "--freq", dest="freq", type="eng_float",
help="Set frequency [default=%default]") help="Set frequency [default=%default]")
parser.add_option("-a", "--arfcn", dest="arfcn", type="intx", parser.add_option("-a", "--arfcn", dest="arfcn", type="intx",
help="Set ARFCN instead of frequency (for PCS1900 add 0x8000 (2**15) to the ARFCN number)") help="Set ARFCN instead of frequency (for PCS1900 add"
"0x8000 (2**15) to the ARFCN number)")
parser.add_option("-g", "--gain", dest="gain", type="eng_float",
parser.add_option("-g", "--gain", dest="gain", type="eng_float",
default=eng_notation.num_to_str(30), default=eng_notation.num_to_str(30),
help="Set gain [default=%default]") help="Set gain [default=%default]")
parser.add_option("-s", "--samp-rate", dest="samp_rate", type="eng_float", parser.add_option("-s", "--samp-rate", dest="samp_rate", type="eng_float",
default=eng_notation.num_to_str(1000000), default=eng_notation.num_to_str(1000000),
help="Set samp_rate [default=%default]") help="Set samp_rate [default=%default]")
parser.add_option("-p", "--ppm", dest="ppm", type="intx", default=0,
help="Set ppm [default=%default]")
parser.add_option("-b", "--burst-file", dest="burst_file",
help="File where the captured bursts are saved")
parser.add_option("-c", "--cfile", dest="cfile",
help="File where the captured data are saved")
parser.add_option("", "--args", dest="args", type="string", default="",
help="Set device arguments [default=%default]")
parser.add_option("-v", "--verbose", action="store_true", parser.add_option("-T", "--rec-length", dest="rec_length", type="float",
help="If set, the captured bursts are printed to stdout") default='Inf', help="Set length of recording in seconds "
"[default=infinity]")
parser.add_option("-T", "--rec-length", dest="rec_length", type="eng_float", parser.add_option("-p", "--freq-corr", dest="freq_corr", type="eng_float",
help="Set length of recording in seconds [default=%default]") default="0", help="Set frequency correction in"
" ppm [default=%default]")
osmogroup = OptionGroup(parser, 'Additional osmosdr source options',
"Options specific to a subset of SDR receivers "
"supported by osmosdr source.")
osmogroup.add_option("-w", "--bandwidth", dest="bandwidth", type="eng_float",
default="0", help="Set bandwidth [default=samp_rate]")
osmogroup.add_option("", "--bb-gain", dest="bb_gain", type="eng_float",
default=eng_notation.num_to_str(20),
help="Set baseband gain [default=%default]")
osmogroup.add_option("", "--if-gain", dest="if_gain", type="eng_float",
default=eng_notation.num_to_str(20),
help="Set intermediate freque gain [default=%default]")
osmogroup.add_option("", "--ant", dest="antenna", type="string",
default="", help="Set antenna "
"[default=%default]")
osmogroup.add_option("", "--args", dest="device_args", type="string",
default="", help="Set device arguments "
"[default=%default]")
parser.add_option_group(osmogroup)
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
if options.cfile is None and options.burst_file is None: if not args:
parser.error("Please provide a cfile or a burst file (or both) to save the captured data\n") parser.error("Please provide an output file name to save the captured data\n")
if (options.fc is None and options.arfcn is None) or (options.fc is not None and options.arfcn is not None): output_filename = args[0]
parser.error("You have to provide either a frequency or an ARFCN (but not both).\n")
if (options.freq is None and options.arfcn is None) or \
(options.freq is not None and options.arfcn is not None):
parser.error("You have to provide either a frequency or"
"an ARFCN (but not both).\n")
arfcn = 0 arfcn = 0
fc = 939.4e6 freq = 0
if options.arfcn: if options.arfcn:
if not grgsm.arfcn.is_valid_arfcn(options.arfcn): if not grgsm.arfcn.is_valid_arfcn(options.arfcn):
parser.error("ARFCN is not valid\n") parser.error("ARFCN is not valid\n")
else: else:
arfcn = options.arfcn freq = grgsm.arfcn.arfcn2downlink(options.arfcn)
fc = grgsm.arfcn.arfcn2downlink(arfcn) elif options.freq:
elif options.fc: freq = options.freq
fc = options.fc
arfcn = grgsm.arfcn.downlink2arfcn(options.fc) tb = grgsm_capture(freq=freq,
gain=options.gain,
tb = grgsm_capture(fc=fc, gain=options.gain, samp_rate=options.samp_rate, freq_corr=options.freq_corr,
ppm=options.ppm, arfcn=arfcn, cfile=options.cfile, samp_rate=options.samp_rate,
burst_file=options.burst_file, verbose=options.verbose, output_filename=output_filename,
rec_length=options.rec_length, args=options.args) rec_length=options.rec_length,
bandwidth=options.bandwidth,
bb_gain=options.bb_gain,
if_gain=options.if_gain,
antenna=options.antenna,
device_args=options.device_args)
def signal_handler(signal, frame): def signal_handler(signal, frame):
tb.stop() tb.stop()
tb.wait() tb.wait()
sys.exit(0) sys.exit(0)
signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGINT, signal_handler)
tb.start() tb.start()