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