Posted by & filed under bladeRF.

 

We have just released the 2014.11-rc3 release candidate, which introduces some new features and important fixes. The Windows installer and Ubuntu PPA will be updated over the course of the next week.

As the name implies, we pushed the official first release to the end of November because we felt that it was important to spend the extra time addressing some of the various issues that cropped up. While there are still some issues to investigate and resolve for the 2014.11 release, we are pleased with the results so far and hope you will be too! Below are some of the highlights. You can find more information at the release page on GitHub.
 

libbladeRF timestamp metadata support

One exciting update is the addition of timestamp metadata support in libbladeRF’s synchronous interface, via the added BLADERF_FORMAT_SC16_Q11_META format. When specifying this format to bladerf_sync_config(), you can now use the bladerf_sync_rx() and bladerf_sync_tx()in very much the same way that you have previously. However, with this format, you now may pass a pointer to a bladerf_metadata structure to:

  • Retrieve the timestamp associated with received samples.
  • Specify a timestamp at which you would like to receive samples. The bladerf_sync_rx() function will block until the desired timestamp has occurred, the specified timeout has elapsed, or an error has occured.
  • Detect RX overruns via the BLADERF_META_STATUS_OVERRUN bit in the bladerf_metadata.status field.
  • Transmit bursts of samples immediately or at the specified time. Zeros will be transmitted up to and after the burst.

Some example usages of these new features are included in the libbladeRF/doc/examples directory. Snippets from these examples are included in Synchronous data transmission and reception section of the Doxygen-generated API documentation. Additional information about the sample formats and the bladerf_metadata structure may be found here.

A huge thank you goes out to Ryan Tucker for developing, hosting, and maintaining the bladeRF Automatic Build-O-Matic, which kindly generates nightly builds of firmware, FPGA images, and the documentation linked above.
 

libbladeRF CyUSB3/CyAPI-based backend

A Windows-specific libbladeRF backend that sits atop the Cypress CyUSB3 driver and CyAPI DLL has been introduced. Initial results have shown that this performs very nicely, and it has been reported to work well on some systems/USB 3 controllers that were exhibiting issues with the libusb-based backend implementation.

As this is still a bit experimental, this support must be built from source, and requires the Cypress FX3 SDK. After installing the SDK and running a clean CMake configuration, the SDK location will be detected and support for this new libbladeRF backend will become enabled. When building support for this new backend, the necessary driver files are copied from the SDK into the bladeRF build’s output directory, for convenience.

Note that it is possible to have both the libusb and Cypress backends enabled in libbladeRF; this allows you to switch between them by replacing the driver associated with the bladeRF. In fact, you could have two devices operating simultaneously — one with the libusb backend, and another with the Cypress backend. For example, you could run an instance of the bladeRF-cli for each device:

> bladeRF-cli -p

  Backend:        libusb
  Serial:         xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  USB Bus:        3
  USB Address:    4

  Backend:        CyUSB driver
  Serial:         yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
  USB Bus:        0
  USB Address:    6

> bladeRF-cli -i -d "libusb:serial=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
bladeRF> info

  Serial #:                 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  VCTCXO DAC calibration:   0x87e0
  FPGA size:                40 KLE
  FPGA loaded:              yes
  USB bus:                  3
  USB address:              4
  USB speed:                SuperSpeed
  Backend:                  libusb
  Instance:                 0

... In another console ...

> bladeRF-cli -i -d "cypress:serial=yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
bladeRF> info

  Serial #:                 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
  VCTCXO DAC calibration:   0x8da0
  FPGA size:                115 KLE
  FPGA loaded:              yes
  USB bus:                  0
  USB address:              6
  USB speed:                SuperSpeed
  Backend:                  CyUSB3 driver
  Instance:                 0

 
A better approach would be to specify the backend via the * wildcard, allowing libbladeRF to determine which backend is currently supporting the specified device: 

> bladeRF-cli -i -d '*:serial=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
...
> bladeRF-cli -i -d '*:serial=yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'

For a programatic way to open a specific device via its serial number, with any available backend, see the example in bladerf_open_with_devinfo() documentation.

