new experimental daughterboards with other tuners
[debian/gnuradio] / gr-usrp / src / db_dtt754.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 from usrpm 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():
38     RS = 0  # 0 = 166.66kHz reference
39     ATP = 7  # Disable internal AGC
40     return 0x80 | ATP<<3 | RS
41
42 def control_byte_2():
43     STBY = 0  # powered on
44     XTO = 1  # turn off xtal out, which we don't have
45     ATC = 0  # not clear exactly, possibly speeds up or slows down AGC, which we are not using
46     
47     c = 0xc2 | ATC<<5 | STBY<<4 | XTO
48     return c
49
50 def bandswitch_byte(freq,bw):
51     if(bw>7.5e6):
52         P5 = 1
53     else:
54         P5 = 0
55
56     if freq < 121e6:
57         CP = 0
58         BS = 1
59     elif freq < 141e6:
60         CP = 1
61         BS = 1
62     elif freq < 166e6:
63         CP = 2
64         BS = 1
65     elif freq < 182e6:
66         CP = 3
67         BS = 1
68     elif freq < 286e6:
69         CP = 0
70         BS = 2
71     elif freq < 386e6:
72         CP = 1
73         BS = 2
74     elif freq < 446e6:
75         CP = 2
76         BS = 2
77     elif freq < 466e6:
78         CP = 3
79         BS = 2
80     elif freq < 506e6:
81         CP = 0
82         BS = 8
83     elif freq < 761e6:
84         CP = 1
85         BS = 8
86     elif freq < 846e6:
87         CP = 2
88         BS = 8
89     else:  # limit is ~905 MHz
90         CP = 3
91         BS = 8
92     return CP<<6 | P5 << 4 | BS
93
94 class db_dtt754(db_base.db_base):
95     def __init__(self, usrp, which):
96         """
97         Control custom DTT75403-based daughterboard.
98         
99         @param usrp: instance of usrp.source_c
100         @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively
101         @type which: int
102         """
103         # sets _u and _which
104         db_base.db_base.__init__(self, usrp, which)
105
106         self._i2c_addr = (0x60, 0x62)[which]
107         self.bw = 7e6
108         self._IF = 36e6
109         
110         self.f_ref = 166.6666e3
111         self._inverted = False  
112         
113         g = self.gain_range()                  # initialize gain
114         self.set_gain(float(g[0]+g[1]) / 2)
115
116         self.bypass_adc_buffers(False)
117         
118     # Gain setting
119     def _set_rfagc(self,gain):
120         assert gain <= 60 and gain >= 0
121         # FIXME this has a 0.5V step between gain = 60 and gain = 59.
122         # Why are there two cases instead of a single linear case?
123         if gain == 60:
124             voltage = 4
125         else:
126             voltage = gain/60.0 * 2.25 + 1.25
127         dacword = int(4096*voltage/1.22/3.3)    # 1.22 = opamp gain
128
129         assert dacword>=0 and dacword<4096
130         self._u.write_aux_dac(self._which, 1, dacword)
131
132     def _set_ifagc(self,gain):
133         assert gain <= 35 and gain >= 0
134         voltage = gain/35.0 * 2.1 + 1.4
135         dacword = int(4096*voltage/1.22/3.3)    # 1.22 = opamp gain
136
137         assert dacword>=0 and dacword<4096
138         self._u.write_aux_dac(self._which, 0, dacword)
139
140     def _set_pga(self,pga_gain):
141         assert pga_gain >=0 and pga_gain <=20
142         if(self._which == 0):
143             self._u.set_pga (0, pga_gain)
144         else:
145             self._u.set_pga (2, pga_gain)
146             
147     def gain_range(self):
148         return (0, 115, 1)
149     
150     def set_gain(self,gain):
151         assert gain>=0 and gain<=115
152         if gain>60:
153             rfgain = 60
154             gain = gain - 60
155         else:
156             rfgain = gain
157             gain = 0
158         if gain > 35:
159             ifgain = 35
160             gain = gain - 35
161         else:
162             ifgain = gain
163             gain = 0
164         pgagain = gain
165         self._set_rfagc(rfgain)
166         self._set_ifagc(ifgain)
167         self._set_pga(pgagain)
168         
169     def freq_range(self):
170         return (44e6, 900e6, 10e3)
171
172     def set_freq(self, target_freq):
173         """
174         @returns (ok, actual_baseband_freq) where:
175            ok is True or False and indicates success or failure,
176            actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
177         """
178         r = self.freq_range()
179         if target_freq < r[0] or target_freq > r[1]:
180             return (False, 0)
181         
182         target_lo_freq = target_freq + self._IF;  # High side mixing
183
184         divisor = int(0.5+(target_lo_freq / self.f_ref))
185         actual_lo_freq = self.f_ref*divisor
186
187         if (divisor & ~0x7fff) != 0:            # must be 15-bits or less
188             return (False, 0)
189         
190         # build i2c command string
191         buf = [0] * 5
192         buf[0] = (divisor >> 8) & 0xff          # DB1
193         buf[1] = divisor & 0xff                 # DB2
194         buf[2] = control_byte_1()
195         buf[3] = bandswitch_byte(actual_lo_freq,self.bw)
196         buf[4] = control_byte_2()  
197
198         ok = self._u.write_i2c(self._i2c_addr, int_seq_to_str (buf))
199
200         self.freq = actual_lo_freq - self._IF
201         
202         return (ok, actual_lo_freq)
203
204     def is_quadrature(self):
205         """
206         Return True if this board requires both I & Q analog channels.
207
208         This bit of info is useful when setting up the USRP Rx mux register.
209         """
210         return False
211
212     def spectrum_inverted(self):
213         """
214         The 43.75 MHz version is inverted
215         """
216         return self._inverted
217
218     def set_bw(self,bw):
219         """
220         Choose the SAW filter bandwidth, either 7MHz or 8MHz)
221         """
222         self.bw = bw
223         self.set_freq(self.freq)
224         
225 # hook this daughterboard class into the auto-instantiation framework
226
227 # With DTT75403
228 db_instantiator.add(usrp_dbid.DTT754,
229                     lambda usrp, which : (db_dtt754(usrp, which),))