Forum: GNU Radio USB Bulk Read Fails

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Ujala Q. (Guest)
on 2009-03-11 11:03
(Received via mailing list)
Hi,
I am trying to take samples from USRP in a C program. What I have done
in
order to perform this task is that I have manually taken out all the
functions from all the USRP cc and header files which will be used. I
have
followed the following code which is already available for Linux:

// Simple C++ USRP interfacing demonstration program
//
//
// This program was derived and modified from test_usrp_standard_rx.cc
/* -*- c++ -*- */
/*
* Copyright 2003,2006,2007,2008 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
Page 53 of 90
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* GNU Radio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "usrp_standard.h"
// Dumy Function to process USRP data
void process_data(int *buffer)
{
}
#define SAMPELS_PER_READ (512) // Must be a multiple of 128
int main (int argc, char **argv)
{
bool loopback_p = false;
bool counting_p = false;
bool width_8_p = false;
int which_board = 0;
int decim = 8; // 32 MB/sec
double center_freq = 0;
int fusb_block_size = 0;
int fusb_nblocks = 0;
int nchannels = 1;
int gain = 0;
int mode = 0;
int noverruns = 0;
bool overrun;
int total_reads = 10000;
int i;
int buf[SAMPELS_PER_READ];
int bufsize = SAMPELS_PER_READ*4;

if (loopback_p) mode |= usrp_standard_rx::FPGA_MODE_LOOPBACK;

if (counting_p) mode |= usrp_standard_rx::FPGA_MODE_COUNTING;

usrp_standard_rx *urx = usrp_standard_rx::make (which_board, decim, 1,
-1,
mode, fusb_block_size, fusb_nblocks);

if (urx == 0)
{
fprintf (stderr, "Error: usrp_standard_rx::make\n");
exit (1);
}

if (width_8_p)
{
int width = 8;
int shift = 8;
bool want_q = true;
if (!urx->set_format(usrp_standard_rx::make_format(width, shift,
want_q)))
{
fprintf (stderr, "Error: urx->set_format\n");
exit (1);
}
}
// Set DDC center frequency
urx->set_rx_freq (0, center_freq);
// Set Number of channels
urx->set_nchannels(1);
// Set ADC PGA gain
urx->set_pga(0,gain);
// Set FPGA Mux
urx->set_mux(0x32103210); // Board A only
// Set DDC decimation rate
urx->set_decim_rate(decim);
// Set DDC phase
urx->set_ddc_phase(0,0);

urx->start(); // Start data transfer

printf("USRP Transfer Started\n");
// Do USRP Samples Reading
for (i = 0; i < total_reads; i++)
{
urx->read(&buf, bufsize, &overrun);
if (overrun)
{
printf ("USRP Rx Overrun\n");
noverruns++;
}
// Do whatever you want with the data
process_data(&buf[0]);
}

urx->stop(); // Stop data transfer
printf("USRP Transfer Stoped\n");

delete urx;
return 0;
}

This is my own code written for Windows based on the above code:

#include "usb.h"
#include "usrp_spi_defs.h"
#include "usrp_commands.h"
#include "fpga_regs_standard.h"
#include "ad9862.h"
#include <stdio.h>
#include <math.h>

int d_first_read = 1;

/* the device's vendor and product id */
#define MY_VID 0xFFFE
#define MY_PID 0x0002

/* the device's endpoints */
#define EP_IN 6
#define EP_OUT 0x01

#define SAMPELS_PER_READ (512) // Must be a multiple of 128
#define USB_TIMEOUT (1000)

#define BUF_SIZE 64
#define MAX_CHAN 4
#define MAX_REGS 128

#define MAX_EP0_PKTSIZE 64
#define VRT_VENDOR_IN 0xC0
#define VRT_VENDOR_OUT 0x40

#define REG_RX_A 2   // bypass input buffer / RxPGA
#define REG_RX_B 3

const double POLLING_INTERVAL = 0.1;
double d_rx_freq[MAX_CHAN];
unsigned int d_fpga_shadows[MAX_REGS];
int d_verbose = 0;
struct usb_dev_handle *d_udh;
usb_dev_handle *udh;

int d_fpga_caps;
int d_nchan;
int d_tx_enable;
int d_hw_mux;
int d_sw_mux;
unsigned int d_decim_rate;
int d_usb_data_rate = 16000000;
int d_bytes_per_poll;
int d_rx_enable;

