static int rx_avg(struct bladerf *dev, int16_t *samples, int16_t *avg_i, int16_t *avg_q) { int status; int64_t accum_i, accum_q; unsigned int i; /* Flush out samples and read a buffer's worth of data */ for (i = 0; i < 2 * CAL_NUM_BUFS + 1; i++) { status = bladerf_sync_rx(dev, samples, CAL_BUF_LEN, NULL, CAL_TIMEOUT); if (status != 0) { return status; } } for (i = 0, accum_i = accum_q = 0; i < 2 * CAL_BUF_LEN; i += 2) { accum_i += samples[i]; accum_q += samples[i + 1]; } accum_i /= CAL_BUF_LEN; accum_q /= CAL_BUF_LEN; assert(accum_i < (1 << 12) && accum_i >= (-(1 << 12)) ); assert(accum_q < (1 << 12) && accum_i >= (-(1 << 12)) ); *avg_i = (int16_t) accum_i; *avg_q = (int16_t) accum_q; return 0; }
/* RX samples, retrying if the machine is struggling to keep up. */ static int rx_samples(struct bladerf *dev, int16_t *samples, unsigned int count, uint64_t *ts, uint64_t ts_inc) { int status = 0; struct bladerf_metadata meta; int retry = 0; const int max_retries = 10; bool overrun = true; memset(&meta, 0, sizeof(meta)); meta.timestamp = *ts; while (status == 0 && overrun && retry < max_retries) { meta.timestamp = *ts; status = bladerf_sync_rx(dev, samples, count, &meta, 2000); if (status == BLADERF_ERR_TIME_PAST) { status = bladerf_get_timestamp(dev, BLADERF_MODULE_RX, ts); if (status != 0) { return status; } else { *ts += 20 * ts_inc; retry++; status = 0; } } else if (status == 0) { overrun = (meta.flags & BLADERF_META_STATUS_OVERRUN) != 0; if (overrun) { *ts += count + ts_inc; retry++; } } else { return status; } } if (retry >= max_retries) { status = BLADERF_ERR_IO; } else if (status == 0) { *ts += count + ts_inc; } return status; }
int rf_blade_recv_with_time(void *h, void *data, uint32_t nsamples, bool blocking, time_t *secs, double *frac_secs) { rf_blade_handler_t *handler = (rf_blade_handler_t*) h; struct bladerf_metadata meta; int status; memset(&meta, 0, sizeof(meta)); meta.flags = BLADERF_META_FLAG_RX_NOW; if (2*nsamples > CONVERT_BUFFER_SIZE) { fprintf(stderr, "RX failed: nsamples exceeds buffer size (%d>%d)\n", nsamples, CONVERT_BUFFER_SIZE); return -1; } status = bladerf_sync_rx(handler->dev, handler->rx_buffer, nsamples, &meta, 2000); if (status) { fprintf(stderr, "RX failed: %s\n\n", bladerf_strerror(status)); return -1; } else if (meta.status & BLADERF_META_STATUS_OVERRUN) { if (blade_error_handler) { srslte_rf_error_t error; error.opt = meta.actual_count; error.type = SRSLTE_RF_ERROR_OVERFLOW; blade_error_handler(error); } else { fprintf(stderr, "Overrun detected in scheduled RX. " "%u valid samples were read.\n\n", meta.actual_count); } } timestamp_to_secs(handler->rx_rate, meta.timestamp, secs, frac_secs); srslte_vec_convert_if(handler->rx_buffer, data, 2048, 2*nsamples); return nsamples; }
// Fetch a bunch of samples from the device. bool BladeRFSource::get_samples(IQSampleVector *samples) { int res; std::vector<int16_t> buf(2*m_blockSize); if ((res = bladerf_sync_rx(m_this->m_dev, buf.data(), m_blockSize, 0, 10000)) < 0) { m_this->m_error = "bladerf_sync_rx failed"; return false; } samples->resize(m_blockSize); for (int i = 0; i < m_blockSize; i++) { int16_t re = buf[2*i]; int16_t im = buf[2*i+1]; (*samples)[i] = IQSample(re, im); } return true; }
int rx_avg_magnitude(struct bladerf *dev, int16_t *samples, int16_t dc_i, int16_t dc_q, float *avg_magnitude) { int status; unsigned int i; float var_i, var_q; status = set_tx_dc(dev, dc_i, dc_q); if (status != 0) { return status; } /* Flush out samples and read a buffer's worth of data */ for (i = 0; i < 2 * CAL_NUM_BUFS + 1; i++) { status = bladerf_sync_rx(dev, samples, CAL_BUF_LEN, NULL, CAL_TIMEOUT); if (status != 0) { return status; } } variance(samples, &var_i, &var_q); *avg_magnitude = (float) sqrt(var_i + var_q); return status; }
int sync_rx_example(struct bladerf *dev) { int status, ret; bool done = false; bool have_tx_data = false; /** [user_buffers] */ /* "User" samples buffers and their associated sizes, in units of samples. * Recall that one sample = two int16_t values. */ int16_t *rx_samples = NULL; int16_t *tx_samples = NULL; const unsigned int samples_len = 10000; /* May be any (reasonable) size */ /* Allocate a buffer to store received samples in */ rx_samples = malloc(samples_len * 2 * 1 * sizeof(int16_t)); if (rx_samples == NULL) { perror("malloc"); return BLADERF_ERR_MEM; } /* Allocate a buffer to prepare transmit data in */ tx_samples = malloc(samples_len * 2 * 1 * sizeof(int16_t)); if (tx_samples == NULL) { perror("malloc"); free(rx_samples); return BLADERF_ERR_MEM; } /** [user_buffers] */ /* Initialize synch interface on RX and TX */ status = init_sync(dev); if (status != 0) { goto out; } /** [enable_modules] */ status = bladerf_enable_module(dev, BLADERF_RX, true); if (status != 0) { fprintf(stderr, "Failed to enable RX: %s\n", bladerf_strerror(status)); goto out; } status = bladerf_enable_module(dev, BLADERF_TX, true); if (status != 0) { fprintf(stderr, "Failed to enable TX: %s\n", bladerf_strerror(status)); goto out; } /** [enable_modules] */ /** [rxtx_loop] */ while (status == 0 && !done) { /* Receive samples */ status = bladerf_sync_rx(dev, rx_samples, samples_len, NULL, 5000); if (status == 0) { /* Process these samples, and potentially produce a response * to transmit */ done = do_work(rx_samples, samples_len, &have_tx_data, tx_samples, samples_len); if (!done && have_tx_data) { /* Transmit a response */ status = bladerf_sync_tx(dev, tx_samples, samples_len, NULL, 5000); if (status != 0) { fprintf(stderr, "Failed to TX samples: %s\n", bladerf_strerror(status)); } } } else { fprintf(stderr, "Failed to RX samples: %s\n", bladerf_strerror(status)); } } if (status == 0) { /* Wait a few seconds for any remaining TX samples to finish * reaching the RF front-end */ usleep(2000000); } /** [rxtx_loop] */ out: ret = status; /** [disable_modules] */ /* Disable RX, shutting down our underlying RX stream */ status = bladerf_enable_module(dev, BLADERF_RX, false); if (status != 0) { fprintf(stderr, "Failed to disable RX: %s\n", bladerf_strerror(status)); } /* Disable TX, shutting down our underlying TX stream */ status = bladerf_enable_module(dev, BLADERF_TX, false); if (status != 0) { fprintf(stderr, "Failed to disable TX: %s\n", bladerf_strerror(status)); } /* Free up our resources */ free(rx_samples); free(tx_samples); /** [disable_modules] */ return ret; }
void *rx_task(void *args) { struct test *t = (struct test *) args; int16_t *samples; int status; unsigned int burst_num; struct bladerf_metadata meta; unsigned int idx; state curr_state, next_state; uint64_t burst_start, burst_end, burst_end_prev; bool stop; unsigned int transient_delay = 0; #if ENABLE_RX_FILE FILE *debug = fopen("debug.bin", "wb"); if (!debug) { perror("fopen"); } #endif samples = (int16_t*) malloc(2 * sizeof(samples[0]) * t->params->buf_size); if (samples == NULL) { perror("malloc"); return NULL; } idx = 0; status = 0; burst_num = 0; memset(&meta, 0, sizeof(meta)); meta.flags |= BLADERF_META_FLAG_RX_NOW; curr_state = GET_SAMPLES; next_state = FLUSH_INITIAL_SAMPLES; burst_start = burst_end = burst_end_prev = 0; stop = false; while (status == 0 && burst_num < t->num_bursts && !stop) { switch (curr_state) { case GET_SAMPLES: status = bladerf_sync_rx(t->dev, samples, t->params->buf_size, &meta, t->params->timeout_ms); if (status != 0) { fprintf(stderr, "RX failed in burst %-4u: %s\n", burst_num, bladerf_strerror(status)); } else if (meta.status & BLADERF_META_STATUS_OVERRUN) { fprintf(stderr, "Error: RX overrun detected.\n"); pthread_mutex_lock(&t->lock); t->stop = true; t->rx_ready = true; pthread_mutex_unlock(&t->lock); } else { /* printf("Read %-8u samples @ 0x%08"PRIx64" (%-8"PRIu64")\n", t->params->buf_size, meta.timestamp, meta.timestamp); */ #if ENABLE_RX_FILE fwrite(samples, 2 * sizeof(samples[0]), t->params->buf_size, debug); #endif } idx = 0; curr_state = next_state; break; case FLUSH_INITIAL_SAMPLES: { bool had_transient_spike = false; curr_state = GET_SAMPLES; next_state = FLUSH_INITIAL_SAMPLES; for (; idx < (2 * t->params->buf_size); idx += 2) { const uint32_t sig_pow = samples[idx] * samples[idx] + samples[idx + 1] * samples[idx + 1]; /* Keep flushing samples if we encounter any transient "ON" * samples prior to the TX task being started. */ if (sig_pow >= RX_POWER_THRESH) { had_transient_spike = true; fprintf(stderr, "Flushed an initial buffer due to a " "transient spike.\n"); break; } } if (had_transient_spike) { /* Reset transient delay counter */ transient_delay = 0; } else { transient_delay++; if (transient_delay == 10) { /* After 10 buffers of no transients, we've most likely * rid ourselves of any junk in the RX FIFOs and are * ready to start the test */ next_state = WAIT_FOR_BURST_START; pthread_mutex_lock(&t->lock); t->rx_ready = true; pthread_mutex_unlock(&t->lock); } } break; } case WAIT_FOR_BURST_START: for (; idx < (2 * t->params->buf_size); idx += 2) { const uint32_t sig_pow = samples[idx] * samples[idx] + samples[idx + 1] * samples[idx + 1]; if (sig_pow >= RX_POWER_THRESH) { burst_start = meta.timestamp + (idx / 2); burst_end_prev = burst_end; burst_end = 0; curr_state = WAIT_FOR_BURST_END; assert(burst_start > burst_end_prev); if (burst_num != 0) { const uint64_t gap = burst_start - burst_end_prev; uint64_t delta; if (gap > t->bursts[burst_num].gap) { delta = gap - t->bursts[burst_num].gap; } else { delta = t->bursts[burst_num].gap - gap; } if (delta > 1) { status = BLADERF_ERR_UNEXPECTED; fprintf(stderr, "Burst #%-4u Failed. " " Gap varied by %"PRIu64 " samples." " Expected=%-8"PRIu64 " rx'd=%-8"PRIu64"\n", burst_num + 1, delta, t->bursts[burst_num].gap, gap); } } break; } } /* Need to fetch more samples */ if (idx >= (2 * t->params->buf_size)) { next_state = curr_state; curr_state = GET_SAMPLES; } break; case WAIT_FOR_BURST_END: for (; idx < (2 * t->params->buf_size); idx += 2) { const uint32_t sig_pow = samples[idx] * samples[idx] + samples[idx + 1] * samples[idx + 1]; if (sig_pow < RX_POWER_THRESH) { uint64_t duration, delta; burst_end = meta.timestamp + (idx / 2); assert(burst_end > burst_start); duration = burst_end - burst_start; if (duration > t->bursts[burst_num].duration) { delta = duration - t->bursts[burst_num].duration; } else { delta = t->bursts[burst_num].duration - duration; } if (delta > 1) { status = BLADERF_ERR_UNEXPECTED; fprintf(stderr, "Burst #%-4u Failed. " "Duration varied by %"PRIu64" samples. " "Expected=%-8"PRIu64"rx'd=%-8"PRIu64"\n", burst_num + 1, delta, t->bursts[burst_num].duration, duration); } else { const uint64_t gap = (burst_num == 0) ? 0 : t->bursts[burst_num].gap; printf("Burst #%-4u Passed. gap=%-8"PRIu64 "duration=%-8"PRIu64"\n", burst_num + 1, gap, t->bursts[burst_num].duration); curr_state = WAIT_FOR_BURST_START; burst_num++; } break; } } /* Need to fetch more samples */ if (idx >= (2 * t->params->buf_size)) { next_state = curr_state; curr_state = GET_SAMPLES; } break; } pthread_mutex_lock(&t->lock); stop = t->stop; pthread_mutex_unlock(&t->lock); } free(samples); #if ENABLE_RX_FILE fclose(debug); #endif /* Ensure the TX side is signalled to stop, if it isn't already */ pthread_mutex_lock(&t->lock); t->stop = true; pthread_mutex_unlock(&t->lock); return NULL; }
static int run(struct bladerf *dev, struct app_params *p, int16_t *samples, const struct test_case *t) { int status, status_out; struct bladerf_metadata meta; uint64_t timestamp; unsigned int gap; uint32_t counter; uint64_t tscount_diff; unsigned int i; bool suppress_overrun_msg = false; unsigned int overruns = 0; bool prev_iter_overrun = false; /* Clear out metadata and request that we just received any available * samples, with the timestamp filled in for us */ memset(&meta, 0, sizeof(meta)); meta.flags = BLADERF_META_FLAG_RX_NOW; status = enable_counter_mode(dev, true); if (status != 0) { goto out; } status = perform_sync_init(dev, BLADERF_MODULE_RX, 0, p); if (status != 0) { goto out; } /* Initial read to get a starting timestamp, and counter value */ gap = get_gap(p, t); status = bladerf_sync_rx(dev, samples, gap, &meta, p->timeout_ms); if (status != 0) { fprintf(stderr, "Intial RX failed: %s\n", bladerf_strerror(status)); goto out; } counter = extract_counter_val((uint8_t*) samples); timestamp = meta.timestamp; assert(timestamp >= (uint64_t) counter); tscount_diff = timestamp - (uint64_t) counter; if (t->gap != 0) { printf("\nTest Case: Read size=%"PRIu64" samples, %u iterations\n", t->gap, t->iterations); } else { printf("\nTest Case: Random read size, %u iterations\n", t->iterations); } printf("--------------------------------------------------------\n"); assert((timestamp - tscount_diff) <= UINT32_MAX); status = check_data(samples, &meta, UINT64_MAX, (uint32_t) (timestamp - tscount_diff), meta.actual_count, &suppress_overrun_msg); if (status == DETECTED_OVERRUN) { overruns++; status = 0; } printf("Timestamp-counter diff: %"PRIu64"\n", tscount_diff); printf("Initial timestamp: 0x%016"PRIx64"\n", meta.timestamp); printf("Intital counter value: 0x%08"PRIx32"\n", counter); printf("Initial status: 0x%08"PRIu32"\n", meta.status); for (i = 0; i < t->iterations && status == 0; i++) { timestamp = meta.timestamp + gap; gap = get_gap(p, t); status = bladerf_sync_rx(dev, samples, gap, &meta, p->timeout_ms); if (status != 0) { fprintf(stderr, "RX %u failed: %s\n", i, bladerf_strerror(status)); goto out; } /* If an overrun occured on the previous iteration, we don't know what * the timestamp will actually be on this iteration. */ if (prev_iter_overrun) { timestamp = meta.timestamp; } status = check_data(samples, &meta, timestamp, (uint32_t) (timestamp - tscount_diff), gap, &suppress_overrun_msg); if (status == DETECTED_OVERRUN) { overruns++; status = 0; prev_iter_overrun = true; } } if (status != 0) { printf("Test failed due to errors.\n"); } else if (overruns != 0) { printf("Test failed due to %u overruns.\n", overruns); status = -1; } else { printf("Test passed.\n"); } out: status_out = bladerf_enable_module(dev, BLADERF_MODULE_RX, false); if (status_out != 0) { fprintf(stderr, "Failed to disable RX module: %s\n", bladerf_strerror(status)); } status = first_error(status, status_out); status_out = enable_counter_mode(dev, false); status = first_error(status, status_out); return status; }
/** [example_snippet] */ int sync_rx_example(struct bladerf *dev) { int status, ret; bool done = false; /* "User" samples buffers and their associated sizes, in units of samples. * Recall that one sample = two int16_t values. */ int16_t *rx_samples = NULL; int16_t *tx_samples = NULL; const unsigned int samples_len = 10000; /* May be any (reasonable) size */ /* These items configure the underlying asynch stream used by the sync * interface. The "buffer" here refers to those used internally by worker * threads, not the `samples` buffer above. */ const unsigned int num_buffers = 16; const unsigned int buffer_size = 8192; /* Must be a multiple of 1024 */ const unsigned int num_transfers = 8; const unsigned int timeout_ms = 3500; /* Allocate a buffer to store received samples in */ rx_samples = malloc(samples_len * 2 * sizeof(int16_t)); if (rx_samples == NULL) { perror("malloc"); return BLADERF_ERR_MEM; } /* Allocate a buffer to prepare transmit data in */ tx_samples = malloc(samples_len * 2 * sizeof(int16_t)); if (tx_samples == NULL) { perror("malloc"); free(rx_samples); return BLADERF_ERR_MEM; } /* Configure both the device's RX and TX modules for use with the synchronous * interface. SC16 Q11 samples *without* metadata are used. */ status = bladerf_sync_config(dev, BLADERF_MODULE_RX, BLADERF_FORMAT_SC16_Q11, num_buffers, buffer_size, num_transfers, timeout_ms); if (status != 0) { fprintf(stderr, "Failed to configure RX sync interface: %s\n", bladerf_strerror(status)); goto out; } status = bladerf_sync_config(dev, BLADERF_MODULE_TX, BLADERF_FORMAT_SC16_Q11, num_buffers, buffer_size, num_transfers, timeout_ms); if (status != 0) { fprintf(stderr, "Failed to configure TX sync interface: %s\n", bladerf_strerror(status)); goto out; } /* We must always enable the modules *after* calling bladerf_sync_config(), * and *before* attempting to RX or TX samples. */ status = bladerf_enable_module(dev, BLADERF_MODULE_RX, true); if (status != 0) { fprintf(stderr, "Failed to enable RX module: %s\n", bladerf_strerror(status)); goto out; } status = bladerf_enable_module(dev, BLADERF_MODULE_TX, true); if (status != 0) { fprintf(stderr, "Failed to enable RX module: %s\n", bladerf_strerror(status)); goto out; } /* Receive samples and do work on them and then transmit a response. * * Note we transmit more than `buffer_size` samples to ensure that our * samples are written to the FPGA. (The samples are sent when the * synchronous interface's internal buffer of `buffer_size` samples is * filled.) This is generally not nececssary if you are continuously * streaming TX data. Otherwise, you may need to zero-pad your TX data to * achieve this. */ while (status == 0 && !done) { status = bladerf_sync_rx(dev, rx_samples, samples_len, NULL, 5000); if (status == 0) { done = do_work(rx_samples, samples_len, tx_samples, samples_len); if (!done) { status = bladerf_sync_tx(dev, tx_samples, samples_len, NULL, 5000); if (status != 0) { fprintf(stderr, "Failed to TX samples: %s\n", bladerf_strerror(status)); } } } else { fprintf(stderr, "Failed to RX samples: %s\n", bladerf_strerror(status)); } } if (status == 0) { /* Wait a few seconds for any remaining TX samples to finish */ usleep(2000000); } out: ret = status; /* Disable RX module, shutting down our underlying RX stream */ status = bladerf_enable_module(dev, BLADERF_MODULE_RX, false); if (status != 0) { fprintf(stderr, "Failed to disable RX module: %s\n", bladerf_strerror(status)); } /* Disable TX module, shutting down our underlying TX stream */ status = bladerf_enable_module(dev, BLADERF_MODULE_TX, false); if (status != 0) { fprintf(stderr, "Failed to disable TX module: %s\n", bladerf_strerror(status)); } /* Free up our resources */ free(rx_samples); free(tx_samples); return ret; }