summaryrefslogtreecommitdiff
path: root/gr-pager/src/usrp_flex.py
blob: a9d6593fda03682e64fec3e439d8623b99d0bac6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/usr/bin/env python

#
# Copyright 2006,2007 Free Software Foundation, Inc.
# 
# This file is part of GNU Radio
# 
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# 
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
# 

from gnuradio import gr, gru, usrp, optfir, eng_notation, blks, pager
from gnuradio.eng_option import eng_option
from optparse import OptionParser
import time, os, sys
from string import split, join

"""
This example application demonstrates receiving and demodulating the
FLEX pager protocol.

A receive chain is built up of the following signal processing
blocks:

USRP  - Daughter board source generating complex baseband signal.
CHAN  - Low pass filter to select channel bandwidth
AGC   - Automatic gain control leveling signal at [-1.0, +1.0]
FLEX  - FLEX pager protocol decoder

The following are required command line parameters:

-f FREQ		USRP receive frequency

The following are optional command line parameters:

-R SUBDEV   Daughter board specification, defaults to first found
-c FREQ     Calibration offset.  Gets added to receive frequency.
            Defaults to 0.0 Hz.
-g GAIN     Daughterboard gain setting. Defaults to mid-range.
-r RFSQL	RF squelch in db. Defaults to -50.0.

Once the program is running, ctrl-break (Ctrl-C) stops operation.
"""

class usrp_source_c(gr.hier_block):
    """
    Create a USRP source object supplying complex floats.
    
    Selects user supplied subdevice or chooses first available one.

    Calibration value is the offset from the tuned frequency to 
    the actual frequency.       
    """
    def __init__(self, fg, subdev_spec, decim, gain=None, calibration=0.0):
        self._decim = decim
        self._src = usrp.source_c()
        if subdev_spec is None:
            subdev_spec = usrp.pick_rx_subdevice(self._src)
        self._subdev = usrp.selected_subdev(self._src, subdev_spec)
        self._src.set_mux(usrp.determine_rx_mux_value(self._src, subdev_spec))
        self._src.set_decim_rate(self._decim)

        # If no gain specified, set to midrange
        if gain is None:
            g = self._subdev.gain_range()
            gain = (g[0]+g[1])/2.0

        self._subdev.set_gain(gain)
        self._cal = calibration

        gr.hier_block.__init__(self, fg, self._src, self._src)

    def tune(self, freq):
        result = usrp.tune(self._src, 0, self._subdev, freq+self._cal)
        # TODO: deal with residual

    def rate(self):
        return self._src.adc_rate()/self._decim

class app_flow_graph(gr.flow_graph):
    def __init__(self, options, args, queue):
        gr.flow_graph.__init__(self)
        self.options = options
        self.args = args

        USRP = usrp_source_c(self,          # Flow graph
                    options.rx_subdev_spec, # Daugherboard spec
	            256,                    # IF decimation ratio gets 250K if_rate
                    options.gain,           # Receiver gain
                    options.calibration)    # Frequency offset
        USRP.tune(options.frequency)

        if_rate = USRP.rate()
        channel_rate = 25000                
        channel_decim = int(if_rate / channel_rate)
	
        CHAN_taps = optfir.low_pass(1.0,          # Filter gain
                                    if_rate,      # Sample rate
			            8000,         # One sided modulation bandwidth
	                            10000,        # One sided channel bandwidth
				    0.1,	  # Passband ripple
				    60) 	  # Stopband attenuation
	
        CHAN = gr.freq_xlating_fir_filter_ccf(channel_decim, # Decimation rate
                                              CHAN_taps,     # Filter taps
                                              0.0,           # Offset frequency
                                              if_rate)       # Sample rate

        AGC = gr.agc_cc(1.0/channel_rate,  # Time constant
                        1.0,               # Reference power 
                        1.0,               # Initial gain
                        1.0)               # Maximum gain
	
        FLEX = pager.flex_demod(self, 25000, queue)

        self.connect(USRP, CHAN, AGC, FLEX.INPUT)
	
def main():
    parser = OptionParser(option_class=eng_option)
    parser.add_option("-f", "--frequency", type="eng_float",
                      help="set receive frequency to Hz", metavar="Hz")
    parser.add_option("-R", "--rx-subdev-spec", type="subdev",
                      help="select USRP Rx side A or B", metavar="SUBDEV")
    parser.add_option("-c",   "--calibration", type="eng_float", default=0.0,
                      help="set frequency offset to Hz", metavar="Hz")
    parser.add_option("-g", "--gain", type="int", default=None,
                      help="set RF gain", metavar="dB")
    (options, args) = parser.parse_args()

    if options.frequency < 1e6:
	options.frequency *= 1e6
	
    queue = gr.msg_queue()

    fg = app_flow_graph(options, args, queue)
    try:
        fg.start()
	while 1:
	    if not queue.empty_p():
		msg = queue.delete_head() # Blocking read
		fields = split(msg.to_string(), chr(128))
		print join(fields, '|')
	    else:
		time.sleep(1)

    except KeyboardInterrupt:
        fg.stop()

if __name__ == "__main__":
    main()