struct usb_device *myDev;

usb_dev_handle *open_dev(void);
unsigned int compute_freq_control_word_fpga(double, double, double *,
int);
int _write_fpga_reg (int regno, int value);
int set_rx_freq (int , double);

usb_dev_handle *open_dev(void)
{
  struct usb_bus *bus;
  struct usb_device *dev;

  for(bus = usb_get_busses(); bus; bus = bus->next)
    {
      for(dev = bus->devices; dev; dev = dev->next)
        {
          if(dev->descriptor.idVendor == MY_VID
             && dev->descriptor.idProduct == MY_PID)
            {
  myDev = dev;
              return usb_open(dev);
            }
        }
    }
  return NULL;
}

double rint(double x)
{
//middle value point test
if (ceil(x+0.5) == floor(x+0.5))
{
int a = (int)ceil(x);
if (a%2 == 0)
 {
return ceil(x);
}
 else
 {
return floor(x);
}
}
 else return floor(x+0.5);
}

static unsigned int compute_freq_control_word_fpga(double master_freq,
double target_freq, double *actual_freq, int verbose)
{
  static const int NBITS = 14;

  int v = rint (target_freq / master_freq * pow (2.0, 32.0));

  if (0)
    v = (v >> (32 - NBITS)) << (32 - NBITS); // keep only top NBITS

  *actual_freq = v * master_freq / pow (2.0, 32.0);

  if (verbose)
    fprintf (stderr,"compute_freq_control_word_fpga: target = %g  actual
=
%g  delta = %g\n",target_freq, *actual_freq, *actual_freq -
target_freq);

  return (unsigned int) v;
}

int usrp_hw_rev (struct usb_device *q)
{
  return q->descriptor.bcdDevice & 0x00FF;
}

static struct usb_device *dev_handle_to_dev (usb_dev_handle *udh)
{
  struct usb_dev_handle_kludge {
    int fd;
    struct usb_bus *bus;
    struct usb_device *device;
  };

  //return ((struct usb_dev_handle_kludge *) d_udh)->device;
  return myDev;
}

static int write_cmd (struct usb_dev_handle *udh, int request, int
value,
int index, unsigned char *bytes, int len)
{
  int requesttype = (request & 0x80) ? VRT_VENDOR_IN : VRT_VENDOR_OUT;

  int r = usb_control_msg (udh, requesttype, request, value, index,
   (char *) bytes, len, 1000);
  if (r < 0){
    // we get EPIPE if the firmware stalls the endpoint.
//    if (errno != EPIPE)
  //    fprintf (stderr, "usb_control_msg failed: %s\n", usb_strerror
());
  }

  return r;
}

int usrp_spi_write (struct usb_dev_handle *udh,
int optional_header, int enables, int format,
const void *buf, int len)
{
  if (len < 0 || len > MAX_EP0_PKTSIZE)
    return 0;

  return write_cmd (udh, VRQ_SPI_WRITE,
    optional_header,
    ((enables & 0xff) << 8) | (format & 0xff),
    (unsigned char *) buf, len) == len;
}

static int usrp1_fpga_write (struct usb_dev_handle *udh, int regno, int
value)
{
  // on the rev1 usrp, we use the generic spi_write interface

  unsigned char buf[4];

  buf[0] = (value >> 24) & 0xff; // MSB first
  buf[1] = (value >> 16) & 0xff;
  buf[2] = (value >>  8) & 0xff;
  buf[3] = (value >>  0) & 0xff;

  return usrp_spi_write (udh, 0x00 | (regno &
0x7f),SPI_ENABLE_FPGA,SPI_FMT_MSB | SPI_FMT_HDR_1,&buf, sizeof (buf));
}

int usrp_write_fpga_reg (struct usb_dev_handle *udh, int reg, int value)
{
  switch (usrp_hw_rev (dev_handle_to_dev (udh))){
  case 0: // not supported ;)
    abort();

  default:
    return usrp1_fpga_write (udh, reg, value);
  }
}

int _write_fpga_reg (int regno, int value)
{
  if (d_verbose){
    fprintf (stdout, "_write_fpga_reg(%3d, 0x%08x)\n", regno, value);
    fflush (stdout);
  }

  if (regno >= 0 && regno < MAX_REGS)
    d_fpga_shadows[regno] = value;

  return usrp_write_fpga_reg (d_udh, regno, value);
}