We would love to hear about your experiences and any issues with this new USB backend. Once we have done some more testing and have gotten some more reports on it, we will look to make this an option in the Windows installer!
 

DC calibration fixes

We are happy to report that a handful of fixes have addressed some of the DC calibration errors that have been reported.

Specifically, a timing fix in the FPGA resolved some corrupted SPI reads from the LMS6002D’s registers, which often manifested itself as LMS DC calibration registers reading back as all 31’s in the bladeRF-cli. This timing fix has also allowed the SPI clock to be increased to 40 MHz.

By expanding some parameter ranges in the bladeRF-cli’s TX DC calibration algorithm, the error that reported invalid “m01” and “m23” values has been addressed.

Lastly, a libbladeRF change now ensures that the LMS6002D DC calibration registers are properly written to the device, using values from the calibration tables. This should alleviate the need to run a ‘cal lms’ command, despite having DC calibration tables already auto-loaded.
 

Thread safety in libbladeRF

In libbladeRF v0.16.2 and earlier, users were responsible for ensuring that…

  • …device control functions (e.g., bladerf_set_frequency()) were performed on a device by only one thread at a time.
  • …device control functions were not made on a device from stream callback functions associated with that same device.

However, some users reported that these guidelines were inconvenient, so as of libbladeRF v0.17.0, functions have been made thread-safe where applicable. So if you have a device lock implemented in your code, you should be able to remove this as of libbladeRF v0.17.0. Developers: note that you can run the CMake configuration with -DCMAKE_BUILD_TYPE=Debug -DENABLE_LOCK_CHECKS=Yes to enable some deadlock checks in the libbladeRF and bladeRF-cli code.
 

Toward the 2014.11 release and Onward

Between now and the end of November 2014, our efforts are going to focus on resolving remaining bugs and developing/improving documentation. We are striving for the 2014.11 release to be a stable point in the codebase that application developers and package maintainers can target support for.

As such, new features an major changes will be scheduled for inclusion after this release. (We may stage such additions in a master-next branch, if there is need.) At this time, we have no further plans to introduce any backwards-incompatible API changes. If there is ever a need to do so, it will be after the 2014.11 release, and the major version number on the relevant component(s) will be incremented to denote this.

Once reaching a relatively stable point with the aforementioned release, we will be looking to focus efforts on some developing some fun and interesting projects and tutorials. Suggestions on this are always welcome; feel free to discuss desired topics on the forums or the #bladeRF channel on Freenode.

 

Thank you!

Being my first blog post, I just wanted to take the opportunity to thank everyone in the community for their contributions, support, feedback, comments, questions, and reporting of issues (which is very helpful). It has been really inspiring to see folks with a shared passion and enthusiasm for SDRs collaborate and exchange knowledge. I’m very thankful for the opportunity to be a part of this project, and am greatly looking forward to the journey ahead!

– Jon (jynik)

Posted by & filed under bladeRF.

 

After weeks of development and testing the new Windows installer is finally ready for release. The installer will now install everything from compiled libbladeRF, and drivers to MATLAB and Simulink support. There is now detailed step by step guide available.

 

The first thing I use the MATLAB integration for was to observe the effects of channel fading and shadowing on the transmission of a keyless entry system (that belongs to me).

 

It’s interesting to see what a few simple strides will do to the characteristics of an RF transmission.

 

Lastly, fellow Simulink users, we now have stable bladeRF source and sink blocks.

Posted by & filed under bladeRF.

 

As the title implies we’re going to DEFCON! We’ll have a booth again this year, so come check us out in the vendor area.

In honor of going to DEFCON, we would like to announce our the bladeRF SDR challenge which we will be hosting at our booth. As the following code snippets imply, winners will be award prizes.

bladeRF SDR challenge

 

Bob communicates a message to Alice every 3 minutes. Bob uses these messages to authenticate himself to Alice (via a mutually agreed upon PRN) and instruct Alice who she should send prizes to.

The message is a FSK modulate and Manchester encoded. Bob’s messages contain a packet ID and a pseudo random number (PRN), that is used to validate the authenticity of the packet. By ignoring any repeated packet ID and PRN pairs, Alice is able to protect against replay attacks. Both Alice and Bob have the same PRN generator so Alice knows what to expect from Bob. If the ID and PRN pairs match what Alice is expecting, and the prize field is non-zero, Alice will declare a winner and automatically award a prize.

