blob: 799dd306340c88b66ddf8225cf1ac82ff4a2be20 [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 Krysik50c3e362017-08-26 12:59:15 +020028# Generated: Sat Aug 26 12:54:55 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 Krysik50c3e362017-08-26 12:59:15 +020061 def __init__(self, args="", fc=941.8e6, gain=30, osr=4, ppm=0, samp_rate=2000000.052982, shiftoff=400e3, serverport="4729"):
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 Krysik85ec6ae2017-08-26 12:24:34 +020088 self.fc = fc
Piotr Krysik35582082015-09-02 21:49:12 +020089 self.gain = gain
Piotr Krysik82638ab2017-07-23 19:14:13 +020090 self.osr = osr
Piotr Krysik35582082015-09-02 21:49:12 +020091 self.ppm = ppm
92 self.samp_rate = samp_rate
93 self.shiftoff = shiftoff
Piotr Krysik50c3e362017-08-26 12:59:15 +020094 self.serverport = serverport
Piotr Krysik35582082015-09-02 21:49:12 +020095
96 ##################################################
97 # Variables
98 ##################################################
99 self.ppm_slider = ppm_slider = ppm
100 self.g_slider = g_slider = gain
101 self.fc_slider = fc_slider = fc
102
103 ##################################################
104 # Blocks
105 ##################################################
Piotr Krysik93ba6bc2017-01-23 21:33:09 +0100106 self._ppm_slider_range = Range(-150, 150, 0.1, ppm, 100)
Piotr Krysik35582082015-09-02 21:49:12 +0200107 self._ppm_slider_win = RangeWidget(self._ppm_slider_range, self.set_ppm_slider, "PPM Offset", "counter", float)
108 self.top_layout.addWidget(self._ppm_slider_win)
109 self._g_slider_range = Range(0, 50, 0.5, gain, 100)
110 self._g_slider_win = RangeWidget(self._g_slider_range, self.set_g_slider, "Gain", "counter", float)
111 self.top_layout.addWidget(self._g_slider_win)
Piotr Krysik93ba6bc2017-01-23 21:33:09 +0100112 self._fc_slider_range = Range(800e6, 1990e6, 2e5, fc, 100)
Piotr Krysik35582082015-09-02 21:49:12 +0200113 self._fc_slider_win = RangeWidget(self._fc_slider_range, self.set_fc_slider, "Frequency", "counter_slider", float)
114 self.top_layout.addWidget(self._fc_slider_win)
Piotr Krysik7185b662016-02-14 20:24:54 +0100115 self.rtlsdr_source_0 = osmosdr.source( args="numchan=" + str(1) + " " + args )
Piotr Krysik35582082015-09-02 21:49:12 +0200116 self.rtlsdr_source_0.set_sample_rate(samp_rate)
117 self.rtlsdr_source_0.set_center_freq(fc_slider-shiftoff, 0)
118 self.rtlsdr_source_0.set_freq_corr(ppm_slider, 0)
119 self.rtlsdr_source_0.set_dc_offset_mode(2, 0)
120 self.rtlsdr_source_0.set_iq_balance_mode(2, 0)
121 self.rtlsdr_source_0.set_gain_mode(False, 0)
122 self.rtlsdr_source_0.set_gain(g_slider, 0)
123 self.rtlsdr_source_0.set_if_gain(20, 0)
124 self.rtlsdr_source_0.set_bb_gain(20, 0)
125 self.rtlsdr_source_0.set_antenna("", 0)
126 self.rtlsdr_source_0.set_bandwidth(250e3+abs(shiftoff), 0)
127
128 self.qtgui_freq_sink_x_0 = qtgui.freq_sink_c(
129 1024, #size
130 firdes.WIN_BLACKMAN_hARRIS, #wintype
131 fc_slider, #fc
132 samp_rate, #bw
133 "", #name
134 1 #number of inputs
135 )
136 self.qtgui_freq_sink_x_0.set_update_time(0.10)
137 self.qtgui_freq_sink_x_0.set_y_axis(-140, 10)
Piotr Krysik6577ec22016-07-15 13:21:09 +0200138 self.qtgui_freq_sink_x_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, 0.0, 0, "")
139 self.qtgui_freq_sink_x_0.enable_autoscale(False)
140 self.qtgui_freq_sink_x_0.enable_grid(False)
141 self.qtgui_freq_sink_x_0.set_fft_average(1.0)
142 self.qtgui_freq_sink_x_0.enable_control_panel(False)
143
144 if not True:
145 self.qtgui_freq_sink_x_0.disable_legend()
146
147 if "complex" == "float" or "complex" == "msg_float":
148 self.qtgui_freq_sink_x_0.set_plot_pos_half(not True)
149
150 labels = ["", "", "", "", "",
151 "", "", "", "", ""]
152 widths = [1, 1, 1, 1, 1,
153 1, 1, 1, 1, 1]
154 colors = ["blue", "red", "green", "black", "cyan",
155 "magenta", "yellow", "dark red", "dark green", "dark blue"]
156 alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
157 1.0, 1.0, 1.0, 1.0, 1.0]
158 for i in xrange(1):
159 if len(labels[i]) == 0:
160 self.qtgui_freq_sink_x_0.set_line_label(i, "Data {0}".format(i))
161 else:
162 self.qtgui_freq_sink_x_0.set_line_label(i, labels[i])
163 self.qtgui_freq_sink_x_0.set_line_width(i, widths[i])
164 self.qtgui_freq_sink_x_0.set_line_color(i, colors[i])
165 self.qtgui_freq_sink_x_0.set_line_alpha(i, alphas[i])
Piotr Krysik35582082015-09-02 21:49:12 +0200166
167 self._qtgui_freq_sink_x_0_win = sip.wrapinstance(self.qtgui_freq_sink_x_0.pyqwidget(), Qt.QWidget)
168 self.top_layout.addWidget(self._qtgui_freq_sink_x_0_win)
Piotr Krysik6577ec22016-07-15 13:21:09 +0200169 self.gsm_sdcch8_demapper_0 = grgsm.gsm_sdcch8_demapper(
170 timeslot_nr=1,
171 )
172 self.gsm_receiver_0 = grgsm.receiver(4, ([0]), ([]), False)
173 self.gsm_message_printer_1 = grgsm.message_printer(pmt.intern(""), False,
174 False, False)
Piotr Krysik35582082015-09-02 21:49:12 +0200175 self.gsm_input_0 = grgsm.gsm_input(
Piotr Krysik93ba6bc2017-01-23 21:33:09 +0100176 ppm=ppm-int(ppm),
Piotr Krysik35582082015-09-02 21:49:12 +0200177 osr=4,
178 fc=fc,
179 samp_rate_in=samp_rate,
180 )
181 self.gsm_decryption_0 = grgsm.decryption(([]), 1)
182 self.gsm_control_channels_decoder_0_0 = grgsm.control_channels_decoder()
183 self.gsm_control_channels_decoder_0 = grgsm.control_channels_decoder()
Piotr Krysikfe538eb2016-07-18 18:14:49 +0200184 self.gsm_clock_offset_control_0 = grgsm.clock_offset_control(fc-shiftoff, samp_rate, osr)
Piotr Krysik82638ab2017-07-23 19:14:13 +0200185 self.gsm_bcch_ccch_sdcch4_demapper_0 = grgsm.gsm_bcch_ccch_sdcch4_demapper(
Piotr Krysik6577ec22016-07-15 13:21:09 +0200186 timeslot_nr=0,
187 )
Piotr Krysik50c3e362017-08-26 12:59:15 +0200188 self.blocks_socket_pdu_0_0 = blocks.socket_pdu("UDP_SERVER", "127.0.0.1", serverport, 10000, False)
189 self.blocks_socket_pdu_0 = blocks.socket_pdu("UDP_CLIENT", "127.0.0.1", "4729", 10000, False)
Piotr Krysik35582082015-09-02 21:49:12 +0200190 self.blocks_rotator_cc_0 = blocks.rotator_cc(-2*pi*shiftoff/samp_rate)
191
192 ##################################################
193 # Connections
194 ##################################################
Piotr Krysik50c3e362017-08-26 12:59:15 +0200195 self.msg_connect((self.blocks_socket_pdu_0_0, 'pdus'), (self.gsm_message_printer_1, 'msgs'))
Piotr Krysik82638ab2017-07-23 19:14:13 +0200196 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 +0200197 self.msg_connect((self.gsm_clock_offset_control_0, 'ctrl'), (self.gsm_input_0, 'ctrl_in'))
Piotr Krysik35582082015-09-02 21:49:12 +0200198 self.msg_connect((self.gsm_control_channels_decoder_0, 'msgs'), (self.blocks_socket_pdu_0, 'pdus'))
Piotr Krysik35582082015-09-02 21:49:12 +0200199 self.msg_connect((self.gsm_control_channels_decoder_0_0, 'msgs'), (self.blocks_socket_pdu_0, 'pdus'))
Piotr Krysik35582082015-09-02 21:49:12 +0200200 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 Krysik85ec6ae2017-08-26 12:24:34 +0200222 def get_fc(self):
223 return self.fc
224
225 def set_fc(self, fc):
226 self.fc = fc
227 self.set_fc_slider(self.fc)
228 self.gsm_input_0.set_fc(self.fc)
229
Piotr Krysik35582082015-09-02 21:49:12 +0200230 def get_gain(self):
231 return self.gain
232
233 def set_gain(self, gain):
234 self.gain = gain
235 self.set_g_slider(self.gain)
236
Piotr Krysik82638ab2017-07-23 19:14:13 +0200237 def get_osr(self):
238 return self.osr
239
240 def set_osr(self, osr):
241 self.osr = osr
242
Piotr Krysik35582082015-09-02 21:49:12 +0200243 def get_ppm(self):
244 return self.ppm
245
246 def set_ppm(self, ppm):
247 self.ppm = ppm
248 self.set_ppm_slider(self.ppm)
Piotr Krysik93ba6bc2017-01-23 21:33:09 +0100249 self.gsm_input_0.set_ppm(self.ppm-int(self.ppm))
Piotr Krysik35582082015-09-02 21:49:12 +0200250
251 def get_samp_rate(self):
252 return self.samp_rate
253
254 def set_samp_rate(self, samp_rate):
255 self.samp_rate = samp_rate
Piotr Krysik82638ab2017-07-23 19:14:13 +0200256 self.blocks_rotator_cc_0.set_phase_inc(-2*pi*self.shiftoff/self.samp_rate)
Piotr Krysikfe538eb2016-07-18 18:14:49 +0200257 self.gsm_input_0.set_samp_rate_in(self.samp_rate)
Piotr Krysik35582082015-09-02 21:49:12 +0200258 self.qtgui_freq_sink_x_0.set_frequency_range(self.fc_slider, self.samp_rate)
259 self.rtlsdr_source_0.set_sample_rate(self.samp_rate)
260
261 def get_shiftoff(self):
262 return self.shiftoff
263
264 def set_shiftoff(self, shiftoff):
265 self.shiftoff = shiftoff
Piotr Krysik82638ab2017-07-23 19:14:13 +0200266 self.blocks_rotator_cc_0.set_phase_inc(-2*pi*self.shiftoff/self.samp_rate)
Piotr Krysik35582082015-09-02 21:49:12 +0200267 self.rtlsdr_source_0.set_center_freq(self.fc_slider-self.shiftoff, 0)
268 self.rtlsdr_source_0.set_bandwidth(250e3+abs(self.shiftoff), 0)
Piotr Krysikfe538eb2016-07-18 18:14:49 +0200269
Piotr Krysik50c3e362017-08-26 12:59:15 +0200270 def get_serverport(self):
271 return self.serverport
Piotr Krysikfe538eb2016-07-18 18:14:49 +0200272
Piotr Krysik50c3e362017-08-26 12:59:15 +0200273 def set_serverport(self, serverport):
274 self.serverport = serverport
Piotr Krysik35582082015-09-02 21:49:12 +0200275
276 def get_ppm_slider(self):
277 return self.ppm_slider
278
279 def set_ppm_slider(self, ppm_slider):
280 self.ppm_slider = ppm_slider
281 self.rtlsdr_source_0.set_freq_corr(self.ppm_slider, 0)
282
283 def get_g_slider(self):
284 return self.g_slider
285
286 def set_g_slider(self, g_slider):
287 self.g_slider = g_slider
288 self.rtlsdr_source_0.set_gain(self.g_slider, 0)
289
290 def get_fc_slider(self):
291 return self.fc_slider
292
293 def set_fc_slider(self, fc_slider):
294 self.fc_slider = fc_slider
295 self.qtgui_freq_sink_x_0.set_frequency_range(self.fc_slider, self.samp_rate)
296 self.rtlsdr_source_0.set_center_freq(self.fc_slider-self.shiftoff, 0)
297
298
Piotr Krysik6577ec22016-07-15 13:21:09 +0200299def argument_parser():
Piotr Krysik35582082015-09-02 21:49:12 +0200300 parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
Piotr Krysik6577ec22016-07-15 13:21:09 +0200301 parser.add_option(
302 "", "--args", dest="args", type="string", default="",
303 help="Set Device Arguments [default=%default]")
304 parser.add_option(
Piotr Krysik85ec6ae2017-08-26 12:24:34 +0200305 "-f", "--fc", dest="fc", type="eng_float", default=eng_notation.num_to_str(941.8e6),
306 help="Set GSM channel's central frequency [default=%default]")
307 parser.add_option(
Piotr Krysik6577ec22016-07-15 13:21:09 +0200308 "-g", "--gain", dest="gain", type="eng_float", default=eng_notation.num_to_str(30),
Piotr Krysik35582082015-09-02 21:49:12 +0200309 help="Set gain [default=%default]")
Piotr Krysik6577ec22016-07-15 13:21:09 +0200310 parser.add_option(
Piotr Krysik82638ab2017-07-23 19:14:13 +0200311 "", "--osr", dest="osr", type="intx", default=4,
312 help="Set OverSampling Ratio [default=%default]")
313 parser.add_option(
Piotr Krysik93ba6bc2017-01-23 21:33:09 +0100314 "-p", "--ppm", dest="ppm", type="eng_float", default=eng_notation.num_to_str(0),
Piotr Krysik35582082015-09-02 21:49:12 +0200315 help="Set ppm [default=%default]")
Piotr Krysik6577ec22016-07-15 13:21:09 +0200316 parser.add_option(
317 "-s", "--samp-rate", dest="samp_rate", type="eng_float", default=eng_notation.num_to_str(2000000.052982),
Piotr Krysik35582082015-09-02 21:49:12 +0200318 help="Set samp_rate [default=%default]")
Piotr Krysik6577ec22016-07-15 13:21:09 +0200319 parser.add_option(
320 "-o", "--shiftoff", dest="shiftoff", type="eng_float", default=eng_notation.num_to_str(400e3),
Piotr Krysik82638ab2017-07-23 19:14:13 +0200321 help="Set Frequency Shiftoff [default=%default]")
Piotr Krysikfe538eb2016-07-18 18:14:49 +0200322 parser.add_option(
Piotr Krysik50c3e362017-08-26 12:59:15 +0200323 "", "--serverport", dest="serverport", type="string", default="4729",
324 help="Set UDP server listening port [default=%default]")
Piotr Krysik6577ec22016-07-15 13:21:09 +0200325 return parser
326
327
328def main(top_block_cls=grgsm_livemon, options=None):
329 if options is None:
330 options, _ = argument_parser().parse_args()
331
332 from distutils.version import StrictVersion
333 if StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0"):
334 style = gr.prefs().get_string('qtgui', 'style', 'raster')
335 Qt.QApplication.setGraphicsSystem(style)
Piotr Krysik35582082015-09-02 21:49:12 +0200336 qapp = Qt.QApplication(sys.argv)
Piotr Krysik6577ec22016-07-15 13:21:09 +0200337
Piotr Krysik50c3e362017-08-26 12:59:15 +0200338 tb = top_block_cls(args=options.args, fc=options.fc, gain=options.gain, osr=options.osr, ppm=options.ppm, samp_rate=options.samp_rate, shiftoff=options.shiftoff, serverport=options.serverport)
Piotr Krysik35582082015-09-02 21:49:12 +0200339 tb.start()
340 tb.show()
341
342 def quitting():
343 tb.stop()
344 tb.wait()
345 qapp.connect(qapp, Qt.SIGNAL("aboutToQuit()"), quitting)
346 qapp.exec_()
Piotr Krysik6577ec22016-07-15 13:21:09 +0200347
348
349if __name__ == '__main__':
350 main()