long  fpga_master_clock_freq ()
{
return 64000000;
}

long converter_rate()
{
  return fpga_master_clock_freq();
}

long adc_rate()  { return converter_rate(); }

int set_rx_freq (int channel, double freq)
{
unsigned int v;
 if (channel < 0 || channel > MAX_CHAN)
return 0;
 v = compute_freq_control_word_fpga (adc_rate(),freq,
&d_rx_freq[channel],
d_verbose);

  return _write_fpga_reg (FR_RX_FREQ_0 + channel, v);
}

//
------------------------------------------------------------------------------------------------------------------------------

int tx_enable () { return d_tx_enable; }

static int usrp_set_switch (struct usb_dev_handle *udh, int cmd_byte,
int
on)
{
return write_cmd (udh, cmd_byte, on, 0, 0, 0) == 0;
}

int usrp_set_fpga_tx_enable (struct usb_dev_handle *udh, int on)
{
return usrp_set_switch (udh, VRQ_FPGA_SET_TX_ENABLE, on);
}

int set_tx_enable (int on)
{
  d_tx_enable = on;
  // fprintf (stderr, "set_tx_enable %d\n", on);
  return usrp_set_fpga_tx_enable (d_udh, on);
}

int disable_tx ()
{
int enabled = tx_enable ();
 if (enabled)
set_tx_enable (0);
 return enabled;
}

void restore_tx (int on)
{
if (on != tx_enable ())
set_tx_enable (on);
}

int write_hw_mux_reg ()
{
int s = disable_tx ();
int ok = _write_fpga_reg (FR_TX_MUX, d_hw_mux | d_nchan);
restore_tx (s);
return ok;
}

int nddcs()
{
return (d_fpga_caps & bmFR_RB_CAPS_NDDC_MASK) >>
bmFR_RB_CAPS_NDDC_SHIFT;
}

int set_nchannels (int nchan)
{
  if (!(nchan == 1 || nchan == 2 || nchan == 4))
    return 0;

  if (nchan > nddcs())
    return 0;

  d_nchan = nchan;

  return write_hw_mux_reg ();
}

//--------------------------------------------------------------------------------------------------------------------------------
int usrp_spi_read (struct usb_dev_handle *udh,
               int optional_header, int enables, int format,
               void *buf, int len)
{
  if (len < 0 || len > MAX_EP0_PKTSIZE)
    return 0;

  return write_cmd (udh, VRQ_SPI_READ,
                    optional_header,
                    ((enables & 0xff) << 8) | (format & 0xff),
                    (unsigned char *) buf, len) == len;
}

int usrp_9862_read (struct usb_dev_handle *udh, int which_codec,int
regno,
unsigned char *value)
{
  return usrp_spi_read (udh, 0x80 | (regno & 0x3f),which_codec == 0 ?
SPI_ENABLE_CODEC_A : SPI_ENABLE_CODEC_B,
                        SPI_FMT_MSB | SPI_FMT_HDR_1,
                        value, 1);
}

const int _read_9862 (int which_codec, int regno, unsigned char *value)
{
  return usrp_9862_read (d_udh, which_codec, regno, value);
}


int usrp_9862_write (struct usb_dev_handle *udh, int which_codec, int
regno,
int value)
{
unsigned char buf[1];
  if (0)
    fprintf (stderr, "usrp_9862_write which = %d, reg = %2d, val = %3d
(0x%02x)\n",which_codec, regno, value, value);


  buf[0] = value;

  return usrp_spi_write (udh, 0x00 | (regno & 0x3f),
                         which_codec == 0 ? SPI_ENABLE_CODEC_A :
SPI_ENABLE_CODEC_B,
                         SPI_FMT_MSB | SPI_FMT_HDR_1,
                         buf, 1);
}

int _write_9862 (int which_codec, int regno, unsigned char value)
{
  if (0 && d_verbose){
    // FIXME really want to enable logging in usrp_prims:usrp_9862_write
    fprintf(stdout, "_write_9862(codec = %d, regno = %2d, val =
0x%02x)\n",
which_codec, regno, value);
    fflush(stdout);
  }
  return usrp_9862_write (d_udh, which_codec, regno, value);
}

