blob: 240f8fb0bd539f0d6433d104f5bb47c565156a8f [file] [log] [blame]
Roman Khassraf996103f2015-09-27 11:22:35 +02001#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# @file
4# @author Piotr Krysik <ptrkrysik@gmail.com>
5# @author Roman Khassraf <rkhassraf@gmail.com>
6# @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
39
40
Roman Khassraf98af2c92016-09-23 07:26:13 +020041# from wideband_receiver import *
Roman Khassraf996103f2015-09-27 11:22:35 +020042
Piotr Krysik8715da02016-01-06 22:21:09 +010043class receiver_with_decoder(grgsm.hier_block):
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):
Piotr Krysik8715da02016-01-06 22:21:09 +010045 grgsm.hier_block.__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
Piotr Krysik8715da02016-01-06 22:21:09 +0100135class wideband_receiver(grgsm.hier_block):
Roman Khassraf996103f2015-09-27 11:22:35 +0200136 def __init__(self, OSR=4, fc=939.4e6, samp_rate=0.4e6):
Piotr Krysik8715da02016-01-06 22:21:09 +0100137 grgsm.hier_block.__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))
Roman Khassraf98af2c92016-09-23 07:26:13 +0200171 for chan in xrange(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 = {}
Roman Khassraf98af2c92016-09-23 07:26:13 +0200178 for chan in xrange(0, self.channels_num):
179 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
Roman Khassraf98af2c92016-09-23 07:26:13 +0200210 print "Args=", args
211 self.rtlsdr_source = osmosdr.source(args="numchan=" + str(1) + " " + args)
Piotr Krysik881b6c32017-03-30 10:53:25 +0200212 self.rtlsdr_source.set_min_output_buffer(int(sample_rate*rec_len))
Roman Khassraf996103f2015-09-27 11:22:35 +0200213 self.rtlsdr_source.set_sample_rate(sample_rate)
Roman Khassraf98af2c92016-09-23 07:26:13 +0200214
Roman Khassraf996103f2015-09-27 11:22:35 +0200215 # capture half of GSM channel lower than channel center (-0.1MHz)
216 # this is needed when even number of channels is captured in order to process full captured bandwidth
Roman Khassraf98af2c92016-09-23 07:26:13 +0200217
Roman Khassraf996103f2015-09-27 11:22:35 +0200218 self.rtlsdr_source.set_center_freq(carrier_frequency - 0.1e6, 0)
Roman Khassraf98af2c92016-09-23 07:26:13 +0200219
Roman Khassraf996103f2015-09-27 11:22:35 +0200220 # correction of central frequency
Roman Khassraf98af2c92016-09-23 07:26:13 +0200221 # if the receiver has large frequency offset
Roman Khassraf996103f2015-09-27 11:22:35 +0200222 # the value of this variable should be set close to that offset in ppm
Roman Khassrafa5f5a312016-11-20 22:11:46 +0100223 self.rtlsdr_source.set_freq_corr(ppm, 0)
Roman Khassraf98af2c92016-09-23 07:26:13 +0200224
Roman Khassraf996103f2015-09-27 11:22:35 +0200225 self.rtlsdr_source.set_dc_offset_mode(2, 0)
226 self.rtlsdr_source.set_iq_balance_mode(0, 0)
227 self.rtlsdr_source.set_gain_mode(True, 0)
228 self.rtlsdr_source.set_bandwidth(sample_rate, 0)
Piotr Krysik881b6c32017-03-30 10:53:25 +0200229 self.rtlsdr_source.set_gain(gain, 0)
230 self.rtlsdr_source.set_if_gain(32, 0)
231 self.rtlsdr_source.set_bb_gain(30, 0)
Roman Khassraf996103f2015-09-27 11:22:35 +0200232 self.head = blocks.head(gr.sizeof_gr_complex * 1, int(rec_len * sample_rate))
Roman Khassraf98af2c92016-09-23 07:26:13 +0200233
Roman Khassraf996103f2015-09-27 11:22:35 +0200234 # shift again by -0.1MHz in order to align channel center in 0Hz
Roman Khassrafa5f5a312016-11-20 22:11:46 +0100235 self.blocks_rotator_cc = blocks.rotator_cc(-2 * pi * 0.1e6 / sample_rate)
Roman Khassraf98af2c92016-09-23 07:26:13 +0200236
Roman Khassraf996103f2015-09-27 11:22:35 +0200237 self.wideband_receiver = wideband_receiver(OSR=4, fc=carrier_frequency, samp_rate=sample_rate)
238 self.gsm_extract_system_info = grgsm.extract_system_info()
Roman Khassraf98af2c92016-09-23 07:26:13 +0200239
Roman Khassraf996103f2015-09-27 11:22:35 +0200240 self.connect((self.rtlsdr_source, 0), (self.head, 0))
241 self.connect((self.head, 0), (self.blocks_rotator_cc, 0))
Roman Khassraf98af2c92016-09-23 07:26:13 +0200242 self.connect((self.blocks_rotator_cc, 0), (self.wideband_receiver, 0))
Roman Khassraf996103f2015-09-27 11:22:35 +0200243 self.msg_connect(self.wideband_receiver, 'msgs', self.gsm_extract_system_info, 'msgs')
Roman Khassraf98af2c92016-09-23 07:26:13 +0200244
Roman Khassraf996103f2015-09-27 11:22:35 +0200245 def set_carrier_frequency(self, carrier_frequency):
246 self.carrier_frequency = carrier_frequency
247 self.rtlsdr_source.set_center_freq(carrier_frequency - 0.1e6, 0)
248
Roman Khassraf98af2c92016-09-23 07:26:13 +0200249
Roman Khassrafe2fbb872015-09-29 19:40:04 +0200250class channel_info(object):
Roman Khassraf996103f2015-09-27 11:22:35 +0200251 def __init__(self, arfcn, freq, cid, lac, mcc, mnc, ccch_conf, power, neighbours, cell_arfcns):
252 self.arfcn = arfcn
253 self.freq = freq
254 self.cid = cid
255 self.lac = lac
256 self.mcc = mcc
257 self.mnc = mnc
258 self.ccch_conf = ccch_conf
259 self.power = power
260 self.neighbours = neighbours
261 self.cell_arfcns = cell_arfcns
Roman Khassraf98af2c92016-09-23 07:26:13 +0200262
Roman Khassraf996103f2015-09-27 11:22:35 +0200263 def get_verbose_info(self):
264 i = " |---- Configuration: %s\n" % self.get_ccch_conf()
265 i += " |---- Cell ARFCNs: " + ", ".join(map(str, self.cell_arfcns)) + "\n"
266 i += " |---- Neighbour Cells: " + ", ".join(map(str, self.neighbours)) + "\n"
267 return i
Roman Khassraf98af2c92016-09-23 07:26:13 +0200268
Roman Khassraf996103f2015-09-27 11:22:35 +0200269 def get_ccch_conf(self):
270 if self.ccch_conf == 0:
271 return "1 CCCH, not combined"
272 elif self.ccch_conf == 1:
273 return "1 CCCH, combined"
274 elif self.ccch_conf == 2:
275 return "2 CCCH, not combined"
276 elif self.ccch_conf == 4:
277 return "3 CCCH, not combined"
278 elif self.ccch_conf == 6:
279 return "4 CCCH, not combined"
280 else:
281 return "Unknown"
Roman Khassraf98af2c92016-09-23 07:26:13 +0200282
Roman Khassraf996103f2015-09-27 11:22:35 +0200283 def getKey(self):
284 return self.arfcn
Roman Khassraf98af2c92016-09-23 07:26:13 +0200285
Roman Khassraf996103f2015-09-27 11:22:35 +0200286 def __cmp__(self, other):
287 if hasattr(other, 'getKey'):
288 return self.getKey().__cmp__(other.getKey())
Roman Khassraf98af2c92016-09-23 07:26:13 +0200289
Roman Khassraf996103f2015-09-27 11:22:35 +0200290 def __repr__(self):
Petter Reinholdtsen284282e2017-08-24 11:33:03 +0200291 return "%s(%s, %s, %s, %s, %s, %s, %s, %s, %s)" % (
292 self.__class__, self.arfcn, self.freq, self.cid, self.lac,
293 self.mcc, self.mnc, self.ccch_conf, self.power,
294 self.neighbours, self.cell_arfcns)
295
296 def __str__(self):
Roman Khassraf98af2c92016-09-23 07:26:13 +0200297 return "ARFCN: %4u, Freq: %6.1fM, CID: %5u, LAC: %5u, MCC: %3u, MNC: %3u, Pwr: %3i" % (
298 self.arfcn, self.freq / 1e6, self.cid, self.lac, self.mcc, self.mnc, self.power)
299
Roman Khassraf996103f2015-09-27 11:22:35 +0200300
301if __name__ == '__main__':
302 parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
303 bands_list = ", ".join(grgsm.arfcn.get_bands())
304 parser.add_option("-b", "--band", dest="band", default="P-GSM",
305 help="Specify the GSM band for the frequency.\nAvailable bands are: " + bands_list)
306 parser.add_option("-s", "--samp-rate", dest="samp_rate", type="float", default=2e6,
Roman Khassraf98af2c92016-09-23 07:26:13 +0200307 help="Set sample rate [default=%default] - allowed values even_number*0.2e6")
Piotr Krysik7185b662016-02-14 20:24:54 +0100308 parser.add_option("-p", "--ppm", dest="ppm", type="intx", default=0,
Roman Khassraf98af2c92016-09-23 07:26:13 +0200309 help="Set frequency correction in ppm [default=%default]")
Roman Khassraf996103f2015-09-27 11:22:35 +0200310 parser.add_option("-g", "--gain", dest="gain", type="eng_float", default=24.0,
Roman Khassraf98af2c92016-09-23 07:26:13 +0200311 help="Set gain [default=%default]")
Piotr Krysik7185b662016-02-14 20:24:54 +0100312 parser.add_option("", "--args", dest="args", type="string", default="",
Roman Khassraf98af2c92016-09-23 07:26:13 +0200313 help="Set device arguments [default=%default]")
Roman Khassraf996103f2015-09-27 11:22:35 +0200314 parser.add_option("--speed", dest="speed", type="intx", default=4,
Roman Khassraf98af2c92016-09-23 07:26:13 +0200315 help="Scan speed [default=%default]. Value range 0-5.")
316 parser.add_option("-v", "--verbose", action="store_true",
Roman Khassraf996103f2015-09-27 11:22:35 +0200317 help="If set, verbose information output is printed: ccch configuration, cell ARFCN's, neighbour ARFCN's")
Roman Khassraf98af2c92016-09-23 07:26:13 +0200318
Roman Khassraf996103f2015-09-27 11:22:35 +0200319 """
320 Dont forget: sudo sysctl kernel.shmmni=32000
321 """
Roman Khassraf98af2c92016-09-23 07:26:13 +0200322
Roman Khassraf996103f2015-09-27 11:22:35 +0200323 (options, args) = parser.parse_args()
Roman Khassraf98af2c92016-09-23 07:26:13 +0200324
Roman Khassraf996103f2015-09-27 11:22:35 +0200325 if options.band not in grgsm.arfcn.get_bands():
326 parser.error("Invalid GSM band\n")
Roman Khassraf98af2c92016-09-23 07:26:13 +0200327
Roman Khassraf996103f2015-09-27 11:22:35 +0200328 if options.speed < 0 or options.speed > 5:
329 parser.error("Invalid scan speed.\n")
Roman Khassraf98af2c92016-09-23 07:26:13 +0200330
Roman Khassrafe2fbb872015-09-29 19:40:04 +0200331 if (options.samp_rate / 0.2e6) % 2 != 0:
332 parser.error("Invalid sample rate. Sample rate must be an even numer * 0.2e6")
Roman Khassraf996103f2015-09-27 11:22:35 +0200333
Roman Khassraf98af2c92016-09-23 07:26:13 +0200334 channels_num = int(options.samp_rate / 0.2e6)
Piotr Krysikdd86a992017-03-30 10:53:58 +0200335 print ""
Roman Khassraf98af2c92016-09-23 07:26:13 +0200336 for arfcn_range in grgsm.arfcn.get_arfcn_ranges(options.band):
337 first_arfcn = arfcn_range[0]
338 last_arfcn = arfcn_range[1]
339 last_center_arfcn = last_arfcn - int((channels_num / 2) - 1)
340
341 current_freq = grgsm.arfcn.arfcn2downlink(first_arfcn + int(channels_num / 2) - 1, options.band)
342 last_freq = grgsm.arfcn.arfcn2downlink(last_center_arfcn, options.band)
343 stop_freq = last_freq + 0.2e6 * channels_num
344
345 while current_freq < stop_freq:
346
347 # silence rtl_sdr output:
348 # open 2 fds
349 null_fds = [os.open(os.devnull, os.O_RDWR) for x in xrange(2)]
350 # save the current file descriptors to a tuple
351 save = os.dup(1), os.dup(2)
352 # put /dev/null fds on 1 and 2
353 os.dup2(null_fds[0], 1)
354 os.dup2(null_fds[1], 2)
355
356 # instantiate scanner and processor
357 scanner = wideband_scanner(rec_len=6 - options.speed,
358 sample_rate=options.samp_rate,
359 carrier_frequency=current_freq,
Piotr Krysik881b6c32017-03-30 10:53:25 +0200360 ppm=options.ppm, gain=options.gain, args=options.args)
Roman Khassraf98af2c92016-09-23 07:26:13 +0200361
362 # start recording
363 scanner.start()
364 scanner.wait()
365 scanner.stop()
366
367 freq_offsets = numpy.fft.ifftshift(
368 numpy.array(range(int(-numpy.floor(channels_num / 2)), int(numpy.floor((channels_num + 1) / 2)))) * 2e5)
369 detected_c0_channels = scanner.gsm_extract_system_info.get_chans()
370
Roman Khassraf996103f2015-09-27 11:22:35 +0200371 found_list = []
Roman Khassraf996103f2015-09-27 11:22:35 +0200372
Roman Khassraf98af2c92016-09-23 07:26:13 +0200373 if detected_c0_channels:
374 chans = numpy.array(scanner.gsm_extract_system_info.get_chans())
375 found_freqs = current_freq + freq_offsets[(chans)]
376
377 cell_ids = numpy.array(scanner.gsm_extract_system_info.get_cell_id())
378 lacs = numpy.array(scanner.gsm_extract_system_info.get_lac())
379 mccs = numpy.array(scanner.gsm_extract_system_info.get_mcc())
380 mncs = numpy.array(scanner.gsm_extract_system_info.get_mnc())
381 ccch_confs = numpy.array(scanner.gsm_extract_system_info.get_ccch_conf())
382 powers = numpy.array(scanner.gsm_extract_system_info.get_pwrs())
383
384 for i in range(0, len(chans)):
385 cell_arfcn_list = scanner.gsm_extract_system_info.get_cell_arfcns(chans[i])
386 neighbour_list = scanner.gsm_extract_system_info.get_neighbours(chans[i])
387
388 info = channel_info(grgsm.arfcn.downlink2arfcn(found_freqs[i], options.band), found_freqs[i],
389 cell_ids[i], lacs[i], mccs[i], mncs[i], ccch_confs[i], powers[i],
390 neighbour_list, cell_arfcn_list)
391 found_list.append(info)
392
393 scanner = None
394
395 # restore file descriptors so we can print the results
396 os.dup2(save[0], 1)
397 os.dup2(save[1], 2)
398 # close the temporary fds
399 os.close(null_fds[0])
400 os.close(null_fds[1])
401
Roman Khassraf996103f2015-09-27 11:22:35 +0200402 for info in sorted(found_list):
403 print info
404 if options.verbose:
405 print info.get_verbose_info()
Roman Khassraf98af2c92016-09-23 07:26:13 +0200406
407 current_freq += channels_num * 0.2e6