Merged r10712:10765 from jcorgan/gpio into trunk. Adds out-of-band and streaming...
[debian/gnuradio] / usrp2 / host / lib / usrp2.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2008,2009 Free Software Foundation, Inc.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <usrp2/usrp2.h>
24 #include "usrp2_impl.h"
25 #include <vector>
26 #include <boost/thread.hpp>
27 #include <boost/weak_ptr.hpp>
28 #include <string>
29 #include <stdexcept>
30
31 namespace usrp2 {
32
33   // --- Table of weak pointers to usrps we know about ---
34
35   // (Could be cleaned up and turned into a template)
36
37   struct usrp_table_entry {
38     // inteface + normalized mac addr ("eth0:01:23:45:67:89:ab")
39     std::string key;
40     boost::weak_ptr<usrp2::usrp2>  value;
41
42     usrp_table_entry(const std::string &_key, boost::weak_ptr<usrp2::usrp2> _value)
43       : key(_key), value(_value) {}
44   };
45
46   typedef std::vector<usrp_table_entry> usrp_table;
47
48   static boost::mutex s_table_mutex;
49   static usrp_table s_table;
50
51   usrp2::sptr
52   usrp2::find_existing_or_make_new(const std::string &ifc, props *pr)
53   {
54     std::string key = ifc + ":" + pr->addr;
55
56     boost::mutex::scoped_lock   guard(s_table_mutex);
57
58     for (usrp_table::iterator p = s_table.begin(); p != s_table.end();){
59       if (p->value.expired())   // weak pointer is now dead
60         p = s_table.erase(p);   // erase it
61       else {
62         if (key == p->key)      // found it
63           return usrp2::sptr(p->value);
64         else                    
65           ++p;                  // keep looking
66       }
67     }
68
69     // We don't have the USRP2 we're looking for
70
71     // create a new one and stick it in the table.
72     usrp2::sptr r(new usrp2::usrp2(ifc, pr));
73     usrp_table_entry t(key, r);
74     s_table.push_back(t);
75
76     return r;
77   }
78
79   // --- end of table code ---
80
81   static bool
82   parse_mac_addr(const std::string &s, std::string &ns)
83   {
84     u2_mac_addr_t p;
85
86     p.addr[0] = 0x00;           // Matt's IAB
87     p.addr[1] = 0x50;
88     p.addr[2] = 0xC2;
89     p.addr[3] = 0x85;
90     p.addr[4] = 0x30;
91     p.addr[5] = 0x00;
92     
93     int len = s.size();
94     switch (len) {
95       
96     case 5:
97       if (sscanf(s.c_str(), "%hhx:%hhx", &p.addr[4], &p.addr[5]) != 2)
98         return false;
99       break;
100       
101     case 17:
102       if (sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
103                  &p.addr[0], &p.addr[1], &p.addr[2],
104                  &p.addr[3], &p.addr[4], &p.addr[5]) != 6)
105         return false;
106       break;
107
108     default:
109       return false;
110     }
111     
112     char buf[128];
113     snprintf(buf, sizeof(buf),
114              "%02x:%02x:%02x:%02x:%02x:%02x",
115              p.addr[0],p.addr[1],p.addr[2],
116              p.addr[3],p.addr[4],p.addr[5]);
117     ns = std::string(buf);
118     return true;
119   }
120
121   usrp2::sptr
122   usrp2::make(const std::string &ifc, const std::string &addr)
123   {
124     std::string naddr = "";
125     if (addr != "" && !parse_mac_addr(addr, naddr))
126       throw std::runtime_error("Invalid MAC address");
127
128     props_vector_t u2s = find(ifc, naddr);
129     int n = u2s.size();
130
131     if (n == 0) {
132       if (addr == "")
133         throw std::runtime_error("No USRPs found on interface " + ifc);
134       else
135         throw std::runtime_error("No USRP found with addr " + addr + " on interface " + ifc);
136     }
137
138     if (n > 1)
139       throw std::runtime_error("Multiple USRPs found on interface; must select by MAC address.");
140
141     return find_existing_or_make_new(ifc, &u2s[0]);
142   }
143
144   // Private constructor.  Sole function is to create an impl.
145   usrp2::usrp2(const std::string &ifc, props *p)
146     : d_impl(new usrp2::impl(ifc, p))
147   {
148     // NOP
149   }
150   
151   // Public class destructor.  d_impl will auto-delete.
152   usrp2::~usrp2()
153   {
154     // NOP
155   }
156   
157   std::string
158   usrp2::mac_addr()
159   {
160     return d_impl->mac_addr();
161   }
162
163   std::string
164   usrp2::interface_name()
165   {
166     return d_impl->interface_name();
167   }
168
169   // Receive
170
171   bool 
172   usrp2::set_rx_gain(double gain)
173   {
174     return d_impl->set_rx_gain(gain);
175   }
176   
177   double
178   usrp2::rx_gain_min()
179   {
180     return d_impl->rx_gain_min();
181   }
182
183   double
184   usrp2::rx_gain_max()
185   {
186     return d_impl->rx_gain_max();
187   }
188
189   double
190   usrp2::rx_gain_db_per_step()
191   {
192     return d_impl->rx_gain_db_per_step();
193   }
194
195   bool
196   usrp2::set_rx_lo_offset(double frequency)
197   {
198     return d_impl->set_rx_lo_offset(frequency);
199   }
200
201   bool
202   usrp2::set_rx_center_freq(double frequency, tune_result *result)
203   {
204     return d_impl->set_rx_center_freq(frequency, result);
205   }
206   
207   double
208   usrp2::rx_freq_min()
209   {
210     return d_impl->rx_freq_min();
211   }
212
213   double
214   usrp2::rx_freq_max()
215   {
216     return d_impl->rx_freq_max();
217   }
218
219   bool
220   usrp2::set_rx_decim(int decimation_factor)
221   {
222     return d_impl->set_rx_decim(decimation_factor);
223   }
224   
225   int
226   usrp2::rx_decim()
227   {
228     return d_impl->rx_decim();
229   }
230
231   bool
232   usrp2::set_rx_scale_iq(int scale_i, int scale_q)
233   {
234     return d_impl->set_rx_scale_iq(scale_i, scale_q);
235   }
236   
237   bool
238   usrp2::start_rx_streaming(unsigned int channel, unsigned int items_per_frame)
239   {
240     return d_impl->start_rx_streaming(channel, items_per_frame);
241   }
242   
243   bool
244   usrp2::rx_samples(unsigned int channel, rx_sample_handler *handler)
245   {
246     return d_impl->rx_samples(channel, handler);
247   }
248
249   bool
250   usrp2::stop_rx_streaming(unsigned int channel)
251   {
252     return d_impl->stop_rx_streaming(channel);
253   }
254
255   unsigned int
256   usrp2::rx_overruns()
257   {
258     return d_impl->rx_overruns();
259   }
260   
261   unsigned int
262   usrp2::rx_missing()
263   {
264     return d_impl->rx_missing();
265   }
266
267   // Transmit
268
269   bool 
270   usrp2::set_tx_gain(double gain)
271   {
272     return d_impl->set_tx_gain(gain);
273   }
274   
275   double
276   usrp2::tx_gain_min()
277   {
278     return d_impl->tx_gain_min();
279   }
280
281   double
282   usrp2::tx_gain_max()
283   {
284     return d_impl->tx_gain_max();
285   }
286
287   double
288   usrp2::tx_gain_db_per_step()
289   {
290     return d_impl->tx_gain_db_per_step();
291   }
292
293   bool
294   usrp2::set_tx_lo_offset(double frequency)
295   {
296     return d_impl->set_tx_lo_offset(frequency);
297   }
298
299   bool
300   usrp2::set_tx_center_freq(double frequency, tune_result *result)
301   {
302     return d_impl->set_tx_center_freq(frequency, result);
303   }
304   
305   double
306   usrp2::tx_freq_min()
307   {
308     return d_impl->tx_freq_min();
309   }
310
311   double
312   usrp2::tx_freq_max()
313   {
314     return d_impl->tx_freq_max();
315   }
316
317
318   bool
319   usrp2::set_tx_interp(int interpolation_factor)
320   {
321     return d_impl->set_tx_interp(interpolation_factor);
322   }
323   
324   int
325   usrp2::tx_interp()
326   {
327     return d_impl->tx_interp();
328   }
329
330   void
331   usrp2::default_tx_scale_iq(int interpolation_factor, int *scale_i, int *scale_q)
332   {
333     d_impl->default_tx_scale_iq(interpolation_factor, scale_i, scale_q);
334   }
335
336   bool
337   usrp2::set_tx_scale_iq(int scale_i, int scale_q)
338   {
339     return d_impl->set_tx_scale_iq(scale_i, scale_q);
340   }
341   
342   bool
343   usrp2::tx_32fc(unsigned int channel,
344                  const std::complex<float> *samples,
345                  size_t nsamples,
346                  const tx_metadata *metadata)
347   {
348     return d_impl->tx_32fc(channel, samples, nsamples, metadata);
349   }
350
351   bool
352   usrp2::tx_16sc(unsigned int channel,
353                  const std::complex<int16_t> *samples,
354                  size_t nsamples,
355                  const tx_metadata *metadata)
356   {
357     return d_impl->tx_16sc(channel, samples, nsamples, metadata);
358   }
359
360   bool
361   usrp2::tx_raw(unsigned int channel,
362                 const uint32_t *items,
363                 size_t nitems,
364                 const tx_metadata *metadata)
365   {
366     return d_impl->tx_raw(channel, items, nitems, metadata);
367   }
368
369   // miscellaneous methods
370
371   bool
372   usrp2::config_mimo(int flags)
373   {
374     return d_impl->config_mimo(flags);
375   }
376
377   bool
378   usrp2::fpga_master_clock_freq(long *freq)
379   {
380     return d_impl->fpga_master_clock_freq(freq);
381   }
382
383   bool
384   usrp2::adc_rate(long *rate)
385   {
386     return d_impl->adc_rate(rate);
387   }
388
389   bool
390   usrp2::dac_rate(long *rate)
391   {
392     return d_impl->dac_rate(rate);
393   }
394
395   bool
396   usrp2::tx_daughterboard_id(int *dbid)
397   {
398     return d_impl->tx_daughterboard_id(dbid);
399   }
400
401   bool
402   usrp2::rx_daughterboard_id(int *dbid)
403   {
404     return d_impl->rx_daughterboard_id(dbid);
405   }
406   
407
408   // low level methods
409
410   bool
411   usrp2::burn_mac_addr(const std::string &new_addr)
412   {
413     return d_impl->burn_mac_addr(new_addr);
414   }
415
416   bool
417   usrp2::sync_to_pps()
418   {
419     return d_impl->sync_to_pps();
420   }
421
422   bool
423   usrp2::sync_every_pps(bool enable)
424   {
425     return d_impl->sync_every_pps(enable);
426   }
427
428   std::vector<uint32_t>
429   usrp2::peek32(uint32_t addr, uint32_t words)
430   {
431     return d_impl->peek32(addr, words);
432   }
433
434   bool
435   usrp2::poke32(uint32_t addr, const std::vector<uint32_t> &data)
436   {
437     return d_impl->poke32(addr, data);
438   }
439
440   bool
441   usrp2::set_gpio_ddr(int bank, uint16_t value, uint16_t mask)
442   {
443     return d_impl->set_gpio_ddr(bank, value, mask);
444   }
445
446   bool
447   usrp2::set_gpio_sels(int bank, std::string src)
448   {
449     return d_impl->set_gpio_sels(bank, src);
450   }
451
452   bool
453   usrp2::write_gpio(int bank, uint16_t value, uint16_t mask)
454   {
455     return d_impl->write_gpio(bank, value, mask);
456   }
457
458   bool
459   usrp2::read_gpio(int bank, uint16_t *value)
460   {
461     return d_impl->read_gpio(bank, value);
462   }
463
464   bool
465   usrp2::enable_gpio_streaming(int bank, int enable)
466   {
467     return d_impl->enable_gpio_streaming(bank, enable);
468   }
469
470 } // namespace usrp2
471
472 std::ostream& operator<<(std::ostream &os, const usrp2::props &x)
473 {
474   os << x.addr;
475
476   char buf[128];
477   snprintf(buf, sizeof(buf)," hw_rev = 0x%04x", x.hw_rev);
478
479   os << buf;
480   return os;
481 }