Merged r10071:10164 from features/cppdb-test into trunk. Implements the fully native...
[debian/gnuradio] / usrp / host / lib / legacy / db_xcvr2450.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_xcvr2450.h>
22 #include <db_base_impl.h>
23 #include <cmath>
24
25
26 /* ------------------------------------------------------------------------
27  *  A few comments about the XCVR2450:
28  *
29  * It is half-duplex.  I.e., transmit and receive are mutually exclusive.
30  * There is a single LO for both the Tx and Rx sides.
31  * For our purposes the board is always either receiving or transmitting.
32  *
33  * Each board is uniquely identified by the *USRP hardware* instance and side
34  * This dictionary holds a weak reference to existing board controller so it
35  * can be created or retrieved as needed.
36  */
37
38
39 /*****************************************************************************/
40
41
42 xcvr2450::xcvr2450(usrp_basic_sptr _usrp, int which)
43   : d_weak_usrp(_usrp), d_which(which)
44 {
45   // Handler for Tv Rx daughterboards.
46   // 
47   // @param usrp: instance of usrp.source_c
48   // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively
49
50   // Use MSB with no header
51   d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
52
53   if(which == 0) {
54     d_spi_enable = SPI_ENABLE_RX_A;
55   }
56   else {
57     d_spi_enable = SPI_ENABLE_RX_B;
58   }
59
60   // Sane defaults
61   d_mimo = 1;          // 0 = OFF, 1 = ON
62   d_int_div = 192;     // 128 = min, 255 = max
63   d_frac_div = 0;      // 0 = min, 65535 = max
64   d_highband = 0;      // 0 = freq <= 5.4e9, 1 = freq > 5.4e9
65   d_five_gig = 0;      // 0 = freq <= 3.e9, 1 = freq > 3e9
66   d_cp_current = 0;    // 0 = 2mA, 1 = 4mA
67   d_ref_div = 4;       // 1 to 7
68   d_rssi_hbw = 0;      // 0 = 2 MHz, 1 = 6 MHz
69   d_txlpf_bw = 1;      // 1 = 12 MHz, 2 = 18 MHz, 3 = 24 MHz
70   d_rxlpf_bw = 1;      // 0 = 7.5 MHz, 1 = 9.5 MHz, 2 = 14 MHz, 3 = 18 MHz
71   d_rxlpf_fine = 2;    // 0 = 90%, 1 = 95%, 2 = 100%, 3 = 105%, 4 = 110%
72   d_rxvga_ser = 1;     // 0 = RXVGA controlled by B7:1, 1=controlled serially
73   d_rssi_range = 1;    // 0 = low range (datasheet typo), 1=high range (0.5V - 2.0V) 
74   d_rssi_mode = 1;     // 0 = enable follows RXHP, 1 = enabled
75   d_rssi_mux = 0;      // 0 = RSSI, 1 = TEMP
76   d_rx_hp_pin = 0;     // 0 = Fc set by rx_hpf, 1 = 600 KHz
77   d_rx_hpf = 0;        // 0 = 100Hz, 1 = 30KHz
78   d_rx_ant = 0;        // 0 = Ant. #1, 1 = Ant. #2
79   d_tx_ant = 0;        // 0 = Ant. #1, 1 = Ant. #2
80   d_txvga_ser = 1;     // 0 = TXVGA controlled by B6:1, 1=controlled serially
81   d_tx_driver_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin)
82   d_tx_vga_lin = 2;    // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin)
83   d_tx_upconv_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin)
84   d_tx_bb_gain = 3;    // 0=maxgain-5dB, 1=max-3dB, 2=max-1.5dB, 3=max
85   d_pabias_delay = 15; // 0 = 0, 15 = 7uS
86   d_pabias = 0;        // 0 = 0 uA, 63 = 315uA
87   d_rx_rf_gain = 0;    // 0 = 0dB, 1 = 0dB, 2 = 15dB, 3 = 30dB
88   d_rx_bb_gain = 16;   // 0 = min, 31 = max (0 - 62 dB)
89
90   d_txgain = 63;       // 0 = min, 63 = max
91
92   // Initialize GPIO and ATR
93   tx_write_io(TX_SAFE_IO, TX_OE_MASK);
94   tx_write_oe(TX_OE_MASK, ~0);
95   tx_set_atr_txval(TX_SAFE_IO);
96   tx_set_atr_rxval(TX_SAFE_IO);
97   tx_set_atr_mask(TX_OE_MASK);
98   rx_write_io(RX_SAFE_IO, RX_OE_MASK);
99   rx_write_oe(RX_OE_MASK, ~0);
100   rx_set_atr_rxval(RX_SAFE_IO);
101   rx_set_atr_txval(RX_SAFE_IO);
102   rx_set_atr_mask(RX_OE_MASK);
103         
104   // Initialize chipset
105   // TODO: perform reset sequence to ensure power up defaults
106   set_reg_standby();
107   set_reg_bandselpll();
108   set_reg_cal();
109   set_reg_lpf();
110   set_reg_rxrssi_ctrl();
111   set_reg_txlin_gain();
112   set_reg_pabias();
113   set_reg_rxgain();
114   set_reg_txgain();
115   //FIXME: set_freq(2.45e9);
116 }
117
118 xcvr2450::~xcvr2450()
119 {
120   //printf("xcvr2450::destructor\n");
121   tx_set_atr_txval(TX_SAFE_IO);
122   tx_set_atr_rxval(TX_SAFE_IO);
123   rx_set_atr_rxval(RX_SAFE_IO);
124   rx_set_atr_txval(RX_SAFE_IO);
125 }
126
127 bool
128 xcvr2450::operator==(xcvr2450_key x)
129 {
130   if((x.serial_no == usrp()->serial_number()) && (x.which == d_which)) {
131     return true;
132   }
133   else {
134     return false;
135   }
136 }
137
138 void
139 xcvr2450::set_reg_standby()
140 {
141   d_reg_standby = ((d_mimo<<17) | 
142                    (1<<16)      | 
143                    (1<<6)       | 
144                    (1<<5)       | 
145                    (1<<4)       | 2);
146   send_reg(d_reg_standby);
147 }
148
149 void
150 xcvr2450::set_reg_int_divider()
151 {
152   d_reg_int_divider = (((d_frac_div & 0x03)<<16) | 
153                        (d_int_div<<4)            | 3);
154   send_reg(d_reg_int_divider);
155 }
156
157 void
158 xcvr2450::set_reg_frac_divider()
159 {
160   d_reg_frac_divider = ((d_frac_div & 0xfffc)<<2) | 4;
161   send_reg(d_reg_frac_divider);
162 }
163         
164 void
165 xcvr2450::set_reg_bandselpll()
166 {
167   d_reg_bandselpll = ((d_mimo<<17)      |
168                       (1<<16)           |
169                       (1<<15)           |
170                       (1<<11)           |
171                       (d_highband<<10)  |
172                       (d_cp_current<<9) |
173                       (d_ref_div<<5)    |
174                       (d_five_gig<<4)   | 5);
175   send_reg(d_reg_bandselpll);
176 }
177      
178 void
179 xcvr2450::set_reg_cal()
180 {
181   // FIXME do calibration
182   d_reg_cal = (1<<14)|6;
183   send_reg(d_reg_cal);
184 }
185
186 void
187 xcvr2450::set_reg_lpf()
188 {
189   d_reg_lpf = (
190              (d_rssi_hbw<<15)  |
191              (d_txlpf_bw<<10)  |
192              (d_rxlpf_bw<<9)   |
193              (d_rxlpf_fine<<4) | 7);
194   send_reg(d_reg_lpf);
195 }
196
197 void
198 xcvr2450::set_reg_rxrssi_ctrl()
199 {
200   d_reg_rxrssi_ctrl = ((d_rxvga_ser<<16)  |
201                        (d_rssi_range<<15) |
202                        (d_rssi_mode<<14)  |
203                        (d_rssi_mux<<12)   |
204                        (1<<9)             |
205                        (d_rx_hpf<<6)      |
206                        (1<<4)             | 8);
207   send_reg(d_reg_rxrssi_ctrl);
208 }
209
210 void
211 xcvr2450::set_reg_txlin_gain()
212 {
213   d_reg_txlin_gain = ((d_txvga_ser<<14)     |
214                       (d_tx_driver_lin<<12) |
215                       (d_tx_vga_lin<<10)    |
216                       (d_tx_upconv_lin<<6)  |
217                       (d_tx_bb_gain<<4)     | 9);
218   send_reg(d_reg_txlin_gain);
219 }
220
221 void
222 xcvr2450::set_reg_pabias()
223 {
224   d_reg_pabias = (
225                   (d_pabias_delay<<10) |
226                   (d_pabias<<4)        | 10);
227   send_reg(d_reg_pabias);
228 }
229
230 void
231 xcvr2450::set_reg_rxgain()
232 {
233   d_reg_rxgain = (
234                   (d_rx_rf_gain<<9) |
235                   (d_rx_bb_gain<<4) | 11);
236   send_reg(d_reg_rxgain);
237 }
238
239 void
240 xcvr2450::set_reg_txgain()
241 {
242   d_reg_txgain = (d_txgain<<4) | 12;
243   send_reg(d_reg_txgain);
244 }
245
246 void
247 xcvr2450::send_reg(int v)
248 {
249   // Send 24 bits, it keeps last 18 clocked in
250   char c[3];
251   c[0] = (char)((v >> 16) & 0xff);
252   c[1] = (char)((v >>  8) & 0xff);
253   c[2] = (char)((v & 0xff));
254   std::string s(c, 3);
255   
256   usrp()->_write_spi(0, d_spi_enable, d_spi_format, s);
257   //printf("xcvr2450: Setting reg %d to %06X\n", (v&15), v);
258 }
259
260 // --------------------------------------------------------------------
261 // These methods control the GPIO bus.  Since the board has to access
262 // both the io_rx_* and io_tx_* pins, we define our own methods to do so.
263 // This bypasses any code in db_base.
264 //
265 // The board operates in ATR mode, always.  Thus, when the board is first
266 // initialized, it is in receive mode, until bits show up in the TX FIFO.
267 //
268
269 // FIXME these should just call the similarly named common_* method on usrp_basic
270
271 bool
272 xcvr2450::tx_write_oe(int value, int mask)
273 {
274   int reg;
275   if(d_which)
276     reg = FR_OE_0;
277   else
278     reg = FR_OE_2;
279   return usrp()->_write_fpga_reg(reg, (mask << 16) | value);
280 }
281    
282 bool
283 xcvr2450::tx_write_io(int value, int mask)
284 {
285   int reg;
286   if(d_which)
287     reg = FR_IO_0;
288   else
289     reg = FR_IO_2;
290   return usrp()->_write_fpga_reg(reg, (mask << 16) | value);
291 }
292
293 int
294 xcvr2450::tx_read_io()
295 {
296   int val;
297   if(d_which)
298     val = FR_RB_IO_RX_A_IO_TX_A;
299   else
300     val = FR_RB_IO_RX_B_IO_TX_B;
301   int t = usrp()->_read_fpga_reg(val);
302   return t & 0xffff;
303 }
304
305 bool
306 xcvr2450::rx_write_oe(int value, int mask)
307 {
308   int reg;
309   if(d_which)
310     reg = FR_OE_1;
311   else
312     reg = FR_OE_3;
313   return usrp()->_write_fpga_reg(reg, (mask << 16) | value);
314 }
315
316 bool
317 xcvr2450::rx_write_io(int value, int mask)
318 {
319   int reg;
320   if(d_which)
321     reg = FR_IO_1;
322   else
323     reg = FR_IO_3;
324   return usrp()->_write_fpga_reg(reg, (mask << 16) | value);
325 }
326
327 int
328 xcvr2450::rx_read_io()
329 {
330   int val;
331   if(d_which)
332     val = FR_RB_IO_RX_A_IO_TX_A;
333   else
334     val = FR_RB_IO_RX_B_IO_TX_B;
335   int t = usrp()->_read_fpga_reg(val);
336   return (t >> 16) & 0xffff;
337 }
338
339 bool
340 xcvr2450::tx_set_atr_mask(int v)
341 {
342   int reg;
343   if(d_which)
344     reg = FR_ATR_MASK_0;
345   else
346     reg = FR_ATR_MASK_2;
347   return usrp()->_write_fpga_reg(reg, v);
348 }
349
350 bool
351 xcvr2450::tx_set_atr_txval(int v)
352 {
353   int reg;
354   if(d_which)
355     reg = FR_ATR_TXVAL_0;
356   else
357     reg = FR_ATR_TXVAL_2;
358   return usrp()->_write_fpga_reg(reg, v);
359 }
360
361 bool
362 xcvr2450::tx_set_atr_rxval(int v)
363 {
364   int reg;
365   if(d_which)
366     reg = FR_ATR_RXVAL_0;
367   else
368     reg = FR_ATR_RXVAL_2;
369   return usrp()->_write_fpga_reg(reg, v);
370 }
371
372 bool
373 xcvr2450::rx_set_atr_mask(int v)
374 {
375   int reg;
376   if(d_which)
377     reg = FR_ATR_MASK_1;
378   else
379     reg = FR_ATR_MASK_3;
380   return usrp()->_write_fpga_reg(reg, v);
381 }
382
383 bool
384 xcvr2450::rx_set_atr_txval(int v)
385 {
386   int reg;
387   if(d_which)
388     reg = FR_ATR_TXVAL_1;
389   else
390     reg = FR_ATR_TXVAL_3;
391   return usrp()->_write_fpga_reg(reg, v);
392 }
393
394 bool
395 xcvr2450::rx_set_atr_rxval(int v)
396 {
397   int reg;
398   if(d_which)
399     reg = FR_ATR_RXVAL_1;
400   else
401     reg = FR_ATR_RXVAL_3;
402   return usrp()->_write_fpga_reg(reg, v);
403 }
404
405 // ----------------------------------------------------------------
406
407 void
408 xcvr2450::set_gpio()
409 {
410   // We calculate four values:
411   //
412   // io_rx_while_rx: what to drive onto io_rx_* when receiving
413   // io_rx_while_tx: what to drive onto io_rx_* when transmitting
414   // io_tx_while_rx: what to drive onto io_tx_* when receiving
415   // io_tx_while_tx: what to drive onto io_tx_* when transmitting
416   //
417   // B1-B7 is ignored as gain is set serially for now.
418   
419   int rx_hp, tx_antsel, rx_antsel, tx_pa_sel;
420   if(d_rx_hp_pin)
421     rx_hp = 0;
422   else
423     rx_hp = RX_HP;
424   
425   if(d_tx_ant)
426     tx_antsel = ANTSEL_TX1_RX2;
427   else
428     tx_antsel = ANTSEL_TX2_RX1;
429
430   if(d_rx_ant)
431     rx_antsel = ANTSEL_TX1_RX2;
432   else
433     rx_antsel = ANTSEL_TX2_RX1;
434
435   if(d_five_gig)
436     tx_pa_sel = HB_PA_OFF;
437   else
438     tx_pa_sel = LB_PA_OFF;
439
440   int io_rx_while_rx = EN|rx_hp|RX_EN;
441   int io_rx_while_tx = EN|rx_hp;
442   int io_tx_while_rx = HB_PA_OFF|LB_PA_OFF|rx_antsel|AD9515DIV;
443   int io_tx_while_tx = tx_pa_sel|tx_antsel|TX_EN|AD9515DIV;
444   rx_set_atr_rxval(io_rx_while_rx);
445   rx_set_atr_txval(io_rx_while_tx);
446   tx_set_atr_rxval(io_tx_while_rx);
447   tx_set_atr_txval(io_tx_while_tx);
448         
449   //printf("GPIO: RXRX=%04X RXTX=%04X TXRX=%04X TXTX=%04X",
450   //  io_rx_while_rx, io_rx_while_tx, io_tx_while_rx, io_tx_while_tx);
451 }
452   
453
454 struct freq_result_t
455 xcvr2450::set_freq(double target_freq)
456 {
457   struct freq_result_t args = {false, 0};
458
459   double scaler;
460
461   if(target_freq > 3e9) {
462     d_five_gig = 1;
463     d_ref_div = 1;
464     d_ad9515_div = 3;
465     scaler = 4.0/5.0;
466   }
467   else {
468     d_five_gig = 0;
469     d_ref_div = 1;
470     d_ad9515_div = 3;
471     scaler = 4.0/3.0;
472   }
473
474   if(target_freq > 5.27e9) {
475     d_highband = 1;
476   }
477   else {
478     d_highband = 0;
479   }
480
481   double vco_freq = target_freq*scaler;
482   double sys_clk = usrp()->fpga_master_clock_freq();  // Usually 64e6 
483   double ref_clk = sys_clk / d_ad9515_div;
484         
485   double phdet_freq = ref_clk/d_ref_div;
486   double div = vco_freq/phdet_freq;
487   d_int_div = int(floor(div));
488   d_frac_div = int((div-d_int_div)*65536.0);
489   double actual_freq = phdet_freq*(d_int_div+(d_frac_div/65536.0))/scaler;
490   
491   //printf("RF=%f VCO=%f R=%d PHD=%f DIV=%3.5f I=%3d F=%5d ACT=%f",
492   //     target_freq, vco_freq, d_ref_div, phdet_freq,
493   //     div, d_int_div, d_frac_div, actual_freq);
494
495   set_gpio();
496   set_reg_int_divider();
497   set_reg_frac_divider();
498   set_reg_bandselpll();
499
500   args.ok = lock_detect();
501   args.baseband_freq = actual_freq;
502
503   if(args.ok) {
504     if((target_freq > 5.275e9) && (target_freq <= 5.35e9)) {
505       d_highband = 0;
506       set_reg_bandselpll();
507       args.ok = lock_detect();
508       printf("swap to 0 at %f, ok %d\n", target_freq, args.ok);
509     }
510     if((target_freq >= 5.25e9) && (target_freq <= 5.275e9)) {
511       d_highband = 1;
512       set_reg_bandselpll();
513       args.ok = lock_detect();
514       printf("swap to 1 at %f, ok %d\n", target_freq, args.ok);
515     }
516     if(!args.ok){
517       printf("Fail %f\n", target_freq);
518     }
519   }
520   return args;
521 }
522
523 bool
524 xcvr2450::lock_detect()
525 {
526   /*
527     @returns: the value of the VCO/PLL lock detect bit.
528     @rtype: 0 or 1
529   */
530   if(rx_read_io() & LOCKDET) {
531     return true;
532   }
533   else {      // Give it a second chance
534     if(rx_read_io() & LOCKDET)
535       return true;
536     else
537       return false;
538   }
539 }
540
541 bool
542 xcvr2450::set_rx_gain(float gain)
543 {
544   if(gain < 0.0) 
545     gain = 0.0;
546   if(gain > 92.0)
547     gain = 92.0;
548
549   // Split the gain between RF and baseband
550   // This is experimental, not prescribed
551   if(gain < 31.0) {
552     d_rx_rf_gain = 0;                      // 0 dB RF gain
553     rx_bb_gain = int(gain/2.0);
554   }
555   
556   if(gain >= 30.0 and gain < 60.5) {
557     d_rx_rf_gain = 2;                    // 15 dB RF gain
558     d_rx_bb_gain = int((gain-15.0)/2.0);
559   }
560   
561   if(gain >= 60.5) {
562     d_rx_rf_gain = 3;                      // 30.5 dB RF gain
563     d_rx_bb_gain = int((gain-30.5)/2.0);
564   }
565   
566   set_reg_rxgain();
567   
568   return true;
569 }
570
571 bool
572 xcvr2450::set_tx_gain(float gain)
573 {
574   if(gain < 0.0) {
575     gain = 0.0;
576   }
577   if(gain > 30.0) {
578     gain = 30.0;
579   }
580   
581   d_txgain = int((gain/30.0)*63);
582   set_reg_txgain();
583
584   return true;
585 }
586
587
588 /*****************************************************************************/
589
590
591 //_xcvr2450_inst = weakref.WeakValueDictionary()
592 std::vector<xcvr2450_sptr> _xcvr2450_inst;
593
594 xcvr2450_sptr
595 _get_or_make_xcvr2450(usrp_basic_sptr usrp, int which)
596 {
597   xcvr2450_sptr inst;
598   xcvr2450_key key = {usrp->serial_number(), which};
599   std::vector<xcvr2450_sptr>::iterator itr; // =
600   //std::find(_xcvr2450_inst.begin(), _xcvr2450_inst.end(), key);
601
602   for(itr = _xcvr2450_inst.begin(); itr != _xcvr2450_inst.end(); itr++) {
603     if(*(*itr) == key) {
604       printf("Using existing xcvr2450 instance\n");
605       inst = *itr;
606       break;
607     }
608   }
609   
610   if(itr != _xcvr2450_inst.end()) {
611     printf("Creating new xcvr2450 instance\n");
612     inst = xcvr2450_sptr(new xcvr2450(usrp, which));
613     _xcvr2450_inst.push_back(inst);
614   }
615
616   return inst;
617 }
618
619
620 /*****************************************************************************/
621
622
623 db_xcvr2450_base::db_xcvr2450_base(usrp_basic_sptr usrp, int which)
624   : db_base(usrp, which)
625 {
626   /*
627    * Abstract base class for all xcvr2450 boards.
628    * 
629    * Derive board specific subclasses from db_xcvr2450_base_{tx,rx}
630    *
631    * @param usrp: instance of usrp.source_c
632    * @param which: which side: 0 or 1 corresponding to side A or B respectively
633    * @type which: int
634    */
635   
636   d_xcvr = _get_or_make_xcvr2450(usrp, which);
637 }
638
639 db_xcvr2450_base::~db_xcvr2450_base()
640 {
641 }
642
643 struct freq_result_t
644 db_xcvr2450_base::set_freq(double target_freq)
645 {
646   /*
647    * @returns (ok, actual_baseband_freq) where:
648    * ok is True or False and indicates success or failure,
649    * actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
650    */
651   return d_xcvr->set_freq(target_freq);
652 }
653
654 bool
655 db_xcvr2450_base::is_quadrature()
656 {
657   /*
658    * Return True if this board requires both I & Q analog channels.
659    *
660    * This bit of info is useful when setting up the USRP Rx mux register.
661    */
662    return true;
663 }
664
665 double
666 db_xcvr2450_base::freq_min()
667 {
668   return 2.4e9;
669 }
670
671 double
672 db_xcvr2450_base::freq_max()
673 {
674   return 6.0e9;
675 }
676
677
678 /******************************************************************************/
679
680
681 db_xcvr2450_tx::db_xcvr2450_tx(usrp_basic_sptr usrp, int which)
682   : db_xcvr2450_base(usrp, which)
683 {
684   printf("db_xcvr2450_tx::db_xcvr2450_tx\n");
685 }
686
687 db_xcvr2450_tx::~db_xcvr2450_tx()
688 {
689 }
690
691 float
692 db_xcvr2450_tx::gain_min()
693 {
694   return 0;
695 }
696
697 float
698 db_xcvr2450_tx::gain_max()
699 {
700   return 30;
701 }
702
703 float
704 db_xcvr2450_tx::gain_db_per_step()
705 {
706   return (30.0/63.0);
707 }
708
709 bool
710 db_xcvr2450_tx::set_gain(float gain)
711 {
712   return d_xcvr->set_tx_gain(gain);
713 }
714
715 bool
716 db_xcvr2450_tx::i_and_q_swapped()
717 {
718   return true;
719 }
720
721
722 /******************************************************************************/
723
724
725 db_xcvr2450_rx::db_xcvr2450_rx(usrp_basic_sptr usrp, int which)
726   : db_xcvr2450_base(usrp, which)
727 {
728   /*
729    * @param usrp: instance of usrp.source_c
730    * @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
731    */
732   
733   printf("db_xcvr2450_rx:d_xcvr_2450_rx\n");
734 }
735
736 db_xcvr2450_rx::~db_xcvr2450_rx()
737 {
738 }
739
740 float
741 db_xcvr2450_rx::gain_min()
742 {
743   return 0.0;
744 }
745
746 float
747 db_xcvr2450_rx::gain_max()
748 {
749   return 92.0;
750 }
751
752 float
753 db_xcvr2450_rx::gain_db_per_step()
754 {
755   return 1;
756 }
757
758 bool
759 db_xcvr2450_rx::set_gain(float gain)
760 {
761   return d_xcvr->set_rx_gain(gain);
762 }