2 # Copyright 2005 Free Software Foundation, Inc.
4 # This file is part of GNU Radio
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 2, or (at your option)
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.
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.
27 import db_instantiator
29 def int_seq_to_str(seq):
30 """convert a sequence of integers into a string"""
31 return ''.join (map (chr, seq))
33 def str_to_int_seq(str):
34 """convert a string to a list of integers"""
37 def control_byte_1(fast_tuning_p, reference_divisor):
41 if reference_divisor == 512:
43 elif reference_divisor == 640:
45 elif reference_divisor == 1024:
51 def control_byte_2(target_freq, shutdown_tx_PGA):
52 if target_freq < 158e6: # VHF low
54 elif target_freq < 464e6: # VHF high
62 class db_tv_rx(db_base.db_base):
63 def __init__(self, usrp, which, first_IF, second_IF):
65 Control Microtune 4937 based USRP daughterboard.
67 @param usrp: instance of usrp.source_c
68 @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively
72 db_base.db_base.__init__(self, usrp, which)
74 self._i2c_addr = (0x60, 0x61)[which]
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
82 g = self.gain_range() # initialize gain
83 self.set_gain(float(g[0]+g[1]) / 2)
85 self.bypass_adc_buffers(False)
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?
95 voltage = gain/60.0 * 2.25 + 1.25
96 dacword = int(4096*voltage/1.22/3.3) # 1.22 = opamp gain
98 assert dacword>=0 and dacword<4096
99 self._u.write_aux_dac(self._which, 1, dacword)
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
106 assert dacword>=0 and dacword<4096
107 self._u.write_aux_dac(self._which, 0, dacword)
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)
114 self._u.set_pga (2, pga_gain)
116 def gain_range(self):
119 def set_gain(self,gain):
120 assert gain>=0 and gain<=115
134 self._set_rfagc(rfgain)
135 self._set_ifagc(ifgain)
136 self._set_pga(pgagain)
138 def freq_range(self):
139 return (50e6, 860e6, 10e3)
141 def set_freq(self, target_freq):
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.
147 r = self.freq_range()
148 if target_freq < r[0] or target_freq > r[1]:
151 target_lo_freq = target_freq + self._first_IF; # High side mixing
152 f_ref = 4e6 / self._reference_divisor # frequency steps
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;
158 if (divisor & ~0x7fff) != 0: # must be 15-bits or less
161 # build i2c command string
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)
168 ok = self._u.write_i2c(self._i2c_addr, int_seq_to_str (buf))
170 return (ok, actual_freq - self._second_IF)
172 def is_quadrature(self):
174 Return True if this board requires both I & Q analog channels.
176 This bit of info is useful when setting up the USRP Rx mux register.
180 def spectrum_inverted(self):
182 The 43.75 MHz version is inverted
184 return self._inverted
186 # hook this daughterboard class into the auto-instantiation framework
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),))
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),))
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),))