Imported Upstream version 3.0.4
[debian/gnuradio] / gr-usrp / src / db_tv_rx.py
1 #
2 # Copyright 2005 Free Software Foundation, Inc.
3
4 # This file is part of GNU Radio
5
6 # GNU Radio is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3, or (at your option)
9 # any later version.
10
11 # GNU Radio is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with GNU Radio; see the file COPYING.  If not, write to
18 # the Free Software Foundation, Inc., 51 Franklin Street,
19 # Boston, MA 02110-1301, USA.
20
21
22 __all__ = ['tv_rx']
23
24 import math
25 import usrp_dbid
26 import db_base
27 import db_instantiator
28
29 def int_seq_to_str(seq):
30     """convert a sequence of integers into a string"""
31     return ''.join (map (chr, seq))
32
33 def str_to_int_seq(str):
34     """convert a string to a list of integers"""
35     return map (ord, str)
36
37 def control_byte_1(fast_tuning_p, reference_divisor):
38     c = 0x88
39     if fast_tuning_p:
40         c |= 0x40
41     if reference_divisor == 512:
42         c |= 0x3 << 1
43     elif reference_divisor == 640:
44         c |= 0x0 << 1
45     elif reference_divisor == 1024:
46         c |= 0x1 << 1
47     else:
48         assert 0
49     return c
50
51 def control_byte_2(target_freq, shutdown_tx_PGA):
52     if target_freq < 158e6:        # VHF low
53         c = 0xa0
54     elif target_freq < 464e6:      # VHF high
55         c = 0x90
56     else:                          # UHF
57         c = 0x30
58     if shutdown_tx_PGA:
59         c |= 0x08
60     return c
61
62 class db_tv_rx(db_base.db_base):
63     def __init__(self, usrp, which, first_IF, second_IF):
64         """
65         Control Microtune 4937 based USRP daughterboard.
66         
67         @param usrp: instance of usrp.source_c
68         @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively
69         @type which: int
70         """
71         # sets _u and _which
72         db_base.db_base.__init__(self, usrp, which)
73
74         self._i2c_addr = (0x60, 0x61)[which]
75
76         self._first_IF = first_IF
77         self._second_IF = second_IF
78         self._reference_divisor = 640
79         self._fast_tuning = False
80         self._inverted = False      # FIXME get rid of this
81         
82         g = self.gain_range()                  # initialize gain
83         self.set_gain(float(g[0]+g[1]) / 2)
84
85         self.bypass_adc_buffers(False)
86         
87     # Gain setting
88     def _set_rfagc(self,gain):
89         assert gain <= 60 and gain >= 0
90         # FIXME this has a 0.5V step between gain = 60 and gain = 59.
91         # Why are there two cases instead of a single linear case?
92         if gain == 60:
93             voltage = 4
94         else:
95             voltage = gain/60.0 * 2.25 + 1.25
96         dacword = int(4096*voltage/1.22/3.3)    # 1.22 = opamp gain
97
98         assert dacword>=0 and dacword<4096
99         self._u.write_aux_dac(self._which, 1, dacword)
100
101     def _set_ifagc(self,gain):
102         assert gain <= 35 and gain >= 0
103         voltage = gain/35.0 * 2.1 + 1.4
104         dacword = int(4096*voltage/1.22/3.3)    # 1.22 = opamp gain
105
106         assert dacword>=0 and dacword<4096
107         self._u.write_aux_dac(self._which, 0, dacword)
108
109     def _set_pga(self,pga_gain):
110         assert pga_gain >=0 and pga_gain <=20
111         if(self._which == 0):
112             self._u.set_pga (0, pga_gain)
113         else:
114             self._u.set_pga (2, pga_gain)
115             
116     def gain_range(self):
117         return (0, 115, 1)
118     
119     def set_gain(self,gain):
120         assert gain>=0 and gain<=115
121         if gain>60:
122             rfgain = 60
123             gain = gain - 60
124         else:
125             rfgain = gain
126             gain = 0
127         if gain > 35:
128             ifgain = 35
129             gain = gain - 35
130         else:
131             ifgain = gain
132             gain = 0
133         pgagain = gain
134         self._set_rfagc(rfgain)
135         self._set_ifagc(ifgain)
136         self._set_pga(pgagain)
137         
138     def freq_range(self):
139         return (50e6, 860e6, 10e3)
140
141     def set_freq(self, target_freq):
142         """
143         @returns (ok, actual_baseband_freq) where:
144            ok is True or False and indicates success or failure,
145            actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
146         """
147         r = self.freq_range()
148         if target_freq < r[0] or target_freq > r[1]:
149             return (False, 0)
150         
151         target_lo_freq = target_freq + self._first_IF;  # High side mixing
152         f_ref = 4e6 / self._reference_divisor   # frequency steps
153
154         divisor = int((target_lo_freq + (f_ref * 4)) / (f_ref * 8))  
155         actual_lo_freq = (f_ref * 8 * divisor)
156         actual_freq = actual_lo_freq - self._first_IF;
157
158         if (divisor & ~0x7fff) != 0:            # must be 15-bits or less
159             return (False, 0)
160         
161         # build i2c command string
162         buf = [0] * 4
163         buf[0] = (divisor >> 8) & 0xff          # DB1
164         buf[1] = divisor & 0xff                 # DB2
165         buf[2] = control_byte_1(self._fast_tuning, self._reference_divisor)
166         buf[3] = control_byte_2(actual_freq, True)  
167
168         ok = self._u.write_i2c(self._i2c_addr, int_seq_to_str (buf))
169
170         return (ok, actual_freq - self._second_IF)
171
172     def is_quadrature(self):
173         """
174         Return True if this board requires both I & Q analog channels.
175
176         This bit of info is useful when setting up the USRP Rx mux register.
177         """
178         return False
179
180     def spectrum_inverted(self):
181         """
182         The 43.75 MHz version is inverted
183         """
184         return self._inverted
185
186 # hook this daughterboard class into the auto-instantiation framework
187
188 # With MT4937DI5-3x7702 with second downconversion
189 db_instantiator.add(usrp_dbid.TV_RX,
190                     lambda usrp, which : (db_tv_rx(usrp, which, 43.75e6, 5.75e6),))
191
192 # With MT4937DI5-3x8680, and 3x8769 without second downconversion
193 db_instantiator.add(usrp_dbid.TV_RX_REV_2,
194                     lambda usrp, which : (db_tv_rx(usrp, which, 44e6, 20e6),))
195
196 # With MT4937DI5-3x7901 without second downconversion, basically the same as tvrx2
197 db_instantiator.add(usrp_dbid.TV_RX_REV_3,
198                     lambda usrp, which : (db_tv_rx(usrp, which, 44e6, 20e6),))