Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
Sign up
Find file
Copy path
bladeRF/host/libraries/libbladeRF_test/test_scheduled_retune/src/main.c
Find file
Copy path
Fetching contributors…

/* | |
* 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; | |
} |