blob: b77acbbb31d27a5add6257712ab78ad67c278291 [file] [log] [blame]
Piotr Krysik35582082015-09-02 21:49:12 +02001#!/usr/bin/env python2
Piotr Krysik6577ec22016-07-15 13:21:09 +02002# -*- coding: utf-8 -*-
Piotr Krysikea34c012016-10-02 18:53:43 +02003# @file
Piotr Krysika6268a52017-08-23 16:02:19 +02004# @author (C) 2014-2016 by Piotr Krysik <ptrkrysik@gmail.com>
Piotr Krysikea34c012016-10-02 18:53:43 +02005# @section LICENSE
6#
7# Gr-gsm is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 3, or (at your option)
10# any later version.
11#
12# Gr-gsm is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with gr-gsm; see the file COPYING. If not, write to
19# the Free Software Foundation, Inc., 51 Franklin Street,
20# Boston, MA 02110-1301, USA.
21#
22#
Piotr Krysik35582082015-09-02 21:49:12 +020023##################################################
24# GNU Radio Python Flow Graph
Piotr Krysik332e0b52016-02-13 18:37:32 +010025# Title: Gr-gsm Livemon
Piotr Krysik6577ec22016-07-15 13:21:09 +020026# Author: Piotr Krysik
27# Description: Interactive monitor of a single C0 channel with analysis performed by Wireshark (command to run wireshark: sudo wireshark -k -f udp -Y gsmtap -i lo)
Piotr Krysik82638ab2017-07-23 19:14:13 +020028# Generated: Sun Jul 23 19:07:48 2017
Piotr Krysik35582082015-09-02 21:49:12 +020029##################################################
30
31if __name__ == '__main__':
32 import ctypes
33 import sys
34 if sys.platform.startswith('linux'):
35 try:
36 x11 = ctypes.cdll.LoadLibrary('libX11.so')
37 x11.XInitThreads()
38 except:
39 print "Warning: failed to XInitThreads()"
40
41from PyQt4 import Qt
42from gnuradio import blocks
43from gnuradio import eng_notation
44from gnuradio import gr
45from gnuradio import qtgui
46from gnuradio.eng_option import eng_option
47from gnuradio.filter import firdes
48from gnuradio.qtgui import Range, RangeWidget
49from math import pi
50from optparse import OptionParser
51import grgsm
52import osmosdr
53import pmt
54import sip
55import sys
56import time
57
58
Piotr Krysik332e0b52016-02-13 18:37:32 +010059class grgsm_livemon(gr.top_block, Qt.QWidget):
Piotr Krysik35582082015-09-02 21:49:12 +020060
Piotr Krysik82638ab2017-07-23 19:14:13 +020061 def __init__(self, args="", gain=30, osr=4, ppm=0, samp_rate=2000000.052982, shiftoff=400e3, fc=941.8e6):
Piotr Krysik332e0b52016-02-13 18:37:32 +010062 gr.top_block.__init__(self, "Gr-gsm Livemon")
Piotr Krysik35582082015-09-02 21:49:12 +020063 Qt.QWidget.__init__(self)
Piotr Krysik332e0b52016-02-13 18:37:32 +010064 self.setWindowTitle("Gr-gsm Livemon")
Piotr Krysik35582082015-09-02 21:49:12 +020065 try:
Piotr Krysik6577ec22016-07-15 13:21:09 +020066 self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc'))
Piotr Krysik35582082015-09-02 21:49:12 +020067 except:
Piotr Krysik6577ec22016-07-15 13:21:09 +020068 pass
Piotr Krysik35582082015-09-02 21:49:12 +020069 self.top_scroll_layout = Qt.QVBoxLayout()
70 self.setLayout(self.top_scroll_layout)
71 self.top_scroll = Qt.QScrollArea()
72 self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame)
73 self.top_scroll_layout.addWidget(self.top_scroll)
74 self.top_scroll.setWidgetResizable(True)
75 self.top_widget = Qt.QWidget()
76 self.top_scroll.setWidget(self.top_widget)
77 self.top_layout = Qt.QVBoxLayout(self.top_widget)
78 self.top_grid_layout = Qt.QGridLayout()
79 self.top_layout.addLayout(self.top_grid_layout)
80
Piotr Krysik332e0b52016-02-13 18:37:32 +010081 self.settings = Qt.QSettings("GNU Radio", "grgsm_livemon")
Piotr Krysik35582082015-09-02 21:49:12 +020082 self.restoreGeometry(self.settings.value("geometry").toByteArray())
83
84 ##################################################
85 # Parameters
86 ##################################################
Piotr Krysik6577ec22016-07-15 13:21:09 +020087 self.args = args
Piotr Krysik35582082015-09-02 21:49:12 +020088 self.gain = gain
Piotr Krysik82638ab2017-07-23 19:14:13 +020089 self.osr = osr
Piotr Krysik35582082015-09-02 21:49:12 +020090 self.ppm = ppm
91 self.samp_rate = samp_rate
92 self.shiftoff = shiftoff
Piotr Krysik82638ab2017-07-23 19:14:13 +020093 self.fc = fc
Piotr Krysik35582082015-09-02 21:49:12 +020094
95 ##################################################
96 # Variables
97 ##################################################
98 self.ppm_slider = ppm_slider = ppm
99 self.g_slider = g_slider = gain
100 self.fc_slider = fc_slider = fc
101
102 ##################################################
103 # Blocks
104 ##################################################
Piotr Krysik93ba6bc2017-01-23 21:33:09 +0100105 self._ppm_slider_range = Range(-150, 150, 0.1, ppm, 100)
Piotr Krysik35582082015-09-02 21:49:12 +0200106 self._ppm_slider_win = RangeWidget(self._ppm_slider_range, self.set_ppm_slider, "PPM Offset", "counter", float)
107 self.top_layout.addWidget(self._ppm_slider_win)
108 self._g_slider_range = Range(0, 50, 0.5, gain, 100)
109 self._g_slider_win = RangeWidget(self._g_slider_range, self.set_g_slider, "Gain", "counter", float)
110 self.top_layout.addWidget(self._g_slider_win)
Piotr Krysik93ba6bc2017-01-23 21:33:09 +0100111 self._fc_slider_range = Range(800e6, 1990e6, 2e5, fc, 100)
Piotr Krysik35582082015-09-02 21:49:12 +0200112 self._fc_slider_win = RangeWidget(self._fc_slider_range, self.set_fc_slider, "Frequency", "counter_slider", float)
113 self.top_layout.addWidget(self._fc_slider_win)
Piotr Krysik7185b662016-02-14 20:24:54 +0100114 self.rtlsdr_source_0 = osmosdr.source( args="numchan=" + str(1) + " " + args )
Piotr Krysik35582082015-09-02 21:49:12 +0200115 self.rtlsdr_source_0.set_sample_rate(samp_rate)
116 self.rtlsdr_source_0.set_center_freq(fc_slider-shiftoff, 0)
117 self.rtlsdr_source_0.set_freq_corr(ppm_slider, 0)
118 self.rtlsdr_source_0.set_dc_offset_mode(2, 0)
119 self.rtlsdr_source_0.set_iq_balance_mode(2, 0)
120 self.rtlsdr_source_0.set_gain_mode(False, 0)
121 self.rtlsdr_source_0.set_gain(g_slider, 0)
122 self.rtlsdr_source_0.set_if_gain(20, 0)
123 self.rtlsdr_source_0.set_bb_gain(20, 0)
124 self.rtlsdr_source_0.set_antenna("", 0)
125 self.rtlsdr_source_0.set_bandwidth(250e3+abs(shiftoff), 0)
126
127 self.qtgui_freq_sink_x_0 = qtgui.freq_sink_c(
128 1024, #size
129 firdes.WIN_BLACKMAN_hARRIS, #wintype
130 fc_slider, #fc
131 samp_rate, #bw
132 "", #name
133 1 #number of inputs
134 )
135 self.qtgui_freq_sink_x_0.set_update_time(0.10)
136 self.qtgui_freq_sink_x_0.set_y_axis(-140, 10)
Piotr Krysik6577ec22016-07-15 13:21:09 +0200137 self.qtgui_freq_sink_x_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, 0.0, 0, "")
138 self.qtgui_freq_sink_x_0.enable_autoscale(False)
139 self.qtgui_freq_sink_x_0.enable_grid(False)
140 self.qtgui_freq_sink_x_0.set_fft_average(1.0)
141 self.qtgui_freq_sink_x_0.enable_control_panel(False)
142
143 if not True:
144 self.qtgui_freq_sink_x_0.disable_legend()
145
146 if "complex" == "float" or "complex" == "msg_float":
147 self.qtgui_freq_sink_x_0.set_plot_pos_half(not True)
148
149 labels = ["", "", "", "", "",
150 "", "", "", "", ""]
151 widths = [1, 1, 1, 1, 1,
152 1, 1, 1, 1, 1]
153 colors = ["blue", "red", "green", "black", "cyan",
154 "magenta", "yellow", "dark red", "dark green", "dark blue"]
155 alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
156 1.0, 1.0, 1.0, 1.0, 1.0]
157 for i in xrange(1):
158 if len(labels[i]) == 0:
159 self.qtgui_freq_sink_x_0.set_line_label(i, "Data {0}".format(i))
160 else:
161 self.qtgui_freq_sink_x_0.set_line_label(i, labels[i])
162 self.qtgui_freq_sink_x_0.set_line_width(i, widths[i])
163 self.qtgui_freq_sink_x_0.set_line_color(i, colors[i])
164 self.qtgui_freq_sink_x_0.set_line_alpha(i, alphas[i])
Piotr Krysik35582082015-09-02 21:49:12 +0200165
166 self._qtgui_freq_sink_x_0_win = sip.wrapinstance(self.qtgui_freq_sink_x_0.pyqwidget(), Qt.QWidget)
167 self.top_layout.addWidget(self._qtgui_freq_sink_x_0_win)
Piotr Krysik6577ec22016-07-15 13:21:09 +0200168 self.gsm_sdcch8_demapper_0 = grgsm.gsm_sdcch8_demapper(
169 timeslot_nr=1,
170 )
171 self.gsm_receiver_0 = grgsm.receiver(4, ([0]), ([]), False)
172 self.gsm_message_printer_1 = grgsm.message_printer(pmt.intern(""), False,
173 False, False)
Piotr Krysik35582082015-09-02 21:49:12 +0200174 self.gsm_input_0 = grgsm.gsm_input(
Piotr Krysik93ba6bc2017-01-23 21:33:09 +0100175 ppm=ppm-int(ppm),
Piotr Krysik35582082015-09-02 21:49:12 +0200176 osr=4,
177 fc=fc,
178 samp_rate_in=samp_rate,
179 )
180 self.gsm_decryption_0 = grgsm.decryption(([]), 1)
181 self.gsm_control_channels_decoder_0_0 = grgsm.control_channels_decoder()
182 self.gsm_control_channels_decoder_0 = grgsm.control_channels_decoder()
Piotr Krysikfe538eb2016-07-18 18:14:49 +0200183 self.gsm_clock_offset_control_0 = grgsm.clock_offset_control(fc-shiftoff, samp_rate, osr)
Piotr Krysik82638ab2017-07-23 19:14:13 +0200184 self.gsm_bcch_ccch_sdcch4_demapper_0 = grgsm.gsm_bcch_ccch_sdcch4_demapper(
Piotr Krysik6577ec22016-07-15 13:21:09 +0200185 timeslot_nr=0,
186 )
187 self.blocks_socket_pdu_0_0 = blocks.socket_pdu("UDP_SERVER", "127.0.0.1", "4729", 10000, False)
188 self.blocks_socket_pdu_0 = blocks.socket_pdu("UDP_CLIENT", "127.0.0.1", "4729", 10000, False)
Piotr Krysik35582082015-09-02 21:49:12 +0200189 self.blocks_rotator_cc_0 = blocks.rotator_cc(-2*pi*shiftoff/samp_rate)
190
191 ##################################################
192 # Connections
193 ##################################################
Piotr Krysik82638ab2017-07-23 19:14:13 +0200194 self.msg_connect((self.gsm_bcch_ccch_sdcch4_demapper_0, 'bursts'), (self.gsm_control_channels_decoder_0, 'bursts'))
Piotr Krysik6577ec22016-07-15 13:21:09 +0200195 self.msg_connect((self.gsm_clock_offset_control_0, 'ctrl'), (self.gsm_input_0, 'ctrl_in'))
Piotr Krysik35582082015-09-02 21:49:12 +0200196 self.msg_connect((self.gsm_control_channels_decoder_0, 'msgs'), (self.blocks_socket_pdu_0, 'pdus'))
197 self.msg_connect((self.gsm_control_channels_decoder_0, 'msgs'), (self.gsm_message_printer_1, 'msgs'))
198 self.msg_connect((self.gsm_control_channels_decoder_0_0, 'msgs'), (self.blocks_socket_pdu_0, 'pdus'))
199 self.msg_connect((self.gsm_control_channels_decoder_0_0, 'msgs'), (self.gsm_message_printer_1, 'msgs'))
200 self.msg_connect((self.gsm_decryption_0, 'bursts'), (self.gsm_control_channels_decoder_0_0, 'bursts'))
Piotr Krysik82638ab2017-07-23 19:14:13 +0200201 self.msg_connect((self.gsm_receiver_0, 'C0'), (self.gsm_bcch_ccch_sdcch4_demapper_0, 'bursts'))
Piotr Krysik35582082015-09-02 21:49:12 +0200202 self.msg_connect((self.gsm_receiver_0, 'measurements'), (self.gsm_clock_offset_control_0, 'measurements'))
203 self.msg_connect((self.gsm_receiver_0, 'C0'), (self.gsm_sdcch8_demapper_0, 'bursts'))
204 self.msg_connect((self.gsm_sdcch8_demapper_0, 'bursts'), (self.gsm_decryption_0, 'bursts'))
205 self.connect((self.blocks_rotator_cc_0, 0), (self.gsm_input_0, 0))
206 self.connect((self.blocks_rotator_cc_0, 0), (self.qtgui_freq_sink_x_0, 0))
207 self.connect((self.gsm_input_0, 0), (self.gsm_receiver_0, 0))
208 self.connect((self.rtlsdr_source_0, 0), (self.blocks_rotator_cc_0, 0))
209
210 def closeEvent(self, event):
Piotr Krysik332e0b52016-02-13 18:37:32 +0100211 self.settings = Qt.QSettings("GNU Radio", "grgsm_livemon")
Piotr Krysik35582082015-09-02 21:49:12 +0200212 self.settings.setValue("geometry", self.saveGeometry())
213 event.accept()
214
Piotr Krysik6577ec22016-07-15 13:21:09 +0200215
216 def get_args(self):
217 return self.args
218
219 def set_args(self, args):
220 self.args = args
221
Piotr Krysik35582082015-09-02 21:49:12 +0200222 def get_gain(self):
223 return self.gain
224
225 def set_gain(self, gain):
226 self.gain = gain
227 self.set_g_slider(self.gain)
228
Piotr Krysik82638ab2017-07-23 19:14:13 +0200229 def get_osr(self):
230 return self.osr
231
232 def set_osr(self, osr):
233 self.osr = osr
234
Piotr Krysik35582082015-09-02 21:49:12 +0200235 def get_ppm(self):
236 return self.ppm
237
238 def set_ppm(self, ppm):
239 self.ppm = ppm
240 self.set_ppm_slider(self.ppm)
Piotr Krysik93ba6bc2017-01-23 21:33:09 +0100241 self.gsm_input_0.set_ppm(self.ppm-int(self.ppm))
Piotr Krysik35582082015-09-02 21:49:12 +0200242
243 def get_samp_rate(self):
244 return self.samp_rate
245
246 def set_samp_rate(self, samp_rate):
247 self.samp_rate = samp_rate
Piotr Krysik82638ab2017-07-23 19:14:13 +0200248 self.blocks_rotator_cc_0.set_phase_inc(-2*pi*self.shiftoff/self.samp_rate)
Piotr Krysikfe538eb2016-07-18 18:14:49 +0200249 self.gsm_input_0.set_samp_rate_in(self.samp_rate)
Piotr Krysik35582082015-09-02 21:49:12 +0200250 self.qtgui_freq_sink_x_0.set_frequency_range(self.fc_slider, self.samp_rate)
251 self.rtlsdr_source_0.set_sample_rate(self.samp_rate)
252
253 def get_shiftoff(self):
254 return self.shiftoff
255
256 def set_shiftoff(self, shiftoff):
257 self.shiftoff = shiftoff
Piotr Krysik82638ab2017-07-23 19:14:13 +0200258 self.blocks_rotator_cc_0.set_phase_inc(-2*pi*self.shiftoff/self.samp_rate)
Piotr Krysik35582082015-09-02 21:49:12 +0200259 self.rtlsdr_source_0.set_center_freq(self.fc_slider-self.shiftoff, 0)
260 self.rtlsdr_source_0.set_bandwidth(250e3+abs(self.shiftoff), 0)
Piotr Krysikfe538eb2016-07-18 18:14:49 +0200261
Piotr Krysik82638ab2017-07-23 19:14:13 +0200262 def get_fc(self):
263 return self.fc
Piotr Krysikfe538eb2016-07-18 18:14:49 +0200264
Piotr Krysik82638ab2017-07-23 19:14:13 +0200265 def set_fc(self, fc):
266 self.fc = fc
267 self.set_fc_slider(self.fc)
268 self.gsm_input_0.set_fc(self.fc)
Piotr Krysik35582082015-09-02 21:49:12 +0200269
270 def get_ppm_slider(self):
271 return self.ppm_slider
272
273 def set_ppm_slider(self, ppm_slider):
274 self.ppm_slider = ppm_slider
275 self.rtlsdr_source_0.set_freq_corr(self.ppm_slider, 0)
276
277 def get_g_slider(self):
278 return self.g_slider
279
280 def set_g_slider(self, g_slider):
281 self.g_slider = g_slider
282 self.rtlsdr_source_0.set_gain(self.g_slider, 0)
283
284 def get_fc_slider(self):
285 return self.fc_slider
286
287 def set_fc_slider(self, fc_slider):
288 self.fc_slider = fc_slider
289 self.qtgui_freq_sink_x_0.set_frequency_range(self.fc_slider, self.samp_rate)
290 self.rtlsdr_source_0.set_center_freq(self.fc_slider-self.shiftoff, 0)
291
292
Piotr Krysik6577ec22016-07-15 13:21:09 +0200293def argument_parser():
Piotr Krysik35582082015-09-02 21:49:12 +0200294 parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
Piotr Krysik6577ec22016-07-15 13:21:09 +0200295 parser.add_option(
296 "", "--args", dest="args", type="string", default="",
297 help="Set Device Arguments [default=%default]")
298 parser.add_option(
Piotr Krysik6577ec22016-07-15 13:21:09 +0200299 "-g", "--gain", dest="gain", type="eng_float", default=eng_notation.num_to_str(30),
Piotr Krysik35582082015-09-02 21:49:12 +0200300 help="Set gain [default=%default]")
Piotr Krysik6577ec22016-07-15 13:21:09 +0200301 parser.add_option(
Piotr Krysik82638ab2017-07-23 19:14:13 +0200302 "", "--osr", dest="osr", type="intx", default=4,
303 help="Set OverSampling Ratio [default=%default]")
304 parser.add_option(
Piotr Krysik93ba6bc2017-01-23 21:33:09 +0100305 "-p", "--ppm", dest="ppm", type="eng_float", default=eng_notation.num_to_str(0),
Piotr Krysik35582082015-09-02 21:49:12 +0200306 help="Set ppm [default=%default]")
Piotr Krysik6577ec22016-07-15 13:21:09 +0200307 parser.add_option(
308 "-s", "--samp-rate", dest="samp_rate", type="eng_float", default=eng_notation.num_to_str(2000000.052982),
Piotr Krysik35582082015-09-02 21:49:12 +0200309 help="Set samp_rate [default=%default]")
Piotr Krysik6577ec22016-07-15 13:21:09 +0200310 parser.add_option(
311 "-o", "--shiftoff", dest="shiftoff", type="eng_float", default=eng_notation.num_to_str(400e3),
Piotr Krysik82638ab2017-07-23 19:14:13 +0200312 help="Set Frequency Shiftoff [default=%default]")
Piotr Krysikfe538eb2016-07-18 18:14:49 +0200313 parser.add_option(
Piotr Krysik82638ab2017-07-23 19:14:13 +0200314 "-f", "--fc", dest="fc", type="eng_float", default=eng_notation.num_to_str(941.8e6),
315 help="Set GSM channel's central frequency [default=%default]")
Piotr Krysik6577ec22016-07-15 13:21:09 +0200316 return parser
317
318
319def main(top_block_cls=grgsm_livemon, options=None):
320 if options is None:
321 options, _ = argument_parser().parse_args()
322
323 from distutils.version import StrictVersion
324 if StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0"):
325 style = gr.prefs().get_string('qtgui', 'style', 'raster')
326 Qt.QApplication.setGraphicsSystem(style)
Piotr Krysik35582082015-09-02 21:49:12 +0200327 qapp = Qt.QApplication(sys.argv)
Piotr Krysik6577ec22016-07-15 13:21:09 +0200328
Piotr Krysik82638ab2017-07-23 19:14:13 +0200329 tb = top_block_cls(args=options.args, gain=options.gain, osr=options.osr, ppm=options.ppm, samp_rate=options.samp_rate, shiftoff=options.shiftoff, fc=options.fc)
Piotr Krysik35582082015-09-02 21:49:12 +0200330 tb.start()
331 tb.show()
332
333 def quitting():
334 tb.stop()
335 tb.wait()
336 qapp.connect(qapp, Qt.SIGNAL("aboutToQuit()"), quitting)
337 qapp.exec_()
Piotr Krysik6577ec22016-07-15 13:21:09 +0200338
339
340if __name__ == '__main__':
341 main()