usrp: Cleanup for merge of bitshark daughterboard code
[debian/gnuradio] / usrp / host / lib / db_bitshark_rx.cc
1 //
2 // Copyright 2010 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 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <usrp/db_bitshark_rx.h>
26 #include <db_base_impl.h>
27 #include <cmath>
28 #include <cstdio>
29 #include <string.h>
30 #include <stdint.h>
31
32 /* Note: Thie general structure of this file is based on the db_dbsrx.cc 
33    codebase for the dbsrx daughterboard. */
34
35 /* The following defines specify the address map provided by the
36    Bitshark card. These registers are all accessed over I2C. */
37 #define RF_CENTER_FREQ_REG 0x00
38 #define RF_CHAN_FILTER_BW_REG 0x01
39 #define RF_GAIN_REG 0x02
40 #define BB_GAIN_REG 0x03
41 #define ADF4350_REG 0x10
42 #define SKY73202_REG 0x11
43 #define CLOCK_SCHEME_REG 0x20
44
45 /* The following table lists the registers provided by the BURX board that
46    are accessible over I2C:
47    --------------------------------------------------------
48    |RegAddr: 0x00-RF Center Freq register |
49        |4-bytes 0x00|
50        |4-byte unsigned RF center freq (in KHz)|
51    |RegAddr: 0x01-RF channel filter bandwidth register |
52        |4-bytes 0x00|
53        |4-byte unsigned RF channel filter bw (in KHz)|
54    |RegAddr: 0x02-RF gain register |
55        |7-bytes 0x00|
56        |1-byte signed RF gain (in dB)|
57    |RegAddr: 0x03-Baseband gain register |
58        |4-bytes 0x00|
59        |4-byte signed baseband filter gain (in dB)|
60    |RegAddr: 0x10-ADF4350 register |
61        |4-bytes 0x00|
62        |4-byte ADF4350 register value (actual ADF4350 reg addr embedded 
63         within 4-byte value)|
64    |RegAddr: 0x11-SKY73202 register |
65        |5-bytes 0x00|
66        |1-byte reg 0 of SKY73202 |
67        |1-byte reg 1 of SKY73202 |
68        |1-byte reg 2 of SKY73202 |
69    |RegAddr: 0x20-Clock Scheme |
70        |3-bytes 0x00|
71        |1-byte indicating clocking scheme:
72         -0x00 -> BURX local TCXO off, BURX accepts ref clock from
73                  USRP (freq of USRP's ref clock specified in bytes 2-5)
74         -0x01 -> BURX local TCXO on, BURX uses its local TCXO as its ref
75                  clock, TCXO signal output for use by USRP |
76        |4-byte USRP ref clock freq in hz (only needed if byte 1 set to 0x00) |
77        
78   ---------------------------------------------------------------------------
79    
80    As an example, lets say the client wants to set an RF center freq of
81    1000 MHz.  In KHz, this translates to 1000000 (resolution is only down to
82    steps of 1 KHz), which is 0x000F4240 in hex.  So the complete 9-byte I2C 
83    sequence that the client should send is as follows:
84    byte 0: 0x00-register 0x00 is the target of the write operation
85    bytes 1-4: 0x00 (padding)
86    byte 5: 0x40 (LSB of the 1000000 KHz value, in hex)
87    byte 6: 0x42
88    byte 7: 0x0F
89    byte 8: 0x00 (MSB of the 1000000 KHz value, in hex)
90
91    If using the usrper cmd-line application on a PC, this sequence would
92    be sent as follows (assuming that the BURX is in slot A):
93    
94    # usrper i2c_write 0x47 000000000040420F00
95    
96    How about another example...lets say the client wants to setup the clock
97    scheme to use scheme #1 where the 26 MHz TCXO on the BURX board is enabled,
98    and is provided to the USRP.  26 MHz (i.e. 26 million), in hex, is 0x18CBA80.
99    So the complete 9-byte I2C sequence that the client should send is as follows:
100    byte 0: 0x20-register 0x20 is the target of the write operation
101    bytes 1-3: 0x00 (padding)
102    byte 4: 0x01 (indicating that clock scheme #1 is wanted)
103    byte 5: 0x80 (LSB of the BURX ref clk freq)
104    byte 6: 0xBA
105    byte 7: 0x8C
106    byte 8: 0x01 (MSB of the BURX ref clk freq)
107    
108    To enable the BURX local ref clk, which will also make it available on the
109    on-board U.FL connector as a source for the USRP, a user can also use
110    the usrper cmd-line application on a PC.  The following sequence would
111    be sent (assuming that the BURX is in slot A):
112    
113    # usrper i2c_write 0x47 200000000180BA8C01
114
115 */
116
117 #define NUM_BYTES_IN_I2C_CMD 9   
118
119 /*****************************************************************************/
120
121 db_bitshark_rx::db_bitshark_rx(usrp_basic_sptr _usrp, int which)
122   : db_base(_usrp, which)
123 {
124     // Control Bitshark receiver USRP daughterboard.
125     // 
126     // @param usrp: instance of usrp.source_c
127     // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively
128
129     // turn off all outputs
130     usrp()->_write_oe(d_which, 0, 0xffff);
131
132     if (which == 0) 
133     {
134         d_i2c_addr = 0x47;
135     }
136     else 
137     {
138         d_i2c_addr = 0x45;
139     }
140
141     // initialize gain
142     set_gain((gain_min() + gain_max()) / 2.0);
143
144     // by default, assume we're using the USRPs clock as the ref clk,
145     // so setup the clock scheme and frequency.  If the user wants
146     // to use the Bitshark's TCXO, the clock scheme should be set
147     // to 1, the freq should be set to 26000000, and a top-level
148     // 'make' and 'make install' needs to be executed.  In addition, 
149     // a U.FL to SMA cable needs to connect J6 on the Bitshark to 
150     // the external clk input on the USRP
151     set_clock_scheme(0,64000000);
152
153     set_bw(8e6); // Default IF bandwidth to match USRP1 max host bandwidth
154
155     bypass_adc_buffers(true);
156 }
157
158 db_bitshark_rx::~db_bitshark_rx()
159 {
160     shutdown();
161 }
162
163 /************ Private Functions **********************/
164
165 void
166 db_bitshark_rx::_set_pga(int pga_gain)
167 {
168     assert(pga_gain>=0 && pga_gain<=20);
169     if(d_which == 0) 
170     {
171         usrp()->set_pga (0, pga_gain);
172         usrp()->set_pga (1, pga_gain);
173     }
174     else 
175     {
176         usrp()->set_pga (2, pga_gain);
177         usrp()->set_pga (3, pga_gain);
178     }
179 }
180
181 /************ Public Functions **********************/
182 void
183 db_bitshark_rx::shutdown()
184 {
185     if (!d_is_shutdown)
186     {
187         d_is_shutdown = true;
188     }
189 }
190
191 bool
192 db_bitshark_rx::set_bw (float bw)
193 {
194     std::vector<int> args(NUM_BYTES_IN_I2C_CMD,0);
195     uint16_t rf_bw_in_khz = (uint16_t)(bw/1000.0);
196     char val[4];
197     bool result = false;
198     uint8_t try_count = 0;
199     
200     memset(val,0x00,4);
201     if (rf_bw_in_khz < 660  || rf_bw_in_khz > 56000) 
202     {
203         fprintf(stderr, "db_bitshark_rx::set_bw: bw (=%d) must be between 660 KHz and 56 MHz inclusive\n", rf_bw_in_khz);
204         return false;
205     }
206     //fprintf(stdout,"Setting bw: requested bw in khz is %d\r\n",rf_bw_in_khz);
207     memcpy(val,&rf_bw_in_khz,4);
208     args[0] = RF_CHAN_FILTER_BW_REG;
209     args[5] = val[0];
210     args[6] = val[1];
211     args[7] = val[2];
212     args[8] = val[3];
213     while ((result != true) && (try_count < 3))
214     {
215         result=usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args));
216         try_count++;
217     }
218
219     if (result == false)
220     {
221         fprintf(stderr, "db_bitshark_rx:set_bw: giving up after 3 tries without success\n");
222     }
223     
224     return result;
225 }
226
227 /* The gain referenced below is RF gain only.  There are two independent
228    gain settings at RF: a digital step attenuator (providing 0, -6, -12, and
229    -18 dB of attenuation), and a second LNA (LNA2) that provides ~25 dB of
230    gain (roughly...it actually depends on the RF freq).  So combining these
231    two stages can provide an overall gain range from 0 (which is mapped
232    to -18 dB on the step attenuator + LNA2 turned off) to 42 (which is
233    mapped to 0 dB on the step attenuator + LNA2 turned on).  
234    
235    There could be better ways to map these, but this is sufficient for
236    now. */
237 float
238 db_bitshark_rx::gain_min()
239 {
240     return 0;
241 }
242
243 float
244 db_bitshark_rx::gain_max()
245 {
246     return 42;
247 }
248
249 float
250 db_bitshark_rx::gain_db_per_step()
251 {
252     return 6;
253 }
254
255 bool 
256 db_bitshark_rx::set_gain(float gain)
257 {
258     // Set the gain.
259     // 
260     // @param gain:  RF gain in decibels, range of 0-42
261     // @returns True/False
262     
263     std::vector<int> args(NUM_BYTES_IN_I2C_CMD,0);
264     bool result = false;
265     uint8_t try_count = 0;
266         
267     if (gain < gain_min() || gain > gain_max()) 
268     {
269         fprintf(stderr,"db_bitshark_rx::set_gain: gain (=%f) must be between %f and %f inclusive\n", gain,gain_min(),gain_max());
270         return false;
271     }
272     //fprintf(stdout,"db_bitshark_rx::set_gain: requested gain of %f\r\n",gain);
273     args[0] = RF_GAIN_REG;
274     args[5] = (int)gain;
275
276     while ((result != true) && (try_count < 3))
277     {
278         result=usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args));
279         try_count++;
280     }
281
282     if (result == false)
283     {
284         fprintf(stderr, "db_bitshark_rx:set_gain: giving up after 3 tries without success\n");
285     }
286     
287     return result;
288 }
289
290
291 bool 
292 db_bitshark_rx::set_clock_scheme(uint8_t clock_scheme, uint32_t ref_clk_freq)
293 {
294     // Set the clock scheme for determining how the BURX
295     // dboard receives its clock.  Note: Ideally, the constructor for the
296     // BURX board could simply call this method to set how it wants the
297     // clock scheme configured.  However, depending on the application
298     // using the daughterboard, the constructor may run _after_ some
299     // other portion of the application needs the FPGA.  And if the
300     // the clock source for the FPGA was the BURX's 26 MHz TCXO, we're in
301     // a chicken-before-the-egg dilemna.  So the solution is to leave
302     // this function here for reference in case an app wants to use it,
303     // and also give the user the ability to set the clock scheme through
304     // the usrper cmd-line application (see example at the top of this
305     // file).
306     // 
307     // @param clock_scheme
308     // @param ref_clk_freq in Hz
309     // @returns True/False
310     
311     std::vector<int> args(NUM_BYTES_IN_I2C_CMD,0);
312     bool result = false;
313     uint8_t try_count = 0;
314     char val[4];
315         
316     if (clock_scheme > 1) 
317     {
318         fprintf(stderr,"db_bitshark_rx::set_clock_scheme: invalid scheme %d\n",clock_scheme);
319         return false;
320     }
321     //fprintf(stdout,"db_bitshark_rx::set_clock_scheme: requested clock schem of %d with freq %d Hz \n",clock_scheme,ref_clk_freq);
322     memcpy(val,&ref_clk_freq,4);
323     args[0] = CLOCK_SCHEME_REG;
324     args[4] = (int)clock_scheme;
325     args[5] = val[0];
326     args[6] = val[1];
327     args[7] = val[2];
328     args[8] = val[3];
329
330     while ((result != true) && (try_count < 3))
331     {
332         result=usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args));
333         try_count++;
334     }
335
336     if (result == false)
337     {
338         fprintf(stderr, "db_bitshark_rx:set_clock_scheme: giving up after 3 tries without success\n");
339     }
340     return result;
341 }
342
343 double
344 db_bitshark_rx::freq_min()
345 {    
346     return 300e6;
347 }
348
349 double
350 db_bitshark_rx::freq_max()
351 {    
352     return 4e9;
353 }
354
355 struct freq_result_t
356 db_bitshark_rx::set_freq(double freq)
357 {
358     // Set the frequency.
359     // 
360     // @param freq:  target RF frequency in Hz
361     // @type freq:   double
362     // 
363     // @returns (ok, actual_baseband_freq) where:
364     //   ok is True or False and indicates success or failure,
365     //   actual_baseband_freq is RF frequency that corresponds to DC in the IF.
366     
367     std::vector<int> args(NUM_BYTES_IN_I2C_CMD,0);
368     std::vector<int> bytes(2);
369     char val[4];
370     freq_result_t act_freq = {false, 0};
371     uint32_t freq_in_khz = (uint32_t)(freq/1000.0);
372     bool result = false;
373     uint8_t try_count = 0;
374         
375     memset(val,0x00,4);
376     if(!(freq>=freq_min() && freq<=freq_max())) 
377     {
378         return act_freq;
379     }
380     
381     //fprintf(stdout,"db_bitshark_rx::set_freq: requested freq is %d KHz\n",freq_in_khz);
382     memcpy(val,&freq_in_khz,4);
383     args[0] = RF_CENTER_FREQ_REG;
384     args[5] = val[0];
385     args[6] = val[1];
386     args[7] = val[2];
387     args[8] = val[3];
388
389     while ((result != true) && (try_count < 3))
390     {
391         result=usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args));
392         try_count++;
393     }
394
395     if (result == false)
396     {
397         fprintf(stderr, "db_bitshark_rx:set_freq: giving up after 3 tries without success\n");
398     }
399         
400     act_freq.ok = result;
401     act_freq.baseband_freq = (double)freq;
402     return act_freq;
403 }
404
405 bool 
406 db_bitshark_rx::is_quadrature()
407 {    
408     // Return True if this board requires both I & Q analog channels.  
409     return true;
410 }
411
412 bool
413 db_bitshark_rx::i_and_q_swapped()
414 {
415     // Returns True since our I and Q channels are swapped
416     return true;
417 }