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.

Posted by & filed under bladeRF.

 

yatebts

 

For Immediate  Release

 

YateBTS developer Legba and bladeRF creator Nuand have announced a partnership to connect 3.5 billion people worldwide with no access to a mobile connection

 

Contact:  David Burgess, CEO of Legba, Inc.

 

Website:  leg.ba

 

Email:  office@leg.ba

 

(Apr 30, 2014 – NEW YORK ) – The partnership brings together Legba‘s YateBTS open source software for 2.5G networks with Nuand’s bladeRF software de ned radio platform, based on Lime Microsystems‘ fully programmable RF transceiver technology. This has resulted in the release of YateBTS 3.0 providing a complete end to end solution.

 

The software defined radio technology builds on proven military implementations and seeks to bring the technology into affordable public mobile networks for the 3.5 billion people who currently are without any wireless connectivity.

 

Key Facts:

  • The affordable bladeRF board has an entirely programmable FPGA and a large community of developers.  It uses Lime’s field programmable RF transceiver to deliver a simple, high performance and low cost software defined radio board.

 

  • The partnership among Legba, Nuand and Lime Microsystems proves traditional mobile networks can be expanded and made more affordable by innovative solutions.

 

Supporting Quotes

 

“This technology redefines the development and sales model with close partnership among silicon vendors, ODMs and software developers becoming the new way of building solutions. Our collaboration shows that innovative and cost optimised wireless networks could be implemented to provide mobile coverage to countless communities that is not economically viable using the existing solutions,” Ebrahim Bushehri, CEO of Lime Microsystems.

 

“I am happy to announce the collaboration with the creators of bladeRF – a low-cost, open source software defined radio – and with Lime Microsystems, the developers of the highly flexible field programmable RF chip. bladeRF’s features have allowed us to integrate and fully program it in our YateBTS products.” David Burgess, CEO of Legba, Inc.

 

“I am very pleased to announce that Nuand, Legba and Lime Microsystems have partnered in an endeavour which enables researchers and professionals to take advantage of bladeRF within the YateBTS products. Our shared philosophies have allowed us to deliver a mature solution for mobile operators.” Robert Ghilduta, CEO of Nuand, LLC

 

About  Legba and SS7Ware

 

Legba, Inc. (www.leg.ba) provides innovative infrastructure for mobile operators.

 

Nuand, LLC (www.nuand.com) developed a low-cost, open source USB 3.0 software defined radio platform.

 

Lime Microsystems (www.limemicro.com) specialises in field programmable RF (FPRF) transceiver ICs for the next generation of wireless broadband systems.

 

Legal Notices

 

YateBTS is a trademark of Legba, Inc. bladeRF is a trademark of Nuand, Inc.

 

===