Merged eb/gcell-wip2 rev 10130:10152 into trunk.
[debian/gnuradio] / gr-usrp / src / db_flexrf.py
1 #
2 # Copyright 2005,2007 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 version 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
22 from gnuradio import usrp1
23 import time,math
24
25 from usrpm import usrp_dbid
26 import db_base
27 import db_instantiator
28 from usrpm.usrp_fpga_regs import *
29
30 #debug_using_gui = True                  # Must be set to True or False
31 debug_using_gui = False                  # Must be set to True or False
32
33 if debug_using_gui:
34     import flexrf_debug_gui
35
36 # d'board i/o pin defs
37 # Tx and Rx have shared defs, but different i/o regs
38 AUX_RXAGC = (1 << 8)
39 POWER_UP = (1 << 7)         # enables power supply
40 RX_TXN = (1 << 6)           # Tx only: T/R antenna switch for TX/RX port
41 RX2_RX1N = (1 << 6)         # Rx only: antenna switch between RX2 and TX/RX port
42 ENABLE = (1 << 5)           # enables mixer
43 AUX_SEN = (1 << 4)
44 AUX_SCLK = (1 << 3)
45 PLL_LOCK_DETECT = (1 << 2)
46 AUX_SDO = (1 << 1)
47 CLOCK_OUT = (1 << 0)
48
49 SPI_ENABLE_TX_A = usrp1.SPI_ENABLE_TX_A
50 SPI_ENABLE_TX_B = usrp1.SPI_ENABLE_TX_B
51 SPI_ENABLE_RX_A = usrp1.SPI_ENABLE_RX_A
52 SPI_ENABLE_RX_B = usrp1.SPI_ENABLE_RX_B
53
54 class flexrf_base(db_base.db_base):
55     """
56     Abstract base class for all flexrf boards.
57
58     Derive board specific subclasses from db_flexrf_base_{tx,rx}
59     """
60     def __init__(self, usrp, which):
61         """
62         @param usrp: instance of usrp.source_c
63         @param which: which side: 0 or 1 corresponding to side A or B respectively
64         @type which: int
65         """
66         # sets _u  _which _tx and _slot
67         db_base.db_base.__init__(self, usrp, which)
68
69         self.first = True
70         self.spi_format = usrp1.SPI_FMT_MSB | usrp1.SPI_FMT_HDR_0
71
72         self._u._write_oe(self._which, 0, 0xffff)   # turn off all outputs
73         self._enable_refclk(False)                      # disable refclk
74
75         g = self.gain_range()                       # initialize gain
76         self.set_gain(float(g[0]+g[1]) / 2)
77
78         self.set_auto_tr(False)
79         
80         if debug_using_gui:
81             title = "FlexRF Debug Rx"
82             if self._tx:
83                 title = "FlexRF Debug Tx"
84             self.gui = flexrf_debug_gui.flexrf_debug_gui(self, title)
85             self.gui.Show(True)
86
87
88     def __del__(self):
89         #print "flexrf_base.__del__"
90         self._u.write_io(self._which, self.power_off, POWER_UP)   # turn off power to board
91         # Power down VCO/PLL
92         self.PD = 3 
93         self._write_control(self._compute_control_reg())
94         self._enable_refclk(False)                       # turn off refclk
95         self.set_auto_tr(False)
96
97     def _write_all(self, R, control, N):
98         """
99         Write R counter latch, control latch and N counter latch to VCO.
100
101         Adds 10ms delay between writing control and N if this is first call.
102         This is the required power-up sequence.
103         
104         @param R: 24-bit R counter latch
105         @type R: int
106         @param control: 24-bit control latch
107         @type control: int
108         @param N: 24-bit N counter latch
109         @type N: int
110         """
111         self._write_R(R)
112         self._write_control( control)
113         if self.first:
114             time.sleep(0.010)
115             self.first = False
116         self._write_N(N)
117
118     def _write_control(self, control):
119         self._write_it((control & ~0x3) | 0)
120
121     def _write_R(self, R):
122         self._write_it((R & ~0x3) | 1)
123
124     def _write_N(self, N):
125         self._write_it((N & ~0x3) | 2)
126
127     def _write_it(self, v):
128         s = ''.join((chr((v >> 16) & 0xff),
129                      chr((v >>  8) & 0xff),
130                      chr(v & 0xff)))
131         self._u._write_spi(0, self.spi_enable, self.spi_format, s)
132         
133     def _lock_detect(self):
134         """
135         @returns: the value of the VCO/PLL lock detect bit.
136         @rtype: 0 or 1
137         """
138         if self._u.read_io(self._which) & PLL_LOCK_DETECT:
139             return True
140         else:      # Give it a second chance
141             if self._u.read_io(self._which) & PLL_LOCK_DETECT:
142                 return True
143             else:
144                 return False
145         
146     def _compute_regs(self, freq):
147         """
148         Determine values of R, control, and N registers, along with actual freq.
149         
150         @param freq: target frequency in Hz
151         @type freq: float
152         @returns: (R, control, N, actual_freq)
153         @rtype: tuple(int, int, int, float)
154         
155         Override this in derived classes.
156         """
157         raise NotImplementedError
158
159     def _refclk_freq(self):
160         # return float(self._u.fpga_master_clock_freq())/self._refclk_divisor()
161         return 64e6/self._refclk_divisor()
162
163     def set_freq(self, freq):
164         """
165         @returns (ok, actual_baseband_freq) where:
166            ok is True or False and indicates success or failure,
167            actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
168         """
169
170         # Offsetting the LO helps get the Tx carrier leakage out of the way.
171         # This also ensures that on Rx, we're not getting hosed by the
172         # FPGA's DC removal loop's time constant.  We were seeing a
173         # problem when running with discontinuous transmission.
174         # Offsetting the LO made the problem go away.
175         freq += self._lo_offset
176         
177         R, control, N, actual_freq = self._compute_regs(freq)
178         if R==0:
179             return(False,0)
180         self._write_all(R, control, N)
181         return (self._lock_detect(), actual_freq)
182
183     def gain_range(self):
184         """
185         Return range of gain that can be set by this d'board.
186
187         @returns (min_gain, max_gain, step_size)
188         Where gains are expressed in decibels (your mileage may vary)
189         """
190         return (self._u.pga_min(), self._u.pga_max(), self._u.pga_db_per_step())
191
192     def set_gain(self, gain):
193         """
194         Set the gain.
195
196         @param gain:  gain in decibels
197         @returns True/False
198         """
199         return self._set_pga(gain)
200
201     def _set_pga(self, pga_gain):
202         if(self._which == 0):
203             self._u.set_pga (0, pga_gain)
204             self._u.set_pga (1, pga_gain)
205         else:
206             self._u.set_pga (2, pga_gain)
207             self._u.set_pga (3, pga_gain)
208
209     def is_quadrature(self):
210         """
211         Return True if this board requires both I & Q analog channels.
212
213         This bit of info is useful when setting up the USRP Rx mux register.
214         """
215         return True
216
217     def set_lo_offset(self, offset):
218         """
219         Set amount by which LO is offset from requested tuning frequency.
220         
221         @param offset: offset in Hz
222         """
223         self._lo_offset = offset
224
225     def lo_offset(self):
226         """
227         Get amount by which LO is offset from requested tuning frequency.
228         
229         @returns Offset in Hz
230         """
231         return self._lo_offset
232         
233 # ----------------------------------------------------------------
234
235 class flexrf_base_tx(flexrf_base):
236     def __init__(self, usrp, which):
237         """
238         @param usrp: instance of usrp.sink_c
239         @param which: 0 or 1 corresponding to side TX_A or TX_B respectively.
240         """
241         flexrf_base.__init__(self, usrp, which)
242         self.spi_enable = (SPI_ENABLE_TX_A, SPI_ENABLE_TX_B)[which]
243
244         # power up the transmit side, but don't enable the mixer
245         self._u._write_oe(self._which,(POWER_UP|RX_TXN|ENABLE), 0xffff)
246         self._u.write_io(self._which, (self.power_on|RX_TXN), (POWER_UP|RX_TXN|ENABLE))
247         self.set_lo_offset(4e6)
248
249     def __del__(self):
250         #print "flexrf_base_tx.__del__"
251         # Power down and leave the T/R switch in the R position
252         self._u.write_io(self._which, (self.power_off|RX_TXN), (POWER_UP|RX_TXN|ENABLE))
253         flexrf_base.__del__(self)
254
255     def set_auto_tr(self, on):
256         if on:
257             self.set_atr_mask (RX_TXN | ENABLE)
258             self.set_atr_txval(0      | ENABLE)
259             self.set_atr_rxval(RX_TXN | 0)
260         else:
261             self.set_atr_mask (0)
262             self.set_atr_txval(0)
263             self.set_atr_rxval(0)
264
265     def set_enable(self, on):
266         """
267         Enable transmitter if on is True
268         """
269         mask = RX_TXN | ENABLE
270         if on:
271             v = ENABLE
272         else:
273             v = RX_TXN
274         self._u.write_io(self._which, v, mask)
275
276     def gain_range(self):
277         """
278         Return range of gain that can be set by this d'board.
279
280         @returns (min_gain, max_gain, step_size)
281         Where gains are expressed in decibels (your mileage may vary)
282
283         Flex Tx boards require that the PGA be maxed out to properly bias their circuitry.
284         """
285         g = self._u.pga_max()
286         return (g, g, 1.0)
287
288     def set_gain(self, gain):
289         """
290         Set the gain.
291
292         @param gain:  gain in decibels
293         @returns True/False
294         """
295         return self._set_pga(self._u.pga_max())
296
297 class flexrf_base_rx(flexrf_base):
298     def __init__(self, usrp, which):
299         """
300         @param usrp: instance of usrp.source_c
301         @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
302         """
303         flexrf_base.__init__(self, usrp, which)
304         self.spi_enable = (SPI_ENABLE_RX_A, SPI_ENABLE_RX_B)[which]
305         
306         self._u._write_oe(self._which, (POWER_UP|RX2_RX1N|ENABLE), 0xffff)
307         self._u.write_io(self._which,  (self.power_on|RX2_RX1N|ENABLE), (POWER_UP|RX2_RX1N|ENABLE))
308
309         # set up for RX on TX/RX port
310         self.select_rx_antenna('TX/RX')
311
312         self.bypass_adc_buffers(True)
313         self.set_lo_offset(-4e6)
314
315     def __del__(self):
316         # print "flexrf_base_rx.__del__"
317         # Power down
318         self._u.write_io(self._which, self.power_off, (POWER_UP|ENABLE))
319         flexrf_base.__del__(self)
320     
321     def set_auto_tr(self, on):
322         if on:
323             self.set_atr_mask (ENABLE)
324             self.set_atr_txval(     0)
325             self.set_atr_rxval(ENABLE)
326         else:
327             self.set_atr_mask (0)
328             self.set_atr_txval(0)
329             self.set_atr_rxval(0)
330
331     def select_rx_antenna(self, which_antenna):
332         """
333         Specify which antenna port to use for reception.
334         @param which_antenna: either 'TX/RX' or 'RX2'
335         """
336         if which_antenna in (0, 'TX/RX'):
337             self._u.write_io(self._which, 0,        RX2_RX1N)
338         elif which_antenna in (1, 'RX2'):
339             self._u.write_io(self._which, RX2_RX1N, RX2_RX1N)
340         else:
341             raise ValueError, "which_antenna must be either 'TX/RX' or 'RX2'"
342
343     def set_gain(self, gain):
344         """
345         Set the gain.
346
347         @param gain:  gain in decibels
348         @returns True/False
349         """
350         maxgain = self.gain_range()[1] - self._u.pga_max()
351         mingain = self.gain_range()[0]
352         if gain > maxgain:
353             pga_gain = gain-maxgain
354             assert pga_gain <= self._u.pga_max()
355             agc_gain = maxgain
356         else:
357             pga_gain = 0
358             agc_gain = gain
359         V_maxgain = .2
360         V_mingain = 1.2
361         V_fullscale = 3.3
362         dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale
363         assert dac_value>=0 and dac_value<4096
364         return self._u.write_aux_dac(self._which, 0, int(dac_value)) and \
365                self._set_pga(int(pga_gain))
366
367 # ----------------------------------------------------------------
368
369 class _AD4360_common(object):
370     def __init__(self):
371         # R-Register Common Values
372         self.R_RSV = 0   # bits 23,22
373         self.BSC = 3   # bits 21,20 Div by 8 to be safe
374         self.TEST = 0  # bit 19
375         self.LDP = 1   # bit 18
376         self.ABP = 0   # bit 17,16   3ns
377
378         # N-Register Common Values
379         self.N_RSV = 0      # bit 7
380         
381         # Control Register Common Values
382         self.PD = 0       # bits 21,20   Normal operation
383         self.PL = 0       # bits 13,12   11mA
384         self.MTLD = 1     # bit 11       enabled
385         self.CPG = 0      # bit 10       CP setting 1
386         self.CP3S = 0     # bit 9        Normal
387         self.PDP = 1      # bit 8        Positive
388         self.MUXOUT = 1   # bits 7:5     Digital Lock Detect
389         self.CR = 0       # bit 4        Normal
390         self.PC = 1       # bits 3,2     Core power 10mA
391
392     def _compute_regs(self, freq):
393         """
394         Determine values of R, control, and N registers, along with actual freq.
395         
396         @param freq: target frequency in Hz
397         @type freq: float
398         @returns: (R, control, N, actual_freq)
399         @rtype: tuple(int, int, int, float)
400         """
401
402         #  Band-specific N-Register Values
403         phdet_freq = self._refclk_freq()/self.R_DIV
404         desired_n = round(freq*self.freq_mult/phdet_freq)
405         actual_freq = desired_n * phdet_freq
406         B = math.floor(desired_n/self._prescaler())
407         A = desired_n - self._prescaler()*B
408         self.B_DIV = int(B)    # bits 20:8
409         self.A_DIV = int(A)    # bit 6:2
410         #assert self.B_DIV >= self.A_DIV
411         if self.B_DIV < self.A_DIV:
412             return (0,0,0,0)
413         R = (self.R_RSV<<22) | (self.BSC<<20) | (self.TEST<<19) | (self.LDP<<18) \
414             | (self.ABP<<16) | (self.R_DIV<<2)
415         
416         control = self._compute_control_reg()
417
418         N = (self.DIVSEL<<23) | (self.DIV2<<22) | (self.CPGAIN<<21) | (self.B_DIV<<8) | \
419             (self.N_RSV<<7) | (self.A_DIV<<2)
420
421         return (R,control,N,actual_freq/self.freq_mult)
422
423     def _compute_control_reg(self):
424         control = (self.P<<22) | (self.PD<<20) | (self.CP2<<17) | (self.CP1<<14) | (self.PL<<12) \
425                   | (self.MTLD<<11) | (self.CPG<<10) | (self.CP3S<<9) | (self.PDP<<8) | \
426                   (self.MUXOUT<<5) | (self.CR<<4) | (self.PC<<2)
427         return control    
428
429     def _refclk_divisor(self):
430         """
431         Return value to stick in REFCLK_DIVISOR register
432         """
433         return 1
434     
435     def _prescaler(self):
436         if self.P == 0:
437             return 8
438         elif self.P == 1:
439             return 16
440         else:
441             return 32
442
443 #----------------------------------------------------------------------
444 class _2400_common(_AD4360_common):
445     def __init__(self):
446         _AD4360_common.__init__(self)
447
448         # Band-specific R-Register Values
449         self.R_DIV = 16  # bits 15:2
450    
451         # Band-specific C-Register values
452         self.P = 1        # bits 23,22   Div by 16/17
453         self.CP2 = 7      # bits 19:17
454         self.CP1 = 7      # bits 16:14
455
456         # Band specifc N-Register Values
457         self.DIVSEL = 0   # bit 23
458         self.DIV2 = 0     # bit 22
459         self.CPGAIN = 0   # bit 21
460         self.freq_mult = 1
461
462     def freq_range(self):           # FIXME
463         return (2300e6, 2700e6, 4e6)
464
465 #----------------------------------------------------------------------
466 class _1200_common(_AD4360_common):
467     def __init__(self):
468         _AD4360_common.__init__(self)
469
470         # Band-specific R-Register Values
471         self.R_DIV = 16  # bits 15:2  DIV by 16 for a 1 MHz phase detector freq
472    
473         # Band-specific C-Register values
474         self.P = 1        # bits 23,22   Div by 16/17
475         self.CP2 = 7      # bits 19:17   1.25 mA
476         self.CP1 = 7      # bits 16:14   1.25 mA
477
478         # Band specifc N-Register Values
479         self.DIVSEL = 0   # bit 23
480         self.DIV2 = 1     # bit 22
481         self.CPGAIN = 0   # bit 21
482         self.freq_mult = 2
483
484     def freq_range(self):           # FIXME
485         return (1150e6, 1350e6, 4e6)
486
487 #-------------------------------------------------------------------------
488 class _1800_common(_AD4360_common):
489     def __init__(self):
490         _AD4360_common.__init__(self)
491
492         # Band-specific R-Register Values
493         self.R_DIV = 16  # bits 15:2  DIV by 16 for a 1 MHz phase detector freq
494    
495         # Band-specific C-Register values
496         self.P = 1        # bits 23,22   Div by 16/17
497         self.CP2 = 7      # bits 19:17   1.25 mA
498         self.CP1 = 7      # bits 16:14   1.25 mA
499
500         # Band specifc N-Register Values
501         self.DIVSEL = 0   # bit 23
502         self.DIV2 = 0     # bit 22
503         self.freq_mult = 1
504         self.CPGAIN = 0   # bit 21
505
506     def freq_range(self):           # FIXME
507         return (1600e6, 2000e6, 4e6)
508
509 #-------------------------------------------------------------------------
510 class _900_common(_AD4360_common):
511     def __init__(self):
512         _AD4360_common.__init__(self)
513
514         # Band-specific R-Register Values
515         self.R_DIV = 16  # bits 15:2  DIV by 16 for a 1 MHz phase detector freq
516    
517         # Band-specific C-Register values
518         self.P = 1        # bits 23,22   Div by 16/17
519         self.CP2 = 7      # bits 19:17   1.25 mA
520         self.CP1 = 7      # bits 16:14   1.25 mA
521
522         # Band specifc N-Register Values
523         self.DIVSEL = 0   # bit 23
524         self.DIV2 = 1     # bit 22
525         self.freq_mult = 2
526         self.CPGAIN = 0   # bit 21
527
528     def freq_range(self):           # FIXME
529         return (800e6, 1000e6, 4e6)
530
531 #-------------------------------------------------------------------------
532 class _400_common(_AD4360_common):
533     def __init__(self):
534         _AD4360_common.__init__(self)
535
536         # Band-specific R-Register Values
537         self.R_DIV = 16  # bits 15:2 
538    
539         # Band-specific C-Register values
540         self.P = 0        # bits 23,22   Div by 8/9
541         self.CP2 = 7      # bits 19:17   1.25 mA
542         self.CP1 = 7      # bits 16:14   1.25 mA
543
544         # Band specifc N-Register Values  These are different for TX/RX
545         self.DIVSEL = 0   # bit 23
546         if self._tx:
547             self.DIV2 = 1 # bit 22
548         else:
549             self.DIV2 = 0 # bit 22   # RX side has built-in DIV2 in AD8348
550         self.freq_mult = 2
551
552         self.CPGAIN = 0   # bit 21
553
554     def freq_range(self):           
555         #return (350e6, 465e6, 1e6)    # FIXME prototype
556         return (400e6, 500e6, 1e6)     # final version
557     
558
559 #------------------------------------------------------------    
560 class db_flexrf_2400_tx(_2400_common, flexrf_base_tx):
561     def __init__(self, usrp, which):
562         self.power_on = 0
563         self.power_off = 0    # powering it off kills the serial bus
564         flexrf_base_tx.__init__(self, usrp, which)
565         _2400_common.__init__(self)
566         
567 class db_flexrf_2400_rx(_2400_common, flexrf_base_rx):
568     def __init__(self, usrp, which):
569         self.power_on = 0
570         self.power_off = 0   # Powering it off kills the serial bus
571         flexrf_base_rx.__init__(self, usrp, which)
572         _2400_common.__init__(self)
573
574     def gain_range(self):
575         """
576         Return range of gain that can be set by this d'board.
577         
578         @returns (min_gain, max_gain, step_size)
579         Where gains are expressed in decibels (your mileage may vary)
580         """
581         return (self._u.pga_min(), self._u.pga_max() + 70, 0.05)
582
583     def i_and_q_swapped(self):
584         return True
585
586 class db_flexrf_1200_tx(_1200_common, flexrf_base_tx):
587     def __init__(self, usrp, which):
588         self.power_on = 0
589         self.power_off = 0    # powering it off kills the serial bus
590         flexrf_base_tx.__init__(self, usrp, which)
591         _1200_common.__init__(self)
592         
593 class db_flexrf_1200_rx(_1200_common, flexrf_base_rx):
594     def __init__(self, usrp, which):
595         self.power_on = 0
596         self.power_off = 0    # powering it off kills the serial bus
597         flexrf_base_rx.__init__(self, usrp, which)
598         _1200_common.__init__(self)
599
600     def gain_range(self):
601         """
602         Return range of gain that can be set by this d'board.
603         
604         @returns (min_gain, max_gain, step_size)
605         Where gains are expressed in decibels (your mileage may vary)
606         """
607         return (self._u.pga_min(), self._u.pga_max() + 70, 0.05)
608
609     def i_and_q_swapped(self):
610         return True
611
612 class db_flexrf_1800_tx(_1800_common, flexrf_base_tx):
613     def __init__(self, usrp, which):
614         self.power_on = 0
615         self.power_off = 0    # powering it off kills the serial bus
616         flexrf_base_tx.__init__(self, usrp, which)
617         _1800_common.__init__(self)
618         
619 class db_flexrf_1800_rx(_1800_common, flexrf_base_rx):
620     def __init__(self, usrp, which):
621         self.power_on = 0
622         self.power_off = 0    # powering it off kills the serial bus
623         flexrf_base_rx.__init__(self, usrp, which)
624         _1800_common.__init__(self)
625
626     def gain_range(self):
627         """
628         Return range of gain that can be set by this d'board.
629         
630         @returns (min_gain, max_gain, step_size)
631         Where gains are expressed in decibels (your mileage may vary)
632         """
633         return (self._u.pga_min(), self._u.pga_max() + 70, 0.05)
634
635     def i_and_q_swapped(self):
636         return True
637
638 class db_flexrf_900_tx(_900_common, flexrf_base_tx):
639     def __init__(self, usrp, which):
640         self.power_on = 0
641         self.power_off = 0    # powering it off kills the serial bus
642         flexrf_base_tx.__init__(self, usrp, which)
643         _900_common.__init__(self)
644         
645 class db_flexrf_900_rx(_900_common, flexrf_base_rx):
646     def __init__(self, usrp, which):
647         self.power_on = 0
648         self.power_off = 0    # powering it off kills the serial bus
649         flexrf_base_rx.__init__(self, usrp, which)
650         _900_common.__init__(self)
651
652     def gain_range(self):
653         """
654         Return range of gain that can be set by this d'board.
655         
656         @returns (min_gain, max_gain, step_size)
657         Where gains are expressed in decibels (your mileage may vary)
658         """
659         return (self._u.pga_min(), self._u.pga_max() + 70, 0.05)
660
661     def i_and_q_swapped(self):
662         return True
663
664 class db_flexrf_400_tx(_400_common, flexrf_base_tx):
665     def __init__(self, usrp, which):
666         self.power_on = POWER_UP
667         self.power_off = 0
668         flexrf_base_tx.__init__(self, usrp, which)
669         _400_common.__init__(self)
670         
671 class db_flexrf_400_rx(_400_common, flexrf_base_rx):
672     def __init__(self, usrp, which):
673         self.power_on = POWER_UP
674         self.power_off = 0
675         flexrf_base_rx.__init__(self, usrp, which)
676         _400_common.__init__(self)
677
678     def gain_range(self):
679         """
680         Return range of gain that can be set by this d'board.
681         
682         @returns (min_gain, max_gain, step_size)
683         Where gains are expressed in decibels (your mileage may vary)
684         """
685         return (self._u.pga_min(), self._u.pga_max() + 45, 0.035)
686
687     def i_and_q_swapped(self):
688         return True
689     
690 # hook these daughterboard classes into the auto-instantiation framework
691
692 db_instantiator.add(usrp_dbid.FLEX_2400_TX, lambda usrp, which : (db_flexrf_2400_tx(usrp, which),))
693 db_instantiator.add(usrp_dbid.FLEX_2400_RX, lambda usrp, which : (db_flexrf_2400_rx(usrp, which),))
694 db_instantiator.add(usrp_dbid.FLEX_1200_TX, lambda usrp, which : (db_flexrf_1200_tx(usrp, which),))
695 db_instantiator.add(usrp_dbid.FLEX_1200_RX, lambda usrp, which : (db_flexrf_1200_rx(usrp, which),))
696 db_instantiator.add(usrp_dbid.FLEX_1800_TX, lambda usrp, which : (db_flexrf_1800_tx(usrp, which),))
697 db_instantiator.add(usrp_dbid.FLEX_1800_RX, lambda usrp, which : (db_flexrf_1800_rx(usrp, which),))
698 db_instantiator.add(usrp_dbid.FLEX_900_TX,  lambda usrp, which : (db_flexrf_900_tx(usrp, which),))
699 db_instantiator.add(usrp_dbid.FLEX_900_RX,  lambda usrp, which : (db_flexrf_900_rx(usrp, which),))
700 db_instantiator.add(usrp_dbid.FLEX_400_TX,  lambda usrp, which : (db_flexrf_400_tx(usrp, which),))
701 db_instantiator.add(usrp_dbid.FLEX_400_RX,  lambda usrp, which : (db_flexrf_400_rx(usrp, which),))