Fix for simultaneous tx-rx using libusb_contexts
authorttsou <ttsou@vt.edu>
Tue, 25 Aug 2009 18:53:34 +0000 (14:53 -0400)
committerttsou <ttsou@vt.edu>
Tue, 15 Sep 2009 22:06:27 +0000 (18:06 -0400)
usrp/host/include/usrp/usrp_basic.h
usrp/host/include/usrp/usrp_prims.h
usrp/host/lib/fusb.h
usrp/host/lib/fusb_libusb1.cc
usrp/host/lib/fusb_libusb1.h
usrp/host/lib/fusb_sysconfig_libusb1.cc
usrp/host/lib/usrp_basic.cc
usrp/host/lib/usrp_prims.cc

index c79908a86574548cf473d25230838b4f05e2579c..2430ff5c4c32bd735e2dfd9a115b615506028381 100644 (file)
@@ -66,6 +66,7 @@ protected:
 
 protected:
   struct libusb_device_handle  *d_udh;
+  struct libusb_context                *d_ctx;
   int                           d_usb_data_rate;       // bytes/sec
   int                           d_bytes_per_poll;      // how often to poll for overruns
   bool                          d_verbose;
index df410b408db929f920ad35894615a9f2cfb71f92..05ad0046e5f6c966dfdddfebaf26c340acdc1d36 100644 (file)
@@ -43,12 +43,16 @@ enum usrp_load_status_t { ULS_ERROR = 0, ULS_OK, ULS_ALREADY_LOADED };
 
 struct libusb_device_handle;
 struct libusb_device;
+struct libusb_context;
 
 /*!
  * \brief initialize libusb; probe busses and devices.
- * Safe to call more than once.
+ * If new_context is set to true, initiate and returns new libusb_context.
+ * If new_context is set to false, intiate default context if not already
+ * initiated and return NULL. It is NOT safe to call more than once with
+ * new_context set to true since a new context is initiated each time.
  */
-void usrp_one_time_init ();
+libusb_context* usrp_one_time_init (bool new_context);
 
 /*
  * force a rescan of the buses and devices
@@ -65,7 +69,7 @@ void usrp_rescan ();
  *   configured USRP (firmware loaded)
  *   unconfigured Cypress FX2 (only if fx2_ok_p is true)
  */
-struct libusb_device *usrp_find_device (int nth, bool fx2_ok_p = false);
+struct libusb_device *usrp_find_device (int nth, bool fx2_ok_p = false, libusb_context *ctx = NULL);
 
 bool usrp_usrp_p (struct libusb_device *q);            //< is this a USRP
 bool usrp_usrp0_p (struct libusb_device *q);           //< is this a USRP Rev 0
@@ -119,7 +123,7 @@ usrp_load_firmware (struct libusb_device_handle *udh, const char *filename, bool
  * then rescans the busses and devices.
  */
 usrp_load_status_t
-usrp_load_firmware_nth (int nth, const char *filename, bool force);
+usrp_load_firmware_nth (int nth, const char *filename, bool force, libusb_context *ctx);
 
 /*!
  * \brief load fpga configuration bitstream
@@ -134,7 +138,8 @@ usrp_load_fpga (struct libusb_device_handle *udh, const char *filename, bool for
  */
 bool usrp_load_standard_bits (int nth, bool force,
                              const std::string fpga_filename = "",
-                             const std::string firmware_filename = "");
+                             const std::string firmware_filename = "",
+                             libusb_context *ctx = NULL);
 
 /*!
  * \brief copy the given \p hash into the USRP hash slot \p which.
index bfe34d5b881d572167dbf5ef783ebaa16d3d5292..fbd651204a5121a47890af1588f01a0d7b646093 100644 (file)
@@ -27,6 +27,7 @@
 
 
 struct  libusb_device_handle;
+struct         libusb_context;
 class   fusb_ephandle;
 
 /*!
@@ -116,7 +117,8 @@ public:
   /*!
    * \brief returns fusb_devhandle or throws if trouble
    */
