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