The challenge lies in assuming the position of Eve and figuring out a way to use the modulation and/or coding scheme to come up with a way of leveraging Bob’s packet to trick Alice.

NOTE: Do not try bruteforcing the PRN, srand() will have a different seed at DEFCON.

 

Alice – the message receiving, prize dispensing program

#include <libbladeRF.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
 
#define NUM_SAMPLES (512)
 
#define NUM_XFERS 1
 
struct bladerf *dev = NULL ;
int16_t rx_samples[2*2*NUM_SAMPLES] ;
 
/***************************************************************************/
/* Moving average functions                                                */
/***************************************************************************/
 
struct ma {
    int num;
    int idx;
    int total;
    int *samps;
};
 
void ma_clear(struct ma *ma) {
    memset(ma->samps, 0, sizeof(int) * ma->num);
    ma->idx = 0;
    ma->total = 0;
}
 
int ma_create(struct ma *ma) {
    ma->samps = (int *)malloc(sizeof(int) * ma->num);
    if (ma->samps == NULL)
        return 1;
    ma_clear(ma);
 
    return 0;
}
 
int g = 0;
int moving_avg(struct ma *ma, int sample) {
    ma->total -= ma->samps[ma->idx];
    ma->samps[ma->idx] = sample;
    ma->idx++;
    ma->idx %= ma->num;
    ma->total += sample;
    return ma->total/ma->num;
}
 
/***************************************************************************/
/* Packet deserialization functions                                        */
/***************************************************************************/
 
void deserialize(unsigned char *ptr, char *ser_buf, int len) {
    int i, j, p;
    p = 0;
    len /= 8;
    for (i = 0; i < len; i++) {
        ptr[i] = 0;
        for (j = 0; j < 8; j++) {
            ptr[i] |= ((ser_buf[p++] == '1' ? 1 : 0) << (7 - j));
        }
    }
    ptr[i] = 0;
}
 
struct packet {
    unsigned int preamble;
    unsigned int id;
    unsigned int prn;
#define PRIZE_NONE    0
#define PRIZE_PAYPAL  1
#define PRIZE_BITCOIN 2
    int prize;
    char recipient[40];
};
 
#define PACKET_SZ sizeof(struct packet)
 
/***************************************************************************/
/* Packet decoding and modulation functions                                */
/***************************************************************************/
 
char demod[1000];
char demanchester[500];
unsigned int pkt_id = 0;
unsigned int pkt_prn = 0;
unsigned int victory_time = 0;
void analyze() {
    struct packet pkt;
    int len;
    int i, j;
    int word;
    int good;
 
    len = strlen(demod);
    printf("len: %d\n", len);
    printf("raw: %s\n", demod);
 
    good = 1;
 
    printf("Manchester:\n");
    j = 0;
    for (i = 0; i < len; i+=2) {
        printf("%c%c", demod[i], (demod[i] == demod[i+1]) ? 'X' : '.');
        /* Manchester decoding found an error bit */
        if (demod[i] == demod[i+1])
            good = 0;
        demanchester[j++] = demod[i];
    }
    printf("\n");
 
    printf("Demanchester:\n");
    for (i = 0; i < len; i+=2) {
        printf("%c", demod[i]);
    }
    printf("\n");
 
    printf("Grouped binary:\n");
    for (i = 0; i < len; i+=2) {
        if (((len - i) % 16) == 0) printf(" ");
        printf("%c", demod[i]);
    }
    printf("\n");
 
    printf("Grouped binary in hex:\n");
    word = 0;
    for (i = 0; i < len; i+=2) {
        if (((len - i) % 16) == 0) {
            printf(" %.2x", word);
            word = 0;
        }
        word = (word<<1) | (demod[i] - '0');
    }
    printf("\n");
 
    /* The packet passed Manchester decoding, so deserialize it */
    if (good) {
        deserialize((unsigned char *)&pkt, demanchester, sizeof(pkt));
        /* Make sure no one is replaying a previous transmission */
        if (pkt.id == pkt_id && pkt.prn == pkt_prn) {
            /* Enforce 5 minutes between victories */
            if (victory_time + 5 * 60 < time(NULL)) {
                pkt_id++;
                pkt_prn = rand();
                if (pkt.prize != PRIZE_NONE) {
                    victory_time = time(NULL);
                    printf("WINNER! Good packet from Bob:");
                } else {
                    printf("Good packet received from Bob:");
                }
            } else {
                printf("Victory timer hasn't yet elapsed: ");
            }
            printf("id(%d) prn(%d) prize(%d) recipient(%s)\n",
                    pkt.id, pkt.prn, pkt.prize, pkt.recipient);
        }
    }
}
 