-  static fusb_devhandle *make_devhandle (libusb_device_handle *udh);
+  static fusb_devhandle *make_devhandle (libusb_device_handle *udh,
+                                         libusb_context *ctx);
 
   /*!
    * \brief Returns max block size in bytes (hard limit).
index 07e05c2309411d265d686a30b8f9826599d017c5..0559022bbed5b862ca272096028eb929807e9353 100644 (file)
@@ -124,8 +124,9 @@ alloc_lut (fusb_ephandle_libusb1 *self, int buffer_length, int endpoint,
 //                             device handle
 // ------------------------------------------------------------------------
 
-fusb_devhandle_libusb1::fusb_devhandle_libusb1 (libusb_device_handle *udh)
-  : fusb_devhandle (udh), d_teardown (false)
+fusb_devhandle_libusb1::fusb_devhandle_libusb1 (libusb_device_handle *udh,
+                                                libusb_context *ctx)
+  : fusb_devhandle (udh), d_ctx (ctx), d_teardown (false)
 {
   // that's it 
 }
@@ -258,6 +259,24 @@ fusb_devhandle_libusb1::_cancel_lut (libusb_transfer *lut)
 
 }
 
+/*
+ * Reimplementing _reap for context use and compatibiliy with libusb-0.12.
+ * Returns false on error, true otherwise.
+ */
+
+bool
+fusb_devhandle_libusb1::_reap (bool ok_to_block_p)
+{
+  int ret;
+
+  if ((ret = libusb_handle_events(d_ctx)) < 0) {
+    fprintf (stderr, "fusb::_reap libusb_handle_events()\n");
+    return false;
+  }
+  
+  return true;
+}
+
 void
 fusb_devhandle_libusb1::_wait_for_completion ()
 {
@@ -267,17 +286,9 @@ fusb_devhandle_libusb1::_wait_for_completion ()
   tv.tv_sec = 1;
   tv.tv_usec =  0;
 
-  // The regular libusb_handle_events sets a hardcoded timeout of 2
-  // seconds. Most of these calls should be changed to appropriate block / non-
-  // blocking version using libusb_handle_events_timeout. This was just a test
-  // usage. 
-
-  while (!d_pending_rqsts.empty ()) {
-    if ((ret = libusb_handle_events_timeout(NULL, &tv)) < 0) {
-      fprintf (stderr, "fusb: libusb_handle_events error %d\n", ret);
-      break;
-    }
-  }
+  while (!d_pending_rqsts.empty ()) 
+    if (!_reap(true)) 
+      break; 
 
 }
 
@@ -346,7 +357,6 @@ fusb_ephandle_libusb1::~fusb_ephandle_libusb1 ()
 bool
 fusb_ephandle_libusb1::start ()
 {
-
   if (d_started)
     return true;
 
@@ -390,12 +400,7 @@ fusb_ephandle_libusb1::stop ()
   }
 
   d_devhandle->_cancel_pending_rqsts (this);
-
-  // Do work, reap transfers, etc. 
-  if (libusb_handle_events(NULL) < 0) { 
-    perror ("fusb::libusb_handle_events");
-    return false;
-  }
+  d_devhandle->_reap (false);
 
   while (1) {
     libusb_transfer *lut;
@@ -405,15 +410,13 @@ fusb_ephandle_libusb1::stop ()
     if (d_free_list.size () == (unsigned) d_nblocks)
       break;
 
-    if (libusb_handle_events(NULL) < 0) {
-      perror ("fusb::libusb_handle_events");
-      return false;
-    }
+    if (!d_devhandle->_reap(true))
+      break;
   }
 
   d_started = false;
-  return true;
 
+  return true;
 }
 
 // ------------------------------------------------------------------------
@@ -425,7 +428,6 @@ fusb_ephandle_libusb1::stop ()
 int
 fusb_ephandle_libusb1::write (const void *buffer, int nbytes)
 {
-
   if (!d_started)      // doesn't matter here, but keeps semantics constant
     return -1;
   
@@ -456,7 +458,7 @@ fusb_ephandle_libusb1::write (const void *buffer, int nbytes)
     d_write_work_in_progress = 0;
   }
 
