Merge pull request #136 from osqzss/develop

Update players
This commit is contained in:
OSQZSS 2018-03-07 16:15:06 +09:00 committed by GitHub
commit 4733b8a42d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 1050 additions and 693 deletions

3
.gitignore vendored
View File

@ -38,3 +38,6 @@ gps-sdr-sim-lut
# Temporary files
*.swp
# Netbeans project folder
nbproject/*

View File

@ -2,7 +2,7 @@
GPS-SDR-SIM generates GPS baseband signal data streams, which can be converted
to RF using software-defined radio (SDR) platforms, such as
[bladeRF](http://nuand.com/), [HackRF](https://github.com/mossmann/hackrf/wiki), and [USRP](http://www.ettus.com/).
[ADALM-Pluto](https://wiki.analog.com/university/tools/pluto), [bladeRF](http://nuand.com/), [HackRF](https://github.com/mossmann/hackrf/wiki), and [USRP](http://www.ettus.com/).
### Windows build instructions
@ -35,11 +35,11 @@ These files are then used to generate the simulated pseudorange and
Doppler for the GPS satellites in view. This simulated range data is
then used to generate the digitized I/Q samples for the GPS signal.
The bladeRF command line interface requires I/Q pairs stored as signed
The bladeRF and ADALM-Pluto command line interface requires I/Q pairs stored as signed
16-bit integers, while the hackrf_transfer and gps-sdr-sim-uhd.py
support signed bytes.
HackRF and bladeRF require 2.6 MHz sample rate, while the USRP2 requires
HackRF, bladeRF and ADALM-Pluto require 2.6 MHz sample rate, while the USRP2 requires
2.5 MHz (an even integral decimator of 100 MHz).
The simulation start time can be specified if the corresponding set of ephemerides
@ -91,6 +91,8 @@ The user motion can be specified in either dynamic or static mode:
The TX port of a particular SDR platform is connected to the GPS receiver
under test through a DC block and a fixed 50-60dB attenuator.
#### BladeRF:
The simulated GPS signal file, named "gpssim.bin", can be loaded
into the bladeRF for playback as shown below:
@ -106,30 +108,50 @@ tx start
```
You can also execute these commands via the `bladeRF-cli` script option as below:
```
> bladeRF-cli -s bladerf.script
```
For the HackRF:
#### HackRF:
```
> hackrf_transfer -t gpssim.bin -f 1575420000 -s 2600000 -a 1 -x 0
```
For UHD supported devices (tested with USRP2 only):
#### UHD supported devices (tested with USRP2 only):
```
> gps-sdr-sim-uhd.py -t gpssim.bin -s 2500000 -x 0
```
For LimeSDR (in case of 1 Msps 1-bit file, to get full BaseBand dynamic and low RF power):
#### LimeSDR (in case of 1 Msps 1-bit file, to get full BaseBand dynamic and low RF power):
```
> limeplayer -s 1000000 -b 1 -d 2047 -g 0.1 < ../circle.1b.1M.bin
```
#### ADALM-Pluto (PlutoSDR):
The ADALM-Pluto device is expected to have its network interface up and running and is accessible
via "pluto.local" by default.
Default settings:
```
> plutoplayer -t gpssim.bin
```
Set TX attenuation:
```
> plutoplayer -t gpssim.bin -a -30.0
```
Default -20.0dB. Applicable range 0.0dB to -80.0dB in 0.25dB steps.
Set RF bandwidth:
```
> plutoplayer -t gpssim.bin -b 3.0
```
Default 3.0MHz. Applicable range 1.0MHz to 5.0MHz.
### License
Copyright &copy; 2015 Takuji Ebinuma
Copyright &copy; 2015-2018 Takuji Ebinuma
Distributed under the [MIT License](http://www.opensource.org/licenses/mit-license.php).

View File

@ -1,5 +1,28 @@
CC=gcc -O2 -Wall
DIALECT = -std=c11
CFLAGS += $(DIALECT) -O3 -g -W -Wall
LIBS = -lm
CFLAGS += $(shell pkg-config --cflags libbladeRF)
CFLAGS += $(shell pkg-config --cflags libhackrf)
CFLAGS += $(shell pkg-config --cflags libiio libad9361)
.PHONY: all bladeplayer hackplayer limeplayer plutoplayer clean
all: bladeplayer hackplayer limeplayer plutoplayer
%.o: %.c *.h
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
bladeplayer: bladeplayer.o $(SDR_OBJ) $(COMPAT)
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(shell pkg-config --libs libbladeRF)
hackplayer: hackplayer.o $(COMPAT)
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(shell pkg-config --libs libhackrf)
limeplayer: limeplayer.c
$(CC) -o limeplayer limeplayer.c -lLimeSuite
gcc -O2 -Wall -o limeplayer limeplayer.c -lLimeSuite
plutoplayer: plutoplayer.o $(COMPAT)
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(shell pkg-config --libs libiio libad9361)
clean:
rm -f *.o bladeplayer hackplayer limeplayer plutoplayer

59
player/README.md Normal file
View File

@ -0,0 +1,59 @@
## How to build the player software on Linux
### bladeRF
#### Build and install libbladeRF
https://github.com/Nuand/bladeRF/wiki/Getting-Started:-Linux
#### Build bladeplayer
```
$ make bladeplayer
```
### HackRF One
#### Build and install libhackrf
https://github.com/mossmann/hackrf/tree/master/host
#### Build hackplayer
```
$ make hackplayer
```
### LimeSDR
#### Build and install libLimeSuite
http://wiki.myriadrf.org/Lime_Suite
#### Build limeplayer
```
$ make limeplayer
```
### ADALM-Pluto
#### Build and install libiio
https://wiki.analog.com/resources/tools-software/linux-software/libiio
#### Build and insatall libad9361
```
$ git clone https://github.com/analogdevicesinc/libad9361-iio.git
$ cd libad9361-iio
$ cmake ./
$ make all
$ sudo make install
```
#### Build plutoplayer
```
$ make plutoplayer
```

View File

@ -7,7 +7,9 @@
#ifdef _WIN32
#include "getopt.h"
#else
#include <getopt.h>
#include <unistd.h>
#include <errno.h>
#endif
#define TX_FREQUENCY 1575420000
@ -25,291 +27,291 @@
void usage(void)
{
fprintf(stderr, "Usage: bladeplayer [options]\n"
" -f <tx_file> I/Q sampling data file (required)\n"
" -b <iq_bits> I/Q data format [1/16] (default: 16)\n"
" -g <tx_vga1> TX VGA1 gain (default: %d)\n",
TX_VGA1);
fprintf(stderr, "Usage: bladeplayer [options]\n"
" -f <tx_file> I/Q sampling data file (required)\n"
" -b <iq_bits> I/Q data format [1/16] (default: 16)\n"
" -g <tx_vga1> TX VGA1 gain (default: %d)\n",
TX_VGA1);
return;
return;
}
int main(int argc, char *argv[])
{
int status;
char *devstr = NULL;
struct bladerf *dev = NULL;
int status;
char *devstr = NULL;
struct bladerf *dev = NULL;
FILE *fp;
int16_t *tx_buffer;
enum state {INIT, READ_FILE, PAD_TRAILING, DONE};
enum state state = INIT;
FILE *fp;
int16_t *tx_buffer;
enum state {INIT, READ_FILE, PAD_TRAILING, DONE};
enum state state = INIT;
int compressed = 0;
uint8_t *read_buffer;
size_t samples_read;
int16_t lut[256][8];
int16_t amp = AMPLITUDE;
int i,k;
int compressed = 0;
uint8_t *read_buffer;
size_t samples_read;
int16_t lut[256][8];
int16_t amp = AMPLITUDE;
uint32_t i,k;
int gain = TX_VGA1;
int result;
int data_format;
char txfile[128];
int gain = TX_VGA1;
int result;
int data_format;
char txfile[128];
// Empty TX file name
txfile[0] = 0;
// Empty TX file name
txfile[0] = 0;
if (argc<3) {
usage();
exit(1);
}
if (argc<3) {
usage();
exit(1);
}
while ((result=getopt(argc,argv,"g:b:f:"))!=-1)
{
switch (result)
{
case 'g':
gain = atoi(optarg);
if (gain>-4 || gain<-35)
{
printf("ERROR: Invalid TX VGA1 gain.\n");
exit(1);
}
break;
case 'b':
data_format = atoi(optarg);
if (data_format!=1 && data_format!=16)
{
printf("ERROR: Invalid I/Q data format.\n");
exit(1);
}
else if (data_format==1)
compressed = 1;
break;
case 'f':
strcpy(txfile, optarg);
break;
case ':':
case '?':
usage();
exit(1);
default:
break;
}
}
while ((result=getopt(argc,argv,"g:b:f:"))!=-1)
{
switch (result)
{
case 'g':
gain = atoi(optarg);
if (gain>-4 || gain<-35)
{
printf("ERROR: Invalid TX VGA1 gain.\n");
exit(1);
}
break;
case 'b':
data_format = atoi(optarg);
if (data_format!=1 && data_format!=16)
{
printf("ERROR: Invalid I/Q data format.\n");
exit(1);
}
else if (data_format==1)
compressed = 1;
break;
case 'f':
strcpy(txfile, optarg);
break;
case ':':
case '?':
usage();
exit(1);
default:
break;
}
}
// Open TX file.
if (txfile[0]==0)
{
printf("ERROR: I/Q sampling data file is not specified.\n");
exit(1);
}
// Open TX file.
if (txfile[0]==0)
{
printf("ERROR: I/Q sampling data file is not specified.\n");
exit(1);
}
fp = fopen(txfile, "rb");
fp = fopen(txfile, "rb");
if (fp==NULL) {
fprintf(stderr, "ERROR: Failed to open TX file: %s\n", argv[1]);
exit(1);
}
if (fp==NULL) {
fprintf(stderr, "ERROR: Failed to open TX file: %s\n", argv[1]);
exit(1);
}
// Initializing device.
printf("Opening and initializing device...\n");
// Initializing device.
printf("Opening and initializing device...\n");
status = bladerf_open(&dev, devstr);
if (status != 0) {
fprintf(stderr, "Failed to open device: %s\n", bladerf_strerror(status));
goto out;
}
status = bladerf_open(&dev, devstr);
if (status != 0) {
fprintf(stderr, "Failed to open device: %s\n", bladerf_strerror(status));
goto out;
}
status = bladerf_set_frequency(dev, BLADERF_MODULE_TX, TX_FREQUENCY);
if (status != 0) {
fprintf(stderr, "Faield to set TX frequency: %s\n", bladerf_strerror(status));
goto out;
}
else {
printf("TX frequency: %u Hz\n", TX_FREQUENCY);
}
status = bladerf_set_frequency(dev, BLADERF_MODULE_TX, TX_FREQUENCY);
if (status != 0) {
fprintf(stderr, "Faield to set TX frequency: %s\n", bladerf_strerror(status));
goto out;
}
else {
printf("TX frequency: %u Hz\n", TX_FREQUENCY);
}
status = bladerf_set_sample_rate(dev, BLADERF_MODULE_TX, TX_SAMPLERATE, NULL);
if (status != 0) {
fprintf(stderr, "Failed to set TX sample rate: %s\n", bladerf_strerror(status));
goto out;
}
else {
printf("TX sample rate: %u sps\n", TX_SAMPLERATE);
}
status = bladerf_set_sample_rate(dev, BLADERF_MODULE_TX, TX_SAMPLERATE, NULL);
if (status != 0) {
fprintf(stderr, "Failed to set TX sample rate: %s\n", bladerf_strerror(status));
goto out;
}
else {
printf("TX sample rate: %u sps\n", TX_SAMPLERATE);
}
status = bladerf_set_bandwidth(dev, BLADERF_MODULE_TX, TX_BANDWIDTH, NULL);
if (status != 0) {
fprintf(stderr, "Failed to set TX bandwidth: %s\n", bladerf_strerror(status));
goto out;
}
else {
printf("TX bandwidth: %u Hz\n", TX_BANDWIDTH);
}
status = bladerf_set_bandwidth(dev, BLADERF_MODULE_TX, TX_BANDWIDTH, NULL);
if (status != 0) {
fprintf(stderr, "Failed to set TX bandwidth: %s\n", bladerf_strerror(status));
goto out;
}
else {
printf("TX bandwidth: %u Hz\n", TX_BANDWIDTH);
}
status = bladerf_set_txvga1(dev, gain);
if (status != 0) {
fprintf(stderr, "Failed to set TX VGA1 gain: %s\n", bladerf_strerror(status));
goto out;
}
else {
printf("TX VGA1 gain: %d dB\n", gain);
}
status = bladerf_set_txvga1(dev, gain);
if (status != 0) {
fprintf(stderr, "Failed to set TX VGA1 gain: %s\n", bladerf_strerror(status));
goto out;
}
else {
printf("TX VGA1 gain: %d dB\n", gain);
}
status = bladerf_set_txvga2(dev, TX_VGA2);
if (status != 0) {
fprintf(stderr, "Failed to set TX VGA2 gain: %s\n", bladerf_strerror(status));
goto out;
}
else {
printf("TX VGA2 gain: %d dB\n", TX_VGA2);
}
status = bladerf_set_txvga2(dev, TX_VGA2);
if (status != 0) {
fprintf(stderr, "Failed to set TX VGA2 gain: %s\n", bladerf_strerror(status));
goto out;
}
else {
printf("TX VGA2 gain: %d dB\n", TX_VGA2);
}
// Application code goes here.
printf("Running...\n");
// Application code goes here.
printf("Running...\n");
// Allocate a buffer to hold each block of samples to transmit.
tx_buffer = (int16_t*)malloc(SAMPLES_PER_BUFFER * 2 * sizeof(int16_t));
if (tx_buffer == NULL) {
fprintf(stderr, "Failed to allocate TX buffer.\n");
goto out;
}
// Allocate a buffer to hold each block of samples to transmit.
tx_buffer = (int16_t*)malloc(SAMPLES_PER_BUFFER * 2 * sizeof(int16_t));
// if compressed
read_buffer = (uint8_t*)malloc(SAMPLES_PER_BUFFER / 4);
if (tx_buffer == NULL) {
fprintf(stderr, "Failed to allocate TX buffer.\n");
goto out;
}
if (read_buffer == NULL) {
fprintf(stderr, "Failed to allocate read buffer.\n");
goto out;
}
// if compressed
read_buffer = (uint8_t*)malloc(SAMPLES_PER_BUFFER / 4);
for (i=0; i<256; i++)
{
for (k=0; k<8; k++)
lut[i][k] = ((i>>(7-k))&0x1)?amp:-amp;
}
if (read_buffer == NULL) {
fprintf(stderr, "Failed to allocate read buffer.\n");
goto out;
}
// Configure the TX module for use with the synchronous interface.
status = bladerf_sync_config(dev,
BLADERF_MODULE_TX,
BLADERF_FORMAT_SC16_Q11,
NUM_BUFFERS,
SAMPLES_PER_BUFFER,
NUM_TRANSFERS,
TIMEOUT_MS);
for (i=0; i<256; i++)
{
for (k=0; k<8; k++)
lut[i][k] = ((i>>(7-k))&0x1)?amp:-amp;
}
if (status != 0) {
fprintf(stderr, "Failed to configure TX sync interface: %s\n", bladerf_strerror(status));
goto out;
}
// Configure the TX module for use with the synchronous interface.
status = bladerf_sync_config(dev,
BLADERF_MODULE_TX,
BLADERF_FORMAT_SC16_Q11,
NUM_BUFFERS,
SAMPLES_PER_BUFFER,
NUM_TRANSFERS,
TIMEOUT_MS);
// We must always enable the modules *after* calling bladerf_sync_config().
status = bladerf_enable_module(dev, BLADERF_MODULE_TX, true);
if (status != 0) {
fprintf(stderr, "Failed to enable TX module: %s\n", bladerf_strerror(status));
goto out;
}
if (status != 0) {
fprintf(stderr, "Failed to configure TX sync interface: %s\n", bladerf_strerror(status));
goto out;
}
// Keep writing samples while there is more data to send and no failures have occurred.
while (state != DONE && status == 0) {
// We must always enable the modules *after* calling bladerf_sync_config().
status = bladerf_enable_module(dev, BLADERF_MODULE_TX, true);
if (status != 0) {
fprintf(stderr, "Failed to enable TX module: %s\n", bladerf_strerror(status));
goto out;
}
int16_t *tx_buffer_current = tx_buffer;
unsigned int buffer_samples_remaining = SAMPLES_PER_BUFFER;
// Keep writing samples while there is more data to send and no failures have occurred.
while (state != DONE && status == 0) {
// if compressed
unsigned int read_samples_remaining = SAMPLES_PER_BUFFER / 4;
int16_t *tx_buffer_current = tx_buffer;
unsigned int buffer_samples_remaining = SAMPLES_PER_BUFFER;
// Keep adding to the buffer until it is full or a failure occurs
while (buffer_samples_remaining > 0 && status == 0 && state != DONE) {
size_t samples_populated = 0;
// if compressed
unsigned int read_samples_remaining = SAMPLES_PER_BUFFER / 4;
switch(state) {
case INIT:
case READ_FILE:
// Read from the input file
if (compressed)
{
int16_t *write_buffer_current = tx_buffer;
// Keep adding to the buffer until it is full or a failure occurs
while (buffer_samples_remaining > 0 && status == 0 && state != DONE) {
size_t samples_populated = 0;
samples_read = fread(read_buffer,
sizeof(uint8_t),
read_samples_remaining,
fp);
switch(state) {
case INIT:
case READ_FILE:
// Read from the input file
if (compressed)
{
int16_t *write_buffer_current = tx_buffer;
samples_populated = samples_read * 4;
buffer_samples_remaining = read_samples_remaining * 4;
samples_read = fread(read_buffer,
sizeof(uint8_t),
read_samples_remaining,
fp);
// Expand compressed data into TX buffer
for (i=0; i<samples_read; i++)
{
memcpy(write_buffer_current, lut[read_buffer[i]], 8);
// Advance the write buffer pointer
write_buffer_current += 8;
}
}
else
{
samples_populated = fread(tx_buffer_current,
2 * sizeof(int16_t),
buffer_samples_remaining,
fp);
}
samples_populated = samples_read * 4;
buffer_samples_remaining = read_samples_remaining * 4;
// If the end of the file was reached, pad the rest of the buffer and finish.
if (feof(fp)) {
state = PAD_TRAILING;
}
// Check for errors
else if (ferror(fp)) {
status = errno;
}
// Expand compressed data into TX buffer
for (i=0; i<samples_read; i++)
{
memcpy(write_buffer_current, lut[read_buffer[i]], 8);
// Advance the write buffer pointer
write_buffer_current += 8;
}
}
else
{
samples_populated = fread(tx_buffer_current,
2 * sizeof(int16_t),
buffer_samples_remaining,
fp);
}
break;
// If the end of the file was reached, pad the rest of the buffer and finish.
if (feof(fp)) {
state = PAD_TRAILING;
}
// Check for errors
else if (ferror(fp)) {
status = errno;
}
case PAD_TRAILING:
// Populate the remainder of the buffer with zeros.
memset(tx_buffer_current, 0, buffer_samples_remaining * 2 * sizeof(uint16_t));
break;
state = DONE;
break;
case PAD_TRAILING:
// Populate the remainder of the buffer with zeros.
memset(tx_buffer_current, 0, buffer_samples_remaining * 2 * sizeof(uint16_t));
case DONE:
default:
break;
}
state = DONE;
break;
// Advance the buffer pointer.
buffer_samples_remaining -= (unsigned int)samples_populated;
tx_buffer_current += (2 * samples_populated);
}
case DONE:
default:
break;
}
// If there were no errors, transmit the data buffer.
if (status == 0) {
bladerf_sync_tx(dev, tx_buffer, SAMPLES_PER_BUFFER, NULL, TIMEOUT_MS);
}
}
// Advance the buffer pointer.
buffer_samples_remaining -= (unsigned int)samples_populated;
tx_buffer_current += (2 * samples_populated);
}
// 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));
}
// If there were no errors, transmit the data buffer.
if (status == 0) {
bladerf_sync_tx(dev, tx_buffer, SAMPLES_PER_BUFFER, NULL, TIMEOUT_MS);
}
}
// Free up our resources
free(tx_buffer);
// 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));
}
// if compressed
free(read_buffer);
// Free up our resources
free(tx_buffer);
// Close TX file
fclose(fp);
// if compressed
free(read_buffer);
// Close TX file
fclose(fp);
out:
printf("Closing device...\n");
bladerf_close(dev);
printf("Closing device...\n");
bladerf_close(dev);
return(0);
return(0);
}

View File

@ -1,22 +1,25 @@
#define _CRT_SECURE_NO_WARNINGS
#include <hackrf.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#ifdef _WIN32
#include <windows.h>
#ifdef _WIN64
typedef int64_t ssize_t;
#else
typedef int32_t ssize_t;
#endif
typedef int bool;
#define true 1
#define false 0
#include "getopt.h"
#else
#include <stdbool.h>
#include <sys/types.h>
#include <getopt.h>
#include <signal.h>
#endif
#include <libhackrf/hackrf.h>
static hackrf_device* device = NULL;
@ -25,199 +28,210 @@ volatile uint32_t byte_count = 0;
volatile bool do_exit = false;
static transceiver_mode_t transceiver_mode = TRANSCEIVER_MODE_TX;
//static transceiver_mode_t transceiver_mode = TRANSCEIVER_MODE_TX;
#define FD_BUFFER_SIZE (8*1024)
#define FREQ_ONE_MHZ (1000000ull)
#ifdef _WIN32
BOOL WINAPI sighandler(int signum)
{
if (CTRL_C_EVENT == signum) {
fprintf(stdout, "Caught signal %d\n", signum);
do_exit = true;
return TRUE;
}
return FALSE;
if(CTRL_C_EVENT == signum) {
fprintf(stdout, "Caught signal %d\n", signum);
do_exit = true;
return TRUE;
}
return FALSE;
}
#else
static void sighandler(int signum) {
fprintf(stdout, "Caught signal %d\n", signum);
do_exit = true;
}
#endif
int tx_callback(hackrf_transfer* transfer) {
size_t bytes_to_read;
size_t bytes_to_read;
if( fd != NULL )
{
ssize_t bytes_read;
byte_count += transfer->valid_length;
bytes_to_read = transfer->valid_length;
bytes_read = fread(transfer->buffer, 1, bytes_to_read, fd);
if (bytes_read != bytes_to_read) {
return -1; // EOF
} else {
return 0;
}
} else {
return -1;
}
if( fd != NULL )
{
ssize_t bytes_read;
byte_count += transfer->valid_length;
bytes_to_read = transfer->valid_length;
bytes_read = fread(transfer->buffer, 1, bytes_to_read, fd);
if (bytes_read != bytes_to_read) {
return -1; // EOF
} else {
return 0;
}
} else {
return -1;
}
}
static void usage() {
fprintf(stderr, "Usage: hackplayer [options]\n"
" -t <filename> Transmit data from file (required)\n");
fprintf(stderr, "Usage: hackplayer [options]\n"
" -t <filename> Transmit data from file (required)\n");
return;
return;
}
int main(int argc, char** argv) {
int opt;
int result;
const char* path = NULL;
uint32_t sample_rate_hz = 2600000;
uint32_t baseband_filter_bw_hz = 0;
unsigned int txvga_gain=0;
uint64_t freq_hz = 1575420000;
uint32_t amp_enable = 1;
int opt;
int result;
const char* path = NULL;
uint32_t sample_rate_hz = 2600000;
uint32_t baseband_filter_bw_hz = 0;
unsigned int txvga_gain=0;
uint64_t freq_hz = 1575420000;
uint32_t amp_enable = 1;
while( (opt = getopt(argc, argv, "t:")) != EOF )
{
result = HACKRF_SUCCESS;
switch( opt )
{
case 't':
path = optarg;
break;
default:
printf("unknown argument '-%c %s'\n", opt, optarg);
usage();
return EXIT_FAILURE;
}
while( (opt = getopt(argc, argv, "t:")) != EOF )
{
result = HACKRF_SUCCESS;
switch( opt )
{
case 't':
path = optarg;
break;
default:
printf("unknown argument '-%c %s'\n", opt, optarg);
usage();
return EXIT_FAILURE;
}
if( result != HACKRF_SUCCESS ) {
printf("argument error: '-%c %s' %s (%d)\n", opt, optarg, hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
}
if( result != HACKRF_SUCCESS ) {
printf("argument error: '-%c %s' %s (%d)\n", opt, optarg, hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
}
if( path == NULL ) {
printf("specify a path to a file to transmit\n");
usage();
return EXIT_FAILURE;
}
if( path == NULL ) {
printf("specify a path to a file to transmit\n");
usage();
return EXIT_FAILURE;
}
// Compute default value depending on sample rate
baseband_filter_bw_hz = hackrf_compute_baseband_filter_bw_round_down_lt(sample_rate_hz);
// Compute default value depending on sample rate
baseband_filter_bw_hz = hackrf_compute_baseband_filter_bw_round_down_lt(sample_rate_hz);
result = hackrf_init();
if( result != HACKRF_SUCCESS ) {
printf("hackrf_init() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
result = hackrf_init();
if( result != HACKRF_SUCCESS ) {
printf("hackrf_init() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
result = hackrf_open_by_serial(NULL, &device);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_open() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
result = hackrf_open_by_serial(NULL, &device);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_open() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
fd = fopen(path, "rb");
if( fd == NULL ) {
printf("Failed to open file: %s\n", path);
return EXIT_FAILURE;
}
fd = fopen(path, "rb");
if( fd == NULL ) {
printf("Failed to open file: %s\n", path);
return EXIT_FAILURE;
}
// Change fd buffer to have bigger one to store or read data on/to HDD
result = setvbuf(fd , NULL , _IOFBF , FD_BUFFER_SIZE);
if( result != 0 ) {
printf("setvbuf() failed: %d\n", result);
usage();
return EXIT_FAILURE;
}
// Change fd buffer to have bigger one to store or read data on/to HDD
result = setvbuf(fd , NULL , _IOFBF , FD_BUFFER_SIZE);
if( result != 0 ) {
printf("setvbuf() failed: %d\n", result);
usage();
return EXIT_FAILURE;
}
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
#ifdef _WIN32
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
#else
signal(SIGINT, sighandler);
#endif
printf("call hackrf_sample_rate_set(%.03f MHz)\n", ((float)sample_rate_hz/(float)FREQ_ONE_MHZ));
result = hackrf_set_sample_rate_manual(device, sample_rate_hz, 1);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_sample_rate_set() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
printf("call hackrf_sample_rate_set(%.03f MHz)\n", ((float)sample_rate_hz/(float)FREQ_ONE_MHZ));
result = hackrf_set_sample_rate_manual(device, sample_rate_hz, 1);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_sample_rate_set() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
printf("call hackrf_baseband_filter_bandwidth_set(%.03f MHz)\n",
((float)baseband_filter_bw_hz/(float)FREQ_ONE_MHZ));
result = hackrf_set_baseband_filter_bandwidth(device, baseband_filter_bw_hz);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_baseband_filter_bandwidth_set() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
printf("call hackrf_baseband_filter_bandwidth_set(%.03f MHz)\n",
((float)baseband_filter_bw_hz/(float)FREQ_ONE_MHZ));
result = hackrf_set_baseband_filter_bandwidth(device, baseband_filter_bw_hz);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_baseband_filter_bandwidth_set() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
result = hackrf_set_txvga_gain(device, txvga_gain);
result |= hackrf_start_tx(device, tx_callback, NULL);
result = hackrf_set_txvga_gain(device, txvga_gain);
result |= hackrf_start_tx(device, tx_callback, NULL);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_start_?x() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
if( result != HACKRF_SUCCESS ) {
printf("hackrf_start_?x() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
printf("call hackrf_set_freq(%.03f MHz)\n", ((double)freq_hz/(double)FREQ_ONE_MHZ));
result = hackrf_set_freq(device, freq_hz);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_set_freq() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
printf("call hackrf_set_freq(%.03f MHz)\n", ((double)freq_hz/(double)FREQ_ONE_MHZ));
result = hackrf_set_freq(device, freq_hz);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_set_freq() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
printf("call hackrf_set_amp_enable(%u)\n", amp_enable);
result = hackrf_set_amp_enable(device, (uint8_t)amp_enable);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_set_amp_enable() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
printf("call hackrf_set_amp_enable(%u)\n", amp_enable);
result = hackrf_set_amp_enable(device, (uint8_t)amp_enable);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_set_amp_enable() failed: %s (%d)\n", hackrf_error_name(result), result);
usage();
return EXIT_FAILURE;
}
printf("Stop with Ctrl-C\n");
while( (hackrf_is_streaming(device) == HACKRF_TRUE) && (do_exit == false) ) {
// Show something?
}
printf("Stop with Ctrl-C\n");
while( (hackrf_is_streaming(device) == HACKRF_TRUE) && (do_exit == false) ) {
// Show something?
}
result = hackrf_is_streaming(device);
if (do_exit) {
printf("\nUser cancel, exiting...\n");
} else {
printf("\nExiting... hackrf_is_streaming() result: %s (%d)\n", hackrf_error_name(result), result);
}
result = hackrf_is_streaming(device);
if (do_exit) {
printf("\nUser cancel, exiting...\n");
} else {
printf("\nExiting... hackrf_is_streaming() result: %s (%d)\n", hackrf_error_name(result), result);
}
if(device != NULL) {
result = hackrf_stop_tx(device);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_stop_tx() failed: %s (%d)\n", hackrf_error_name(result), result);
} else {
printf("hackrf_stop_tx() done\n");
}
if(device != NULL) {
result = hackrf_stop_tx(device);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_stop_tx() failed: %s (%d)\n", hackrf_error_name(result), result);
} else {
printf("hackrf_stop_tx() done\n");
}
result = hackrf_close(device);
if( result != HACKRF_SUCCESS )
{
printf("hackrf_close() failed: %s (%d)\n", hackrf_error_name(result), result);
} else {
printf("hackrf_close() done\n");
}
hackrf_exit();
printf("hackrf_exit() done\n");
}
result = hackrf_close(device);
if( result != HACKRF_SUCCESS )
{
printf("hackrf_close() failed: %s (%d)\n", hackrf_error_name(result), result);
} else {
printf("hackrf_close() done\n");
}
if(fd != NULL) {
fclose(fd);
fd = NULL;
printf("fclose(fd) done\n");
}
hackrf_exit();
printf("hackrf_exit() done\n");
}
printf("exit\n");
return EXIT_SUCCESS;
if(fd != NULL) {
fclose(fd);
fd = NULL;
printf("fclose(fd) done\n");
}
printf("exit\n");
return EXIT_SUCCESS;
}

View File

@ -27,11 +27,11 @@
static int control_c_received = 0;
static void control_c_handler (int sig, siginfo_t *siginfo, void *context){
control_c_received = 1;
control_c_received = 1;
}
static void print_usage(const char *progname){
printf("Usage: %s [option] < file" "\n"
printf("Usage: %s [option] < file" "\n"
"\t" "-g <gain> or --gain <gain> with gain in [0.0 .. 1.0] set the so-called normalized RF gain in LimeSDR (default: 1.0 max RF power)" "\n"
"\t" "-c <channel> or --channel <channel> with channel either 0 or 1 (default: 0)" "\n"
"\t" "-a <antenna> or --antenna <antenna> with antenna in { 0, 1, 2 } (default:" STRINGIFY(DEFAULT_ANTENNA) ")" "\n"
@ -39,53 +39,53 @@ static void print_usage(const char *progname){
"\t" "-b <bits> or --bits <bits> select bit count in IQ sample in { 1, 8, 12, 16 }, (default: 16)" "\n"
"\t" "-s <samplerate> or --samplerate <samplerate> configure BB sample rate (default: " STRINGIFY(TX_SAMPLERATE) ")" "\n"
"\t" "-d <dynamic> --dynamic <dynamic> configure dynamic for the 1-bit mode (default: 2047, max 12-bit signed value supported by LimeSDR)" "\n"
"Example:" "\n"
"\t" "./limeplayer -s 1000000 -b 1 -d 1023 -g 0.1 < ../circle.1b.1M.bin" "\n", progname);
exit(0);
"Example:" "\n"
"\t" "./limeplayer -s 1000000 -b 1 -d 1023 -g 0.1 < ../circle.1b.1M.bin" "\n", progname);
exit(0);
}
int main(int argc, char *const argv[]){
struct sigaction control_c;
struct sigaction control_c;
memset(&control_c, 0, sizeof(control_c));
control_c.sa_sigaction = &control_c_handler;
memset(&control_c, 0, sizeof(control_c));
control_c.sa_sigaction = &control_c_handler;
/* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler. */
control_c.sa_flags = SA_SIGINFO;
/* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler. */
control_c.sa_flags = SA_SIGINFO;
if (sigaction(SIGTERM, &control_c, NULL) < 0) {
perror ("sigaction");
return(EXIT_CODE_CONTROL_C);
}
if (sigaction(SIGQUIT, &control_c, NULL) < 0) {
perror ("sigaction");
return(EXIT_CODE_CONTROL_C);
}
if (sigaction(SIGINT, &control_c, NULL) < 0) {
perror ("sigaction");
return(EXIT_CODE_CONTROL_C);
}
if (sigaction(SIGTERM, &control_c, NULL) < 0) {
perror ("sigaction");
return(EXIT_CODE_CONTROL_C);
}
if (sigaction(SIGQUIT, &control_c, NULL) < 0) {
perror ("sigaction");
return(EXIT_CODE_CONTROL_C);
}
if (sigaction(SIGINT, &control_c, NULL) < 0) {
perror ("sigaction");
return(EXIT_CODE_CONTROL_C);
}
int device_count = LMS_GetDeviceList(NULL);
if(device_count < 1){
return(EXIT_CODE_NO_DEVICE);
}
lms_info_str_t *device_list = malloc(sizeof(lms_info_str_t) * device_count);
device_count = LMS_GetDeviceList(device_list);
int device_count = LMS_GetDeviceList(NULL);
if(device_count < 1){
return(EXIT_CODE_NO_DEVICE);
}
lms_info_str_t *device_list = malloc(sizeof(lms_info_str_t) * device_count);
device_count = LMS_GetDeviceList(device_list);
int i = 0;
while(i < device_count){
// printf("device[%d/%d]=%s" "\n", i + 1, device_count, device_list[i]);
i++;
}
int i = 0;
while(i < device_count){
// printf("device[%d/%d]=%s" "\n", i + 1, device_count, device_list[i]);
i++;
}
double gain = 1.0;
int32_t antenna = DEFAULT_ANTENNA;
int32_t channel = 0;
int32_t index = 0;
int32_t bits = 16;
double sampleRate = TX_SAMPLERATE;
int32_t dynamic = 2047;
double gain = 1.0;
int32_t antenna = DEFAULT_ANTENNA;
int32_t channel = 0;
int32_t index = 0;
int32_t bits = 16;
double sampleRate = TX_SAMPLERATE;
int32_t dynamic = 2047;
while (1) {
int option_index = 0;
@ -109,7 +109,7 @@ int main(int argc, char *const argv[]){
#if 1
fprintf(stderr, "option %s", long_options[option_index].name);
if (optarg)
fprintf(stderr, " with arg %s", optarg);
fprintf(stderr, " with arg %s", optarg);
fprintf(stderr, "\n");
#endif
@ -130,272 +130,272 @@ int main(int argc, char *const argv[]){
case 'i':
index = strtol(optarg, NULL, 0);
break;
case 's':
sampleRate = strtod(optarg, NULL);
break;
case 'd':
dynamic = strtol(optarg, NULL, 0);
if(dynamic > 2047){
dynamic = 2047;
}
break;
default:
print_usage(argv[0]);
break;
case 's':
sampleRate = strtod(optarg, NULL);
break;
case 'd':
dynamic = strtol(optarg, NULL, 0);
if(dynamic > 2047){
dynamic = 2047;
}
break;
default:
print_usage(argv[0]);
break;
}
}
// Use correct values
// Use existing device
if(index < 0){
index = 0;
}
if(index >= device_count){
index = 0;
}
printf("Using device index %d [%s]" "\n", index, device_list[index]);
// Use correct values
// Use existing device
if(index < 0){
index = 0;
}
if(index >= device_count){
index = 0;
}
printf("Using device index %d [%s]" "\n", index, device_list[index]);
// Normalized gain shall be in [0.0 .. 1.0]
if(gain < 0.0){
gain = 0.0;
}
if(gain > 1.0){
gain = 1.0;
}
printf("Using normalized gain %lf" "\n", gain);
// Normalized gain shall be in [0.0 .. 1.0]
if(gain < 0.0){
gain = 0.0;
}
if(gain > 1.0){
gain = 1.0;
}
printf("Using normalized gain %lf" "\n", gain);
lms_device_t *device = NULL;
lms_device_t *device = NULL;
if(LMS_Open(&device, device_list[index], NULL)){
return(EXIT_CODE_LMS_OPEN);
}
if(LMS_Open(&device, device_list[index], NULL)){
return(EXIT_CODE_LMS_OPEN);
}
int lmsReset = LMS_Reset(device);
if(lmsReset){
printf("lmsReset %d(%s)" "\n", lmsReset, LMS_GetLastErrorMessage());
}
int lmsInit = LMS_Init(device);
if(lmsInit){
printf("lmsInit %d(%s)" "\n", lmsInit, LMS_GetLastErrorMessage());
}
int lmsReset = LMS_Reset(device);
if(lmsReset){
printf("lmsReset %d(%s)" "\n", lmsReset, LMS_GetLastErrorMessage());
}
int lmsInit = LMS_Init(device);
if(lmsInit){
printf("lmsInit %d(%s)" "\n", lmsInit, LMS_GetLastErrorMessage());
}
int channel_count = LMS_GetNumChannels(device, LMS_CH_TX);
// printf("Tx channel count %d" "\n", channel_count);
if(channel < 0){
channel = 0;
}
if(channel >= channel_count){
channel = 0;
}
printf("Using channel %d" "\n", channel);
int channel_count = LMS_GetNumChannels(device, LMS_CH_TX);
// printf("Tx channel count %d" "\n", channel_count);
if(channel < 0){
channel = 0;
}
if(channel >= channel_count){
channel = 0;
}
printf("Using channel %d" "\n", channel);
int antenna_count = LMS_GetAntennaList(device, LMS_CH_TX, channel, NULL);
// printf("TX%d Channel has %d antenna(ae)" "\n", channel, antenna_count);
lms_name_t antenna_name[antenna_count];
if(antenna_count > 0){
int i = 0;
lms_range_t antenna_bw[antenna_count];
LMS_GetAntennaList(device, LMS_CH_TX, channel, antenna_name);
for(i = 0 ; i < antenna_count ; i++){
LMS_GetAntennaBW(device, LMS_CH_TX, channel, i, antenna_bw + i);
// printf("Channel %d, antenna [%s] has BW [%lf .. %lf] (step %lf)" "\n", channel, antenna_name[i], antenna_bw[i].min, antenna_bw[i].max, antenna_bw[i].step);
}
}
if(antenna < 0){
antenna = DEFAULT_ANTENNA;
}
if(antenna >= antenna_count){
antenna = DEFAULT_ANTENNA;
}
// LMS_SetAntenna(device, LMS_CH_TX, channel, antenna); // SetLOFrequency should take care of selecting the proper antenna
LMS_SetNormalizedGain(device, LMS_CH_TX, channel, gain);
// Disable all other channels
LMS_EnableChannel(device, LMS_CH_TX, 1 - channel, false);
LMS_EnableChannel(device, LMS_CH_RX, 0, false);
LMS_EnableChannel(device, LMS_CH_RX, 1, false);
// Enable our Tx channel
LMS_EnableChannel(device, LMS_CH_TX, channel, true);
int antenna_count = LMS_GetAntennaList(device, LMS_CH_TX, channel, NULL);
// printf("TX%d Channel has %d antenna(ae)" "\n", channel, antenna_count);
lms_name_t antenna_name[antenna_count];
if(antenna_count > 0){
int i = 0;
lms_range_t antenna_bw[antenna_count];
LMS_GetAntennaList(device, LMS_CH_TX, channel, antenna_name);
for(i = 0 ; i < antenna_count ; i++){
LMS_GetAntennaBW(device, LMS_CH_TX, channel, i, antenna_bw + i);
// printf("Channel %d, antenna [%s] has BW [%lf .. %lf] (step %lf)" "\n", channel, antenna_name[i], antenna_bw[i].min, antenna_bw[i].max, antenna_bw[i].step);
}
}
if(antenna < 0){
antenna = DEFAULT_ANTENNA;
}
if(antenna >= antenna_count){
antenna = DEFAULT_ANTENNA;
}
// LMS_SetAntenna(device, LMS_CH_TX, channel, antenna); // SetLOFrequency should take care of selecting the proper antenna
LMS_SetNormalizedGain(device, LMS_CH_TX, channel, gain);
// Disable all other channels
LMS_EnableChannel(device, LMS_CH_TX, 1 - channel, false);
LMS_EnableChannel(device, LMS_CH_RX, 0, false);
LMS_EnableChannel(device, LMS_CH_RX, 1, false);
// Enable our Tx channel
LMS_EnableChannel(device, LMS_CH_TX, channel, true);
int setLOFrequency = LMS_SetLOFrequency(device, LMS_CH_TX, channel, TX_FREQUENCY);
if(setLOFrequency){
printf("setLOFrequency(%lf)=%d(%s)" "\n", TX_FREQUENCY, setLOFrequency, LMS_GetLastErrorMessage());
}
int setLOFrequency = LMS_SetLOFrequency(device, LMS_CH_TX, channel, TX_FREQUENCY);
if(setLOFrequency){
printf("setLOFrequency(%lf)=%d(%s)" "\n", TX_FREQUENCY, setLOFrequency, LMS_GetLastErrorMessage());
}
#ifdef __USE_LPF__
lms_range_t LPFBWRange;
LMS_GetLPFBWRange(device, LMS_CH_TX, &LPFBWRange);
// printf("TX%d LPFBW [%lf .. %lf] (step %lf)" "\n", channel, LPFBWRange.min, LPFBWRange.max, LPFBWRange.step);
double LPFBW = TX_BANDWIDTH;
if(LPFBW < LPFBWRange.min){
LPFBW = LPFBWRange.min;
}
if(LPFBW > LPFBWRange.max){
LPFBW = LPFBWRange.min;
}
int setLPFBW = LMS_SetLPFBW(device, LMS_CH_TX, channel, LPFBW);
if(setLPFBW){
printf("setLPFBW(%lf)=%d(%s)" "\n", LPFBW, setLPFBW, LMS_GetLastErrorMessage());
}
int enableLPF = LMS_SetLPF(device, LMS_CH_TX, channel, true);
if(enableLPF){
printf("enableLPF=%d(%s)" "\n", enableLPF, LMS_GetLastErrorMessage());
}
lms_range_t LPFBWRange;
LMS_GetLPFBWRange(device, LMS_CH_TX, &LPFBWRange);
// printf("TX%d LPFBW [%lf .. %lf] (step %lf)" "\n", channel, LPFBWRange.min, LPFBWRange.max, LPFBWRange.step);
double LPFBW = TX_BANDWIDTH;
if(LPFBW < LPFBWRange.min){
LPFBW = LPFBWRange.min;
}
if(LPFBW > LPFBWRange.max){
LPFBW = LPFBWRange.min;
}
int setLPFBW = LMS_SetLPFBW(device, LMS_CH_TX, channel, LPFBW);
if(setLPFBW){
printf("setLPFBW(%lf)=%d(%s)" "\n", LPFBW, setLPFBW, LMS_GetLastErrorMessage());
}
int enableLPF = LMS_SetLPF(device, LMS_CH_TX, channel, true);
if(enableLPF){
printf("enableLPF=%d(%s)" "\n", enableLPF, LMS_GetLastErrorMessage());
}
#endif
lms_range_t sampleRateRange;
int getSampleRateRange = LMS_GetSampleRateRange(device, LMS_CH_TX, &sampleRateRange);
if(getSampleRateRange){
printf("getSampleRateRange=%d(%s)" "\n", getSampleRateRange, LMS_GetLastErrorMessage());
}else{
// printf("sampleRateRange [%lf MHz.. %lf MHz] (step=%lf Hz)" "\n", sampleRateRange.min / 1e6, sampleRateRange.max / 1e6, sampleRateRange.step);
}
lms_range_t sampleRateRange;
int getSampleRateRange = LMS_GetSampleRateRange(device, LMS_CH_TX, &sampleRateRange);
if(getSampleRateRange){
printf("getSampleRateRange=%d(%s)" "\n", getSampleRateRange, LMS_GetLastErrorMessage());
}else{
// printf("sampleRateRange [%lf MHz.. %lf MHz] (step=%lf Hz)" "\n", sampleRateRange.min / 1e6, sampleRateRange.max / 1e6, sampleRateRange.step);
}
printf("Set sample rate to %lf ..." "\n", sampleRate);
int setSampleRate = LMS_SetSampleRate(device, sampleRate, 0);
if(setSampleRate){
printf("setSampleRate=%d(%s)" "\n", setSampleRate, LMS_GetLastErrorMessage());
}
double actualHostSampleRate = 0.0;
double actualRFSampleRate = 0.0;
int getSampleRate = LMS_GetSampleRate(device, LMS_CH_TX, channel, &actualHostSampleRate, &actualRFSampleRate);
if(getSampleRate){
printf("getSampleRate=%d(%s)" "\n", getSampleRate, LMS_GetLastErrorMessage());
}else{
printf("actualRate %lf (Host) / %lf (RF)" "\n", actualHostSampleRate, actualRFSampleRate);
}
printf("Set sample rate to %lf ..." "\n", sampleRate);
int setSampleRate = LMS_SetSampleRate(device, sampleRate, 0);
if(setSampleRate){
printf("setSampleRate=%d(%s)" "\n", setSampleRate, LMS_GetLastErrorMessage());
}
double actualHostSampleRate = 0.0;
double actualRFSampleRate = 0.0;
int getSampleRate = LMS_GetSampleRate(device, LMS_CH_TX, channel, &actualHostSampleRate, &actualRFSampleRate);
if(getSampleRate){
printf("getSampleRate=%d(%s)" "\n", getSampleRate, LMS_GetLastErrorMessage());
}else{
printf("actualRate %lf (Host) / %lf (RF)" "\n", actualHostSampleRate, actualRFSampleRate);
}
printf("Calibrating ..." "\n");
int calibrate = LMS_Calibrate(device, LMS_CH_TX, channel, TX_BANDWIDTH, 0);
if(calibrate){
printf("calibrate=%d(%s)" "\n", calibrate, LMS_GetLastErrorMessage());
}
printf("Calibrating ..." "\n");
int calibrate = LMS_Calibrate(device, LMS_CH_TX, channel, TX_BANDWIDTH, 0);
if(calibrate){
printf("calibrate=%d(%s)" "\n", calibrate, LMS_GetLastErrorMessage());
}
printf("Setup TX stream ..." "\n");
lms_stream_t tx_stream = {.channel = channel, .fifoSize = 1024*1024, .throughputVsLatency = 0.5, .isTx = true, .dataFmt = LMS_FMT_I12};
int setupStream = LMS_SetupStream(device, &tx_stream);
if(setupStream){
printf("setupStream=%d(%s)" "\n", setupStream, LMS_GetLastErrorMessage());
}
printf("Setup TX stream ..." "\n");
lms_stream_t tx_stream = {.channel = channel, .fifoSize = 1024*1024, .throughputVsLatency = 0.5, .isTx = true, .dataFmt = LMS_FMT_I12};
int setupStream = LMS_SetupStream(device, &tx_stream);
if(setupStream){
printf("setupStream=%d(%s)" "\n", setupStream, LMS_GetLastErrorMessage());
}
struct s16iq_sample_s {
signed short int i;
signed short int q;
};
struct s16iq_sample_s {
signed short int i;
signed short int q;
};
int nSamples = (int)sampleRate / 100;
struct s16iq_sample_s *sampleBuffer = (struct s16iq_sample_s*)malloc(sizeof(struct s16iq_sample_s) * nSamples);
int nSamples = (int)sampleRate / 100;
struct s16iq_sample_s *sampleBuffer = (struct s16iq_sample_s*)malloc(sizeof(struct s16iq_sample_s) * nSamples);
LMS_StartStream(&tx_stream);
LMS_StartStream(&tx_stream);
int loop = 0;
if((12 == bits) || (16 == bits)){
// File contains interleaved 16-bit IQ values, either with only 12-bit data, or with 16-bit data
while((0 == control_c_received) && fread(sampleBuffer, sizeof(struct s16iq_sample_s), nSamples, stdin)){
loop++;
if(0 == (loop % 100)){
struct timeval tv;
gettimeofday(&tv, NULL);
printf("gettimeofday()=> %ld:%06ld ; ", tv.tv_sec, tv.tv_usec);
lms_stream_status_t status;
LMS_GetStreamStatus(&tx_stream, &status); //Obtain TX stream stats
printf("TX rate:%lf MB/s" "\n", status.linkRate / 1e6);
}
if(16 == bits){
// Scale down to 12-bit
// Quick and dirty, so -1 (0xFFFF) to -15 (0xFFF1) scale down to -1 instead of 0
int i = 0;
while(i < nSamples){
sampleBuffer[i].i >>= 4;
sampleBuffer[i].q >>= 4;
i++;
}
}
int sendStream = LMS_SendStream(&tx_stream, sampleBuffer, nSamples, NULL, 1000);
if(sendStream < 0){
printf("sendStream %d(%s)" "\n", sendStream, LMS_GetLastErrorMessage());
}
}
}else if(8 == bits){
// File contains interleaved signed 8-bit IQ values
struct s8iq_sample_s {
signed char i;
signed char q;
};
struct s8iq_sample_s *fileSamples = (struct s8iq_sample_s*)malloc(sizeof(struct s8iq_sample_s) * nSamples);
while((0 == control_c_received) && fread(fileSamples, sizeof(struct s8iq_sample_s), nSamples, stdin)){
loop++;
if(0 == (loop % 100)){
struct timeval tv;
gettimeofday(&tv, NULL);
printf("gettimeofday()=> %ld:%06ld ; ", tv.tv_sec, tv.tv_usec);
lms_stream_status_t status;
LMS_GetStreamStatus(&tx_stream, &status); //Obtain TX stream stats
printf("TX rate:%lf MB/s" "\n", status.linkRate / 1e6);
}
// Up-Scale to 12-bit
int i = 0;
while(i < nSamples){
sampleBuffer[i].i = (fileSamples[i].i << 4);
sampleBuffer[i].q = (fileSamples[i].q << 4);
i++;
}
int sendStream = LMS_SendStream(&tx_stream, sampleBuffer, nSamples, NULL, 1000);
if(sendStream < 0){
printf("sendStream %d(%s)" "\n", sendStream, LMS_GetLastErrorMessage());
}
}
free(fileSamples);
}else if(1 == bits){
// File contains interleaved signed 1-bit IQ values
// Each byte is IQIQIQIQ
int16_t expand_lut[256][8];
int i, j;
for (i=0; i<256; i++){
for (j=0; j<8; j++){
expand_lut[i][j] = ((i>>(7-j))&0x1)?dynamic:-dynamic;
}
}
printf("1-bit mode: using dynamic=%d" "\n", dynamic);
// printf("sizeof(expand_lut[][])=%d, sizeof(expand_lut[0])=%d" "\n", sizeof(expand_lut), sizeof(expand_lut[0]));
int8_t *fileBuffer = (int8_t*)malloc(sizeof(int8_t) * nSamples);
while((0 == control_c_received) && fread(fileBuffer, sizeof(int8_t), nSamples / 4, stdin)){
loop++;
if(0 == (loop % 100)){
struct timeval tv;
gettimeofday(&tv, NULL);
printf("gettimeofday()=> %ld:%06ld ; ", tv.tv_sec, tv.tv_usec);
lms_stream_status_t status;
LMS_GetStreamStatus(&tx_stream, &status); //Obtain TX stream stats
printf("TX rate:%lf MB/s" "\n", status.linkRate / 1e6);
}
// Expand
int src = 0;
int dst = 0;
while(src < (nSamples / 4)){
memcpy(sampleBuffer + dst, expand_lut + fileBuffer[src], sizeof(expand_lut[0]));
dst += 4;
src++;
}
int sendStream = LMS_SendStream(&tx_stream, sampleBuffer, nSamples, NULL, 1000);
if(sendStream < 0){
printf("sendStream %d(%s)" "\n", sendStream, LMS_GetLastErrorMessage());
}
}
free(fileBuffer);
}
int loop = 0;
if((12 == bits) || (16 == bits)){
// File contains interleaved 16-bit IQ values, either with only 12-bit data, or with 16-bit data
while((0 == control_c_received) && fread(sampleBuffer, sizeof(struct s16iq_sample_s), nSamples, stdin)){
loop++;
if(0 == (loop % 100)){
struct timeval tv;
gettimeofday(&tv, NULL);
printf("gettimeofday()=> %ld:%06ld ; ", tv.tv_sec, tv.tv_usec);
lms_stream_status_t status;
LMS_GetStreamStatus(&tx_stream, &status); //Obtain TX stream stats
printf("TX rate:%lf MB/s" "\n", status.linkRate / 1e6);
}
if(16 == bits){
// Scale down to 12-bit
// Quick and dirty, so -1 (0xFFFF) to -15 (0xFFF1) scale down to -1 instead of 0
int i = 0;
while(i < nSamples){
sampleBuffer[i].i >>= 4;
sampleBuffer[i].q >>= 4;
i++;
}
}
int sendStream = LMS_SendStream(&tx_stream, sampleBuffer, nSamples, NULL, 1000);
if(sendStream < 0){
printf("sendStream %d(%s)" "\n", sendStream, LMS_GetLastErrorMessage());
}
}
}else if(8 == bits){
// File contains interleaved signed 8-bit IQ values
struct s8iq_sample_s {
signed char i;
signed char q;
};
struct s8iq_sample_s *fileSamples = (struct s8iq_sample_s*)malloc(sizeof(struct s8iq_sample_s) * nSamples);
while((0 == control_c_received) && fread(fileSamples, sizeof(struct s8iq_sample_s), nSamples, stdin)){
loop++;
if(0 == (loop % 100)){
struct timeval tv;
gettimeofday(&tv, NULL);
printf("gettimeofday()=> %ld:%06ld ; ", tv.tv_sec, tv.tv_usec);
lms_stream_status_t status;
LMS_GetStreamStatus(&tx_stream, &status); //Obtain TX stream stats
printf("TX rate:%lf MB/s" "\n", status.linkRate / 1e6);
}
// Up-Scale to 12-bit
int i = 0;
while(i < nSamples){
sampleBuffer[i].i = (fileSamples[i].i << 4);
sampleBuffer[i].q = (fileSamples[i].q << 4);
i++;
}
int sendStream = LMS_SendStream(&tx_stream, sampleBuffer, nSamples, NULL, 1000);
if(sendStream < 0){
printf("sendStream %d(%s)" "\n", sendStream, LMS_GetLastErrorMessage());
}
}
free(fileSamples);
}else if(1 == bits){
// File contains interleaved signed 1-bit IQ values
// Each byte is IQIQIQIQ
int16_t expand_lut[256][8];
int i, j;
for (i=0; i<256; i++){
for (j=0; j<8; j++){
expand_lut[i][j] = ((i>>(7-j))&0x1)?dynamic:-dynamic;
}
}
printf("1-bit mode: using dynamic=%d" "\n", dynamic);
// printf("sizeof(expand_lut[][])=%d, sizeof(expand_lut[0])=%d" "\n", sizeof(expand_lut), sizeof(expand_lut[0]));
int8_t *fileBuffer = (int8_t*)malloc(sizeof(int8_t) * nSamples);
while((0 == control_c_received) && fread(fileBuffer, sizeof(int8_t), nSamples / 4, stdin)){
loop++;
if(0 == (loop % 100)){
struct timeval tv;
gettimeofday(&tv, NULL);
printf("gettimeofday()=> %ld:%06ld ; ", tv.tv_sec, tv.tv_usec);
lms_stream_status_t status;
LMS_GetStreamStatus(&tx_stream, &status); //Obtain TX stream stats
printf("TX rate:%lf MB/s" "\n", status.linkRate / 1e6);
}
// Expand
int src = 0;
int dst = 0;
while(src < (nSamples / 4)){
memcpy(sampleBuffer + dst, expand_lut + fileBuffer[src], sizeof(expand_lut[0]));
dst += 4;
src++;
}
int sendStream = LMS_SendStream(&tx_stream, sampleBuffer, nSamples, NULL, 1000);
if(sendStream < 0){
printf("sendStream %d(%s)" "\n", sendStream, LMS_GetLastErrorMessage());
}
}
free(fileBuffer);
}
LMS_StopStream(&tx_stream);
LMS_DestroyStream(device, &tx_stream);
LMS_StopStream(&tx_stream);
LMS_DestroyStream(device, &tx_stream);
free(sampleBuffer);
free(sampleBuffer);
LMS_EnableChannel(device, LMS_CH_TX, channel, false);
LMS_Close(device);
LMS_EnableChannel(device, LMS_CH_TX, channel, false);
LMS_Close(device);
if(control_c_received){
return(EXIT_CODE_CONTROL_C);
}
return(0);
if(control_c_received){
return(EXIT_CODE_CONTROL_C);
}
return(0);
}