int main(int argc, char *argv[])
{
   int status;
   unsigned int actual;
   struct bladerf_rational_rate rational_actual, samplerate = { 0, 1500000, 1 } ;
 
   int lock, cnt;
   int i, j, idx, pwr, ma;
 
   int dc_i, dc_q;
 
   struct ma detect;
   struct ma phase;
   int falling;
   int sp;
   int done;
   int demodidx;
   float phi, prev_phi, dphi_dt;
 
 
   /* Increase verbosity */
   bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_DEBUG);
 
   /* Open the device */
   status = bladerf_open(&dev, "") ;
   if( status < 0 ) {
       fprintf( stderr, "bladerf_open() error: %s\n", bladerf_strerror(status) );
       goto close_device;
   }
 
   /* Set the frequency */
   status = bladerf_set_frequency(dev, BLADERF_MODULE_RX, 314500000) ;
   if( status < 0 ) {
       fprintf( stderr, "bladerf_set_frequency() RX error: %s\n", bladerf_strerror(status) );
       goto close_device;
   }
 
   /* Set the bandwidth */
   status = bladerf_set_bandwidth(dev, BLADERF_MODULE_RX, 1500000, &actual) ;
   if( status < 0 ) {
       fprintf( stderr, "bladerf_set_bandwidth() RX error: %s\n", bladerf_strerror(status) );
       goto close_device;
   }
 
   /* Set the samplerate */
 
   status = bladerf_set_rational_sample_rate(dev, BLADERF_MODULE_RX, &samplerate, &rational_actual) ;
   if( status < 0 ) {
       fprintf( stderr, "bladerf_set_sample_rate() RX error: %s\n", bladerf_strerror(status) );
       goto close_device;
   }
   bladerf_set_lna_gain(dev, BLADERF_LNA_GAIN_MAX);
   bladerf_set_rxvga1(dev, BLADERF_RXVGA1_GAIN_MAX);
   bladerf_set_rxvga2(dev, 6);
 
   /* Configure the sync stream */
   status = bladerf_sync_config(
       dev,
       BLADERF_MODULE_RX,
       BLADERF_FORMAT_SC16_Q11,
       128,
       2048,
       NUM_XFERS,
       2000);
   if( status < 0 ) {
       fprintf( stderr, "bladerf_sync_config() RX error: %s\n", bladerf_strerror(status) ) ;
   }
 
   status = bladerf_enable_module(dev, BLADERF_MODULE_RX, true) ;
   if( status < 0 ) {
       fprintf( stderr, "bladerf_enable_module() RX error: %s\n", bladerf_strerror(status) );
       goto close_device;
   }
 
 
   /* Determine DC offset to increase dynamic range and mitigate effects of DC offset */
   dc_i = dc_q = 0;
   status = bladerf_sync_rx(dev, (void *)rx_samples, NUM_SAMPLES, NULL, 1000);
   idx = 0;
   for (i = 0; i < NUM_SAMPLES; i++, idx+=2) {
       dc_i += rx_samples[idx];
       dc_q += rx_samples[idx+1];
   }
 
   dc_i /= NUM_SAMPLES;
   dc_q /= NUM_SAMPLES;
 
   /* Detection moving average is 100 samples long */
   detect.num = 100;
   ma_create(&detect);
   /* Demoulation moving average is 35 samples long */
   phase.num = 35;
   ma_create(&phase);
 
   cnt = 0;
 
   // prep the PRNG
   srand(0x1337BEEF);
   // skip ahead
   for (i = 0; i < 1337; i++)
       rand();
 
   pkt_prn = rand();
   lock=0;
   while(1) {
       status = bladerf_sync_rx(dev, (void *)rx_samples, NUM_SAMPLES, NULL, 1000);
       idx = 0;
       for (i = 0; i < NUM_SAMPLES; i++, idx += 2) {
           /* Account for DC offset */
           rx_samples[idx]   -= dc_i;
           rx_samples[idx+1] -= dc_q;
           cnt++;
 
           if (lock == 0) {
               /* Currently not receiving a packet, look for an signal whose
                * moving averaged energy goes abouve "10000" */
 
               /* the energy of the current sample || I + j * Q || is given by:
                * energy = sqrt(I * I + Q * Q) */
               ma = moving_avg(&detect, rx_samples[idx] * rx_samples[idx] + rx_samples[idx+1] * rx_samples[idx+1]);
 
               if (ma > 10000) {
                   /* Strong energy signal detected start looking for its
                    * falling edge then start demodulation */
                   prev_phi = 0;
 
                   /* Ensure that no other packet is accidentally decoded for
                    * another 350000 samples */
                   lock = 350000;
                   ma_clear(&detect);
                   ma_clear(&phase);
                   cnt = 0;
                   falling = 0;
                   done = 0;
                   demodidx = 0;
               }
           } else {
               lock--;
 
               /* If the packet has been decoded wait a few more samples to
                * ensure that ISI and transmitter anomalies don't accidentally
                * trigger another packet detection */
               if (done) continue;
 
               /* Find the angle of the IQ sample by computing tan^-1(I/Q) */
               phi = atan2f(rx_samples[idx], rx_samples[idx+1]);
 
               /* Unwind the phasor */
               dphi_dt = prev_phi - phi;
               if (dphi_dt < - M_PI)
                   dphi_dt += 2 * M_PI;
               else if (dphi_dt > M_PI)
                   dphi_dt -= 2 * M_PI;
               prev_phi = phi;
 
               ma = moving_avg(&phase, 1000 * dphi_dt);
 
               /* `falling` is used to find the falling edge of the first long
                * synchronization pulse */
               if (falling == 0 && ma < 2100 && cnt > 100) {
                   falling = 1;
                   /* the first symbol is sampled 187 samples after the falling 
                    * edge */
                   sp = 750/4;
               }
 
               if (falling) {
                   if (sp == 0) {
                       /* Demodulate 2000+/-100 radians/s as '1'
                        * demodulate 2200+/-100 radians/s as '0'
                        * detect anything else as an end of packet */
                       if (ma > 1900 && ma < 2100)
                           demod[demodidx++] = '1';
                       else if (ma > 2100 && ma < 2300)
                           demod[demodidx++] = '0';
                       else {
                           /* As previously described, the modem has detected an
                            * invalid symbol so it means the packet may have
                            * ended, so analyze the packet */
                           demod[demodidx++] = 0;
                           analyze();
                           done = 1;
                       }
 
                       /* Safety check */
                       if (demodidx >= 1000)
                           demodidx = 0;
 
                       /* Reload the sampling countdown variable */
                       sp = 750/2;
                   } else {
                       /* Continue counting down the sampling time variable */
                       sp--;
                   }
               }
 
           }
       }
   }
 
