blob: e3d7a61877948ca39137d6b2e84dfa4beadc11c7 [file] [log] [blame]
Roman Khassraf996103f2015-09-27 11:22:35 +02001#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# @file
Piotr Krysika6268a52017-08-23 16:02:19 +02004# @author (C) 2015 by Piotr Krysik <ptrkrysik@gmail.com>
5# @author (C) 2015 by Roman Khassraf <rkhassraf@gmail.com>
Roman Khassraf996103f2015-09-27 11:22:35 +02006# @section LICENSE
7#
8# Gr-gsm is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 3, or (at your option)
11# any later version.
12#
13# Gr-gsm is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with gr-gsm; see the file COPYING. If not, write to
20# the Free Software Foundation, Inc., 51 Franklin Street,
21# Boston, MA 02110-1301, USA.
22#
23#
24from gnuradio import blocks
25from gnuradio import gr
26from gnuradio import eng_notation
27from gnuradio.eng_option import eng_option
28from gnuradio.filter import firdes
29from gnuradio.filter import pfb
30from math import pi
31from optparse import OptionParser
32
33import grgsm
34import numpy
35import os
36import osmosdr
37import pmt
38import time
Vasil Velichkov54580d12019-04-17 18:28:46 +030039import sys
Roman Khassraf996103f2015-09-27 11:22:35 +020040
Roman Khassraf98af2c92016-09-23 07:26:13 +020041# from wideband_receiver import *
Roman Khassraf996103f2015-09-27 11:22:35 +020042
Vasil Velichkov46c90be2019-09-02 04:06:41 +030043class receiver_with_decoder(gr.hier_block2):
Roman Khassraf996103f2015-09-27 11:22:35 +020044 def __init__(self, OSR=4, chan_num=0, fc=939.4e6, ppm=0, samp_rate=0.2e6):
Vasil Velichkov46c90be2019-09-02 04:06:41 +030045 gr.hier_block2.__init__(
Roman Khassraf996103f2015-09-27 11:22:35 +020046 self, "Receiver With Decoder",
Roman Khassraf98af2c92016-09-23 07:26:13 +020047 gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
Roman Khassraf996103f2015-09-27 11:22:35 +020048 gr.io_signature(0, 0, 0),
49 )
Piotr Krysik8715da02016-01-06 22:21:09 +010050 self.message_port_register_hier_out("bursts")
51 self.message_port_register_hier_out("msgs")
Roman Khassraf996103f2015-09-27 11:22:35 +020052
53 ##################################################
54 # Parameters
55 ##################################################
56 self.OSR = OSR
57 self.chan_num = chan_num
58 self.fc = fc
59 self.ppm = ppm
60 self.samp_rate = samp_rate
61
62 ##################################################
63 # Variables
64 ##################################################
Roman Khassraf98af2c92016-09-23 07:26:13 +020065 self.samp_rate_out = samp_rate_out = 1625000.0 / 6.0 * OSR
Roman Khassraf996103f2015-09-27 11:22:35 +020066
67 ##################################################
68 # Blocks
69 ##################################################
70 self.gsm_receiver_0 = grgsm.receiver(OSR, ([chan_num]), ([]))
71 self.gsm_input_0 = grgsm.gsm_input(
72 ppm=ppm,
73 osr=OSR,
74 fc=fc,
75 samp_rate_in=samp_rate,
76 )
77 self.gsm_control_channels_decoder_0 = grgsm.control_channels_decoder()
Piotr Krysikfe538eb2016-07-18 18:14:49 +020078 self.gsm_clock_offset_control_0 = grgsm.clock_offset_control(fc, samp_rate, osr=4)
Piotr Krysik773a1942016-05-20 12:45:54 +020079 self.gsm_bcch_ccch_demapper_0 = grgsm.gsm_bcch_ccch_demapper(0)
Roman Khassraf996103f2015-09-27 11:22:35 +020080
81 ##################################################
82 # Connections
83 ##################################################
84 self.msg_connect(self.gsm_bcch_ccch_demapper_0, 'bursts', self, 'bursts')
85 self.msg_connect(self.gsm_bcch_ccch_demapper_0, 'bursts', self.gsm_control_channels_decoder_0, 'bursts')
Piotr Krysik6577ec22016-07-15 13:21:09 +020086 self.msg_connect(self.gsm_clock_offset_control_0, 'ctrl', self.gsm_input_0, 'ctrl_in')
Roman Khassraf996103f2015-09-27 11:22:35 +020087 self.msg_connect(self.gsm_control_channels_decoder_0, 'msgs', self, 'msgs')
88 self.msg_connect(self.gsm_receiver_0, 'C0', self.gsm_bcch_ccch_demapper_0, 'bursts')
89 self.msg_connect(self.gsm_receiver_0, 'measurements', self.gsm_clock_offset_control_0, 'measurements')
Roman Khassraf98af2c92016-09-23 07:26:13 +020090 self.connect((self.gsm_input_0, 0), (self.gsm_receiver_0, 0))
91 self.connect((self, 0), (self.gsm_input_0, 0))
Roman Khassraf996103f2015-09-27 11:22:35 +020092
93 def get_OSR(self):
94 return self.OSR
95
96 def set_OSR(self, OSR):
97 self.OSR = OSR
Roman Khassraf98af2c92016-09-23 07:26:13 +020098 self.set_samp_rate_out(1625000.0 / 6.0 * self.OSR)
Roman Khassraf996103f2015-09-27 11:22:35 +020099 self.gsm_input_0.set_osr(self.OSR)
100
101 def get_chan_num(self):
102 return self.chan_num
103
104 def set_chan_num(self, chan_num):
105 self.chan_num = chan_num
106
107 def get_fc(self):
108 return self.fc
109
110 def set_fc(self, fc):
111 self.fc = fc
112 self.gsm_input_0.set_fc(self.fc)
113
114 def get_ppm(self):
115 return self.ppm
116
117 def set_ppm(self, ppm):
118 self.ppm = ppm
119 self.gsm_input_0.set_ppm(self.ppm)
120
121 def get_samp_rate(self):
122 return self.samp_rate
123
124 def set_samp_rate(self, samp_rate):
125 self.samp_rate = samp_rate
126 self.gsm_input_0.set_samp_rate_in(self.samp_rate)
127
128 def get_samp_rate_out(self):
129 return self.samp_rate_out
130
131 def set_samp_rate_out(self, samp_rate_out):
132 self.samp_rate_out = samp_rate_out
133
134
Vasil Velichkov46c90be2019-09-02 04:06:41 +0300135class wideband_receiver(gr.hier_block2):
Roman Khassraf996103f2015-09-27 11:22:35 +0200136 def __init__(self, OSR=4, fc=939.4e6, samp_rate=0.4e6):
Vasil Velichkov46c90be2019-09-02 04:06:41 +0300137 gr.hier_block2.__init__(
Roman Khassraf996103f2015-09-27 11:22:35 +0200138 self, "Wideband receiver",
Roman Khassraf98af2c92016-09-23 07:26:13 +0200139 gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
Roman Khassraf996103f2015-09-27 11:22:35 +0200140 gr.io_signature(0, 0, 0),
141 )
Piotr Krysik8715da02016-01-06 22:21:09 +0100142 self.message_port_register_hier_out("bursts")
143 self.message_port_register_hier_out("msgs")
Roman Khassraf996103f2015-09-27 11:22:35 +0200144 self.__init(OSR, fc, samp_rate)
Roman Khassraf98af2c92016-09-23 07:26:13 +0200145
Roman Khassraf996103f2015-09-27 11:22:35 +0200146 def __init(self, OSR=4, fc=939.4e6, samp_rate=0.4e6):
147 ##################################################
148 # Parameters
149 ##################################################
150 self.OSR = OSR
151 self.fc = fc
152 self.samp_rate = samp_rate
Roman Khassraf98af2c92016-09-23 07:26:13 +0200153 self.channels_num = int(samp_rate / 0.2e6)
Roman Khassraf996103f2015-09-27 11:22:35 +0200154 self.OSR_PFB = 2
Roman Khassraf98af2c92016-09-23 07:26:13 +0200155
Roman Khassraf996103f2015-09-27 11:22:35 +0200156 ##################################################
157 # Blocks
158 ##################################################
159 self.pfb_channelizer_ccf_0 = pfb.channelizer_ccf(
160 self.channels_num,
161 (),
162 self.OSR_PFB,
163 100)
164 self.pfb_channelizer_ccf_0.set_channel_map(([]))
165 self.create_receivers()
166
167 ##################################################
168 # Connections
169 ##################################################
170 self.connect((self, 0), (self.pfb_channelizer_ccf_0, 0))
Vasil Velichkov46c90be2019-09-02 04:06:41 +0300171 for chan in range(0, self.channels_num):
Roman Khassraf996103f2015-09-27 11:22:35 +0200172 self.connect((self.pfb_channelizer_ccf_0, chan), (self.receivers_with_decoders[chan], 0))
173 self.msg_connect(self.receivers_with_decoders[chan], 'bursts', self, 'bursts')
174 self.msg_connect(self.receivers_with_decoders[chan], 'msgs', self, 'msgs')
175
176 def create_receivers(self):
177 self.receivers_with_decoders = {}
Vasil Velichkov46c90be2019-09-02 04:06:41 +0300178 for chan in range(0, self.channels_num):
Roman Khassraf98af2c92016-09-23 07:26:13 +0200179 self.receivers_with_decoders[chan] = receiver_with_decoder(fc=self.fc, OSR=self.OSR, chan_num=chan,
180 samp_rate=self.OSR_PFB * 0.2e6)
Roman Khassraf996103f2015-09-27 11:22:35 +0200181
182 def get_OSR(self):
183 return self.OSR
184
185 def set_OSR(self, OSR):
186 self.OSR = OSR
187 self.create_receivers()
188
189 def get_fc(self):
190 return self.fc
191
192 def set_fc(self, fc):
193 self.fc = fc
194 self.create_receivers()
195
196 def get_samp_rate(self):
197 return self.samp_rate
198
199
Roman Khassrafe2fbb872015-09-29 19:40:04 +0200200class wideband_scanner(gr.top_block):
Piotr Krysik881b6c32017-03-30 10:53:25 +0200201 def __init__(self, rec_len=3, sample_rate=2e6, carrier_frequency=939e6, gain=24, ppm=0, args=""):
Roman Khassraf996103f2015-09-27 11:22:35 +0200202 gr.top_block.__init__(self, "Wideband Scanner")
Roman Khassraf98af2c92016-09-23 07:26:13 +0200203
Roman Khassraf996103f2015-09-27 11:22:35 +0200204 self.rec_len = rec_len
205 self.sample_rate = sample_rate
206 self.carrier_frequency = carrier_frequency
207 self.ppm = ppm
Roman Khassraf98af2c92016-09-23 07:26:13 +0200208
Roman Khassraf996103f2015-09-27 11:22:35 +0200209 # if no file name is given process data from rtl_sdr source
Vasil Velichkov46c90be2019-09-02 04:06:41 +0300210 print("Args=", args)
Vasil Velichkov54580d12019-04-17 18:28:46 +0300211 self.rtlsdr_source = osmosdr.source(args="numchan=" + str(1) + " " +
212 str(grgsm.device.get_default_args(args)))
Piotr Krysikea44d982018-06-02 12:27:58 +0200213 #self.rtlsdr_source.set_min_output_buffer(int(sample_rate*rec_len)) #this line causes segfaults on HackRF
Roman Khassraf996103f2015-09-27 11:22:35 +0200214 self.rtlsdr_source.set_sample_rate(sample_rate)
Roman Khassraf98af2c92016-09-23 07:26:13 +0200215
Roman Khassraf996103f2015-09-27 11:22:35 +0200216 # capture half of GSM channel lower than channel center (-0.1MHz)
217 # this is needed when even number of channels is captured in order to process full captured bandwidth
Roman Khassraf98af2c92016-09-23 07:26:13 +0200218
Roman Khassraf996103f2015-09-27 11:22:35 +0200219 self.rtlsdr_source.set_center_freq(carrier_frequency - 0.1e6, 0)
Roman Khassraf98af2c92016-09-23 07:26:13 +0200220
Roman Khassraf996103f2015-09-27 11:22:35 +0200221 # correction of central frequency
Roman Khassraf98af2c92016-09-23 07:26:13 +0200222 # if the receiver has large frequency offset
Roman Khassraf996103f2015-09-27 11:22:35 +0200223 # the value of this variable should be set close to that offset in ppm
Roman Khassrafa5f5a312016-11-20 22:11:46 +0100224 self.rtlsdr_source.set_freq_corr(ppm, 0)
Roman Khassraf98af2c92016-09-23 07:26:13 +0200225
Roman Khassraf996103f2015-09-27 11:22:35 +0200226 self.rtlsdr_source.set_dc_offset_mode(2, 0)
227 self.rtlsdr_source.set_iq_balance_mode(0, 0)
228 self.rtlsdr_source.set_gain_mode(True, 0)
229 self.rtlsdr_source.set_bandwidth(sample_rate, 0)
Piotr Krysik881b6c32017-03-30 10:53:25 +0200230 self.rtlsdr_source.set_gain(gain, 0)
231 self.rtlsdr_source.set_if_gain(32, 0)
232 self.rtlsdr_source.set_bb_gain(30, 0)
Roman Khassraf996103f2015-09-27 11:22:35 +0200233 self.head = blocks.head(gr.sizeof_gr_complex * 1, int(rec_len * sample_rate))
Roman Khassraf98af2c92016-09-23 07:26:13 +0200234
Roman Khassraf996103f2015-09-27 11:22:35 +0200235 # shift again by -0.1MHz in order to align channel center in 0Hz
Roman Khassrafa5f5a312016-11-20 22:11:46 +0100236 self.blocks_rotator_cc = blocks.rotator_cc(-2 * pi * 0.1e6 / sample_rate)
Roman Khassraf98af2c92016-09-23 07:26:13 +0200237
Roman Khassraf996103f2015-09-27 11:22:35 +0200238 self.wideband_receiver = wideband_receiver(OSR=4, fc=carrier_frequency, samp_rate=sample_rate)
239 self.gsm_extract_system_info = grgsm.extract_system_info()
Roman Khassraf98af2c92016-09-23 07:26:13 +0200240
Roman Khassraf996103f2015-09-27 11:22:35 +0200241 self.connect((self.rtlsdr_source, 0), (self.head, 0))
242 self.connect((self.head, 0), (self.blocks_rotator_cc, 0))
Roman Khassraf98af2c92016-09-23 07:26:13 +0200243 self.connect((self.blocks_rotator_cc, 0), (self.wideband_receiver, 0))
Roman Khassraf996103f2015-09-27 11:22:35 +0200244 self.msg_connect(self.wideband_receiver, 'msgs', self.gsm_extract_system_info, 'msgs')
Roman Khassraf98af2c92016-09-23 07:26:13 +0200245
Roman Khassraf996103f2015-09-27 11:22:35 +0200246 def set_carrier_frequency(self, carrier_frequency):
247 self.carrier_frequency = carrier_frequency
248 self.rtlsdr_source.set_center_freq(carrier_frequency - 0.1e6, 0)
249
Roman Khassraf98af2c92016-09-23 07:26:13 +0200250
Roman Khassrafe2fbb872015-09-29 19:40:04 +0200251class channel_info(object):
Roman Khassraf996103f2015-09-27 11:22:35 +0200252 def __init__(self, arfcn, freq, cid, lac, mcc, mnc, ccch_conf, power, neighbours, cell_arfcns):
253 self.arfcn = arfcn
254 self.freq = freq
255 self.cid = cid
256 self.lac = lac
257 self.mcc = mcc
258 self.mnc = mnc
259 self.ccch_conf = ccch_conf
260 self.power = power
261 self.neighbours = neighbours
262 self.cell_arfcns = cell_arfcns
Roman Khassraf98af2c92016-09-23 07:26:13 +0200263
Vasil Velichkov46c90be2019-09-02 04:06:41 +0300264 def __lt__(self, other):
265 return self.arfcn < other.arfcn
266
267
Roman Khassraf996103f2015-09-27 11:22:35 +0200268 def get_verbose_info(self):
269 i = " |---- Configuration: %s\n" % self.get_ccch_conf()
270 i += " |---- Cell ARFCNs: " + ", ".join(map(str, self.cell_arfcns)) + "\n"
271 i += " |---- Neighbour Cells: " + ", ".join(map(str, self.neighbours)) + "\n"
272 return i
Roman Khassraf98af2c92016-09-23 07:26:13 +0200273
Roman Khassraf996103f2015-09-27 11:22:35 +0200274 def get_ccch_conf(self):
275 if self.ccch_conf == 0:
276 return "1 CCCH, not combined"
277 elif self.ccch_conf == 1:
278 return "1 CCCH, combined"
279 elif self.ccch_conf == 2:
280 return "2 CCCH, not combined"
281 elif self.ccch_conf == 4:
282 return "3 CCCH, not combined"
283 elif self.ccch_conf == 6:
284 return "4 CCCH, not combined"
285 else:
286 return "Unknown"
Roman Khassraf98af2c92016-09-23 07:26:13 +0200287
Roman Khassraf996103f2015-09-27 11:22:35 +0200288 def getKey(self):
289 return self.arfcn
Roman Khassraf98af2c92016-09-23 07:26:13 +0200290
Roman Khassraf996103f2015-09-27 11:22:35 +0200291 def __cmp__(self, other):
292 if hasattr(other, 'getKey'):
293 return self.getKey().__cmp__(other.getKey())
Roman Khassraf98af2c92016-09-23 07:26:13 +0200294
Roman Khassraf996103f2015-09-27 11:22:35 +0200295 def __repr__(self):
Petter Reinholdtsen1eeb1b42017-08-27 05:39:11 +0000296 return "%s(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % (
Petter Reinholdtsen284282e2017-08-24 11:33:03 +0200297 self.__class__, self.arfcn, self.freq, self.cid, self.lac,
298 self.mcc, self.mnc, self.ccch_conf, self.power,
299 self.neighbours, self.cell_arfcns)
300
301 def __str__(self):
Roman Khassraf98af2c92016-09-23 07:26:13 +0200302 return "ARFCN: %4u, Freq: %6.1fM, CID: %5u, LAC: %5u, MCC: %3u, MNC: %3u, Pwr: %3i" % (
303 self.arfcn, self.freq / 1e6, self.cid, self.lac, self.mcc, self.mnc, self.power)
304
Vasil Velichkovfb1f65c2018-09-04 23:27:04 +0300305def do_scan(samp_rate, band, speed, ppm, gain, args, prn = None, debug = False):
Petter Reinholdtsen6a7dc442017-08-24 10:46:43 +0200306 signallist = []
307 channels_num = int(samp_rate / 0.2e6)
308 for arfcn_range in grgsm.arfcn.get_arfcn_ranges(band):
Roman Khassraf98af2c92016-09-23 07:26:13 +0200309 first_arfcn = arfcn_range[0]
310 last_arfcn = arfcn_range[1]
311 last_center_arfcn = last_arfcn - int((channels_num / 2) - 1)
312
Piotr Krysik3dfa11b2017-09-06 17:48:38 +0200313 current_freq = grgsm.arfcn.arfcn2downlink(first_arfcn + int(channels_num / 2) - 1)
314 last_freq = grgsm.arfcn.arfcn2downlink(last_center_arfcn)
Roman Khassraf98af2c92016-09-23 07:26:13 +0200315 stop_freq = last_freq + 0.2e6 * channels_num
316
317 while current_freq < stop_freq:
318
Vasil Velichkovfb1f65c2018-09-04 23:27:04 +0300319 if not debug:
320 # silence rtl_sdr output:
321 # open 2 fds
Vasil Velichkov46c90be2019-09-02 04:06:41 +0300322 null_fds = [os.open(os.devnull, os.O_RDWR) for x in range(2)]
Vasil Velichkovfb1f65c2018-09-04 23:27:04 +0300323 # save the current file descriptors to a tuple
324 save = os.dup(1), os.dup(2)
325 # put /dev/null fds on 1 and 2
326 os.dup2(null_fds[0], 1)
327 os.dup2(null_fds[1], 2)
Roman Khassraf98af2c92016-09-23 07:26:13 +0200328
329 # instantiate scanner and processor
Petter Reinholdtsen6a7dc442017-08-24 10:46:43 +0200330 scanner = wideband_scanner(rec_len=6 - speed,
331 sample_rate=samp_rate,
Roman Khassraf98af2c92016-09-23 07:26:13 +0200332 carrier_frequency=current_freq,
Petter Reinholdtsen6a7dc442017-08-24 10:46:43 +0200333 ppm=ppm, gain=gain, args=args)
Roman Khassraf98af2c92016-09-23 07:26:13 +0200334
335 # start recording
336 scanner.start()
337 scanner.wait()
338 scanner.stop()
339
340 freq_offsets = numpy.fft.ifftshift(
341 numpy.array(range(int(-numpy.floor(channels_num / 2)), int(numpy.floor((channels_num + 1) / 2)))) * 2e5)
342 detected_c0_channels = scanner.gsm_extract_system_info.get_chans()
343
Roman Khassraf996103f2015-09-27 11:22:35 +0200344 found_list = []
Roman Khassraf996103f2015-09-27 11:22:35 +0200345
Roman Khassraf98af2c92016-09-23 07:26:13 +0200346 if detected_c0_channels:
347 chans = numpy.array(scanner.gsm_extract_system_info.get_chans())
348 found_freqs = current_freq + freq_offsets[(chans)]
349
350 cell_ids = numpy.array(scanner.gsm_extract_system_info.get_cell_id())
351 lacs = numpy.array(scanner.gsm_extract_system_info.get_lac())
352 mccs = numpy.array(scanner.gsm_extract_system_info.get_mcc())
353 mncs = numpy.array(scanner.gsm_extract_system_info.get_mnc())
354 ccch_confs = numpy.array(scanner.gsm_extract_system_info.get_ccch_conf())
355 powers = numpy.array(scanner.gsm_extract_system_info.get_pwrs())
356
357 for i in range(0, len(chans)):
358 cell_arfcn_list = scanner.gsm_extract_system_info.get_cell_arfcns(chans[i])
359 neighbour_list = scanner.gsm_extract_system_info.get_neighbours(chans[i])
360
Piotr Krysik3dfa11b2017-09-06 17:48:38 +0200361 info = channel_info(grgsm.arfcn.downlink2arfcn(found_freqs[i]), found_freqs[i],
Roman Khassraf98af2c92016-09-23 07:26:13 +0200362 cell_ids[i], lacs[i], mccs[i], mncs[i], ccch_confs[i], powers[i],
363 neighbour_list, cell_arfcn_list)
364 found_list.append(info)
365
366 scanner = None
367
Vasil Velichkovfb1f65c2018-09-04 23:27:04 +0300368
369 if not debug:
370 # restore file descriptors so we can print the results
371 os.dup2(save[0], 1)
372 os.dup2(save[1], 2)
373 # close the temporary fds
374 os.close(null_fds[0])
375 os.close(null_fds[1])
Petter Reinholdtsen6a7dc442017-08-24 10:46:43 +0200376 if prn:
377 prn(found_list)
378 signallist.extend(found_list)
Roman Khassraf98af2c92016-09-23 07:26:13 +0200379
380 current_freq += channels_num * 0.2e6
Petter Reinholdtsen6a7dc442017-08-24 10:46:43 +0200381 return signallist
382
383def argument_parser():
384 parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
385 bands_list = ", ".join(grgsm.arfcn.get_bands())
Piotr Krysik3dfa11b2017-09-06 17:48:38 +0200386 parser.add_option("-b", "--band", dest="band", default="GSM900",
Petter Reinholdtsen6a7dc442017-08-24 10:46:43 +0200387 help="Specify the GSM band for the frequency.\nAvailable bands are: " + bands_list)
388 parser.add_option("-s", "--samp-rate", dest="samp_rate", type="float", default=2e6,
389 help="Set sample rate [default=%default] - allowed values even_number*0.2e6")
390 parser.add_option("-p", "--ppm", dest="ppm", type="intx", default=0,
391 help="Set frequency correction in ppm [default=%default]")
392 parser.add_option("-g", "--gain", dest="gain", type="eng_float", default=24.0,
393 help="Set gain [default=%default]")
394 parser.add_option("", "--args", dest="args", type="string", default="",
Vasil Velichkov54580d12019-04-17 18:28:46 +0300395 help="Set device arguments [default=%default]."
396 " Use --list-devices the view the available devices")
397 parser.add_option("-l", "--list-devices", action="store_true",
398 help="List available SDR devices, use --args to specify hints")
Petter Reinholdtsen6a7dc442017-08-24 10:46:43 +0200399 parser.add_option("--speed", dest="speed", type="intx", default=4,
400 help="Scan speed [default=%default]. Value range 0-5.")
401 parser.add_option("-v", "--verbose", action="store_true",
402 help="If set, verbose information output is printed: ccch configuration, cell ARFCN's, neighbour ARFCN's")
Vasil Velichkovfb1f65c2018-09-04 23:27:04 +0300403 parser.add_option("-d", "--debug", action="store_true",
404 help="Print additional debug messages")
Petter Reinholdtsen6a7dc442017-08-24 10:46:43 +0200405
406 """
407 Dont forget: sudo sysctl kernel.shmmni=32000
408 """
409 return parser
410
411def main(options = None):
412 if options is None:
413 (options, args) = argument_parser().parse_args()
414
Vasil Velichkov54580d12019-04-17 18:28:46 +0300415 if options.list_devices:
416 grgsm.device.print_devices(options.args)
417 sys.exit(0)
418
Petter Reinholdtsen6a7dc442017-08-24 10:46:43 +0200419 if options.band not in grgsm.arfcn.get_bands():
420 parser.error("Invalid GSM band\n")
421
422 if options.speed < 0 or options.speed > 5:
423 parser.error("Invalid scan speed.\n")
424
425 if (options.samp_rate / 0.2e6) % 2 != 0:
426 parser.error("Invalid sample rate. Sample rate must be an even numer * 0.2e6")
427
428 def printfunc(found_list):
429 for info in sorted(found_list):
Vasil Velichkov46c90be2019-09-02 04:06:41 +0300430 print(info)
Petter Reinholdtsen6a7dc442017-08-24 10:46:43 +0200431 if options.verbose:
Vasil Velichkov46c90be2019-09-02 04:06:41 +0300432 print(info.get_verbose_info())
433 print("")
Petter Reinholdtsen6a7dc442017-08-24 10:46:43 +0200434 do_scan(options.samp_rate, options.band, options.speed,
Vasil Velichkovfb1f65c2018-09-04 23:27:04 +0300435 options.ppm, options.gain, options.args, prn = printfunc, debug = options.debug)
Petter Reinholdtsen6a7dc442017-08-24 10:46:43 +0200436
437if __name__ == '__main__':
438 main()