234
player/plutoplayer.c Normal file
View File

@ -0,0 +1,234 @@
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <iio.h>
#include <ad9361.h>
#define NOTUSED(V) ((void) V)
#define MHZ(x) ((long long)(x*1000000.0 + .5))
#define GHZ(x) ((long long)(x*1000000000.0 + .5))
#define NUM_SAMPLES 2600000
#define BUFFER_SIZE (NUM_SAMPLES * 2 * sizeof(int16_t))
struct stream_cfg {
long long bw_hz; // Analog banwidth in Hz
long long fs_hz; // Baseband sample rate in Hz
long long lo_hz; // Local oscillator frequency in Hz
const char* rfport; // Port name
double gain_db; // Hardware gain
};
static void usage() {
fprintf(stderr, "Usage: plutoplayer [options]\n"
" -t <filename> Transmit data from file (required)\n"
" -a <attenuation> Set TX attenuation [dB] (default -20.0)\n"
" -b <bw> Set RF bandwidth [MHz] (default 5.0)\n");
return;
}
static bool stop = false;
static void handle_sig(int sig)
{
NOTUSED(sig);
stop = true;
}
static char* readable_fs(double size, char *buf, size_t buf_size) {
int i = 0;
const char* units[] = {"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
while (size > 1024) {
size /= 1024;
i++;
}
snprintf(buf, buf_size, "%.*f %s", i, size, units[i]);
return buf;
}
/*
*
*/
int main(int argc, char** argv) {
char buf[1024];
int opt;
const char* path = NULL;
struct stream_cfg txcfg;
FILE *fp = NULL;
enum state {INIT, READ_FILE, PAD_TRAILING, DONE};
// TX stream default config
txcfg.bw_hz = MHZ(3.0); // 3.0 MHz RF bandwidth
txcfg.fs_hz = MHZ(2.6); // 2.6 MS/s TX sample rate
txcfg.lo_hz = GHZ(1.575420); // 1.57542 GHz RF frequency
txcfg.rfport = "A";
txcfg.gain_db = -20.0;
struct iio_context *ctx = NULL;
struct iio_device *tx = NULL;
struct iio_device *phydev = NULL;
struct iio_channel *tx0_i = NULL;
struct iio_channel *tx0_q = NULL;
struct iio_buffer *tx_buffer = NULL;
while ((opt = getopt(argc, argv, "t:a:b:")) != EOF) {
switch (opt) {
case 't':
path = optarg;
break;
case 'a':
txcfg.gain_db = atof(optarg);
if(txcfg.gain_db > 0.0) txcfg.gain_db = 0.0;
if(txcfg.gain_db < -80.0) txcfg.gain_db = -80.0;
break;
case 'b':
txcfg.bw_hz = MHZ(atof(optarg));
if(txcfg.bw_hz > MHZ(5.0)) txcfg.bw_hz = MHZ(5.0);
if(txcfg.bw_hz < MHZ(1.0)) txcfg.bw_hz = MHZ(1.0);
break;
default:
printf("Unknown argument '-%c %s'\n", opt, optarg);
usage();
return EXIT_FAILURE;
}
}
signal(SIGINT, handle_sig);
if( path == NULL ) {
printf("Specify a path to a file to transmit\n");
usage();
return EXIT_FAILURE;
}
fp = fopen(path, "rb");
if (fp==NULL) {
fprintf(stderr, "ERROR: Failed to open TX file: %s\n", path);
return EXIT_FAILURE;
}
fseek(fp, 0L, SEEK_END);
size_t sz = ftell(fp);
fseek(fp, 0L, SEEK_SET);
readable_fs((double)sz, buf, sizeof(buf));
printf("* Transmit file size: %s\n", buf);
printf("* Acquiring IIO context\n");
ctx = iio_create_default_context();
if (ctx == NULL) {
ctx = iio_create_network_context("pluto.local");
}
if (ctx == NULL) {
iio_strerror(errno, buf, sizeof(buf));
fprintf(stderr, "Failed creating IIO context: %s\n", buf);
return false;
}
struct iio_scan_context *scan_ctx;
struct iio_context_info **info;
scan_ctx = iio_create_scan_context(NULL, 0);
if (scan_ctx) {
int info_count = iio_scan_context_get_info_list(scan_ctx, &info);
if(info_count > 0) {
printf("* Found %s\n", iio_context_info_get_description(info[0]));
iio_context_info_list_free(info);
}
iio_scan_context_destroy(scan_ctx);
}
printf("* Acquiring devices\n");
int device_count = iio_context_get_devices_count(ctx);
if (!device_count) {
fprintf(stderr, "No supported PLUTOSDR devices found.\n");
goto error_exit;
}
fprintf(stderr, "* Context has %d device(s).\n", device_count);
printf("* Acquiring TX device\n");
tx = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc");
if (tx == NULL) {
iio_strerror(errno, buf, sizeof(buf));
fprintf(stderr, "Error opening PLUTOSDR TX device: %s\n", buf);
goto error_exit;
}
iio_device_set_kernel_buffers_count(tx, 8);
phydev = iio_context_find_device(ctx, "ad9361-phy");
struct iio_channel* phy_chn = iio_device_find_channel(phydev, "voltage0", true);
iio_channel_attr_write(phy_chn, "rf_port_select", txcfg.rfport);
iio_channel_attr_write_longlong(phy_chn, "rf_bandwidth", txcfg.bw_hz);
iio_channel_attr_write_longlong(phy_chn, "sampling_frequency", txcfg.fs_hz);
iio_channel_attr_write_double(phy_chn, "hardwaregain", txcfg.gain_db);
iio_channel_attr_write_bool(
iio_device_find_channel(phydev, "altvoltage0", true)
, "powerdown", true); // Turn OFF RX LO
iio_channel_attr_write_longlong(
iio_device_find_channel(phydev, "altvoltage1", true)
, "frequency", txcfg.lo_hz); // Set TX LO frequency
iio_channel_attr_write_longlong(
iio_device_find_channel(phydev, "altvoltage1", true)
, "frequency", txcfg.lo_hz); // Set TX LO frequency
printf("* Initializing streaming channels\n");
tx0_i = iio_device_find_channel(tx, "voltage0", true);
if (!tx0_i)
tx0_i = iio_device_find_channel(tx, "altvoltage0", true);
tx0_q = iio_device_find_channel(tx, "voltage1", true);
if (!tx0_q)
tx0_q = iio_device_find_channel(tx, "altvoltage1", true);
printf("* Enabling IIO streaming channels\n");
iio_channel_enable(tx0_i);
iio_channel_enable(tx0_q);
ad9361_set_bb_rate(iio_context_find_device(ctx, "ad9361-phy"), txcfg.fs_hz);
printf("* Creating TX buffer\n");
tx_buffer = iio_device_create_buffer(tx, NUM_SAMPLES, false);
if (!tx_buffer) {
fprintf(stderr, "Could not create TX buffer.\n");
goto error_exit;
}
iio_channel_attr_write_bool(
iio_device_find_channel(iio_context_find_device(ctx, "ad9361-phy"), "altvoltage1", true)
, "powerdown", false); // Turn ON TX LO
int32_t ntx = 0;
char *ptx_buffer = (char *)iio_buffer_start(tx_buffer);
printf("* Transmit starts...\n");
// Keep writing samples while there is more data to send and no failures have occurred.
while (!feof(fp) && !stop) {
fread(ptx_buffer, 1, BUFFER_SIZE,fp);
// Schedule TX buffer
ntx = iio_buffer_push(tx_buffer);
if (ntx < 0) {
printf("Error pushing buf %d\n", (int) ntx);
goto error_exit;
}
}
printf("Done.\n");
error_exit:
fclose(fp);
iio_channel_attr_write_bool(
iio_device_find_channel(iio_context_find_device(ctx, "ad9361-phy"), "altvoltage1", true)
, "powerdown", true); // Turn OFF TX LO
if (tx_buffer) { iio_buffer_destroy(tx_buffer); }
if (tx0_i) { iio_channel_disable(tx0_i); }
if (tx0_q) { iio_channel_disable(tx0_q); }
if (ctx) { iio_context_destroy(ctx); }
return EXIT_SUCCESS;
}