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