Cleanup in preparation for merge
[debian/gnuradio] / usrp / host / lib / db_dtt754.cc
1 /* -*- c++ -*- */
2 //
3 // Copyright 2008,2009 Free Software Foundation, Inc.
4 // 
5 // This file is part of GNU Radio
6 // 
7 // GNU Radio is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either asversion 3, or (at your option)
10 // any later version.
11 // 
12 // GNU Radio is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 // 
17 // You should have received a copy of the GNU General Public License
18 // along with GNU Radio; see the file COPYING.  If not, write to
19 // the Free Software Foundation, Inc., 51 Franklin Street,
20 // Boston, MA 02110-1301, USA.
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <usrp/db_dtt754.h>
27 #include <db_base_impl.h>
28
29 int
30 control_byte_1()
31 {
32   int RS = 0;  // 0 = 166.66kHz reference
33   int ATP = 7; // Disable internal AGC
34   return (0x80 | ATP<<3 | RS);
35 }
36
37 int
38 control_byte_2()
39 {
40   int STBY = 0;  // powered on
41   int XTO = 1;   // turn off xtal out, which we don't have
42   int ATC = 0;   // not clear exactly, possibly speeds up or slows down AGC, which we are not using
43   
44   int c = 0xc2 | ATC<<5 | STBY<<4 | XTO;
45   return c;
46 }
47
48 int
49 bandswitch_byte(float freq, float bw)
50 {
51   int P5, CP, BS;
52
53   if(bw>7.5e6) {
54     P5 = 1;
55   }
56   else {
57     P5 = 0;
58   }
59
60   if(freq < 121e6) {
61     CP = 0;
62     BS = 1;
63   }
64   else if(freq < 141e6) {
65     CP = 1;
66     BS = 1;
67   }
68   else if(freq < 166e6) {
69     CP = 2;
70     BS = 1;
71   }
72   else if(freq < 182e6) {
73     CP = 3;
74     BS = 1;
75   }
76   else if(freq < 286e6) {
77     CP = 0;
78     BS = 2;
79   }
80   else if(freq < 386e6) {
81     CP = 1;
82     BS = 2;
83   }
84   else if(freq < 446e6) {
85     CP = 2;
86     BS = 2;
87   }
88   else if(freq < 466e6) {
89     CP = 3;
90     BS = 2;
91   }
92   else if(freq < 506e6) {
93     CP = 0;
94     BS = 8;
95   }
96   else if(freq < 761e6) {
97     CP = 1;
98     BS = 8;
99   }
100   else if(freq < 846e6) {
101     CP = 2;
102     BS = 8;
103   }
104   else { // limit is ~905 MHz
105     CP = 3;
106     BS = 8;
107   }
108   return (CP<<6 | P5 << 4 | BS);
109 }
110
111 db_dtt754::db_dtt754(usrp_basic_sptr _usrp, int which)
112   : db_base(_usrp, which)
113 {
114   /*
115    * Control custom DTT75403-based daughterboard.
116    * 
117    * @param usrp: instance of usrp.source_c
118    * @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively
119    * @type which: int
120    */
121
122   // FIXME: DTT754 and DTT768 can probably inherit from a DTT class
123   
124   if(d_which == 0) {
125     d_i2c_addr = 0x60;
126   }
127   else {
128     d_i2c_addr = 0x62;
129   }
130
131   d_bw = 7e6;
132   d_IF = 36e6;
133         
134   d_f_ref = 166.6666e3;
135   d_inverted = false;
136
137   set_gain((gain_min() + gain_max()) / 2.0);
138
139   bypass_adc_buffers(false);
140 }
141
142 db_dtt754::~db_dtt754()
143 {
144 }
145   
146 float
147 db_dtt754::gain_min()
148 {
149   return 0;
150 }
151
152 float
153 db_dtt754::gain_max()
154 {
155   return 115;
156 }
157
158 float
159 db_dtt754::gain_db_per_step()
160 {
161   return 1;
162 }
163
164 bool
165 db_dtt754::set_gain(float gain)
166 {
167   assert(gain>=0 && gain<=115);
168
169   float rfgain, ifgain, pgagain;
170   if(gain > 60) {
171     rfgain = 60;
172     gain = gain - 60;
173   }
174   else {
175     rfgain = gain;
176     gain = 0;
177   }
178   
179   if(gain > 35) {
180     ifgain = 35;
181     gain = gain - 35;
182   }
183   else {
184     ifgain = gain;
185     gain = 0;
186   }
187   pgagain = gain;
188   
189   _set_rfagc(rfgain);
190   _set_ifagc(ifgain);
191   _set_pga(pgagain);
192
193   return true; // can't fail with the assert in place
194 }
195
196 double
197 db_dtt754::freq_min()
198 {
199   return 44e6;
200 }
201
202 double
203 db_dtt754::freq_max()
204 {
205   return 900e6;
206 }
207
208 struct freq_result_t
209 db_dtt754::set_freq(double target_freq)
210 {
211   /*
212    * @returns (ok, actual_baseband_freq) where:
213    * ok is True or False and indicates success or failure,
214    * actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
215    */
216   
217   freq_result_t ret = {false, 0.0};
218
219   if(target_freq < freq_min() || target_freq > freq_max()) {
220     return ret;
221   }
222         
223   double target_lo_freq = target_freq + d_IF;  // High side mixing
224
225   int divisor = (int)(0.5+(target_lo_freq / d_f_ref));
226   double actual_lo_freq = d_f_ref*divisor;
227   
228   if((divisor & ~0x7fff) != 0) {                // must be 15-bits or less
229     return ret;
230   }
231   
232   // build i2c command string
233   std::vector<int> buf(5);
234   buf[0] = (divisor >> 8) & 0xff;          // DB1
235   buf[1] = divisor & 0xff;                 // DB2
236   buf[2] = control_byte_1();
237   buf[3] = bandswitch_byte(actual_lo_freq, d_bw);
238   buf[4] = control_byte_2();
239
240   bool ok = usrp()->write_i2c(d_i2c_addr, int_seq_to_str (buf));
241
242   d_freq = actual_lo_freq - d_IF;
243         
244   ret.ok = ok;
245   ret.baseband_freq = actual_lo_freq;
246
247   return ret;
248
249 }
250   
251 bool
252 db_dtt754::is_quadrature()
253 {
254   /*
255    * Return True if this board requires both I & Q analog channels.
256    * 
257    * This bit of info is useful when setting up the USRP Rx mux register.
258    */
259      
260   return false;
261 }
262
263 bool
264 db_dtt754::spectrum_inverted()
265 {
266   /*
267    * The 43.75 MHz version is inverted
268    */
269   
270   return d_inverted;
271 }
272
273 bool
274 db_dtt754::set_bw(float bw)
275 {
276   /*
277    * Choose the SAW filter bandwidth, either 7MHz or 8MHz)
278    */
279
280   d_bw = bw;
281   set_freq(d_freq);
282
283   return true; // FIXME: propagate set_freq result
284 }
285
286 void
287 db_dtt754::_set_rfagc(float gain)
288 {
289   assert(gain <= 60 && gain >= 0);
290   // FIXME this has a 0.5V step between gain = 60 and gain = 59.
291   // Why are there two cases instead of a single linear case?
292   float voltage;
293   if(gain == 60) {
294     voltage = 4;
295   }
296   else {
297     voltage = gain/60.0 * 2.25 + 1.25;
298   }
299   
300   int dacword = (int)(4096*voltage/1.22/3.3);    // 1.22 = opamp gain
301     
302   assert(dacword>=0 && dacword<4096);
303   usrp()->write_aux_dac(d_which, 1, dacword);
304 }
305
306 void
307 db_dtt754::_set_ifagc(float gain)
308 {
309   assert(gain <= 35 && gain >= 0);
310   float voltage = gain/35.0 * 2.1 + 1.4;
311   int dacword = (int)(4096*voltage/1.22/3.3);    // 1.22 = opamp gain
312
313   assert(dacword>=0 && dacword<4096);
314   usrp()->write_aux_dac(d_which, 0, dacword);
315 }
316
317 void
318 db_dtt754::_set_pga(float pga_gain)
319 {
320   assert(pga_gain >=0 && pga_gain <=20);
321   if(d_which == 0) {
322     usrp()->set_pga (0, pga_gain);
323   }
324   else {
325     usrp()->set_pga (2, pga_gain);
326   }
327 }