Clean build
[debian/gnuradio] / usrp / host / lib / db_wbxng.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 <usrp/db_wbxng.h>
22 #include <usrp/db_wbxng_adf4350.h>
23 #include <db_base_impl.h>
24
25 // d'board i/o pin defs
26 // Tx and Rx have shared defs, but different i/o regs
27 #define ENABLE_5        (1 << 7)         // enables 5.0V power supply
28 #define ENABLE_33       (1 << 6)         // enables 3.3V supply
29 #define RX_TXN          (1 << 5)         // Tx only: T/R antenna switch for TX/RX port
30 #define RX2_RX1N        (1 << 5)         // Rx only: antenna switch between RX2 and TX/RX port
31 #define BBAMP_EN        (1 << 4)
32 #define PLL_CE          (1 << 3)
33 #define PLL_PDBRF       (1 << 2)
34 #define PLL_MUXOUT      (1 << 1)
35 #define PLL_LOCK_DETECT (1 << 0)
36
37 wbxng_base::wbxng_base(usrp_basic_sptr _usrp, int which, int _power_on)
38   : db_base(_usrp, which), d_power_on(_power_on)
39 {
40   /*
41     @param usrp: instance of usrp.source_c
42     @param which: which side: 0 or 1 corresponding to side A or B respectively
43     @type which: int
44   */
45
46   d_first = true;
47   d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
48
49   usrp()->_write_oe(d_which, 0, 0xffff);   // turn off all outputs
50   _enable_refclk(false);                // disable refclk
51
52   set_auto_tr(false);
53 }
54
55 wbxng_base::~wbxng_base()
56 {
57   delete d_common;
58 }
59
60 void
61 wbxng_base::_write_all(int R, int control, int N)
62 {
63   /*
64     Write R counter latch, control latch and N counter latch to VCO.
65     
66     Adds 10ms delay between writing control and N if this is first call.
67     This is the required power-up sequence.
68     
69     @param R: 24-bit R counter latch
70     @type R: int
71     @param control: 24-bit control latch
72     @type control: int
73     @param N: 24-bit N counter latch
74     @type N: int
75   */
76   timespec t;
77   t.tv_sec = 0;
78   t.tv_nsec = 10000000;
79
80   /*
81   _write_R(R);
82   _write_control(control);
83   if(d_first) {
84     //time.sleep(0.010);
85     nanosleep(&t, NULL);
86     d_first = false;
87   }
88   _write_N(N);
89   */
90 }
91
92 void
93 wbxng_base::_write_control(int control)
94 {
95   //_write_it((control & ~0x3) | 0);
96 }
97
98 void
99 wbxng_base::_write_R(int R)
100 {
101   //_write_it((R & ~0x3) | 1);
102 }
103
104 void
105 wbxng_base::_write_N(int N)
106 {
107   //_write_it((N & ~0x3) | 2);
108 }
109
110 void
111 wbxng_base::_write_it(int v)
112 {
113   char s[3];
114   s[0] = (char)((v >> 16) & 0xff);
115   s[1] = (char)((v >>  8) & 0xff);
116   s[2] = (char)(v & 0xff);
117   std::string str(s, 3);
118   //usrp()->_write_spi(0, d_spi_enable, d_spi_format, str);
119 }
120         
121 bool
122 wbxng_base::_lock_detect()
123 {
124   /*
125     @returns: the value of the VCO/PLL lock detect bit.
126     @rtype: 0 or 1
127   */
128   /*
129   if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) {
130     return true;
131   }
132   else {      // Give it a second chance
133     // FIXME: make portable sleep
134     timespec t;
135     t.tv_sec = 0;
136     t.tv_nsec = 100000000;
137     nanosleep(&t, NULL);
138     
139     if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) {
140       return true;
141     }
142     else {
143       return false;
144     }
145   }
146   */
147   throw std::runtime_error("_lock_detect called from wbxng_base\n");
148 }
149
150 /*
151 bool
152 wbxng_base::_compute_regs(double freq, int &retR, int &retcontrol,
153                            int &retN, double &retfreq)
154 {
155   **COMMENT**
156     Determine values of R, control, and N registers, along with actual freq.
157     
158     @param freq: target frequency in Hz
159     @type freq: float
160     @returns: (R, control, N, actual_freq)
161     @rtype: tuple(int, int, int, float)
162     
163     Override this in derived classes.
164   **COMMENT**
165   
166   //raise NotImplementedError;
167   throw std::runtime_error("_compute_regs called from wbxng_base\n");
168 }
169 */
170
171 int
172 wbxng_base::_compute_control_reg()
173 {
174   throw std::runtime_error("_compute_control_reg called from wbxng_base\n");
175   //return d_common->_compute_control_reg();
176 }
177
178 int
179 wbxng_base::_refclk_divisor()
180 {
181   throw std::runtime_error("_refclk_divisor called from wbxng_base\n");
182   //return d_common->_refclk_divisor();
183 }
184
185 double
186 wbxng_base::_refclk_freq()
187 {
188   throw std::runtime_error("_refclk_divisor called from wbxng_base\n");
189   // *** TODO *** Magic Number 64e6?
190   //return 64e6/_refclk_divisor();
191 }
192
193 struct freq_result_t
194 wbxng_base::set_freq(double freq)
195 {
196   /*
197     @returns (ok, actual_baseband_freq) where:
198     ok is True or False and indicates success or failure,
199     actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
200   */
201
202   struct freq_result_t args = {false, 0};
203
204   // Offsetting the LO helps get the Tx carrier leakage out of the way.
205   // This also ensures that on Rx, we're not getting hosed by the
206   // FPGA's DC removal loop's time constant.  We were seeing a
207   // problem when running with discontinuous transmission.
208   // Offsetting the LO made the problem go away.
209   freq += d_lo_offset;
210   
211   //int R, control, N;
212   //double actual_freq;
213   //_compute_regs(freq, R, control, N, actual_freq);
214
215   //if(R==0) {
216   //  return args;
217   //}
218    
219   //_write_all(R, control, N);
220   //args.ok = _lock_detect();
221   //args.baseband_freq = actual_freq;
222   return args;
223 }
224
225 bool
226 wbxng_base::_set_pga(float pga_gain)
227 {
228   /*
229   if(d_which == 0) {
230     usrp()->set_pga(0, pga_gain);
231     usrp()->set_pga(1, pga_gain);
232   }
233   else {
234     usrp()->set_pga(2, pga_gain);
235     usrp()->set_pga(3, pga_gain);
236   }
237   */
238   return true;
239 }
240
241 bool
242 wbxng_base::is_quadrature()
243 {
244   /*
245     Return True if this board requires both I & Q analog channels.
246     
247     This bit of info is useful when setting up the USRP Rx mux register.
248   */
249   return true;
250 }
251
252 double
253 wbxng_base::freq_min()
254 {
255   throw std::runtime_error("freq_min called from wbxng_base\n");
256   //return d_common->freq_min();
257 }
258
259 double
260 wbxng_base::freq_max()
261 {
262   throw std::runtime_error("freq_max called from wbxng_base\n");
263   //return d_common->freq_max();
264 }
265
266 // ----------------------------------------------------------------
267
268 wbxng_base_tx::wbxng_base_tx(usrp_basic_sptr _usrp, int which, int _power_on)
269   : wbxng_base(_usrp, which, _power_on)
270 {
271   /*
272     @param usrp: instance of usrp.sink_c
273     @param which: 0 or 1 corresponding to side TX_A or TX_B respectively.
274   */
275   
276   if(which == 0) {
277     d_spi_enable = SPI_ENABLE_TX_A;
278   }
279   else {
280     d_spi_enable = SPI_ENABLE_TX_B;
281   }
282
283   d_common = new adf4350(_usrp, d_which, d_spi_enable);
284   
285   // power up the transmit side, but don't enable the mixer
286   /*
287   usrp()->_write_oe(d_which,(POWER_UP|RX_TXN|ENABLE), 0xffff);
288   usrp()->write_io(d_which, (power_on()|RX_TXN), (POWER_UP|RX_TXN|ENABLE));
289   set_lo_offset(4e6);
290
291   set_gain((gain_min() + gain_max()) / 2.0);  // initialize gain
292   */
293 }
294
295 wbxng_base_tx::~wbxng_base_tx()
296 {
297   shutdown();
298 }
299
300
301 void
302 wbxng_base_tx::shutdown()
303 {
304   // fprintf(stderr, "wbxng_base_tx::shutdown  d_is_shutdown = %d\n", d_is_shutdown);
305
306   if (!d_is_shutdown){
307     d_is_shutdown = true;
308     // do whatever there is to do to shutdown
309
310     // Power down and leave the T/R switch in the R position
311     //usrp()->write_io(d_which, (power_off()|RX_TXN), (POWER_UP|RX_TXN|ENABLE));
312
313     // Power down VCO/PLL
314     d_PD = 3;
315   
316     _write_control(_compute_control_reg());
317     _enable_refclk(false);                       // turn off refclk
318     set_auto_tr(false);
319   }
320 }
321
322 bool
323 wbxng_base_tx::set_auto_tr(bool on)
324 {
325   bool ok = true;
326   /*
327   if(on) {
328     ok &= set_atr_mask (RX_TXN | ENABLE);
329     ok &= set_atr_txval(0      | ENABLE);
330     ok &= set_atr_rxval(RX_TXN | 0);
331   }
332   else {
333     ok &= set_atr_mask (0);
334     ok &= set_atr_txval(0);
335     ok &= set_atr_rxval(0);
336   }
337   */
338   return ok;
339 }
340
341 bool
342 wbxng_base_tx::set_enable(bool on)
343 {
344   /*
345     Enable transmitter if on is true
346   */
347
348   int v;
349   //int mask = RX_TXN | ENABLE_5 | ENABLE_33;
350   if(on) {
351     v = ENABLE_5 | ENABLE_33;
352   }
353   else {
354     v = RX_TXN;
355   }
356   throw std::runtime_error("set_enable called from wbxng_base_tx\n");
357   //return usrp()->write_io(d_which, v, mask);
358 }
359
360 float
361 wbxng_base_tx::gain_min()
362 {
363   return usrp()->pga_max();
364 }
365
366 float
367 wbxng_base_tx::gain_max()
368 {
369   return usrp()->pga_max();
370 }
371
372 float
373 wbxng_base_tx::gain_db_per_step()
374 {
375   return 1;
376 }
377
378 bool
379 wbxng_base_tx::set_gain(float gain)
380 {
381   /*
382     Set the gain.
383     
384     @param gain:  gain in decibels
385     @returns True/False
386   */
387   return _set_pga(usrp()->pga_max());
388 }
389
390
391 /**************************************************************************/
392
393
394 wbxng_base_rx::wbxng_base_rx(usrp_basic_sptr _usrp, int which, int _power_on)
395   : wbxng_base(_usrp, which, _power_on)
396 {
397   /*
398     @param usrp: instance of usrp.source_c
399     @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
400   */
401
402   if(which == 0) {
403     d_spi_enable = SPI_ENABLE_RX_A;
404   }
405   else {
406     d_spi_enable = SPI_ENABLE_RX_B;
407   }
408
409   d_common = new adf4350(_usrp, d_which, d_spi_enable);
410
411   /*  
412   usrp()->_write_oe(d_which, (POWER_UP|RX2_RX1N|ENABLE), 0xffff);
413   usrp()->write_io(d_which,  (power_on()|RX2_RX1N|ENABLE), 
414                    (POWER_UP|RX2_RX1N|ENABLE));
415   
416   // set up for RX on TX/RX port
417   select_rx_antenna("TX/RX");
418   
419   bypass_adc_buffers(true);
420
421   set_lo_offset(-4e6);
422   */
423 }
424
425 wbxng_base_rx::~wbxng_base_rx()
426 {
427   shutdown();
428 }
429
430 void
431 wbxng_base_rx::shutdown()
432 {
433   // fprintf(stderr, "wbxng_base_rx::shutdown  d_is_shutdown = %d\n", d_is_shutdown);
434
435   if (!d_is_shutdown){
436     d_is_shutdown = true;
437     // do whatever there is to do to shutdown
438
439     // Power down
440     //usrp()->common_write_io(C_RX, d_which, power_off(), (POWER_UP|ENABLE));
441
442     // Power down VCO/PLL
443     d_PD = 3;
444   
445
446     // fprintf(stderr, "wbxng_base_rx::shutdown  before _write_control\n");
447     //_write_control(_compute_control_reg());
448
449     // fprintf(stderr, "wbxng_base_rx::shutdown  before _enable_refclk\n");
450     //_enable_refclk(false);                       // turn off refclk
451
452     // fprintf(stderr, "wbxng_base_rx::shutdown  before set_auto_tr\n");
453     //set_auto_tr(false);
454
455     // fprintf(stderr, "wbxng_base_rx::shutdown  after set_auto_tr\n");
456   }
457 }
458
459 bool
460 wbxng_base_rx::set_auto_tr(bool on)
461 {
462   //bool ok = true;
463   /*
464   if(on) {
465     ok &= set_atr_mask (ENABLE);
466     ok &= set_atr_txval(     0);
467     ok &= set_atr_rxval(ENABLE);
468   }
469   else {
470     ok &= set_atr_mask (0);
471     ok &= set_atr_txval(0);
472     ok &= set_atr_rxval(0);
473   }
474   */
475   return true;
476 }
477
478 /* *** TODO *** Defined select_rx_antenna twice?
479 bool
480 wbxng_base_rx::select_rx_antenna(int which_antenna)
481 {
482   **COMMENT**
483     Specify which antenna port to use for reception.
484     @param which_antenna: either 'TX/RX' or 'RX2'
485   **COMMENT**
486
487   if(which_antenna == 0) {
488     usrp()->write_io(d_which, 0,RX2_RX1N);
489   }
490   else if(which_antenna == 1) {
491     usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
492   }
493   else {
494     return false;
495     // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
496   }
497   return true;
498 }
499 */
500
501 bool
502 wbxng_base_rx::select_rx_antenna(const std::string &which_antenna)
503 {
504   /*
505     Specify which antenna port to use for reception.
506     @param which_antenna: either 'TX/RX' or 'RX2'
507   */
508
509   /*
510   if(which_antenna == "TX/RX") {
511     usrp()->write_io(d_which, 0, RX2_RX1N);
512   }
513   else if(which_antenna == "RX2") {
514     usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
515   }
516   else {
517     // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
518     return false;
519   }
520   */
521   return true;
522 }
523
524 bool
525 wbxng_base_rx::set_gain(float gain)
526 {
527   /*
528     Set the gain.
529     
530     @param gain:  gain in decibels
531     @returns True/False
532   */
533   
534   /*
535   // clamp gain
536   gain = std::max(gain_min(), std::min(gain, gain_max()));
537
538   float pga_gain, agc_gain;
539   float V_maxgain, V_mingain, V_fullscale, dac_value;
540
541   float maxgain = gain_max() - usrp()->pga_max();
542   float mingain = gain_min();
543   if(gain > maxgain) {
544     pga_gain = gain-maxgain;
545     assert(pga_gain <= usrp()->pga_max());
546     agc_gain = maxgain;
547   }
548   else {
549     pga_gain = 0;
550     agc_gain = gain;
551   }
552   
553   V_maxgain = .2;
554   V_mingain = 1.2;
555   V_fullscale = 3.3;
556   dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale;
557
558   assert(dac_value>=0 && dac_value<4096);
559
560   return (usrp()->write_aux_dac(d_which, 0, int(dac_value))
561           && _set_pga(int(pga_gain)));
562   */
563   return false;
564 }
565
566 // ----------------------------------------------------------------
567
568 db_wbxng_tx::db_wbxng_tx(usrp_basic_sptr usrp, int which)
569   : wbxng_base_tx(usrp, which)
570 {
571 }
572
573 db_wbxng_tx::~db_wbxng_tx()
574 {
575 }
576
577 /*
578 bool
579 db_wbxng_tx::_compute_regs(double freq, int &retR, int &retcontrol,
580                                  int &retN, double &retfreq)
581 {
582   return d_common->_compute_regs(_refclk_freq(), freq, retR,
583                                  retcontrol, retN, retfreq);
584 }
585 */
586
587
588 db_wbxng_rx::db_wbxng_rx(usrp_basic_sptr usrp, int which)
589   : wbxng_base_rx(usrp, which)
590 {
591   set_gain((gain_min() + gain_max()) / 2.0);  // initialize gain
592 }
593
594 db_wbxng_rx::~db_wbxng_rx()
595 {
596 }
597
598 float
599 db_wbxng_rx::gain_min()
600 {
601   return usrp()->pga_min();
602 }
603
604 float
605 db_wbxng_rx::gain_max()
606 {
607   return usrp()->pga_max()+70;
608 }
609
610 float
611 db_wbxng_rx::gain_db_per_step()
612 {
613   return 0.05;
614 }
615
616
617 bool
618 db_wbxng_rx::i_and_q_swapped()
619 {
620   return true;
621 }
622
623 /*
624 bool
625 db_wbxng_rx::_compute_regs(double freq, int &retR, int &retcontrol,
626                                  int &retN, double &retfreq)
627 {
628   return d_common->_compute_regs(_refclk_freq(), freq, retR,
629                                  retcontrol, retN, retfreq);
630 }
631 */
632