Cleanup in preparation for merge
[debian/gnuradio] / usrp / host / lib / db_tv_rx.cc
1 //
2 // Copyright 2008,2009 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 asversion 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 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <usrp/db_tv_rx.h>
26 #include <db_base_impl.h>
27
28 /*****************************************************************************/
29
30 int
31 control_byte_1(bool fast_tuning_p, int reference_divisor)
32 {
33   int c = 0x88;
34   if(fast_tuning_p) {
35     c |= 0x40;
36   }
37
38   if(reference_divisor == 512) {
39     c |= 0x3 << 1;
40   }
41   else if(reference_divisor == 640) {
42     c |= 0x0 << 1;
43   }
44   else if(reference_divisor == 1024) {
45     c |= 0x1 << 1;
46   }
47   else {
48     assert(0);
49   }
50
51   return c;
52 }
53
54 int
55 control_byte_2(double target_freq, bool shutdown_tx_PGA)
56 {
57   int c;
58   if(target_freq < 158e6) {        // VHF low
59     c = 0xa0;
60   }
61   else if(target_freq < 464e6) {   // VHF high
62     c = 0x90;
63   }
64   else {                           // UHF
65     c = 0x30;
66   }
67
68   if(shutdown_tx_PGA) {
69     c |= 0x08;
70   }
71
72   return c;
73 }
74
75
76 /*****************************************************************************/
77
78
79 db_tv_rx::db_tv_rx(usrp_basic_sptr usrp, int which,
80                    double first_IF, double second_IF)
81   : db_base(usrp, which)
82 {
83   // Handler for Tv Rx daughterboards.
84   // 
85   // @param usrp: instance of usrp.source_c
86   // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively
87
88   if(which == 0) {
89     d_i2c_addr = 0x60;
90   }
91   else {
92     d_i2c_addr = 0x61;
93   }
94
95   d_first_IF = first_IF;
96   d_second_IF = second_IF;
97   d_reference_divisor = 640;
98   d_fast_tuning = false;
99   d_inverted = false;                     // FIXME get rid of this
100   
101   set_gain((gain_min() + gain_max()) / 2.0);       // initialize gain
102
103   bypass_adc_buffers(false);
104 }
105
106 db_tv_rx::~db_tv_rx()
107 {
108 }
109
110 // Gain setting
111 void
112 db_tv_rx::_set_rfagc(float gain)
113 {
114   float voltage;
115
116   assert(gain <= 60 && gain >= 0);
117   // FIXME this has a 0.5V step between gain = 60 and gain = 59.
118   // Why are there two cases instead of a single linear case?
119   if(gain == 60) {
120     voltage = 4;
121   }
122   else {
123     voltage = gain/60.0 * 2.25 + 1.25;
124   }
125   int dacword = int(4096*voltage/1.22/3.3);    // 1.22 = opamp gain
126
127   assert(dacword>=0 && dacword<4096);
128   usrp()->write_aux_dac(d_which, 1, dacword);
129 }
130
131 void
132 db_tv_rx::_set_ifagc(float gain)
133 {
134   float voltage;
135
136   assert(gain <= 35 && gain >= 0);
137   voltage = gain/35.0 * 2.1 + 1.4;
138   int dacword = int(4096*voltage/1.22/3.3);    // 1.22 = opamp gain
139   
140   assert(dacword>=0 && dacword<4096);
141   usrp()->write_aux_dac(d_which, 0, dacword);
142 }
143
144 void
145 db_tv_rx::_set_pga(float pga_gain)
146 {
147   assert(pga_gain >=0 && pga_gain <=20);
148   if(d_which == 0) {
149     usrp()->set_pga(0, pga_gain);
150   }
151   else {
152     usrp()->set_pga (2, pga_gain);
153   }
154 }           
155
156 double
157 db_tv_rx::freq_min()
158 {
159   return 50e6;
160 }
161
162 double
163 db_tv_rx::freq_max()
164 {
165   return 860e6;
166 }
167
168 struct freq_result_t
169 db_tv_rx::set_freq(double target_freq)
170 {
171   // Set the frequency.
172   // 
173   // @param freq:  target RF frequency in Hz
174   // @type freq:   double
175   // 
176   // @returns (ok, actual_baseband_freq) where:
177   //   ok is True or False and indicates success or failure,
178   //   actual_baseband_freq is RF frequency that corresponds to DC in the IF.
179   
180   freq_result_t args = {false, 0};
181
182   double fmin = freq_min();
183   double fmax = freq_max();
184   if((target_freq < fmin) || (target_freq > fmax)) {
185     return args;
186   }
187   
188   double target_lo_freq = target_freq + d_first_IF;    // High side mixing
189   double f_ref = 4.0e6 / (double)(d_reference_divisor); // frequency steps
190
191   int divisor = int((target_lo_freq + (f_ref * 4)) / (f_ref * 8));  
192   double actual_lo_freq = (f_ref * 8 * divisor);
193   double actual_freq = actual_lo_freq - d_first_IF;
194
195   if((divisor & ~0x7fff) != 0) {                // must be 15-bits or less
196     return args;
197   }
198
199   // build i2c command string
200   std::vector<int> buf(4);
201   buf[0] = (divisor >> 8) & 0xff;         // DB1
202   buf[1] = divisor & 0xff;                // DB2
203   buf[2] = control_byte_1(d_fast_tuning, d_reference_divisor);
204   buf[3] = control_byte_2(actual_freq, true);
205
206   args.ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf));
207   args.baseband_freq = actual_freq - d_second_IF;
208   return args;
209 }
210
211 float
212 db_tv_rx::gain_min()
213 {
214   return 0;
215 }
216
217 float
218 db_tv_rx::gain_max()
219 {
220   return 115;
221 }
222
223 float
224 db_tv_rx::gain_db_per_step()
225 {
226   return 1;
227 }
228
229 bool 
230 db_tv_rx::set_gain(float gain)
231 {
232   // Set the gain.
233   // 
234   // @param gain:  gain in decibels
235   // @returns True/False
236
237   float rfgain, ifgain, pgagain;
238
239   assert(gain>=0 && gain<=115);
240   if(gain>60) {
241     rfgain = 60;
242     gain = gain - 60;
243   }
244   else {
245     rfgain = gain;
246     gain = 0;
247   }
248    
249   if(gain > 35) {
250     ifgain = 35;
251     gain = gain - 35;
252   }
253   else {
254     ifgain = gain;
255     gain = 0;
256   }
257
258   pgagain = gain;
259   _set_rfagc(rfgain);
260   _set_ifagc(ifgain);
261   _set_pga(pgagain);
262
263   return true;
264 }
265
266 bool 
267 db_tv_rx::is_quadrature()
268 {
269   // Return True if this board requires both I & Q analog channels.  
270   return false;
271 }
272
273 bool
274 db_tv_rx::spectrum_inverted() 
275 {
276   // The 43.75 MHz version is inverted
277   return d_inverted;
278 }