Imported Upstream version 3.0
[debian/gnuradio] / gr-usrp / src / db_dbs_rx.py
1 #
2 # Copyright 2005 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 2, 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 import math
23 import usrp_dbid
24 import db_base
25 import db_instantiator
26
27 def int_seq_to_str (seq):
28     """convert a sequence of integers into a string"""
29     return ''.join (map (chr, seq))
30
31 def str_to_int_seq (str):
32     """convert a string to a list of integers"""
33     return map (ord, str)
34
35 class db_dbs_rx (db_base.db_base):
36     def __init__ (self, usrp, which):
37         """
38         Control DBS receiver based USRP daughterboard.
39         
40         @param usrp: instance of usrp.source_c
41         @param which: which side: 0 or 1 corresponding to RX_A or RX_B respectively
42         @type which: int
43         """
44         # sets _u and _which
45         db_base.db_base.__init__(self, usrp, which)
46
47         self._u._write_oe(self._which,0x0001,0x0001)
48         self.i2c_addr = (0x67, 0x65)[self._which]
49         # set basic parameters
50         # set default values
51         self.n = 950
52         self.div2 = 0
53         self.osc = 5
54         self.cp = 3
55         self.r = 4
56         self.r_int = 1
57         self.fdac = 127
58         self.m = 2
59         self.dl = 0
60         self.ade = 0
61         self.adl = 0
62         self.gc2 = 31
63         self.diag = 0
64
65         # FIXME this should be in the core dboard class
66         self.refclk_divisor = 16
67         self._enable_refclk(True)
68
69         g = self.gain_range()
70         self.set_gain(float(g[0]+g[1]) / 2)
71         self.bypass_adc_buffers(True)
72         
73     def __del__(self):
74         if self._u:
75             self._enable_refclk(False)
76
77     def _write_reg (self, regno, v):
78         """regno is in [0,5], v is value to write to register"""
79         assert (0 <= regno and regno <= 5)
80         self._u.write_i2c (self.i2c_addr, int_seq_to_str ((regno, v)))
81         
82     def _write_regs (self, starting_regno, vals):
83         """starting_regno is in [0,5],
84         vals is a seq of integers to write to consecutive registers"""
85         self._u.write_i2c (self.i2c_addr,
86                           int_seq_to_str ((starting_regno,) + tuple (vals)))
87         
88     def _read_status (self):
89         """If successful, return list of two ints: [status_info, filter_DAC]"""
90         s = self._u.read_i2c (self.i2c_addr, 2)
91         if len (s) != 2:
92             return None
93         return str_to_int_seq (s)
94
95     def _send_reg(self,regno):
96         assert (0 <= regno and regno <= 5)
97         if regno == 0:
98             self._write_reg(0,(self.div2<<7) + (self.n>>8))
99         if regno == 1:
100             self._write_reg(1,self.n & 255)
101         if regno == 2:
102             self._write_reg(2,self.osc + (self.cp<<3) + (self.r_int<<5))
103         if regno == 3:
104             self._write_reg(3,self.fdac)
105         if regno == 4:
106             self._write_reg(4,self.m + (self.dl<<5) + (self.ade<<6) + (self.adl<<7))
107         if regno == 5:
108             self._write_reg(5,self.gc2 + (self.diag<<5))
109
110     # BW setting
111     def _set_m(self,m):
112         assert m>0 and m<32
113         self.m = m
114         self._send_reg(4)
115     
116     def _set_fdac(self,fdac):
117         assert fdac>=0 and fdac<128
118         self.fdac = fdac
119         self._send_reg(3)
120         
121     def set_bw (self, bw):
122         #assert (bw>=4e6 and bw<=33e6)
123         assert (bw>=1e6 and bw<=33e6)
124         if bw >= 4e6:
125             m_max = int(min(31,math.floor(self._refclk_freq()/1e6)))
126         elif bw >= 2e6:      # Outside of Specs!
127             m_max = int(min(31,math.floor(self._refclk_freq()/.5e6)))
128         else:      # Way outside of Specs!
129             m_max = int(min(31,math.floor(self._refclk_freq()/.25e6)))
130         
131         m_min = int(math.ceil(self._refclk_freq()/2.5e6))
132         m_test = m_max
133         while m_test >= m_min:
134             fdac_test = int(round(((bw * m_test / self._refclk_freq())-4)/.145))
135             if fdac_test>127:
136                 m_test = m_test - 1
137             else:
138                 break
139         if (m_test>=m_min and fdac_test >=0):
140             self._set_m(m_test)
141             self._set_fdac(fdac_test)
142             return (self.m,self.fdac,self._refclk_freq()/self.m*(4+0.145*self.fdac))
143         else:
144             print "Failed to set bw"
145
146     # Gain setting
147     def _set_dl(self,dl):
148         assert dl == 0 or dl == 1
149         self.dl = dl
150         self._send_reg(4)
151         
152     def _set_gc2(self,gc2):
153         assert gc2<32 and gc2>=0
154         self.gc2 = gc2
155         self._send_reg(5)
156
157     def _set_gc1(self,gc1):
158         assert gc1>=0 and gc1<4096
159         self.gc1 = gc1
160         self._u.write_aux_dac(self._which,0,int(gc1))
161
162     def _set_pga(self, pga_gain):
163         assert pga_gain >=0 and pga_gain <=20
164         if(self._which == 0):
165             self._u.set_pga (0, pga_gain)
166             self._u.set_pga (1, pga_gain)
167         else:
168             self._u.set_pga (2, pga_gain)
169             self._u.set_pga (3, pga_gain)
170             
171     def gain_range(self):
172         return (0, 104, 1)
173     
174     def set_gain(self,gain):
175         if not (gain>=0 and gain<105):
176             raise ValueError, "gain out of range"
177         gc1 = 0
178         gc2 = 0
179         dl = 0
180         pga = 0
181         if gain <56:
182             gc1 = int((-gain*1.85/56.0 + 2.6)*4096.0/3.3)
183             gain = 0
184         else:
185             gc1 = 0
186             gain = gain - 56
187         if gain < 24:
188             gc2 = int(round(31.0 * (1-gain/24.0)))
189             gain = 0
190         else:
191             gc2 = 0
192             gain = gain - 24
193         if gain >= 4.58:
194             dl = 1
195             gain = gain - 4.58
196         pga = gain
197         self._set_gc1(gc1)
198         self._set_gc2(gc2)
199         self._set_dl(dl)
200         self._set_pga(pga)
201         
202     # Frequency setting
203     def _set_osc(self,osc):
204         assert osc>=0 and osc<8
205         self.osc = osc
206         self._send_reg(2)
207
208     def _set_cp(self,cp):
209         assert cp>=0 and cp<4
210         self.cp = cp
211         self._send_reg(2)
212
213     def _set_n(self,n):
214         assert n>256 and n<32768
215         self.n = n
216         self._send_reg(0)
217         self._send_reg(1)
218
219     def _set_div2(self,div2):
220         assert div2 == 0 or div2 == 1
221         self.div2 = div2
222         self._send_reg(0)
223
224     def _set_r(self,r):
225         assert r>=0 and r<128
226         self.r = r
227         self.r_int = int(round(math.log10(r)/math.log10(2)) - 1)
228         self._send_reg(2)
229         
230     # FIXME  How do we handle ADE and ADL properly?
231     def _set_ade(self,ade):
232         assert ade == 0 or ade == 1
233         self.ade = ade
234         self._send_reg(4)
235         
236     def freq_range(self):
237         return (500e6, 2.6e9, 1e6)
238
239     def _refclk_divisor(self):
240         """
241         Return value to stick in REFCLK_DIVISOR register
242         """
243         return 16
244     
245     def set_freq(self, freq):
246         """
247         Set the frequency.
248
249         @param freq:  target frequency in Hz
250         @type freq:   float
251
252         @returns (ok, actual_baseband_freq) where:
253            ok is True or False and indicates success or failure,
254            actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
255         """
256         if not (freq>=500e6 and freq<=2.6e9):
257             return (False, 0)
258         
259         if(freq<1150e6):
260             self._set_div2(0)
261             vcofreq = 4 * freq
262         else:
263             self._set_div2(1)
264             vcofreq = 2 * freq
265         self._set_ade(1)
266         rmin=max(2,self._refclk_freq()/2e6)
267         rmax=min(128,self._refclk_freq()/150e3)
268         r = 2
269         n=0
270         best_r = 2
271         best_n =0
272         best_delta = 10e6
273         while r <= rmax:
274             n = round(freq/(self._refclk_freq()/r))
275             if r<rmin or n<256:
276                 r = r * 2
277                 continue
278             delta = abs(n*self._refclk_freq()/r - freq)
279             if delta < 75e3:
280                 best_r = r
281                 best_n = n
282                 break
283             if delta < best_delta*0.9:
284                 best_r = r
285                 best_n = n
286                 best_delta = delta
287             r = r * 2
288         self._set_r(int(best_r))
289
290         self._set_n(int(round(best_n)))
291  
292         if vcofreq < 2433e6:
293             vco = 0
294         elif vcofreq < 2711e6:
295             vco=1
296         elif vcofreq < 3025e6:
297             vco=2
298         elif vcofreq < 3341e6:
299             vco=3
300         elif vcofreq < 3727e6:
301             vco=4
302         elif vcofreq < 4143e6:
303             vco=5
304         elif vcofreq < 4493e6:
305             vco=6
306         else:
307             vco=7
308
309         self._set_osc(vco)
310
311         # Set CP current
312         adc_val = 0
313         while adc_val == 0 or adc_val == 7:
314             (byte1,byte2) = self._read_status()
315             adc_val = byte1 >> 2
316             if(adc_val == 0):
317                 if vco <= 0:
318                     return (False, 0)
319                 else:
320                     vco = vco - 1
321             elif(adc_val == 7):
322                 if(vco >= 7):
323                     return (False, 0)
324                 else:
325                     vco = vco + 1
326             self._set_osc(vco)
327         if adc_val == 1 or adc_val == 2:
328             self._set_cp(1)
329         elif adc_val == 3 or adc_val == 4:
330             self._set_cp(2)
331         else:
332             self._set_cp(3)
333                     
334         return (True, self.n * self._refclk_freq() / self.r)
335
336     def is_quadrature(self):
337         """
338         Return True if this board requires both I & Q analog channels.
339
340         This bit of info is useful when setting up the USRP Rx mux register.
341         """
342         return True
343
344 # hook this daughterboard class into the auto-instantiation framework
345 db_instantiator.add(usrp_dbid.DBS_RX, lambda usrp, which : (db_dbs_rx(usrp, which),))