close_device:
   bladerf_close(dev) ;
   return status ;
}

Bob – the program responsible for sending authenticated messages to Alice every 5 minutes.

#include <libbladeRF.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <iso646.h>
 
#define NUM_SAMPLES (1024)
#define NUM_XFERS 1
 
void serialize(char *ser_buf, unsigned char *ptr, size_t len) {
    int i, j, p;
    p = 0;
    for (i = 0; i < len; i++) {
        for (j = 0; j < 8; j++) {
            ser_buf[p++] = '0' + ((ptr[i] >> (7 - j)) & 1);
        }
    }
    ser_buf[p] = 0;
}
 
struct bladerf *dev = NULL;
 
struct packet {
    unsigned int preamble;
    unsigned int id;
    unsigned int prn;
#define PRIZE_NONE    0
#define PRIZE_PAYPAL  1
#define PRIZE_BITCOIN 2
    int prize;
    char recipient[40];
};
 
#define PACKET_SZ sizeof(struct packet)
 
int send_pkt(struct packet *pkt) {
    float theta;
    int16_t *tx_samples;
    int num_tx_samps;
    int msg_len;
    int samp_idx;
    int status;
    int i, j;
    char msg[(PACKET_SZ * 16) + 1];
 
    msg_len = PACKET_SZ * 8;
 
    // convert from packed binary to ASCII binary representation
    serialize(msg, (unsigned char *)pkt, PACKET_SZ);
    printf("Pre-Machester: (%d) %s\n", (int)strlen(msg), msg);
 
    // do the manchester encoding
    for (i = (PACKET_SZ * 8) - 1; i >= 0; i--) {
        msg[2 * i] = msg[i];
        msg[2 * i + 1] = (msg[i] == '1') ? '0' : '1';
    }
    // message is now 2x as long!
    msg_len *= 2;
 
    // print out the machester encoded string
    msg[PACKET_SZ * 16] = 0;
    printf("Machester: (%d) %s\n", (int)strlen(msg), msg);
 
    // do the FSK modulation
    theta = 0;
    samp_idx = 0;
 
    num_tx_samps = (3500 + (msg_len * 750/2) + (NUM_SAMPLES - 1) ) & ~(NUM_SAMPLES - 1);
    tx_samples = (int16_t *)malloc(sizeof(int16_t) * 2 * num_tx_samps);
    memset(tx_samples, 0, sizeof(int16_t) * 2 * num_tx_samps);
 
    for (i = 0; i < 350 * 10; i++) {
        theta += 2200.0f/1500000.0f;
        tx_samples[samp_idx++] = 2000*sin(theta); // I sample
        tx_samples[samp_idx++] = 2000*cos(theta); // Q sample
    }
 
    for (i = 0; i < msg_len;  i++) {
        for (j = 0; j < (750/2); j++) {
            // do the actual modulation by figuring out the rate of change of
            // theta based on the bit
            theta += 2 * MP_I * (msg[i] == '1' ? 2200.0f : 2000.0f)/1.5e6f;
 
            tx_samples[samp_idx++] = sin(theta); // I sample
            tx_samples[samp_idx++] = cos(theta); // Q sample
 
            // sines and cosines are cyclic
            if (theta > 2 * M_PI)
                theta -= 2 * M_PI;
            if (theta < 2 * M_PI)
                theta += 2 * M_PI;
        }
    }
 
    status = bladerf_sync_tx(dev, (void *)tx_samples, num_tx_samps, NULL, 1000);
    free(tx_samples);
    return status;
}
 
