Skip to content
Permalink
Fetching contributors…
Cannot retrieve contributors at this time
362 lines (303 sloc) 10.4 KB
/*
* This file is part of the bladeRF project:
* http://www.github.com/nuand/bladeRF
*
* Copyright (C) 2015 Nuand LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
* This program exercises the scheduled retune functionality added in
* FPGA v0.2.0.
*
* When configured for TX, it transmits a tone for 1ms every 10 ms. During the
* "off time" the device is scheduled to retune to a different frequency,
* per the list of frequencies provided to this program.
*
* When configured for RX, this program reads samples to a samples.bin file.
*
* The "hop set" file should be a newline-delimited list of frequencies.
* The M or G suffixes may be used, as well as scientific notation.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <inttypes.h>
#include <libbladeRF.h>
#include "test_common.h"
#include "devcfg.h"
#include "hop_set.h"
#define VERBOSITY BLADERF_LOG_LEVEL_INFO
#define TIMEOUT_MS 2500
#define ITERATIONS 500
#define SAMPLE_RATE 5000000
#define BANDWIDTH 5000000
#define NUM_SAMPLES 2000
#define TS_INC 50000
#define RETUNE_INC (NUM_SAMPLES + (TS_INC - NUM_SAMPLES) / 10)
#define SCHEDULE_AHEAD 4
int schedule_retune(struct bladerf *dev, bladerf_module m, struct hop_set *hops,
bool quick_tune, uint64_t *hop_ts)
{
int status;
if (quick_tune) {
struct hop_params p;
hop_set_next(hops, &p);
status = bladerf_schedule_retune(dev, m, *hop_ts, 0, &p.qt);
} else {
unsigned int freq = hop_set_next(hops, NULL);
status = bladerf_schedule_retune(dev, m, *hop_ts, freq, NULL);
}
if (status == 0) {
*hop_ts += TS_INC;
}
return status;
}
int run_test(struct bladerf *dev, bladerf_module module,
struct hop_set *hops, bool quick_tune)
{
int status = -1;
int16_t *samples = NULL;
struct bladerf_metadata meta;
unsigned int i;
uint64_t retune_ts;
FILE *out = NULL;
memset(&meta, 0, sizeof(meta));
samples = calloc(2 * NUM_SAMPLES, sizeof(samples[0]));
if (samples == NULL) {
perror("malloc");
return -1;
}
if (module == BLADERF_MODULE_TX) {
/* Set IQ values to ~ sqrt(2)/2 */
for (i = 0; i < (2 * NUM_SAMPLES); i += 2) {
samples[i] = samples[i+1] = 1448;
}
} else {
out = fopen("samples.bin", "wb");
if (out == NULL) {
perror("fopen");
status = -1;
goto out;
}
}
status = bladerf_get_timestamp(dev, module, &meta.timestamp);
if (status != 0) {
fprintf(stderr, "Failed to get initial timestamp: %s\n",
bladerf_strerror(status));
goto out;
}
/* Add some initial startup delay */
meta.timestamp += (SAMPLE_RATE / 50);
if (module == BLADERF_MODULE_TX) {
meta.flags = BLADERF_META_FLAG_TX_BURST_START |
BLADERF_META_FLAG_TX_BURST_END;
} else {
meta.flags = 0;
}
retune_ts = meta.timestamp + RETUNE_INC;
/* Set initial frequency */
status = bladerf_set_frequency(dev, module, hop_set_next(hops, NULL));
if (status != 0) {
fprintf(stderr, "Failed to set initial frequency: %s\n",
bladerf_strerror(status));
goto out;
}
/* Schedule first N hops */
for (i = 0; i < SCHEDULE_AHEAD; i++) {
status = schedule_retune(dev, module, hops, quick_tune, &retune_ts);
if (status != 0) {
fprintf(stderr, "Failed to schedule initial retune #%u: %s\n",
i, bladerf_strerror(status));
goto out;
}
}
for (i = 0; i < ITERATIONS; i++) {
if (module == BLADERF_MODULE_TX) {
status = bladerf_sync_tx(dev, samples, NUM_SAMPLES, &meta, TIMEOUT_MS);
if (status != 0) {
fprintf(stderr, "Failed to TX @ iteration %u: %s\n",
i + 1, bladerf_strerror(status));
goto out;
}
} else {
size_t n_written;
status = bladerf_sync_rx(dev, samples, NUM_SAMPLES, &meta, TIMEOUT_MS);
if (status != 0) {
fprintf(stderr, "Failed to RX @ iteration %u: %s\n",
i + 1, bladerf_strerror(status));
goto out;
}
n_written = fwrite(samples, 2 * sizeof(int16_t), NUM_SAMPLES, out);
if (n_written != NUM_SAMPLES) {
fprintf(stderr, "File write of samples failed.\n");
status = -1;
goto out;
}
}
/* Update timestamp for next transmission */
meta.timestamp += TS_INC;
/* Schedule an additional retune */
status = schedule_retune(dev, module, hops, quick_tune, &retune_ts);
if (status == BLADERF_ERR_QUEUE_FULL) {
printf("Retune queue full @ iteration %u. Trying again next "
"iteration.\n", i);
} else if (status != 0) {
fprintf(stderr, "Failed to schedule retune @ %"PRIu64": %s\n",
meta.timestamp + RETUNE_INC, bladerf_strerror(status));
goto out;
}
}
/* If transmitting, wait until we read back a timestamp that is in the
* future past our scheduled transmissions*/
if (module == BLADERF_MODULE_TX) {
fprintf(stderr, "Waiting for transmission to complete...\n");
status = wait_for_timestamp(dev, BLADERF_MODULE_TX,
meta.timestamp, 2500);
if (status == BLADERF_ERR_TIMEOUT) {
fprintf(stderr, "Wait timed out.\n");
} else if (status != 0) {
fprintf(stderr, "Wait failed: %s\n", bladerf_strerror(status));
} else {
fprintf(stderr, "Done waiting.\n");
}
}
out:
if (out != NULL) {
fclose(out);
}
free(samples);
return status;
}
int main(int argc, char *argv[])
{
int status, disable_status;
struct bladerf *dev = NULL;
const char *dev_str = NULL;
const char *hop_file = NULL;
const char *mode = NULL;
const char *module_str = NULL;
const char *board_name = NULL;
struct hop_set *hops = NULL;
struct devcfg config;
bladerf_module module;
bool quick_tune;
size_t i;
if (argc < 3) {
fprintf(stderr, "Usage: %s [device str] <rx/tx> <hop file> <quick/normal>\n",
argv[0]);
return 1;
} else if (argc >= 5) {
dev_str = argv[1];
module_str = argv[2];
hop_file = argv[3];
mode = argv[4];
} else {
module_str = argv[1];
hop_file = argv[2];
mode = argv[3];
}
if (!strcasecmp(module_str, "rx")) {
module = BLADERF_MODULE_RX;
} else if (!strcasecmp(module_str, "tx")) {
module = BLADERF_MODULE_TX;
} else {
fprintf(stderr, "Invalid module: %s\n", module_str);
return 1;
}
if (!strcasecmp(mode, "quick")) {
quick_tune = true;
} else if (!strcasecmp(mode, "normal")) {
quick_tune = false;
} else {
fprintf(stderr, "Invalid tuning mode: %s\n", mode);
return 1;
}
hops = hop_set_load(hop_file);
if (hops == NULL) {
return 1;
}
bladerf_log_set_verbosity(VERBOSITY);
status = bladerf_open(&dev, dev_str);
if (status != 0) {
fprintf(stderr, "Unable to open device: %s\n",
bladerf_strerror(status));
goto out;
}
board_name = bladerf_get_board_name(dev);
devcfg_init(&config);
config.tx_samplerate = SAMPLE_RATE;
config.tx_bandwidth = BANDWIDTH;
config.samples_per_buffer = 4096;
config.num_buffers = 16;
config.num_transfers = 8;
status = devcfg_apply(dev, &config);
if (status != 0) {
fprintf(stderr, "Failed to configure device.\n");
goto out;
}
if (quick_tune) {
status = hop_set_load_quick_tunes(dev, module, hops);
if (status != 0) {
goto out;
}
}
printf("Hop set:\n");
for (i = 0; i < hops->count; i++) {
if (quick_tune) {
struct hop_params p;
hop_set_next(hops, &p);
if (strcasecmp(board_name, "bladerf1") == 0) {
printf(" f=%-10u nint=%-6u nfrac=%-8u flags=0x%02x vcocap=%u\n",
p.f, p.qt.nint, p.qt.nfrac, p.qt.flags, p.qt.vcocap);
} else if (strcasecmp(board_name, "bladerf2") == 0) {
printf(" f=%-10u nios_profile=%-8u rffe_profile=%-8u\n",
p.f, p.qt.nios_profile, p.qt.rffe_profile);
}
} else {
printf(" f=%u\n", hop_set_next(hops, NULL));
}
}
hops->idx = 0;
printf("\n");
status = devcfg_perform_sync_config(dev, module,
BLADERF_FORMAT_SC16_Q11_META,
&config, true);
if (status != 0) {
goto out;
}
printf("Running test with %s module...\n",
module == BLADERF_MODULE_RX ? "RX" : "TX");
fflush(stdout);
status = run_test(dev, module, hops, quick_tune);
printf("Done.\n");
fflush(stdout);
disable_status = bladerf_enable_module(dev, module, false);
if (disable_status != 0) {
fprintf(stderr, "Failed to disable_status TX module: %s\n",
bladerf_strerror(status));
goto out;
}
status = (status == 0) ? disable_status : status;
out:
bladerf_close(dev);
hop_set_free(hops);
return status;
}
You can’t perform that action at this time.