Fix missing set_bw call in new daughterboard API. Reconciled implementations between...
[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 bool
154 db_dbs_rx::set_bw (float bw)
155 {
156   if (bw < 1e6 || bw > 33e6) {
157     fprintf(stderr, "db_dbs_rx::set_bw: bw (=%f) must be between 1e6 and 33e6 inclusive\n", bw);
158     return false;
159   }
160
161   // struct bw_t ret = {0, 0, 0};
162   int m_max, m_min, m_test, fdac_test;
163   if(bw >= 4e6)
164     m_max = int(std::min(31, (int)floor(_refclk_freq()/1e6)));
165   else if(bw >= 2e6)      // Outside of Specs!
166     m_max = int(std::min(31, (int)floor(_refclk_freq()/.5e6)));
167   else      // Way outside of Specs!
168     m_max = int(std::min(31, (int)floor(_refclk_freq()/.25e6)));
169   
170   m_min = int(ceil(_refclk_freq()/2.5e6));
171   m_test = m_max;
172   while(m_test >= m_min) {
173     fdac_test = static_cast<int>(round(((bw * m_test / _refclk_freq())-4)/.145));
174     if(fdac_test > 127)
175       m_test = m_test - 1;
176     else
177       break;
178   }
179
180   if(m_test>=m_min && fdac_test>=0) {
181     _set_m(m_test);
182     _set_fdac(fdac_test);
183
184     //ret.m = d_m;
185     //ret.fdac = d_fdac;
186     //ret.div = _refclk_freq()/d_m*(4+0.145*d_fdac);
187   }
188   else {
189     fprintf(stderr, "db_dbs_rx::set_bw: failed\n");
190     return false;
191   }
192
193   return true;
194 }
195
196 // Gain setting
197 void
198 db_dbs_rx::_set_dl(int dl)
199 {
200   assert(dl == 0 || dl == 1);
201   d_dl = dl;
202   _send_reg(4);
203 }
204
205 void
206 db_dbs_rx::_set_gc2(int gc2)
207 {
208   assert(gc2<32 && gc2>=0);
209   d_gc2 = gc2;
210   _send_reg(5);
211 }
212
213 void
214 db_dbs_rx::_set_gc1(int gc1)
215 {
216   assert(gc1>=0 && gc1<4096);
217   d_gc1 = gc1;
218   usrp()->write_aux_dac(d_which, 0, gc1);
219 }
220
221 void
222 db_dbs_rx::_set_pga(int pga_gain)
223 {
224   assert(pga_gain>=0 && pga_gain<=20);
225   if(d_which == 0) {
226     usrp()->set_pga (0, pga_gain);
227     usrp()->set_pga (1, pga_gain);
228   }
229   else {
230     usrp()->set_pga (2, pga_gain);
231     usrp()->set_pga (3, pga_gain);
232   }
233 }
234
235 float
236 db_dbs_rx::gain_min()
237 {
238   return 0;
239 }
240
241 float
242 db_dbs_rx::gain_max()
243 {
244   return 104;
245 }
246
247 float
248 db_dbs_rx::gain_db_per_step()
249 {
250   return 1;
251 }
252
253 bool 
254 db_dbs_rx::set_gain(float gain)
255 {
256   // Set the gain.
257   // 
258   // @param gain:  gain in decibels
259   // @returns True/False
260
261   if(!(gain>=0 && gain<105)) {
262     throw std::runtime_error("gain out of range\n");
263   }
264
265   int gc1=0, gc2=0, dl=0, pga=0;
266
267   if(gain < 56) {
268     gc1 = int((-gain*1.85/56.0 + 2.6)*4096.0/3.3);
269     gain = 0;
270   }
271   else {
272     gc1 = 0;
273     gain -= 56;
274   }
275    
276   if(gain < 24) {
277     gc2 = static_cast<int>(round(31.0 * (1-gain/24.0)));
278     gain = 0;
279   }
280   else {
281     gc2 = 0;
282     gain -=24;
283   }
284   
285   if(gain >= 4.58) {
286     dl = 1;
287     gain -= 4.58;
288   }
289
290   pga = gain;
291   _set_gc1(gc1);
292   _set_gc2(gc2);
293   _set_dl(dl);
294   _set_pga(pga);
295
296   return true;
297 }
298
299 // Frequency setting
300 void
301 db_dbs_rx::_set_osc(int osc)
302 {
303   assert(osc>=0 && osc<8);
304   d_osc = osc;
305   _send_reg(2);
306 }
307
308 void
309 db_dbs_rx::_set_cp(int cp)
310 {
311   assert(cp>=0 && cp<4);
312   d_cp = cp;
313   _send_reg(2);
314 }
315
316 void
317 db_dbs_rx::_set_n(int n)
318 {
319   assert(n>256 && n<32768);
320   d_n = n;
321   _send_reg(0);
322   _send_reg(1);
323 }
324
325 void
326 db_dbs_rx::_set_div2(int div2)
327 {
328   assert(div2 == 0 || div2 == 1);
329   d_div2 = div2;
330   _send_reg(0);
331 }
332
333 void
334 db_dbs_rx::_set_r(int r)
335 {
336   assert(r>=0 && r<128);
337   d_r = r;
338   d_r_int = static_cast<int>(round(log10(r)/log10(2)) - 1);
339   _send_reg(2);
340 }
341
342 // FIXME  How do we handle ADE and ADL properly?
343 void
344 db_dbs_rx::_set_ade(int ade)
345 {
346   assert(ade == 0 || ade == 1);
347   d_ade = ade;
348   _send_reg(4);
349 }
350
351 double
352 db_dbs_rx::freq_min()
353 {
354   return 500e6;
355 }
356
357 double
358 db_dbs_rx::freq_max()
359 {
360   return 2.6e9;
361 }
362
363 struct freq_result_t
364 db_dbs_rx::set_freq(double freq)
365 {
366   // Set the frequency.
367   // 
368   // @param freq:  target RF frequency in Hz
369   // @type freq:   double
370   // 
371   // @returns (ok, actual_baseband_freq) where:
372   //   ok is True or False and indicates success or failure,
373   //   actual_baseband_freq is RF frequency that corresponds to DC in the IF.
374   
375   freq_result_t args = {false, 0};
376   
377   if(!(freq>=freq_min() && freq<=freq_max())) {
378     return args;
379   }
380   
381   double vcofreq;
382   if(freq<1150e6) {
383     _set_div2(0);
384     vcofreq = 4 * freq;
385   }
386   else {
387     _set_div2(1);
388     vcofreq = 2 * freq;
389   }
390   
391   _set_ade(1);
392   int rmin = std::max(2, (int)(_refclk_freq()/2e6));
393   int rmax = std::min(128, (int)(_refclk_freq()/500e3));
394   int r = 2;
395   int n = 0;
396   int best_r = 2;
397   int best_n = 0;
398   int best_delta = 10e6;
399   int delta;
400   
401   while(r <= rmax) {
402     n = static_cast<int>(round(freq/(_refclk_freq()/r)));
403     if(r<rmin || n<256) {
404       r = r * 2;
405       continue;
406     }
407     delta = (int)fabs(n*_refclk_freq()/r - freq);
408     if(delta < 75e3) {
409       best_r = r;
410       best_n = n;
411       break;
412     }
413     if(delta < best_delta*0.9) {
414       best_r = r;
415       best_n = n;
416       best_delta = delta;
417     }
418     r = r * 2;
419   }
420   _set_r(best_r);
421
422   _set_n(static_cast<int>(round(best_n)));
423  
424   int vco;
425   if(vcofreq < 2433e6)
426     vco = 0;
427   else if(vcofreq < 2711e6)
428     vco=1;
429   else if(vcofreq < 3025e6)
430     vco=2;
431   else if(vcofreq < 3341e6)
432     vco=3;
433   else if(vcofreq < 3727e6)
434     vco=4;
435   else if(vcofreq < 4143e6)
436     vco=5;
437   else if(vcofreq < 4493e6)
438     vco=6;
439   else
440     vco=7;
441   
442   _set_osc(vco);
443   
444   // Set CP current
445   int adc_val = 0;
446   std::vector<int> bytes(2);
447   while(adc_val == 0 || adc_val == 7) {
448     bytes = _read_status();
449     adc_val = bytes[0] >> 2;
450     if(adc_val == 0) {
451       if(vco <= 0) {
452         return args;
453       }
454       else {
455         vco = vco - 1;
456       }
457     }
458     else if(adc_val == 7) {
459       if(vco >= 7) {
460         return args;
461       }
462       else {
463         vco = vco + 1;
464       }
465     }
466     _set_osc(vco);
467   }
468   
469   if(adc_val == 1 || adc_val == 2) {
470     _set_cp(1);
471   }
472   else if(adc_val == 3 || adc_val == 4) {
473     _set_cp(2);
474   }
475   else {
476     _set_cp(3);
477   }
478   
479   args.ok = true;
480   args.baseband_freq = d_n * _refclk_freq() / d_r;
481   return args;
482 }
483
484 int
485 db_dbs_rx::_refclk_divisor()
486 {
487   //Return value to stick in REFCLK_DIVISOR register
488   return 16;
489 }
490
491 bool 
492 db_dbs_rx::is_quadrature()
493 {
494   // Return True if this board requires both I & Q analog channels.  
495   return true;
496 }