Merged eb/gcell-wip2 rev 10130:10152 into trunk.
[debian/gnuradio] / gr-usrp / src / db_dtt768.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_4():
38     C = 0   # Charge Pump Current, no info on how to choose
39     R = 4   # 125 kHz fref
40     
41
42     ATP = 7  # Disable internal AGC
43     return 0x80 | C<<5 | R
44
45 def control_byte_5(freq,agcmode = 1):
46     if(agcmode):
47         if freq < 150e6:
48             return 0x3B
49         elif freq < 420e6:
50             return 0x7E
51         else:
52             return 0xB7
53     else:
54         if freq < 150e6:
55             return 0x39
56         elif freq < 420e6:
57             return 0x7C
58         else:
59             return 0xB5
60         
61 def control_byte_6():
62     ATC = 0   # AGC time constant = 100ms, 1 = 3S
63     IFE = 1   # IF AGC amplifier enable
64     AT = 0    # AGC control, ???
65     
66     return ATC << 5 | IFE << 4 | AT
67
68 def control_byte_7():
69     SAS = 1  # SAW Digital mode
70     AGD = 1  # AGC disable
71     ADS = 0  # AGC detector into ADC converter
72     T = 0    # Test mode, undocumented
73     return SAS << 7 | AGD << 5 | ADS << 4 | T
74
75 class db_dtt768(db_base.db_base):
76     def __init__(self, usrp, which):
77         """
78         Control custom DTT76803-based daughterboard.
79         
80         @param usrp: instance of usrp.source_c
81         @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively
82         @type which: int
83         """
84         # sets _u and _which
85         db_base.db_base.__init__(self, usrp, which)
86
87         self._i2c_addr = (0x60, 0x62)[which]
88         self._IF = 44e6
89         
90         self.f_ref = 125e3
91         self._inverted = False  
92         
93         g = self.gain_range()                  # initialize gain
94         self.set_gain(float(g[0]+g[1]) / 2)
95
96         self.bypass_adc_buffers(False)
97         
98     # Gain setting
99     def _set_rfagc(self,gain):
100         assert gain <= 60 and gain >= 0
101         # FIXME this has a 0.5V step between gain = 60 and gain = 59.
102         # Why are there two cases instead of a single linear case?
103         if gain == 60:
104             voltage = 4
105         else:
106             voltage = gain/60.0 * 2.25 + 1.25
107         dacword = int(4096*voltage/1.22/3.3)    # 1.22 = opamp gain
108
109         assert dacword>=0 and dacword<4096
110         self._u.write_aux_dac(self._which, 1, dacword)
111
112     def _set_ifagc(self,gain):
113         assert gain <= 35 and gain >= 0
114         voltage = gain/35.0 * 2.1 + 1.4
115         dacword = int(4096*voltage/1.22/3.3)    # 1.22 = opamp gain
116
117         assert dacword>=0 and dacword<4096
118         self._u.write_aux_dac(self._which, 0, dacword)
119
120     def _set_pga(self,pga_gain):
121         assert pga_gain >=0 and pga_gain <=20
122         if(self._which == 0):
123             self._u.set_pga (0, pga_gain)
124         else:
125             self._u.set_pga (2, pga_gain)
126             
127     def gain_range(self):
128         return (0, 115, 1)
129     
130     def set_gain(self,gain):
131         assert gain>=0 and gain<=115
132         if gain>60:
133             rfgain = 60
134             gain = gain - 60
135         else:
136             rfgain = gain
137             gain = 0
138         if gain > 35:
139             ifgain = 35
140             gain = gain - 35
141         else:
142             ifgain = gain
143             gain = 0
144         pgagain = gain
145         self._set_rfagc(rfgain)
146         self._set_ifagc(ifgain)
147         self._set_pga(pgagain)
148         
149     def freq_range(self):
150         return (44e6, 900e6, 10e3)
151
152     def set_freq(self, target_freq):
153         """
154         @returns (ok, actual_baseband_freq) where:
155            ok is True or False and indicates success or failure,
156            actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
157         """
158         r = self.freq_range()
159         if target_freq < r[0] or target_freq > r[1]:
160             return (False, 0)
161         
162         target_lo_freq = target_freq + self._IF;  # High side mixing
163
164         divisor = int(0.5+(target_lo_freq / self.f_ref))
165         actual_lo_freq = self.f_ref*divisor
166
167         if (divisor & ~0x7fff) != 0:            # must be 15-bits or less
168             return (False, 0)
169         
170         # build i2c command string
171         buf = [0] * 6
172         buf[0] = (divisor >> 8) & 0xff          # DB1
173         buf[1] = divisor & 0xff                 # DB2
174         buf[2] = control_byte_4()
175         buf[3] = control_byte_5(target_freq)
176         buf[4] = control_byte_6()
177         buf[5] = control_byte_7()
178
179         ok = self._u.write_i2c(self._i2c_addr, int_seq_to_str (buf))
180
181         self.freq = actual_lo_freq - self._IF
182         
183         return (ok, actual_lo_freq)
184
185     def is_quadrature(self):
186         """
187         Return True if this board requires both I & Q analog channels.
188
189         This bit of info is useful when setting up the USRP Rx mux register.
190         """
191         return False
192
193     def spectrum_inverted(self):
194         """
195         The 43.75 MHz version is inverted
196         """
197         return self._inverted
198
199 # hook this daughterboard class into the auto-instantiation framework
200
201 # With DTT76803
202 db_instantiator.add(usrp_dbid.DTT768,
203                     lambda usrp, which : (db_dtt768(usrp, which),))