double pga_min () { return 0.0; }

double pga_db_per_step ()  { return 20.0 / 20; }

int set_pga (int which, double gain)
{
int codec;
int reg;
char cur_rx;
int int_gain;
 if (which < 0 || which > 3)
return 0;
 //gain = std::max (pga_min (), gain);
//gain = std::min (pga_max (), gain);
 codec = which >> 1;
reg = (which & 1) == 0 ? REG_RX_A : REG_RX_B;
 // read current value to get input buffer bypass flag.
 //unsigned
 if (!_read_9862 (codec, reg, &cur_rx))
return 0;

   int_gain = (int) rint ((gain - pga_min ()) / pga_db_per_step());

  cur_rx = (cur_rx & RX_X_BYPASS_INPUT_BUFFER) | (int_gain & 0x7f);
  return _write_9862 (codec, reg, cur_rx);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int map_sw_mux_to_hw_mux (int sw_mux, int *hw_mux_ptr)
{
  // confirm that all I's are either 0,1,2,3
int i;
int q_and ;
int q_or ;
  for ( i = 0; i < 8; i += 2){
    int t = (sw_mux >> (4 * i)) & 0xf;
    if (!(0 <= t && t <= 3))
      return 0;
  }
  // confirm that all Q's are either 0,1,2,3 or 0xf
  for ( i = 1; i < 8; i += 2){
    int t = (sw_mux >> (4 * i)) & 0xf;
    if (!(t == 0xf || (0 <= t && t <= 3)))
      return 0;
  }
  // confirm that all Q inputs are 0xf (const zero input),
  // or none of them are 0xf
   q_and = 1;
   q_or =  0;
  for ( i = 0; i < 4; i++){
    int qx_is_0xf = ((sw_mux >> (8 * i + 4)) & 0xf) == 0xf;
    q_and &= qx_is_0xf;
    q_or  |= qx_is_0xf;
  }
  if (q_and || !q_or){          // OK
    int hw_mux_value = 0;
    for (i = 0; i < 8; i++){
      int t = (sw_mux >> (4 * i)) & 0x3;
      hw_mux_value |= t << (2 * i + 4);
    }
    if (q_and)
      hw_mux_value |= 0x8;      // all Q's zero
    *hw_mux_ptr = hw_mux_value;
    return 1;
  }
  else
    return 0;
}




int set_mux (int mux)
{
  if (!map_sw_mux_to_hw_mux (mux, &d_hw_mux))
    return 0;
  // fprintf (stderr, "sw_mux = 0x%08x  hw_mux = 0x%08x\n", mux,
d_hw_mux);
  d_sw_mux = mux;
  return write_hw_mux_reg ();
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int rx_enable () { return d_rx_enable; }

int usrp_set_fpga_rx_enable (struct usb_dev_handle *udh, int on)
{
  return usrp_set_switch (udh, VRQ_FPGA_SET_RX_ENABLE, on);
}

int set_rx_enable (int on)
{
  d_rx_enable = on;
  return usrp_set_fpga_rx_enable (d_udh, on);
}

int has_rx_halfband()
{
  return (d_fpga_caps & bmFR_RB_CAPS_RX_HAS_HALFBAND) ? 1 : 0;
}

void set_usb_data_rate (int usb_data_rate)
{
d_usb_data_rate = usb_data_rate;
d_bytes_per_poll = (int) (usb_data_rate * POLLING_INTERVAL);
}

int nchannels () { return d_nchan; }

int disable_rx ()
{
int enabled = rx_enable ();
if (enabled)
set_rx_enable (0);
return enabled;
}

void restore_rx (int on)
{
  if (on != rx_enable ())
    set_rx_enable (on);
}

int set_decim_rate(unsigned int rate)
{
int s;
int v;
int ok;

  if (has_rx_halfband()){
    if ((rate & 0x1) || rate < 4 || rate > 256){
      fprintf (stderr, "usrp_standard_rx::set_decim_rate: rate must be
EVEN
and in [4, 256]\n");
      return 0;
    }
  }
  else {
    if (rate < 4 || rate > 128){
      fprintf (stderr, "usrp_standard_rx::set_decim_rate: rate must be
in
[4, 128]\n");
      return 0;
    }
  }

  d_decim_rate = rate;
  set_usb_data_rate ((adc_rate () / rate * nchannels ())
     * (2 * sizeof (short)));

  s = disable_rx ();
  v = has_rx_halfband() ? d_decim_rate/2 - 1 : d_decim_rate - 1;
  ok = _write_fpga_reg (FR_DECIM_RATE, v);
  restore_rx (s);
  return ok;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int set_ddc_phase(int channel, int phase)
{

if (channel < 0 || channel >= MAX_CHAN)
    return 0;
  return _write_fpga_reg(FR_RX_PHASE_0 + channel, phase);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int start ()
{
  if (!start ())
    return 0;
  // add our code here
  return 1;
}

int stop (){
  int ok ;
  ok= stop ();  // add our code here
  return ok;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int fusb_generic_read (void *buffer, int nbytes)
{
/*if (!d_started)       // doesn't matter here, but keeps semantics
constant
return -1;

if (!d_input_p)
return -1;
*/

if(usb_bulk_read(d_udh,0|EP_IN, (char *) buffer, nbytes,
             USB_TIMEOUT))
    {
      printf("error: bulk read failed\n");
    }
else
if(usb_bulk_read(d_udh, EP_IN, (char *) buffer, nbytes, USB_TIMEOUT)
    {
      printf("error: bulk read failed\n");
      return;
    }

else
return usb_bulk_read (d_udh, EP_IN, (char *) buffer, nbytes,
             USB_TIMEOUT);
}

int read (void *buf, int len, int *overrun)
{
  int r;
  int bogus_overrun;
  int d_bytes_seen = 0;

  if (overrun)
    *overrun = 0;

  if (len < 0 || (len % 512) != 0){
    fprintf (stderr, "read: invalid length = %d\n", len);
    return -1;
  }

  r = fusb_generic_read (buf, len);
  if (r > 0)
    d_bytes_seen += r;

  /*
   * In many cases, the FPGA reports an rx overrun right after we
   * enable the Rx path.  If this is our first read, check for the
   * overrun to clear the condition, then ignore the result.
   */
/*  if (0 && d_first_read){ // FIXME
    d_first_read = 0;
    usrp_check_rx_overrun (d_udh, &bogus_overrun);
  }

  if (overrun != 0 && d_bytes_seen >= d_bytes_per_poll){
    d_bytes_seen = 0;
    if (!usrp_check_rx_overrun (d_udh, overrun)){
      fprintf (stderr, "usrp_basic_rx: usrp_check_rx_overrun failed\n");
      usb_strerror ();
    }
  }
*/
  return r;
}


int main(void)
{
  usb_dev_handle *udh; /* the device handle */
  char tmp[BUF_SIZE];

  int a;
  int noverruns = 0;
  int overrun;
  int total_reads = 10000;
  int i;
  int buf[SAMPELS_PER_READ];
  int bufsize = sizeof(buf);
  char * tempBuf[4*SAMPELS_PER_READ];

  udh = d_udh;

  usb_init(); /* initialize the library */
  usb_find_busses(); /* find all busses */
  usb_find_devices(); /* find all connected devices */


  if(!(d_udh = open_dev()))
    {
      printf("error: device not found!\n");
      return 0;
    }

  if(usb_set_configuration(d_udh, 1) < 0)
    {
      printf("error: setting config 1 failed\n");
      usb_close(d_udh);
      return 0;
    }

  if(usb_claim_interface(d_udh, 0) < 0)
    {
      printf("error: claiming interface 0 failed\n");
      usb_close(d_udh);
      return 0;
    }


  set_rx_freq (0,0);

  set_nchannels (1);

  set_pga (0, 0);

  set_mux(0x32103210); // Board A only

  set_decim_rate(8);

  set_ddc_phase(0,0);

  printf("USRP Transfer Starts\n");


  // Do USRP Samples Reading
for (i = 0; i < 6; i++)
{
read(&buf, bufsize, &overrun);
if (overrun)
{
printf ("USRP Rx Overrun\n");
noverruns++;
}
// Do whatever you want with the data
 }


  printf("USRP Transfer Stopped\n");

  usb_release_interface(d_udh, 0);
  usb_close(d_udh);

  return 0;
}

However, bulk read fails with this code. Please can you tell me where I
am
going wrong?
This topic is locked and can not be replied to.