-  return nbytes;
+  return n;
 }
 
 #else
@@ -515,8 +517,8 @@ fusb_ephandle_libusb1::get_write_work_in_progress ()
       return lut;
     }
 
-    // Do work, reap transfers, etc. 
-    libusb_handle_events(NULL);
+    if (!d_devhandle->_reap (true))
+      return 0;
   }
 }
 
@@ -603,10 +605,9 @@ fusb_ephandle_libusb1::reload_read_buffer ()
 
   while (1) {
 
-    while ((lut = completed_list_get ()) == 0 ) {
-      if (libusb_handle_events(NULL) < 0) 
-        fprintf (stderr, "fusb: libusb_handle_events\n");
-    }
+    while ((lut = completed_list_get ()) == 0 ) 
+      if (!d_devhandle->_reap(true))
+        return false; 
 
     if (lut->status != LIBUSB_TRANSFER_COMPLETED) {
       fprintf (stderr, "fust: (rd status %d) %s\n", lut->status, 
index 1661b7ab8a23d409f495244a984a5c6b85d1e967..4bc49aafbda8db3ef416f5768628044b71c93330 100644 (file)
@@ -27,6 +27,8 @@
 #include <list>
 
 struct libusb_transfer;
+struct libusb_context;
+
 class fusb_ephandle_libusb1;
 
 /*!
@@ -35,7 +37,8 @@ class fusb_ephandle_libusb1;
 class fusb_devhandle_libusb1 : public fusb_devhandle
 {
 private:
-  std::list<libusb_transfer*>  d_pending_rqsts;
+  std::list<libusb_transfer*>   d_pending_rqsts;
+  libusb_context               *d_ctx;
 
   void pending_add (struct libusb_transfer *lut);
   struct libusb_transfer * pending_get ();
@@ -44,7 +47,7 @@ private:
 
 public:
   // CREATORS
-  fusb_devhandle_libusb1 (libusb_device_handle *udh);
+  fusb_devhandle_libusb1 (libusb_device_handle *udh, libusb_context *ctx);
   virtual ~fusb_devhandle_libusb1 ();
 
   // MANIPULATORS
@@ -54,6 +57,7 @@ public:
   bool _submit_lut (libusb_transfer *);
   bool _cancel_lut (libusb_transfer *);
   void _cancel_pending_rqsts (fusb_ephandle_libusb1 *eph);
+  bool _reap (bool ok_to_block_p);
   void _wait_for_completion ();
 
   // accessors to work from callback context
index e0d9458e11f25739ce6acbf4d819054618c7d743..c82bfe9a166b34f6068ff4830c20fd05fa529793 100644 (file)
@@ -27,10 +27,12 @@ static const int MAX_BLOCK_SIZE = 16 * 1024;                // hard limit
 static const int DEFAULT_BLOCK_SIZE =   4 * 1024;
 static const int FUSB_BUFFER_SIZE = 2 * (1L << 20);    // 2 MB
 
+struct libusb_context;
+
 fusb_devhandle *
-fusb_sysconfig::make_devhandle (libusb_device_handle *udh)
+fusb_sysconfig::make_devhandle (libusb_device_handle *udh, libusb_context *ctx)
 {
-  return new fusb_devhandle_libusb1 (udh);
+  return new fusb_devhandle_libusb1 (udh, ctx);
 }
        
 int fusb_sysconfig::max_block_size ()
index a8b44edabb963b66fd8d4790bdb46a8d81ef1144..3a0368894ec392b0a37632add712cc51fb217916 100644 (file)
@@ -108,7 +108,7 @@ usrp_basic::usrp_basic (int which_board,
                        open_interface (struct libusb_device *dev),
                        const std::string fpga_filename,
                        const std::string firmware_filename)
-  : d_udh (0),
+  : d_udh (0), d_ctx (0),
     d_usb_data_rate (16000000),        // SWAG, see below
     d_bytes_per_poll ((int) (POLLING_INTERVAL * d_usb_data_rate)),
     d_verbose (false), d_fpga_master_clock_freq(64000000), d_db(2)
@@ -125,12 +125,12 @@ usrp_basic::usrp_basic (int which_board,
    */
   memset (d_fpga_shadows, 0, sizeof (d_fpga_shadows));
 
-  usrp_one_time_init ();
+  d_ctx = usrp_one_time_init(true);
 
-  if (!usrp_load_standard_bits (which_board, false, fpga_filename, firmware_filename))
+  if (!usrp_load_standard_bits (which_board, false, fpga_filename, firmware_filename, d_ctx))
     throw std::runtime_error ("usrp_basic/usrp_load_standard_bits");
 
-  struct libusb_device *dev = usrp_find_device (which_board);
+  struct libusb_device *dev = usrp_find_device (which_board, false, d_ctx);
   if (dev == 0){
     fprintf (stderr, "usrp_basic: can't find usrp[%d]\n", which_board);
     throw std::runtime_error ("usrp_basic/usrp_find_device");
@@ -153,6 +153,7 @@ usrp_basic::usrp_basic (int which_board,
 
   _write_fpga_reg (FR_MODE, 0);                // ensure we're in normal mode
   _write_fpga_reg (FR_DEBUG_EN, 0);    // disable debug outputs
+
 }
 
 void
@@ -175,12 +176,11 @@ usrp_basic::~usrp_basic ()
   if (d_udh)
     libusb_close (d_udh);
 
-  // There's no reference count on the number of times libusb is initialized.
-  // libusb_init can be called multiple times, but libusb_exit shuts down
-  // everything. Leave libusb running for now. Need to add a count so that it
-  // exits nicely. 
+  // Each object should be running in it's own context. If running in default
+  // (NULL) context then something went wrong. 
 
-  //libusb_exit (NULL);
+  assert (d_ctx != NULL);
+  libusb_exit (d_ctx);
 }
 
 void
@@ -819,7 +819,7 @@ usrp_basic_rx::usrp_basic_rx (int which_board, int fusb_block_size, int fusb_nbl
   if (fusb_nblocks == 0)
     fusb_nblocks = std::max (1, FUSB_BUFFER_SIZE / fusb_block_size);
 
-  d_devhandle = fusb_sysconfig::make_devhandle (d_udh);
+  d_devhandle = fusb_sysconfig::make_devhandle (d_udh, d_ctx);
   d_ephandle = d_devhandle->make_ephandle (USRP_RX_ENDPOINT, true,
                                           fusb_block_size, fusb_nblocks);
 
@@ -870,7 +870,7 @@ usrp_basic_rx::start ()
     fprintf (stderr, "usrp_basic_rx: set_rx_enable failed\n");
     return false;
   }
-  
   return true;
 }
 
@@ -1222,7 +1222,7 @@ usrp_basic_tx::usrp_basic_tx (int which_board, int fusb_block_size, int fusb_nbl
   if (fusb_nblocks == 0)
     fusb_nblocks = std::max (1, FUSB_BUFFER_SIZE / fusb_block_size);
 
-  d_devhandle = fusb_sysconfig::make_devhandle (d_udh);
+  d_devhandle = fusb_sysconfig::make_devhandle (d_udh, d_ctx);
   d_ephandle = d_devhandle->make_ephandle (USRP_TX_ENDPOINT, false,
                                           fusb_block_size, fusb_nblocks);
 
index e1e3e30747ef61e95d2fc6f3e12dd429b8696470..d651a4529704612ffc89c103e6668fbacaefe9ce 100644 (file)
@@ -103,15 +103,30 @@ get_proto_filename(const std::string user_filename, const char *env_var, const c
 
 static void power_down_9862s (struct libusb_device_handle *udh);
 
-void
-usrp_one_time_init ()
+libusb_context *
+usrp_one_time_init (bool new_context)
 {
+
   static bool first = true;
+  libusb_context *ctx = NULL;
+  int ret;
 
-  if (first){
+  // On first call create default context in addition to any new requested
+  // context. The default context is probably useless in this form, but keep
+  // it for now due to compatibility reasons.
+
+  if (first) {
     first = false;
-    libusb_init (NULL);                        // usb library init
+    if ((ret = libusb_init (NULL)) < 0)
+      fprintf (stderr, "usrp: libusb_init failed %i\n", ret);
   }
+
+  if (new_context) {
+    if ((ret = libusb_init (&ctx)) < 0)
+      fprintf (stderr, "usrp: libusb_init failed %i\n", ret);
+  }
+
+  return ctx;
 }
 
 void
@@ -204,16 +219,17 @@ usrp_configured_usrp_p (struct libusb_device *q)
 // ----------------------------------------------------------------
 
 struct libusb_device *
-usrp_find_device (int nth, bool fx2_ok_p)
+usrp_find_device (int nth, bool fx2_ok_p, libusb_context *ctx)
 {
   libusb_device **list;
 
   struct libusb_device *q;
   int   n_found = 0;
 
-  usrp_one_time_init ();
-  size_t cnt = libusb_get_device_list(NULL, &list);
+//usrp_one_time_init (false);
+  assert (ctx != NULL);
+
+  size_t cnt = libusb_get_device_list(ctx, &list);
   size_t i = 0;
 
   if (cnt < 0)
@@ -228,7 +244,12 @@ usrp_find_device (int nth, bool fx2_ok_p)
     }
   }
 
+/*
+ * The list needs to be freed. Right just release it if nothing is found.
+ */
+
   libusb_free_device_list(list, 1);
+
   return 0;    // not found
 }
 
@@ -727,9 +748,10 @@ usrp_load_fpga (struct libusb_device_handle *udh,
 }
 
 static libusb_device_handle *
-open_nth_cmd_interface (int nth)
+open_nth_cmd_interface (int nth, libusb_context *ctx)
 {
-  struct libusb_device *udev = usrp_find_device (nth);
+
+  struct libusb_device *udev = usrp_find_device (nth, false, ctx);
   if (udev == 0){
     fprintf (stderr, "usrp: failed to find usrp[%d]\n", nth);
     return 0;
@@ -777,8 +799,9 @@ mdelay (int millisecs)
 }
 
 usrp_load_status_t
-usrp_load_firmware_nth (int nth, const char *filename, bool force){
-  struct libusb_device_handle *udh = open_nth_cmd_interface (nth);
+usrp_load_firmware_nth (int nth, const char *filename, bool force, libusb_context *ctx)
+{
+  struct libusb_device_handle *udh = open_nth_cmd_interface (nth, ctx);
   if (udh == 0)
     return ULS_ERROR;
 
@@ -839,16 +862,19 @@ load_status_msg (usrp_load_status_t s, const char *type, const char *filename)
 bool
 usrp_load_standard_bits (int nth, bool force,
                         const std::string fpga_filename,
-                        const std::string firmware_filename)
+                        const std::string firmware_filename,
+                        libusb_context *ctx)
 {
   usrp_load_status_t   s;
   const char           *filename;
   const char           *proto_filename;
   int hw_rev;
 
+  assert (ctx != NULL);
+
   // first, figure out what hardware rev we're dealing with
   {
-    struct libusb_device *udev = usrp_find_device (nth);
+    struct libusb_device *udev = usrp_find_device (nth, false, ctx);
     if (udev == 0){
       fprintf (stderr, "usrp: failed to find usrp[%d]\n", nth);
       return false;
@@ -865,8 +891,7 @@ usrp_load_standard_bits (int nth, bool force,
     fprintf (stderr, "Can't find firmware: %s\n", proto_filename);
     return false;
   }
-
-  s = usrp_load_firmware_nth (nth, filename, force);
+  s = usrp_load_firmware_nth (nth, filename, force, ctx);
   load_status_msg (s, "firmware", filename);
 
   if (s == ULS_ERROR)
@@ -885,8 +910,7 @@ usrp_load_standard_bits (int nth, bool force,
     fprintf (stderr, "Can't find fpga bitstream: %s\n", proto_filename);
     return false;
   }
-
-  struct libusb_device_handle *udh = open_nth_cmd_interface (nth);
+  struct libusb_device_handle *udh = open_nth_cmd_interface (nth, ctx);
   if (udh == 0)
     return false;