int main(int argc, char *argv[])
{
    int status;
    unsigned int actual;
    struct bladerf_rational_rate rational_actual, samplerate = { 0, 1500000, 1 } ;
    struct packet pkt;
    int pkt_id, i;
 
    /* Increase verbosity */
    bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_DEBUG);
 
    /* Open the device */
    status = bladerf_open(&dev, NULL);
    if( status < 0 ) {
        fprintf( stderr, "bladerf_open() error: %s\n", bladerf_strerror(status) );
        goto close_device;
    }
 
    /* Set the frequency */
    status = bladerf_set_frequency(dev, BLADERF_MODULE_TX, 314500000) ;
    if( status < 0 ) {
        fprintf( stderr, "bladerf_set_frequency() RX error: %s\n", bladerf_strerror(status) );
        goto close_device;
    }
 
    /* Set the bandwidth */
    status = bladerf_set_bandwidth(dev, BLADERF_MODULE_TX, 1500000, &actual) ;
    if( status < 0 ) {
        fprintf( stderr, "bladerf_set_bandwidth() RX error: %s\n", bladerf_strerror(status) );
        goto close_device;
    }
 
    /* Set the samplerate */
    status = bladerf_set_rational_sample_rate(dev, BLADERF_MODULE_TX, &samplerate, &rational_actual) ;
    if( status < 0 ) {
        fprintf( stderr, "bladerf_set_sample_rate() RX error: %s\n", bladerf_strerror(status) );
        goto close_device;
    }
 
    /* Max out the gain */
    status = bladerf_set_txvga2(dev, BLADERF_TXVGA2_GAIN_MAX);
    if (status < 0)
        return status;
 
    status = bladerf_set_txvga1(dev, BLADERF_TXVGA1_GAIN_MAX);
    if (status < 0)
        return status;
 
    /* Configure the sync stream */
    status = bladerf_sync_config(
            dev,
            BLADERF_MODULE_TX,
            BLADERF_FORMAT_SC16_Q11,
            128,
            2048,
            NUM_XFERS,
            2000);
    if( status < 0 ) {
        fprintf( stderr, "bladerf_sync_config() RX error: %s\n", bladerf_strerror(status) ) ;
    }
 
    status = bladerf_enable_module(dev, BLADERF_MODULE_TX, true) ;
    if( status < 0 ) {
        fprintf( stderr, "bladerf_enable_module() RX error: %s\n", bladerf_strerror(status) );
        goto close_device;
    }
 
    // prep the PRNG
    srand(0x1337BEEF);
    // skip ahead
    for (i = 0; i < 1337; i++)
        rand();
 
    pkt_id = 0;
    while (1) {
        memset(&pkt, 0, sizeof(pkt));
        pkt.preamble = 0xffffffff;
        pkt.id = pkt_id++;
        pkt.prn = rand();
        pkt.prize = PRIZE_NONE;
 
        send_pkt(&pkt);
 
        sleep(3 * 60);
    }
 
