├── README.md └── flex.py /README.md: -------------------------------------------------------------------------------- 1 | #FLEX_hackrf 2 | 3 | flex_hackrf is an attempt to make a functional flex decoder / scanner using the hackrf as a source. It is heavenly based on the examples that come with gr-pager and I would like to thank Johnathan Corgan for his work on creating this addon to gnuradio. 4 | This is a modified version of mothran's flex_hackrf script, that should work with GNU Radio 3.7. I didn't do much, all the credit goes to Johnathan and mothran! 5 | 6 | 7 | ##Usage 8 | 9 | Make sure your hackrf is function and open to be read from: 10 | hackrf_info 11 | 12 | 13 | Now run flex.py 14 | 15 | python flex.py -f FREQENCY 16 | 17 | 18 | Example: 19 | 20 | python flex.py -f 931.95M 21 | 22 | If you do not see any "Using Volk machine" output then it did not detect and signals within the predifined range. You might need to run 23 | 24 | killall python 25 | 26 | to kill the program if that happens. Currently flex_hackrf only scans between 929 Mhz and 932 Mhz. 27 | -------------------------------------------------------------------------------- /flex.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2006,2007,2009 Free Software Foundation, Inc. 4 | # 5 | # This file is part of GNU Radio 6 | # 7 | # GNU Radio 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 | # GNU Radio 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 GNU Radio; 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 | # Modified by Mothran for use with HackRF 23 | # Modified by Dennis Mantz to work with GNU Radio 3.7 24 | from gnuradio import gr, eng_notation, filter, pager, blocks 25 | from gnuradio.eng_option import eng_option 26 | from optparse import OptionParser 27 | from string import split, join, printable 28 | import sys 29 | import osmosdr 30 | 31 | 32 | class app_top_block(gr.top_block): 33 | def __init__(self, options, queue): 34 | gr.top_block.__init__(self, "flex_hackrf") 35 | 36 | # Set up HackRF source 37 | self.u = osmosdr.source( args="numchan=" + str(1) + " " + "" ) 38 | self.u.set_freq_corr(0, 0) 39 | self.u.set_dc_offset_mode(0, 0) 40 | self.u.set_iq_balance_mode(0, 0) 41 | self.u.set_gain_mode(False, 0) 42 | self.u.set_gain(0, 0) 43 | self.u.set_if_gain(20, 0) 44 | self.u.set_bb_gain(20, 0) 45 | self.u.set_antenna("", 0) 46 | self.u.set_bandwidth(0, 0) 47 | 48 | # Tune hackRF 49 | r = self.u.set_center_freq(options.freq+options.calibration, 0) 50 | if not r: 51 | frange = self.u.get_freq_range() 52 | sys.stderr.write(("\nRequested frequency (%f) out or range [%f, %f]\n") % \ 53 | (freq, frange.start(), frange.stop())) 54 | sys.exit(1) 55 | 56 | if options.verbose: 57 | print "Tuned to center frequency", (options.freq+options.calibration)/1e6, "MHz" 58 | 59 | # Grab >=3 MHz of spectrum, evenly divisible by 25 KHz channels 60 | # (A UHD facility to get sample rate range and granularity would be useful) 61 | 62 | self.u.set_sample_rate(3.125e6) # Works if USRP is 100 Msps and can decimate by 32 63 | rate = self.u.get_sample_rate() 64 | 65 | if rate != 3.125e6: 66 | self.u.set_sample_rate(3.2e6) # Works if USRP is 64 Msps and can decimate by 20 67 | rate = self.u.get_sample_rate() 68 | if (rate != 3.2e6): 69 | print "Unable to set required sample rate for >= 3MHz of 25 KHz channels." 70 | sys.exit(1) 71 | 72 | self.nchan = int(rate/25e3) 73 | if options.verbose: 74 | print "\nReceiving", rate/1e6, "MHz of bandwidth containing", self.nchan, "baseband channels." 75 | 76 | taps = filter.firdes.low_pass(1.0,1.0,1.0/self.nchan*0.4,1.0/self.nchan*0.1,filter.firdes.WIN_HANN) 77 | 78 | if options.verbose: 79 | print "Channel filter has", len(taps), "taps" 80 | 81 | self.bank = filter.analysis_filterbank(self.nchan, taps) 82 | self.connect(self.u, self.bank) 83 | 84 | mid_chan = int(self.nchan/2) 85 | for i in range(self.nchan): 86 | if i < mid_chan: 87 | freq = options.freq+i*25e3 88 | else: 89 | freq = options.freq-(self.nchan-i)*25e3 90 | 91 | if (freq < 929.0e6 or freq > 932.0e6): 92 | self.connect((self.bank, i), blocks.null_sink(gr.sizeof_gr_complex)) 93 | else: 94 | self.connect((self.bank, i), pager.flex_demod(queue, freq, options.verbose)) 95 | 96 | def get_options(): 97 | parser = OptionParser(option_class=eng_option) 98 | parser.add_option('-f', '--freq', type="eng_float", default=931.95e6, 99 | help="Set receive frequency to FREQ [default=%default]", 100 | metavar="FREQ") 101 | parser.add_option("-c", "--calibration", type="eng_float", default=0.0, 102 | help="set frequency offset to Hz", metavar="Hz") 103 | parser.add_option("-v", "--verbose", action="store_true", default=False) 104 | parser.add_option("", "--nchan", type="int", default=None, 105 | help="set to number of channels in capture file", metavar="nchan") 106 | 107 | (options, args) = parser.parse_args() 108 | 109 | return (options, args) 110 | 111 | def make_trans_table(): 112 | table = 256 * ['.'] 113 | for i in range(256): 114 | if (i < 32): 115 | table[i] = '.' 116 | else: 117 | table[i] = chr(i) 118 | return ''.join(table) 119 | 120 | def main(): 121 | 122 | (options, args) = get_options() 123 | 124 | queue = gr.msg_queue() 125 | tb = app_top_block(options, queue) 126 | tb.start() 127 | 128 | conversion_table = make_trans_table() 129 | while 1: 130 | msg = queue.delete_head() # Blocking read 131 | if msg.type() != 0: 132 | break 133 | 134 | page = split(msg.to_string(), chr(128)) 135 | if page[2] == "ALN": 136 | print page[0] + " | " + page[3].replace("\n", "") 137 | 138 | tb.end() 139 | 140 | if __name__ == "__main__": 141 | main() 142 | --------------------------------------------------------------------------------