Merged r10071:10164 from features/cppdb-test into trunk. Implements the fully native...
[debian/gnuradio] / usrp / host / lib / legacy / db_dbs_rx.cc
1 //
2 // Copyright 2008 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 #include <db_dbs_rx.h>
22 #include <db_base_impl.h>
23 #include <cmath>
24
25
26 /*****************************************************************************/
27
28
29 db_dbs_rx::db_dbs_rx(usrp_basic_sptr _usrp, int which)
30   : db_base(_usrp, which)
31 {
32   // Control DBS receiver based USRP daughterboard.
33   // 
34   // @param usrp: instance of usrp.source_c
35   // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively
36
37   usrp()->_write_oe(d_which, 0x0001, 0x0001);
38   if(which == 0) {
39     d_i2c_addr = 0x67;
40   }
41   else {
42     d_i2c_addr = 0x65;
43   }
44
45   d_n = 950;
46   d_div2 = 0;
47   d_osc = 5;
48   d_cp = 3;
49   d_r = 4;
50   d_r_int = 1;
51   d_fdac = 127;
52   d_m = 2;
53   d_dl = 0;
54   d_ade = 0;
55   d_adl = 0;
56   d_gc1 = 0;
57   d_gc2 = 31;
58   d_diag = 0;
59   
60   _enable_refclk(true);
61   
62   set_gain((gain_min() + gain_max()) / 2.0);       // initialize gain
63
64   bypass_adc_buffers(true);
65 }
66
67 db_dbs_rx::~db_dbs_rx()
68 {
69   shutdown();
70 }
71
72 void
73 db_dbs_rx::shutdown()
74 {
75   if (!d_is_shutdown){
76     d_is_shutdown = true;
77     // do whatever there is to do to shutdown orderly
78     _enable_refclk(false);
79   }
80 }
81
82 void
83 db_dbs_rx::_write_reg (int regno, int v)
84 {
85   //regno is in [0,5], v is value to write to register"""
86   assert (0 <= regno && regno <= 5);
87   std::vector<int> args(2);
88   args[0] = regno;
89   args[1] = v;
90   usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args));
91 }
92
93 void
94 db_dbs_rx::_write_regs (int starting_regno, const std::vector<int> &vals)
95 {
96   // starting_regno is in [0,5],
97   // vals is a seq of integers to write to consecutive registers"""
98
99   //FIXME
100   std::vector<int> args;
101   args.push_back(starting_regno);
102   args.insert(args.end(), vals.begin(), vals.end());
103   usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args));
104 }
105         
106 std::vector<int>
107 db_dbs_rx::_read_status ()
108 {
109   //If successful, return list of two ints: [status_info, filter_DAC]"""
110   std::string s = usrp()->read_i2c (d_i2c_addr, 2);
111   if(s.size() != 2) {
112     std::vector<int> ret(0);
113     return ret;
114   }
115   return str_to_int_seq (s);
116 }
117
118 void
119 db_dbs_rx::_send_reg(int regno)
120 {
121   assert(0 <= regno && regno <= 5);
122   if(regno == 0)
123     _write_reg(0,(d_div2<<7) + (d_n>>8));
124   if(regno == 1)
125     _write_reg(1,d_n & 255);
126   if(regno == 2)
127     _write_reg(2,d_osc + (d_cp<<3) + (d_r_int<<5));
128   if(regno == 3)
129     _write_reg(3,d_fdac);
130   if(regno == 4)
131     _write_reg(4,d_m + (d_dl<<5) + (d_ade<<6) + (d_adl<<7));
132   if(regno == 5)
133     _write_reg(5,d_gc2 + (d_diag<<5));
134 }
135
136 // BW setting
137 void
138 db_dbs_rx::_set_m(int m)
139 {
140   assert(m>0 && m<32);
141   d_m = m;
142   _send_reg(4);
143 }
144   
145 void
146 db_dbs_rx::_set_fdac(int fdac)
147 {
148   assert(fdac>=0 && fdac<128);
149   d_fdac = fdac;
150   _send_reg(3);
151 }
152
153 struct bw_t
154 db_dbs_rx::set_bw (float bw)
155 {
156   assert(bw>=1e6 && bw<=33e6);
157
158   struct bw_t ret = {0, 0, 0};
159   int m_max, m_min, m_test, fdac_test;
160   if(bw >= 4e6)
161     m_max = int(std::min(31, (int)floor(_refclk_freq()/1e6)));
162   else if(bw >= 2e6)      // Outside of Specs!
163     m_max = int(std::min(31, (int)floor(_refclk_freq()/.5e6)));
164   else      // Way outside of Specs!
165     m_max = int(std::min(31, (int)floor(_refclk_freq()/.25e6)));
166   
167   m_min = int(ceil(_refclk_freq()/2.5e6));
168   m_test = m_max;
169   while(m_test >= m_min) {
170     fdac_test = static_cast<int>(round(((bw * m_test / _refclk_freq())-4)/.145));
171     if(fdac_test > 127)
172       m_test = m_test - 1;
173     else
174       break;
175   }
176
177   if(m_test>=m_min && fdac_test>=0) {
178     _set_m(m_test);
179     _set_fdac(fdac_test);
180
181     ret.m = d_m;
182     ret.fdac = d_fdac;
183     ret.div = _refclk_freq()/d_m*(4+0.145*d_fdac);
184   }
185   else {
186     fprintf(stderr, "Failed to set bw\n");
187   }
188   return ret;
189 }
190
191 // Gain setting
192 void
193 db_dbs_rx::_set_dl(int dl)
194 {
195   assert(dl == 0 || dl == 1);
196   d_dl = dl;
197   _send_reg(4);
198 }
199
200 void
201 db_dbs_rx::_set_gc2(int gc2)
202 {
203   assert(gc2<32 && gc2>=0);
204   d_gc2 = gc2;
205   _send_reg(5);
206 }
207
208 void
209 db_dbs_rx::_set_gc1(int gc1)
210 {
211   assert(gc1>=0 && gc1<4096);
212   d_gc1 = gc1;
213   usrp()->write_aux_dac(d_which, 0, gc1);
214 }
215
216 void
217 db_dbs_rx::_set_pga(int pga_gain)
218 {
219   assert(pga_gain>=0 && pga_gain<=20);
220   if(d_which == 0) {
221     usrp()->set_pga (0, pga_gain);
222     usrp()->set_pga (1, pga_gain);
223   }
224   else {
225     usrp()->set_pga (2, pga_gain);
226     usrp()->set_pga (3, pga_gain);
227   }
228 }
229
230 float
231 db_dbs_rx::gain_min()
232 {
233   return 0;
234 }
235
236 float
237 db_dbs_rx::gain_max()
238 {
239   return 104;
240 }
241
242 float
243 db_dbs_rx::gain_db_per_step()
244 {
245   return 1;
246 }
247
248 bool 
249 db_dbs_rx::set_gain(float gain)
250 {
251   // Set the gain.
252   // 
253   // @param gain:  gain in decibels
254   // @returns True/False
255
256   if(!(gain>=0 && gain<105)) {
257     throw std::runtime_error("gain out of range\n");
258   }
259
260   int gc1=0, gc2=0, dl=0, pga=0;
261
262   if(gain < 56) {
263     gc1 = int((-gain*1.85/56.0 + 2.6)*4096.0/3.3);
264     gain = 0;
265   }
266   else {
267     gc1 = 0;
268     gain -= 56;
269   }
270    
271   if(gain < 24) {
272     gc2 = static_cast<int>(round(31.0 * (1-gain/24.0)));
273     gain = 0;
274   }
275   else {
276     gc2 = 0;
277     gain -=24;
278   }
279   
280   if(gain >= 4.58) {
281     dl = 1;
282     gain -= 4.58;
283   }
284
285   pga = gain;
286   _set_gc1(gc1);
287   _set_gc2(gc2);
288   _set_dl(dl);
289   _set_pga(pga);
290
291   return true;
292 }
293
294 // Frequency setting
295 void
296 db_dbs_rx::_set_osc(int osc)
297 {
298   assert(osc>=0 && osc<8);
299   d_osc = osc;
300   _send_reg(2);
301 }
302
303 void
304 db_dbs_rx::_set_cp(int cp)
305 {
306   assert(cp>=0 && cp<4);
307   d_cp = cp;
308   _send_reg(2);
309 }
310
311 void
312 db_dbs_rx::_set_n(int n)
313 {
314   assert(n>256 && n<32768);
315   d_n = n;
316   _send_reg(0);
317   _send_reg(1);
318 }
319
320 void
321 db_dbs_rx::_set_div2(int div2)
322 {
323   assert(div2 == 0 || div2 == 1);
324   d_div2 = div2;
325   _send_reg(0);
326 }
327
328 void
329 db_dbs_rx::_set_r(int r)
330 {
331   assert(r>=0 && r<128);
332   d_r = r;
333   d_r_int = static_cast<int>(round(log10(r)/log10(2)) - 1);
334   _send_reg(2);
335 }
336
337 // FIXME  How do we handle ADE and ADL properly?
338 void
339 db_dbs_rx::_set_ade(int ade)
340 {
341   assert(ade == 0 || ade == 1);
342   d_ade = ade;
343   _send_reg(4);
344 }
345
346 double
347 db_dbs_rx::freq_min()
348 {
349   return 500e6;
350 }
351
352 double
353 db_dbs_rx::freq_max()
354 {
355   return 2.6e9;
356 }
357
358 struct freq_result_t
359 db_dbs_rx::set_freq(double freq)
360 {
361   // Set the frequency.
362   // 
363   // @param freq:  target RF frequency in Hz
364   // @type freq:   double
365   // 
366   // @returns (ok, actual_baseband_freq) where:
367   //   ok is True or False and indicates success or failure,
368   //   actual_baseband_freq is RF frequency that corresponds to DC in the IF.
369   
370   freq_result_t args = {false, 0};
371   
372   if(!(freq>=freq_min() && freq<=freq_max())) {
373     return args;
374   }
375   
376   double vcofreq;
377   if(freq<1150e6) {
378     _set_div2(0);
379     vcofreq = 4 * freq;
380   }
381   else {
382     _set_div2(1);
383     vcofreq = 2 * freq;
384   }
385   
386   _set_ade(1);
387   int rmin = std::max(2, (int)(_refclk_freq()/2e6));
388   int rmax = std::min(128, (int)(_refclk_freq()/500e3));
389   int r = 2;
390   int n = 0;
391   int best_r = 2;
392   int best_n = 0;
393   int best_delta = 10e6;
394   int delta;
395   
396   while(r <= rmax) {
397     n = static_cast<int>(round(freq/(_refclk_freq()/r)));
398     if(r<rmin || n<256) {
399       r = r * 2;
400       continue;
401     }
402     delta = (int)fabs(n*_refclk_freq()/r - freq);
403     if(delta < 75e3) {
404       best_r = r;
405       best_n = n;
406       break;
407     }
408     if(delta < best_delta*0.9) {
409       best_r = r;
410       best_n = n;
411       best_delta = delta;
412     }
413     r = r * 2;
414   }
415   _set_r(best_r);
416
417   _set_n(static_cast<int>(round(best_n)));
418  
419   int vco;
420   if(vcofreq < 2433e6)
421     vco = 0;
422   else if(vcofreq < 2711e6)
423     vco=1;
424   else if(vcofreq < 3025e6)
425     vco=2;
426   else if(vcofreq < 3341e6)
427     vco=3;
428   else if(vcofreq < 3727e6)
429     vco=4;
430   else if(vcofreq < 4143e6)
431     vco=5;
432   else if(vcofreq < 4493e6)
433     vco=6;
434   else
435     vco=7;
436   
437   _set_osc(vco);
438   
439   // Set CP current
440   int adc_val = 0;
441   std::vector<int> bytes(2);
442   while(adc_val == 0 || adc_val == 7) {
443     bytes = _read_status();
444     adc_val = bytes[0] >> 2;
445     if(adc_val == 0) {
446       if(vco <= 0) {
447         return args;
448       }
449       else {
450         vco = vco - 1;
451       }
452     }
453     else if(adc_val == 7) {
454       if(vco >= 7) {
455         return args;
456       }
457       else {
458         vco = vco + 1;
459       }
460     }
461     _set_osc(vco);
462   }
463   
464   if(adc_val == 1 || adc_val == 2) {
465     _set_cp(1);
466   }
467   else if(adc_val == 3 || adc_val == 4) {
468     _set_cp(2);
469   }
470   else {
471     _set_cp(3);
472   }
473   
474   args.ok = true;
475   args.baseband_freq = d_n * _refclk_freq() / d_r;
476   return args;
477 }
478
479 int
480 db_dbs_rx::_refclk_divisor()
481 {
482   //Return value to stick in REFCLK_DIVISOR register
483   return 16;
484 }
485
486 bool 
487 db_dbs_rx::is_quadrature()
488 {
489   // Return True if this board requires both I & Q analog channels.  
490   return true;
491 }