Created
March 27, 2018 11:03
-
-
Save csete/ece39ec9f66d751889821fa7619360e4 to your computer and use it in GitHub Desktop.
Test application for LimeSDR
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* gcc -Wall -Wextra -O2 -o limerx limerx.c -lLimeSuite | |
* | |
* ./limerx [samprate] [oversmapling] | |
*/ | |
#define __STDC_FORMAT_MACROS | |
#include <inttypes.h> | |
#include <signal.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <sys/time.h> | |
#include "lime/LimeSuite.h" | |
#define SAMPLE_BUFFER_MS 10.f | |
#define SAMPLE_BUFFER_SEC (1.e-3f * SAMPLE_BUFFER_MS) | |
#define READ_TIMEOUT_MS (10 * SAMPLE_BUFFER_MS) | |
#define STATUS_DT_MS 1000 | |
static lms_device_t *device = NULL; | |
static bool keep_running; | |
void signal_handler_func(int signal) | |
{ | |
fprintf(stderr, "Caught signal %d\n", signal); | |
if (signal == SIGINT || signal == SIGTERM) | |
keep_running = false; | |
} | |
void device_error() | |
{ | |
if (device != NULL) | |
LMS_Close(device); | |
exit(-1); | |
} | |
static uint64_t time_ms(void) | |
{ | |
struct timeval tval; | |
gettimeofday(&tval, NULL); | |
return 1e3 * tval.tv_sec + 1e-3 * tval.tv_usec; | |
} | |
int main(int argc, char** argv) | |
{ | |
struct sigaction signal_handler; | |
lms_info_str_t *device_list; | |
lms_stream_t stream; | |
int num_dev; | |
int16_t *sample_buffer; | |
size_t sample_count; | |
int samples_read; | |
int samples_last; | |
uint64_t samples_total; | |
float sample_rate; | |
int oversampling; | |
uint64_t tstart, tlast, tnow; | |
float runtime; | |
// register signal handler (CTRL-C to stop application) | |
signal_handler.sa_handler = signal_handler_func; | |
sigemptyset(&signal_handler.sa_mask); | |
signal_handler.sa_flags = 0; | |
sigaction(SIGINT, &signal_handler, NULL); | |
sigaction(SIGTERM, &signal_handler, NULL); | |
sigaction(SIGPIPE, &signal_handler, NULL); | |
// enumerate attached LimeSDR devices and start streaming from the first one | |
num_dev = LMS_GetDeviceList(NULL); | |
if (num_dev < 0) | |
{ | |
fprintf(stderr, "Error probing for LimeSDR devices\n"); | |
device_error(); | |
} | |
if (num_dev == 0) | |
{ | |
fprintf(stderr, "No LimeSDR devices found\n"); | |
exit(0); | |
} | |
device_list = (lms_info_str_t *) malloc(num_dev * sizeof(lms_info_str_t)); | |
if (LMS_GetDeviceList(device_list) != num_dev) | |
{ | |
free(device_list); | |
fprintf(stderr, "LMS_GetDeviceList() returned inconsistent number\n"); | |
device_error(); | |
} | |
fprintf(stderr, "Found %d LimeSDR devices\n", num_dev); | |
// open the first device | |
if (LMS_Open(&device, device_list[0], NULL)) | |
{ | |
fprintf(stderr, "Failed to open LimeSDR\n"); | |
free(device_list); | |
device_error(); | |
} | |
fprintf(stderr, "LimeSDR opened: %s\n", device_list[0]); | |
free(device_list); | |
/* Initialize device with default configuration | |
* Do not use if you want to keep existing configuration | |
* Use LMS_LoadConfig(device, "/path/to/file.ini") to load config from INI | |
*/ | |
if (LMS_Init(device) != 0) | |
{ | |
fprintf(stderr, "Error initializing LimeSDR device\n"); | |
device_error(); | |
} | |
/* Enable RX channel (starting at 0) */ | |
if (LMS_EnableChannel(device, LMS_CH_RX, 0, true) != 0) | |
{ | |
fprintf(stderr, "Failed to enable RX channel\n"); | |
device_error(); | |
} | |
/* Set center frequency */ | |
if (LMS_SetLOFrequency(device, LMS_CH_RX, 0, 145e6) != 0) | |
{ | |
fprintf(stderr, "Failed to set LO frequency\n"); | |
device_error(); | |
} | |
/* Set sample rate oversampling */ | |
sample_rate = argc > 1 ? atof(argv[1]) : 8.0e6; | |
oversampling = argc > 2 ? atoi(argv[2]) : 0; | |
if (LMS_SetSampleRate(device, sample_rate, oversampling) != 0) | |
{ | |
fprintf(stderr, "Failed to set sample rate\n"); | |
device_error(); | |
} | |
fprintf(stderr, "Set sample rate %.0f Hz (oversampling %d)\n", | |
sample_rate, oversampling); | |
// setup stream | |
stream.channel = 0; | |
stream.fifoSize = 1024 * 1024; // samples | |
stream.throughputVsLatency = 1.0; // optimize for max throughput | |
stream.isTx = false; // RX channel | |
stream.dataFmt = LMS_FMT_I12; | |
if (LMS_SetupStream(device, &stream) != 0) | |
{ | |
fprintf(stderr, "Error configuring stream\n"); | |
device_error(); | |
} | |
sample_count = sample_rate * SAMPLE_BUFFER_SEC; | |
sample_buffer = (int16_t *) malloc(2 * sample_count * sizeof(int16_t)); | |
if (LMS_StartStream(&stream) != 0) | |
{ | |
fprintf(stderr, "Failed to start streaming\n"); | |
device_error(); | |
} | |
fprintf(stderr, "Stream started\n"); | |
samples_last = samples_total = 0; | |
tnow = tstart = tlast = time_ms(); | |
keep_running = true; | |
while (keep_running) | |
{ | |
samples_read = LMS_RecvStream(&stream, sample_buffer, sample_count, | |
NULL, READ_TIMEOUT_MS); | |
if (samples_read == -1) | |
{ | |
fprintf(stderr, "An error occurred during streaming\n"); | |
break; | |
} | |
tnow = time_ms(); | |
samples_total += samples_read; | |
samples_last += samples_read; | |
if (tnow - tlast >= STATUS_DT_MS) | |
{ | |
fprintf(stderr, "%.3f ksps\n", | |
(float)samples_last / (float)(tnow - tlast)); | |
tlast = tnow; | |
samples_last = 0; | |
} | |
} | |
tnow = time_ms(); | |
runtime = tnow - tstart; | |
fprintf(stderr, "Stopping stream...\n"); | |
LMS_StopStream(&stream); | |
LMS_DestroyStream(device, &stream); | |
LMS_Close(device); | |
if (sample_buffer) | |
free(sample_buffer); | |
fprintf(stderr, "Read %" PRIu64 " samples in %.3f sec => %.3f ksps\n", | |
samples_total, 1.e-3f * runtime, (float)samples_total / runtime); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment