Added gr-pager component to trunk by merging from r3474:r3537 in
[debian/gnuradio] / gr-pager / src / usrp_flex.py
1 #!/usr/bin/env python
2
3 from gnuradio import gr, gru, usrp, optfir, eng_notation, blks
4 from gnuradio.eng_option import eng_option
5 from optparse import OptionParser
6 import time, os, sys
7
8 from flex_demod import flex_demod
9
10 """
11 This example application demonstrates receiving and demodulating the
12 FLEX pager protocol.
13
14 A receive chain is built up of the following signal processing
15 blocks:
16
17 USRP  - Daughter board source generating complex baseband signal.
18 CHAN  - Low pass filter to select channel bandwidth
19 RFSQL - RF squelch zeroing output when input power below threshold
20 AGC   - Automatic gain control leveling signal at [-1.0, +1.0]
21 FLEX  - FLEX pager protocol decoder
22 SINK  - File sink for decoded output 
23
24 The following are required command line parameters:
25
26 -f FREQ         USRP receive frequency
27
28 The following are optional command line parameters:
29
30 -R SUBDEV   Daughter board specification, defaults to first found
31 -c FREQ     Calibration offset.  Gets added to receive frequency.
32             Defaults to 0.0 Hz.
33 -g GAIN     Daughterboard gain setting. Defaults to mid-range.
34 -r RFSQL        RF squelch in db. Defaults to -50.0.
35
36 Once the program is running, ctrl-break (Ctrl-C) stops operation.
37 """
38
39 def make_filename(dir, freq):
40     t = time.strftime('%Y%m%d-%H%M%S')
41     f = 'r%s-%s.dat' % (t, eng_notation.num_to_str(freq))
42     return os.path.join(dir, f)
43
44 class usrp_source_c(gr.hier_block):
45     """
46     Create a USRP source object supplying complex floats.
47     
48     Selects user supplied subdevice or chooses first available one.
49
50     Calibration value is the offset from the tuned frequency to 
51     the actual frequency.       
52     """
53     def __init__(self, fg, subdev_spec, decim, gain=None, calibration=0.0):
54         self._decim = decim
55         self._src = usrp.source_c()
56         if subdev_spec is None:
57             subdev_spec = usrp.pick_rx_subdevice(self._src)
58         self._subdev = usrp.selected_subdev(self._src, subdev_spec)
59         self._src.set_mux(usrp.determine_rx_mux_value(self._src, subdev_spec))
60         self._src.set_decim_rate(self._decim)
61
62         # If no gain specified, set to midrange
63         if gain is None:
64             g = self._subdev.gain_range()
65             gain = (g[0]+g[1])/2.0
66
67         self._subdev.set_gain(gain)
68         self._cal = calibration
69
70         gr.hier_block.__init__(self, fg, self._src, self._src)
71
72     def tune(self, freq):
73         result = usrp.tune(self._src, 0, self._subdev, freq+self._cal)
74         # TODO: deal with residual
75
76     def rate(self):
77         return self._src.adc_rate()/self._decim
78
79 class app_flow_graph(gr.flow_graph):
80     def __init__(self, options, args):
81         gr.flow_graph.__init__(self)
82         self.options = options
83         self.args = args
84
85         USRP = usrp_source_c(self,          # Flow graph
86                     options.rx_subdev_spec, # Daugherboard spec
87                         250,                    # IF decimation ratio gets 256K if_rate
88                     options.gain,           # Receiver gain
89                     options.calibration)    # Frequency offset
90         USRP.tune(options.frequency)
91
92         if_rate = USRP.rate()
93         channel_rate = 32000                # Oversampled by 10 or 20
94         channel_decim = if_rate // channel_rate
95         
96         CHAN_taps = optfir.low_pass(1.0,          # Filter gain
97                                     if_rate,      # Sample rate
98                                                 8000,         # One sided modulation bandwidth
99                                         10000,        # One sided channel bandwidth
100                                                     0.1,              # Passband ripple
101                                                     60)                   # Stopband attenuation
102         
103         CHAN = gr.freq_xlating_fir_filter_ccf(channel_decim, # Decimation rate
104                                               CHAN_taps,     # Filter taps
105                                               0.0,           # Offset frequency
106                                               if_rate)       # Sample rate
107
108         RFSQL = gr.pwr_squelch_cc(options.rf_squelch, # Power threshold
109                                   125.0/channel_rate, # Time constant
110                                                   channel_rate/20,    # 50ms rise/fall
111                                   False)              # Zero, not gate output
112
113         AGC = gr.agc_cc(1.0/channel_rate,  # Time constant
114                         1.0,               # Reference power 
115                         1.0,               # Initial gain
116                         1.0)               # Maximum gain
117         
118         FLEX = flex_demod(self, 32000)      
119
120         SINK = gr.file_sink(4, options.filename)
121
122         self.connect(USRP, CHAN)
123         self.connect(CHAN, RFSQL)
124         self.connect(RFSQL, AGC)
125         self.connect(AGC, FLEX)
126         self.connect(FLEX, SINK)
127         
128 def main():
129     parser = OptionParser(option_class=eng_option)
130     parser.add_option("-f", "--frequency", type="eng_float",
131                       help="set receive frequency to Hz", metavar="Hz")
132     parser.add_option("-R", "--rx-subdev-spec", type="subdev",
133                       help="select USRP Rx side A or B", metavar="SUBDEV")
134     parser.add_option("-c",   "--calibration", type="eng_float", default=0.0,
135                       help="set frequency offset to Hz", metavar="Hz")
136     parser.add_option("-g", "--gain", type="int", default=None,
137                       help="set RF gain", metavar="dB")
138     parser.add_option("-r", "--rf-squelch", type="eng_float", default=-50.0,
139                       help="set RF squelch to dB", metavar="dB")
140     parser.add_option("-F", "--filename", default=None)
141     parser.add_option("-D", "--dir", default=None)
142     (options, args) = parser.parse_args()
143
144     if options.frequency < 1e6:
145         options.frequency *= 1e6
146         
147     if options.filename is None and options.dir is None:
148         sys.stderr.write('Must specify either -F FILENAME or -D DIR\n')
149         parser.print_help()
150         sys.exit(1)
151
152     if options.filename is None:
153         options.filename = make_filename(options.dir, options.frequency)
154
155     fg = app_flow_graph(options, args)
156     try:
157         fg.run()
158     except KeyboardInterrupt:
159         pass
160
161 if __name__ == "__main__":
162     main()