close_device:
    bladerf_close(dev);
    return status;
}

Posted by & filed under bladeRF.

 

We are preparing for a stable release 1 at the end of summer. In preparation of this we are planning on releasing the first release candidate during the 4th of July weekend and the second sometime in late August. The lastest information can be found directly on out Github milestine tracker, https://github.com/Nuand/bladeRF/issues/milestones

The main oustanding ask for the feature release are:

  • Adding flexible timestamp support directly to the library
  • Finalizing XB-100 and XB-200 board support
  • Completing automated (IQ and DC) calibration for the LMS

The absolutely most important thing we want to accomplish with these upcoming releases is to create an SDR that can double as a calibrated high-quality test equipment.

Lastly, the cases are now in stock and we should be caught back up on the transverter backlog sometime in the last week of this month or so. Please ensure that if you have receuved an address verification address email from us that you respond to it; orders prior to March 2014 will recive this email. Please email us at bladef@nuand.com if you have any questions or concerns.

Posted by & filed under bladeRF.

 

After playing around with a few designs we decided to go with a screw fastened plastic injection molded design for the case.

 

sldprt

 

A few days later the SLA’d 3D printed cases arrived. A frosted material really didn’t have the same effect as the see-through material in our CAD program. However the prototype did verify that the mechanical design was correct.

 

20140213_202734 - Copy 20140213_205850 - Copy

Fast forward another 5 weeks and our first 10 cases arrived, along with pictures of the mold itself.

 

case1 mold

 

We decided to use a very dense (yet clear) Poly Carbonate material to ensure cases can withstand someone sitting on them. Plastic poses one potentially massive risk to any electronic device, which is the risk of electrostatic discharge (or ESD). To ensure this would not to be a problem with our cases, the PC is coated and post-processed at the factory to make it suitable for use as cases for electronic devices.

A sufficient amount of ESD testing was performed on a statistically sufficient number of cases, and even at 30kV ESD sparks the case and the bladeRF did not seem to have any problems. Every bladeRF’s SMA, SMB, USB3, and power jack were zapped numerous times, yet not a single bladeRF suffered any sort of damage. I guess those ESD diodes and packages we scattered around the board really pay off :).

ESD gun at USB connector

 

27 shocks at 30kV

 

27 ESD zaps against the RX SMA port and the surrounding area yet the thing is still able to see GSM basestations moments later.

Now that we have passed ESD testing, the order for the first batch of mass produced cases has been placed. We hope to have them in stock sometime in late June.

PS: This post was written in May but was accidentally not published until June.