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