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 # Temporary files
*.swp *.swp
# Netbeans project folder
nbproject/*

View File

@ -2,7 +2,7 @@
GPS-SDR-SIM generates GPS baseband signal data streams, which can be converted GPS-SDR-SIM generates GPS baseband signal data streams, which can be converted
to RF using software-defined radio (SDR) platforms, such as 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 ### 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 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. 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 16-bit integers, while the hackrf_transfer and gps-sdr-sim-uhd.py
support signed bytes. 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). 2.5 MHz (an even integral decimator of 100 MHz).
The simulation start time can be specified if the corresponding set of ephemerides 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 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. under test through a DC block and a fixed 50-60dB attenuator.
#### BladeRF:
The simulated GPS signal file, named "gpssim.bin", can be loaded The simulated GPS signal file, named "gpssim.bin", can be loaded
into the bladeRF for playback as shown below: 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: You can also execute these commands via the `bladeRF-cli` script option as below:
``` ```
> bladeRF-cli -s bladerf.script > bladeRF-cli -s bladerf.script
``` ```
For the HackRF: #### HackRF:
``` ```
> hackrf_transfer -t gpssim.bin -f 1575420000 -s 2600000 -a 1 -x 0 > 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 > 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 > 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 ### 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). 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 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 #ifdef _WIN32
#include "getopt.h" #include "getopt.h"
#else #else
#include <getopt.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h>
#endif #endif
#define TX_FREQUENCY 1575420000 #define TX_FREQUENCY 1575420000
@ -25,291 +27,291 @@
void usage(void) void usage(void)
{ {
fprintf(stderr, "Usage: bladeplayer [options]\n" fprintf(stderr, "Usage: bladeplayer [options]\n"
" -f <tx_file> I/Q sampling data file (required)\n" " -f <tx_file> I/Q sampling data file (required)\n"
" -b <iq_bits> I/Q data format [1/16] (default: 16)\n" " -b <iq_bits> I/Q data format [1/16] (default: 16)\n"
" -g <tx_vga1> TX VGA1 gain (default: %d)\n", " -g <tx_vga1> TX VGA1 gain (default: %d)\n",
TX_VGA1); TX_VGA1);
return; return;
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int status; int status;
char *devstr = NULL; char *devstr = NULL;
struct bladerf *dev = NULL; struct bladerf *dev = NULL;
FILE *fp; FILE *fp;
int16_t *tx_buffer; int16_t *tx_buffer;
enum state {INIT, READ_FILE, PAD_TRAILING, DONE}; enum state {INIT, READ_FILE, PAD_TRAILING, DONE};
enum state state = INIT; enum state state = INIT;
int compressed = 0; int compressed = 0;
uint8_t *read_buffer; uint8_t *read_buffer;
size_t samples_read; size_t samples_read;
int16_t lut[256][8]; int16_t lut[256][8];
int16_t amp = AMPLITUDE; int16_t amp = AMPLITUDE;
int i,k; uint32_t i,k;
int gain = TX_VGA1; int gain = TX_VGA1;
int result; int result;
int data_format; int data_format;
char txfile[128]; char txfile[128];
// Empty TX file name // Empty TX file name
txfile[0] = 0; txfile[0] = 0;
if (argc<3) { if (argc<3) {
usage(); usage();
exit(1); exit(1);
} }
while ((result=getopt(argc,argv,"g:b:f:"))!=-1) while ((result=getopt(argc,argv,"g:b:f:"))!=-1)
{ {
switch (result) switch (result)
{ {
case 'g': case 'g':
gain = atoi(optarg); gain = atoi(optarg);
if (gain>-4 || gain<-35) if (gain>-4 || gain<-35)
{ {
printf("ERROR: Invalid TX VGA1 gain.\n"); printf("ERROR: Invalid TX VGA1 gain.\n");
exit(1); exit(1);
} }
break; break;
case 'b': case 'b':
data_format = atoi(optarg); data_format = atoi(optarg);
if (data_format!=1 && data_format!=16) if (data_format!=1 && data_format!=16)
{ {
printf("ERROR: Invalid I/Q data format.\n"); printf("ERROR: Invalid I/Q data format.\n");
exit(1); exit(1);
} }
else if (data_format==1) else if (data_format==1)
compressed = 1; compressed = 1;
break; break;
case 'f': case 'f':
strcpy(txfile, optarg); strcpy(txfile, optarg);
break; break;
case ':': case ':':
case '?': case '?':
usage(); usage();
exit(1); exit(1);
default: default:
break; break;
} }
} }
// Open TX file. // Open TX file.
if (txfile[0]==0) if (txfile[0]==0)
{ {
printf("ERROR: I/Q sampling data file is not specified.\n"); printf("ERROR: I/Q sampling data file is not specified.\n");
exit(1); exit(1);
} }
fp = fopen(txfile, "rb"); fp = fopen(txfile, "rb");
if (fp==NULL) { if (fp==NULL) {
fprintf(stderr, "ERROR: Failed to open TX file: %s\n", argv[1]); fprintf(stderr, "ERROR: Failed to open TX file: %s\n", argv[1]);
exit(1); exit(1);
} }
// Initializing device. // Initializing device.
printf("Opening and initializing device...\n"); printf("Opening and initializing device...\n");
status = bladerf_open(&dev, devstr); status = bladerf_open(&dev, devstr);
if (status != 0) { if (status != 0) {
fprintf(stderr, "Failed to open device: %s\n", bladerf_strerror(status)); fprintf(stderr, "Failed to open device: %s\n", bladerf_strerror(status));
goto out; goto out;
} }
status = bladerf_set_frequency(dev, BLADERF_MODULE_TX, TX_FREQUENCY); status = bladerf_set_frequency(dev, BLADERF_MODULE_TX, TX_FREQUENCY);
if (status != 0) { if (status != 0) {
fprintf(stderr, "Faield to set TX frequency: %s\n", bladerf_strerror(status)); fprintf(stderr, "Faield to set TX frequency: %s\n", bladerf_strerror(status));
goto out; goto out;
} }
else { else {
printf("TX frequency: %u Hz\n", TX_FREQUENCY); printf("TX frequency: %u Hz\n", TX_FREQUENCY);
} }
status = bladerf_set_sample_rate(dev, BLADERF_MODULE_TX, TX_SAMPLERATE, NULL); status = bladerf_set_sample_rate(dev, BLADERF_MODULE_TX, TX_SAMPLERATE, NULL);
if (status != 0) { if (status != 0) {
fprintf(stderr, "Failed to set TX sample rate: %s\n", bladerf_strerror(status)); fprintf(stderr, "Failed to set TX sample rate: %s\n", bladerf_strerror(status));
goto out; goto out;
} }
else { else {
printf("TX sample rate: %u sps\n", TX_SAMPLERATE); printf("TX sample rate: %u sps\n", TX_SAMPLERATE);
} }
status = bladerf_set_bandwidth(dev, BLADERF_MODULE_TX, TX_BANDWIDTH, NULL); status = bladerf_set_bandwidth(dev, BLADERF_MODULE_TX, TX_BANDWIDTH, NULL);
if (status != 0) { if (status != 0) {
fprintf(stderr, "Failed to set TX bandwidth: %s\n", bladerf_strerror(status)); fprintf(stderr, "Failed to set TX bandwidth: %s\n", bladerf_strerror(status));
goto out; goto out;
} }
else { else {
printf("TX bandwidth: %u Hz\n", TX_BANDWIDTH); printf("TX bandwidth: %u Hz\n", TX_BANDWIDTH);
} }
status = bladerf_set_txvga1(dev, gain); status = bladerf_set_txvga1(dev, gain);
if (status != 0) { if (status != 0) {
fprintf(stderr, "Failed to set TX VGA1 gain: %s\n", bladerf_strerror(status)); fprintf(stderr, "Failed to set TX VGA1 gain: %s\n", bladerf_strerror(status));
goto out; goto out;
} }
else { else {
printf("TX VGA1 gain: %d dB\n", gain); printf("TX VGA1 gain: %d dB\n", gain);
} }
status = bladerf_set_txvga2(dev, TX_VGA2); status = bladerf_set_txvga2(dev, TX_VGA2);
if (status != 0) { if (status != 0) {
fprintf(stderr, "Failed to set TX VGA2 gain: %s\n", bladerf_strerror(status)); fprintf(stderr, "Failed to set TX VGA2 gain: %s\n", bladerf_strerror(status));
goto out; goto out;
} }
else { else {
printf("TX VGA2 gain: %d dB\n", TX_VGA2); printf("TX VGA2 gain: %d dB\n", TX_VGA2);
} }
// Application code goes here. // Application code goes here.
printf("Running...\n"); printf("Running...\n");
// Allocate a buffer to hold each block of samples to transmit. // Allocate a buffer to hold each block of samples to transmit.
tx_buffer = (int16_t*)malloc(SAMPLES_PER_BUFFER * 2 * sizeof(int16_t)); 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;
}
// if compressed if (tx_buffer == NULL) {
read_buffer = (uint8_t*)malloc(SAMPLES_PER_BUFFER / 4); fprintf(stderr, "Failed to allocate TX buffer.\n");
goto out;
}
if (read_buffer == NULL) { // if compressed
fprintf(stderr, "Failed to allocate read buffer.\n"); read_buffer = (uint8_t*)malloc(SAMPLES_PER_BUFFER / 4);
goto out;
}
for (i=0; i<256; i++) if (read_buffer == NULL) {
{ fprintf(stderr, "Failed to allocate read buffer.\n");
for (k=0; k<8; k++) goto out;
lut[i][k] = ((i>>(7-k))&0x1)?amp:-amp; }
}
// Configure the TX module for use with the synchronous interface. for (i=0; i<256; i++)
status = bladerf_sync_config(dev, {
BLADERF_MODULE_TX, for (k=0; k<8; k++)
BLADERF_FORMAT_SC16_Q11, lut[i][k] = ((i>>(7-k))&0x1)?amp:-amp;
NUM_BUFFERS, }
SAMPLES_PER_BUFFER,
NUM_TRANSFERS,
TIMEOUT_MS);
if (status != 0) { // Configure the TX module for use with the synchronous interface.
fprintf(stderr, "Failed to configure TX sync interface: %s\n", bladerf_strerror(status)); status = bladerf_sync_config(dev,
goto out; 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(). if (status != 0) {
status = bladerf_enable_module(dev, BLADERF_MODULE_TX, true); fprintf(stderr, "Failed to configure TX sync interface: %s\n", bladerf_strerror(status));
if (status != 0) { goto out;
fprintf(stderr, "Failed to enable TX module: %s\n", bladerf_strerror(status)); }
goto out;
}
// Keep writing samples while there is more data to send and no failures have occurred. // We must always enable the modules *after* calling bladerf_sync_config().
while (state != DONE && status == 0) { 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; // Keep writing samples while there is more data to send and no failures have occurred.
unsigned int buffer_samples_remaining = SAMPLES_PER_BUFFER; while (state != DONE && status == 0) {
// if compressed int16_t *tx_buffer_current = tx_buffer;
unsigned int read_samples_remaining = SAMPLES_PER_BUFFER / 4; unsigned int buffer_samples_remaining = SAMPLES_PER_BUFFER;
// Keep adding to the buffer until it is full or a failure occurs // if compressed
while (buffer_samples_remaining > 0 && status == 0 && state != DONE) { unsigned int read_samples_remaining = SAMPLES_PER_BUFFER / 4;
size_t samples_populated = 0;
switch(state) { // Keep adding to the buffer until it is full or a failure occurs
case INIT: while (buffer_samples_remaining > 0 && status == 0 && state != DONE) {
case READ_FILE: size_t samples_populated = 0;
// Read from the input file
if (compressed)
{
int16_t *write_buffer_current = tx_buffer;
samples_read = fread(read_buffer, switch(state) {
sizeof(uint8_t), case INIT:
read_samples_remaining, case READ_FILE:
fp); // Read from the input file
if (compressed)
{
int16_t *write_buffer_current = tx_buffer;
samples_populated = samples_read * 4; samples_read = fread(read_buffer,
buffer_samples_remaining = read_samples_remaining * 4; sizeof(uint8_t),
read_samples_remaining,
fp);
// Expand compressed data into TX buffer samples_populated = samples_read * 4;
for (i=0; i<samples_read; i++) buffer_samples_remaining = read_samples_remaining * 4;
{
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);
}
// If the end of the file was reached, pad the rest of the buffer and finish. // Expand compressed data into TX buffer
if (feof(fp)) { for (i=0; i<samples_read; i++)
state = PAD_TRAILING; {
} memcpy(write_buffer_current, lut[read_buffer[i]], 8);
// Check for errors
else if (ferror(fp)) { // Advance the write buffer pointer
status = errno; 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: break;
// Populate the remainder of the buffer with zeros.
memset(tx_buffer_current, 0, buffer_samples_remaining * 2 * sizeof(uint16_t));
state = DONE; case PAD_TRAILING:
break; // Populate the remainder of the buffer with zeros.
memset(tx_buffer_current, 0, buffer_samples_remaining * 2 * sizeof(uint16_t));
case DONE: state = DONE;
default: break;
break;
}
// Advance the buffer pointer. case DONE:
buffer_samples_remaining -= (unsigned int)samples_populated; default:
tx_buffer_current += (2 * samples_populated); break;
} }
// If there were no errors, transmit the data buffer. // Advance the buffer pointer.
if (status == 0) { buffer_samples_remaining -= (unsigned int)samples_populated;
bladerf_sync_tx(dev, tx_buffer, SAMPLES_PER_BUFFER, NULL, TIMEOUT_MS); tx_buffer_current += (2 * samples_populated);
} }
}
// Disable TX module, shutting down our underlying TX stream. // If there were no errors, transmit the data buffer.
status = bladerf_enable_module(dev, BLADERF_MODULE_TX, false); if (status == 0) {
if (status != 0) { bladerf_sync_tx(dev, tx_buffer, SAMPLES_PER_BUFFER, NULL, TIMEOUT_MS);
fprintf(stderr, "Failed to disable TX module: %s\n", bladerf_strerror(status)); }
} }
// Free up our resources // Disable TX module, shutting down our underlying TX stream.
free(tx_buffer); 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 up our resources
free(read_buffer); free(tx_buffer);
// Close TX file // if compressed
fclose(fp); free(read_buffer);
// Close TX file
fclose(fp);
out: out:
printf("Closing device...\n"); printf("Closing device...\n");
bladerf_close(dev); bladerf_close(dev);
return(0); return(0);
} }

View File

@ -1,22 +1,25 @@
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#include <hackrf.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <getopt.h> #ifdef _WIN32
#include <windows.h> #include <windows.h>
#ifdef _WIN64 #ifdef _WIN64
typedef int64_t ssize_t; typedef int64_t ssize_t;
#else #else
typedef int32_t ssize_t; typedef int32_t ssize_t;
#endif #endif
typedef int bool; typedef int bool;
#define true 1 #define true 1
#define false 0 #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; static hackrf_device* device = NULL;
@ -25,199 +28,210 @@ volatile uint32_t byte_count = 0;
volatile bool do_exit = false; 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 FD_BUFFER_SIZE (8*1024)
#define FREQ_ONE_MHZ (1000000ull) #define FREQ_ONE_MHZ (1000000ull)
#ifdef _WIN32
BOOL WINAPI sighandler(int signum) BOOL WINAPI sighandler(int signum)
{ {
if (CTRL_C_EVENT == signum) { if(CTRL_C_EVENT == signum) {
fprintf(stdout, "Caught signal %d\n", signum); fprintf(stdout, "Caught signal %d\n", signum);
do_exit = true; do_exit = true;
return TRUE; return TRUE;
} }
return FALSE; 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) { int tx_callback(hackrf_transfer* transfer) {
size_t bytes_to_read; size_t bytes_to_read;
if( fd != NULL ) if( fd != NULL )
{ {
ssize_t bytes_read; ssize_t bytes_read;
byte_count += transfer->valid_length; byte_count += transfer->valid_length;
bytes_to_read = transfer->valid_length; bytes_to_read = transfer->valid_length;
bytes_read = fread(transfer->buffer, 1, bytes_to_read, fd); bytes_read = fread(transfer->buffer, 1, bytes_to_read, fd);
if (bytes_read != bytes_to_read) { if (bytes_read != bytes_to_read) {
return -1; // EOF return -1; // EOF
} else { } else {
return 0; return 0;
} }
} else { } else {
return -1; return -1;
} }
} }
static void usage() { static void usage() {
fprintf(stderr, "Usage: hackplayer [options]\n" fprintf(stderr, "Usage: hackplayer [options]\n"
" -t <filename> Transmit data from file (required)\n"); " -t <filename> Transmit data from file (required)\n");
return; return;
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
int opt; int opt;
int result; int result;
const char* path = NULL; const char* path = NULL;
uint32_t sample_rate_hz = 2600000; uint32_t sample_rate_hz = 2600000;
uint32_t baseband_filter_bw_hz = 0; uint32_t baseband_filter_bw_hz = 0;
unsigned int txvga_gain=0; unsigned int txvga_gain=0;
uint64_t freq_hz = 1575420000; uint64_t freq_hz = 1575420000;
uint32_t amp_enable = 1; uint32_t amp_enable = 1;
while( (opt = getopt(argc, argv, "t:")) != EOF ) while( (opt = getopt(argc, argv, "t:")) != EOF )
{ {
result = HACKRF_SUCCESS; result = HACKRF_SUCCESS;
switch( opt ) switch( opt )
{ {
case 't': case 't':
path = optarg; path = optarg;
break; break;
default: default:
printf("unknown argument '-%c %s'\n", opt, optarg); printf("unknown argument '-%c %s'\n", opt, optarg);
usage(); usage();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if( result != HACKRF_SUCCESS ) { if( result != HACKRF_SUCCESS ) {
printf("argument error: '-%c %s' %s (%d)\n", opt, optarg, hackrf_error_name(result), result); printf("argument error: '-%c %s' %s (%d)\n", opt, optarg, hackrf_error_name(result), result);
usage(); usage();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
if( path == NULL ) { if( path == NULL ) {
printf("specify a path to a file to transmit\n"); printf("specify a path to a file to transmit\n");
usage(); usage();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// Compute default value depending on sample rate // Compute default value depending on sample rate
baseband_filter_bw_hz = hackrf_compute_baseband_filter_bw_round_down_lt(sample_rate_hz); baseband_filter_bw_hz = hackrf_compute_baseband_filter_bw_round_down_lt(sample_rate_hz);
result = hackrf_init(); result = hackrf_init();
if( result != HACKRF_SUCCESS ) { if( result != HACKRF_SUCCESS ) {
printf("hackrf_init() failed: %s (%d)\n", hackrf_error_name(result), result); printf("hackrf_init() failed: %s (%d)\n", hackrf_error_name(result), result);
usage(); usage();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
result = hackrf_open_by_serial(NULL, &device); result = hackrf_open_by_serial(NULL, &device);
if( result != HACKRF_SUCCESS ) { if( result != HACKRF_SUCCESS ) {
printf("hackrf_open() failed: %s (%d)\n", hackrf_error_name(result), result); printf("hackrf_open() failed: %s (%d)\n", hackrf_error_name(result), result);
usage(); usage();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
fd = fopen(path, "rb"); fd = fopen(path, "rb");
if( fd == NULL ) { if( fd == NULL ) {
printf("Failed to open file: %s\n", path); printf("Failed to open file: %s\n", path);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// Change fd buffer to have bigger one to store or read data on/to HDD // Change fd buffer to have bigger one to store or read data on/to HDD
result = setvbuf(fd , NULL , _IOFBF , FD_BUFFER_SIZE); result = setvbuf(fd , NULL , _IOFBF , FD_BUFFER_SIZE);
if( result != 0 ) { if( result != 0 ) {
printf("setvbuf() failed: %d\n", result); printf("setvbuf() failed: %d\n", result);
usage(); usage();
return EXIT_FAILURE; 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)); 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); result = hackrf_set_sample_rate_manual(device, sample_rate_hz, 1);
if( result != HACKRF_SUCCESS ) { if( result != HACKRF_SUCCESS ) {
printf("hackrf_sample_rate_set() failed: %s (%d)\n", hackrf_error_name(result), result); printf("hackrf_sample_rate_set() failed: %s (%d)\n", hackrf_error_name(result), result);
usage(); usage();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
printf("call hackrf_baseband_filter_bandwidth_set(%.03f MHz)\n", printf("call hackrf_baseband_filter_bandwidth_set(%.03f MHz)\n",
((float)baseband_filter_bw_hz/(float)FREQ_ONE_MHZ)); ((float)baseband_filter_bw_hz/(float)FREQ_ONE_MHZ));
result = hackrf_set_baseband_filter_bandwidth(device, baseband_filter_bw_hz); result = hackrf_set_baseband_filter_bandwidth(device, baseband_filter_bw_hz);
if( result != HACKRF_SUCCESS ) { if( result != HACKRF_SUCCESS ) {
printf("hackrf_baseband_filter_bandwidth_set() failed: %s (%d)\n", hackrf_error_name(result), result); printf("hackrf_baseband_filter_bandwidth_set() failed: %s (%d)\n", hackrf_error_name(result), result);
usage(); usage();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
result = hackrf_set_txvga_gain(device, txvga_gain); result = hackrf_set_txvga_gain(device, txvga_gain);
result |= hackrf_start_tx(device, tx_callback, NULL); result |= hackrf_start_tx(device, tx_callback, NULL);
if( result != HACKRF_SUCCESS ) { if( result != HACKRF_SUCCESS ) {
printf("hackrf_start_?x() failed: %s (%d)\n", hackrf_error_name(result), result); printf("hackrf_start_?x() failed: %s (%d)\n", hackrf_error_name(result), result);
usage(); usage();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
printf("call hackrf_set_freq(%.03f MHz)\n", ((double)freq_hz/(double)FREQ_ONE_MHZ)); printf("call hackrf_set_freq(%.03f MHz)\n", ((double)freq_hz/(double)FREQ_ONE_MHZ));
result = hackrf_set_freq(device, freq_hz); result = hackrf_set_freq(device, freq_hz);
if( result != HACKRF_SUCCESS ) { if( result != HACKRF_SUCCESS ) {
printf("hackrf_set_freq() failed: %s (%d)\n", hackrf_error_name(result), result); printf("hackrf_set_freq() failed: %s (%d)\n", hackrf_error_name(result), result);
usage(); usage();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
printf("call hackrf_set_amp_enable(%u)\n", amp_enable); printf("call hackrf_set_amp_enable(%u)\n", amp_enable);
result = hackrf_set_amp_enable(device, (uint8_t)amp_enable); result = hackrf_set_amp_enable(device, (uint8_t)amp_enable);
if( result != HACKRF_SUCCESS ) { if( result != HACKRF_SUCCESS ) {
printf("hackrf_set_amp_enable() failed: %s (%d)\n", hackrf_error_name(result), result); printf("hackrf_set_amp_enable() failed: %s (%d)\n", hackrf_error_name(result), result);
usage(); usage();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
printf("Stop with Ctrl-C\n"); printf("Stop with Ctrl-C\n");
while( (hackrf_is_streaming(device) == HACKRF_TRUE) && (do_exit == false) ) { while( (hackrf_is_streaming(device) == HACKRF_TRUE) && (do_exit == false) ) {
// Show something? // Show something?
} }
result = hackrf_is_streaming(device); result = hackrf_is_streaming(device);
if (do_exit) { if (do_exit) {
printf("\nUser cancel, exiting...\n"); printf("\nUser cancel, exiting...\n");
} else { } else {
printf("\nExiting... hackrf_is_streaming() result: %s (%d)\n", hackrf_error_name(result), result); printf("\nExiting... hackrf_is_streaming() result: %s (%d)\n", hackrf_error_name(result), result);
} }
if(device != NULL) { if(device != NULL) {
result = hackrf_stop_tx(device); result = hackrf_stop_tx(device);
if( result != HACKRF_SUCCESS ) { if( result != HACKRF_SUCCESS ) {
printf("hackrf_stop_tx() failed: %s (%d)\n", hackrf_error_name(result), result); printf("hackrf_stop_tx() failed: %s (%d)\n", hackrf_error_name(result), result);
} else { } else {
printf("hackrf_stop_tx() done\n"); printf("hackrf_stop_tx() done\n");
} }
result = hackrf_close(device); result = hackrf_close(device);
if( result != HACKRF_SUCCESS ) if( result != HACKRF_SUCCESS )
{ {
printf("hackrf_close() failed: %s (%d)\n", hackrf_error_name(result), result); printf("hackrf_close() failed: %s (%d)\n", hackrf_error_name(result), result);
} else { } else {
printf("hackrf_close() done\n"); printf("hackrf_close() done\n");
} }
hackrf_exit();
printf("hackrf_exit() done\n");
}
if(fd != NULL) { hackrf_exit();
fclose(fd); printf("hackrf_exit() done\n");
fd = NULL; }
printf("fclose(fd) done\n");
}
printf("exit\n"); if(fd != NULL) {
return EXIT_SUCCESS; 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 int control_c_received = 0;
static void control_c_handler (int sig, siginfo_t *siginfo, void *context){ 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){ 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" "-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" "-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" "\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" "-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" "-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" "\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" "Example:" "\n"
"\t" "./limeplayer -s 1000000 -b 1 -d 1023 -g 0.1 < ../circle.1b.1M.bin" "\n", progname); "\t" "./limeplayer -s 1000000 -b 1 -d 1023 -g 0.1 < ../circle.1b.1M.bin" "\n", progname);
exit(0); exit(0);
} }
int main(int argc, char *const argv[]){ int main(int argc, char *const argv[]){
struct sigaction control_c; struct sigaction control_c;
memset(&control_c, 0, sizeof(control_c)); memset(&control_c, 0, sizeof(control_c));
control_c.sa_sigaction = &control_c_handler; control_c.sa_sigaction = &control_c_handler;
/* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler. */ /* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler. */
control_c.sa_flags = SA_SIGINFO; control_c.sa_flags = SA_SIGINFO;
if (sigaction(SIGTERM, &control_c, NULL) < 0) { if (sigaction(SIGTERM, &control_c, NULL) < 0) {
perror ("sigaction"); perror ("sigaction");
return(EXIT_CODE_CONTROL_C); return(EXIT_CODE_CONTROL_C);
} }
if (sigaction(SIGQUIT, &control_c, NULL) < 0) { if (sigaction(SIGQUIT, &control_c, NULL) < 0) {
perror ("sigaction"); perror ("sigaction");
return(EXIT_CODE_CONTROL_C); return(EXIT_CODE_CONTROL_C);
} }
if (sigaction(SIGINT, &control_c, NULL) < 0) { if (sigaction(SIGINT, &control_c, NULL) < 0) {
perror ("sigaction"); perror ("sigaction");
return(EXIT_CODE_CONTROL_C); return(EXIT_CODE_CONTROL_C);
} }
int device_count = LMS_GetDeviceList(NULL); int device_count = LMS_GetDeviceList(NULL);
if(device_count < 1){ if(device_count < 1){
return(EXIT_CODE_NO_DEVICE); return(EXIT_CODE_NO_DEVICE);
} }
lms_info_str_t *device_list = malloc(sizeof(lms_info_str_t) * device_count); lms_info_str_t *device_list = malloc(sizeof(lms_info_str_t) * device_count);
device_count = LMS_GetDeviceList(device_list); device_count = LMS_GetDeviceList(device_list);
int i = 0; int i = 0;
while(i < device_count){ while(i < device_count){
// printf("device[%d/%d]=%s" "\n", i + 1, device_count, device_list[i]); // printf("device[%d/%d]=%s" "\n", i + 1, device_count, device_list[i]);
i++; i++;
} }
double gain = 1.0; double gain = 1.0;
int32_t antenna = DEFAULT_ANTENNA; int32_t antenna = DEFAULT_ANTENNA;
int32_t channel = 0; int32_t channel = 0;
int32_t index = 0; int32_t index = 0;
int32_t bits = 16; int32_t bits = 16;
double sampleRate = TX_SAMPLERATE; double sampleRate = TX_SAMPLERATE;
int32_t dynamic = 2047; int32_t dynamic = 2047;
while (1) { while (1) {
int option_index = 0; int option_index = 0;
@ -109,7 +109,7 @@ int main(int argc, char *const argv[]){
#if 1 #if 1
fprintf(stderr, "option %s", long_options[option_index].name); fprintf(stderr, "option %s", long_options[option_index].name);
if (optarg) if (optarg)
fprintf(stderr, " with arg %s", optarg); fprintf(stderr, " with arg %s", optarg);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
#endif #endif
@ -130,272 +130,272 @@ int main(int argc, char *const argv[]){
case 'i': case 'i':
index = strtol(optarg, NULL, 0); index = strtol(optarg, NULL, 0);
break; break;
case 's': case 's':
sampleRate = strtod(optarg, NULL); sampleRate = strtod(optarg, NULL);
break; break;
case 'd': case 'd':
dynamic = strtol(optarg, NULL, 0); dynamic = strtol(optarg, NULL, 0);
if(dynamic > 2047){ if(dynamic > 2047){
dynamic = 2047; dynamic = 2047;
} }
break; break;
default: default:
print_usage(argv[0]); print_usage(argv[0]);
break; break;
} }
} }
// Use correct values // Use correct values
// Use existing device // Use existing device
if(index < 0){ if(index < 0){
index = 0; index = 0;
} }
if(index >= device_count){ if(index >= device_count){
index = 0; index = 0;
} }
printf("Using device index %d [%s]" "\n", index, device_list[index]); printf("Using device index %d [%s]" "\n", index, device_list[index]);
// Normalized gain shall be in [0.0 .. 1.0] // Normalized gain shall be in [0.0 .. 1.0]
if(gain < 0.0){ if(gain < 0.0){
gain = 0.0; gain = 0.0;
} }
if(gain > 1.0){ if(gain > 1.0){
gain = 1.0; gain = 1.0;
} }
printf("Using normalized gain %lf" "\n", gain); 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)){ if(LMS_Open(&device, device_list[index], NULL)){
return(EXIT_CODE_LMS_OPEN); return(EXIT_CODE_LMS_OPEN);
} }
int lmsReset = LMS_Reset(device); int lmsReset = LMS_Reset(device);
if(lmsReset){ if(lmsReset){
printf("lmsReset %d(%s)" "\n", lmsReset, LMS_GetLastErrorMessage()); printf("lmsReset %d(%s)" "\n", lmsReset, LMS_GetLastErrorMessage());
} }
int lmsInit = LMS_Init(device); int lmsInit = LMS_Init(device);
if(lmsInit){ if(lmsInit){
printf("lmsInit %d(%s)" "\n", lmsInit, LMS_GetLastErrorMessage()); printf("lmsInit %d(%s)" "\n", lmsInit, LMS_GetLastErrorMessage());
} }
int channel_count = LMS_GetNumChannels(device, LMS_CH_TX); int channel_count = LMS_GetNumChannels(device, LMS_CH_TX);
// printf("Tx channel count %d" "\n", channel_count); // printf("Tx channel count %d" "\n", channel_count);
if(channel < 0){ if(channel < 0){
channel = 0; channel = 0;
} }
if(channel >= channel_count){ if(channel >= channel_count){
channel = 0; channel = 0;
} }
printf("Using channel %d" "\n", channel); printf("Using channel %d" "\n", channel);
int antenna_count = LMS_GetAntennaList(device, LMS_CH_TX, channel, NULL); int antenna_count = LMS_GetAntennaList(device, LMS_CH_TX, channel, NULL);
// printf("TX%d Channel has %d antenna(ae)" "\n", channel, antenna_count); // printf("TX%d Channel has %d antenna(ae)" "\n", channel, antenna_count);
lms_name_t antenna_name[antenna_count]; lms_name_t antenna_name[antenna_count];
if(antenna_count > 0){ if(antenna_count > 0){
int i = 0; int i = 0;
lms_range_t antenna_bw[antenna_count]; lms_range_t antenna_bw[antenna_count];
LMS_GetAntennaList(device, LMS_CH_TX, channel, antenna_name); LMS_GetAntennaList(device, LMS_CH_TX, channel, antenna_name);
for(i = 0 ; i < antenna_count ; i++){ for(i = 0 ; i < antenna_count ; i++){
LMS_GetAntennaBW(device, LMS_CH_TX, channel, i, antenna_bw + 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); // 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){ if(antenna < 0){
antenna = DEFAULT_ANTENNA; antenna = DEFAULT_ANTENNA;
} }
if(antenna >= antenna_count){ if(antenna >= antenna_count){
antenna = DEFAULT_ANTENNA; antenna = DEFAULT_ANTENNA;
} }
// LMS_SetAntenna(device, LMS_CH_TX, channel, antenna); // SetLOFrequency should take care of selecting the proper 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); LMS_SetNormalizedGain(device, LMS_CH_TX, channel, gain);
// Disable all other channels // Disable all other channels
LMS_EnableChannel(device, LMS_CH_TX, 1 - channel, false); LMS_EnableChannel(device, LMS_CH_TX, 1 - channel, false);
LMS_EnableChannel(device, LMS_CH_RX, 0, false); LMS_EnableChannel(device, LMS_CH_RX, 0, false);
LMS_EnableChannel(device, LMS_CH_RX, 1, false); LMS_EnableChannel(device, LMS_CH_RX, 1, false);
// Enable our Tx channel // Enable our Tx channel
LMS_EnableChannel(device, LMS_CH_TX, channel, true); LMS_EnableChannel(device, LMS_CH_TX, channel, true);
int setLOFrequency = LMS_SetLOFrequency(device, LMS_CH_TX, channel, TX_FREQUENCY); int setLOFrequency = LMS_SetLOFrequency(device, LMS_CH_TX, channel, TX_FREQUENCY);
if(setLOFrequency){ if(setLOFrequency){
printf("setLOFrequency(%lf)=%d(%s)" "\n", TX_FREQUENCY, setLOFrequency, LMS_GetLastErrorMessage()); printf("setLOFrequency(%lf)=%d(%s)" "\n", TX_FREQUENCY, setLOFrequency, LMS_GetLastErrorMessage());
} }
#ifdef __USE_LPF__ #ifdef __USE_LPF__
lms_range_t LPFBWRange; lms_range_t LPFBWRange;
LMS_GetLPFBWRange(device, LMS_CH_TX, &LPFBWRange); LMS_GetLPFBWRange(device, LMS_CH_TX, &LPFBWRange);
// printf("TX%d LPFBW [%lf .. %lf] (step %lf)" "\n", channel, LPFBWRange.min, LPFBWRange.max, LPFBWRange.step); // printf("TX%d LPFBW [%lf .. %lf] (step %lf)" "\n", channel, LPFBWRange.min, LPFBWRange.max, LPFBWRange.step);
double LPFBW = TX_BANDWIDTH; double LPFBW = TX_BANDWIDTH;
if(LPFBW < LPFBWRange.min){ if(LPFBW < LPFBWRange.min){
LPFBW = LPFBWRange.min; LPFBW = LPFBWRange.min;
} }
if(LPFBW > LPFBWRange.max){ if(LPFBW > LPFBWRange.max){
LPFBW = LPFBWRange.min; LPFBW = LPFBWRange.min;
} }
int setLPFBW = LMS_SetLPFBW(device, LMS_CH_TX, channel, LPFBW); int setLPFBW = LMS_SetLPFBW(device, LMS_CH_TX, channel, LPFBW);
if(setLPFBW){ if(setLPFBW){
printf("setLPFBW(%lf)=%d(%s)" "\n", LPFBW, setLPFBW, LMS_GetLastErrorMessage()); printf("setLPFBW(%lf)=%d(%s)" "\n", LPFBW, setLPFBW, LMS_GetLastErrorMessage());
} }
int enableLPF = LMS_SetLPF(device, LMS_CH_TX, channel, true); int enableLPF = LMS_SetLPF(device, LMS_CH_TX, channel, true);
if(enableLPF){ if(enableLPF){
printf("enableLPF=%d(%s)" "\n", enableLPF, LMS_GetLastErrorMessage()); printf("enableLPF=%d(%s)" "\n", enableLPF, LMS_GetLastErrorMessage());
} }
#endif #endif
lms_range_t sampleRateRange; lms_range_t sampleRateRange;
int getSampleRateRange = LMS_GetSampleRateRange(device, LMS_CH_TX, &sampleRateRange); int getSampleRateRange = LMS_GetSampleRateRange(device, LMS_CH_TX, &sampleRateRange);
if(getSampleRateRange){ if(getSampleRateRange){
printf("getSampleRateRange=%d(%s)" "\n", getSampleRateRange, LMS_GetLastErrorMessage()); printf("getSampleRateRange=%d(%s)" "\n", getSampleRateRange, LMS_GetLastErrorMessage());
}else{ }else{
// printf("sampleRateRange [%lf MHz.. %lf MHz] (step=%lf Hz)" "\n", sampleRateRange.min / 1e6, sampleRateRange.max / 1e6, sampleRateRange.step); // 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); printf("Set sample rate to %lf ..." "\n", sampleRate);
int setSampleRate = LMS_SetSampleRate(device, sampleRate, 0); int setSampleRate = LMS_SetSampleRate(device, sampleRate, 0);
if(setSampleRate){ if(setSampleRate){
printf("setSampleRate=%d(%s)" "\n", setSampleRate, LMS_GetLastErrorMessage()); printf("setSampleRate=%d(%s)" "\n", setSampleRate, LMS_GetLastErrorMessage());
} }
double actualHostSampleRate = 0.0; double actualHostSampleRate = 0.0;
double actualRFSampleRate = 0.0; double actualRFSampleRate = 0.0;
int getSampleRate = LMS_GetSampleRate(device, LMS_CH_TX, channel, &actualHostSampleRate, &actualRFSampleRate); int getSampleRate = LMS_GetSampleRate(device, LMS_CH_TX, channel, &actualHostSampleRate, &actualRFSampleRate);
if(getSampleRate){ if(getSampleRate){
printf("getSampleRate=%d(%s)" "\n", getSampleRate, LMS_GetLastErrorMessage()); printf("getSampleRate=%d(%s)" "\n", getSampleRate, LMS_GetLastErrorMessage());
}else{ }else{
printf("actualRate %lf (Host) / %lf (RF)" "\n", actualHostSampleRate, actualRFSampleRate); printf("actualRate %lf (Host) / %lf (RF)" "\n", actualHostSampleRate, actualRFSampleRate);
} }
printf("Calibrating ..." "\n"); printf("Calibrating ..." "\n");
int calibrate = LMS_Calibrate(device, LMS_CH_TX, channel, TX_BANDWIDTH, 0); int calibrate = LMS_Calibrate(device, LMS_CH_TX, channel, TX_BANDWIDTH, 0);
if(calibrate){ if(calibrate){
printf("calibrate=%d(%s)" "\n", calibrate, LMS_GetLastErrorMessage()); printf("calibrate=%d(%s)" "\n", calibrate, LMS_GetLastErrorMessage());
} }
printf("Setup TX stream ..." "\n"); printf("Setup TX stream ..." "\n");
lms_stream_t tx_stream = {.channel = channel, .fifoSize = 1024*1024, .throughputVsLatency = 0.5, .isTx = true, .dataFmt = LMS_FMT_I12}; 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); int setupStream = LMS_SetupStream(device, &tx_stream);
if(setupStream){ if(setupStream){
printf("setupStream=%d(%s)" "\n", setupStream, LMS_GetLastErrorMessage()); printf("setupStream=%d(%s)" "\n", setupStream, LMS_GetLastErrorMessage());
} }
struct s16iq_sample_s { struct s16iq_sample_s {
signed short int i; signed short int i;
signed short int q; signed short int q;
}; };
int nSamples = (int)sampleRate / 100; int nSamples = (int)sampleRate / 100;
struct s16iq_sample_s *sampleBuffer = (struct s16iq_sample_s*)malloc(sizeof(struct s16iq_sample_s) * nSamples); 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; int loop = 0;
if((12 == bits) || (16 == bits)){ if((12 == bits) || (16 == bits)){
// File contains interleaved 16-bit IQ values, either with only 12-bit data, or with 16-bit data // 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)){ while((0 == control_c_received) && fread(sampleBuffer, sizeof(struct s16iq_sample_s), nSamples, stdin)){
loop++; loop++;
if(0 == (loop % 100)){ if(0 == (loop % 100)){
struct timeval tv; struct timeval tv;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
printf("gettimeofday()=> %ld:%06ld ; ", tv.tv_sec, tv.tv_usec); printf("gettimeofday()=> %ld:%06ld ; ", tv.tv_sec, tv.tv_usec);
lms_stream_status_t status; lms_stream_status_t status;
LMS_GetStreamStatus(&tx_stream, &status); //Obtain TX stream stats LMS_GetStreamStatus(&tx_stream, &status); //Obtain TX stream stats
printf("TX rate:%lf MB/s" "\n", status.linkRate / 1e6); printf("TX rate:%lf MB/s" "\n", status.linkRate / 1e6);
} }
if(16 == bits){ if(16 == bits){
// Scale down to 12-bit // Scale down to 12-bit
// Quick and dirty, so -1 (0xFFFF) to -15 (0xFFF1) scale down to -1 instead of 0 // Quick and dirty, so -1 (0xFFFF) to -15 (0xFFF1) scale down to -1 instead of 0
int i = 0; int i = 0;
while(i < nSamples){ while(i < nSamples){
sampleBuffer[i].i >>= 4; sampleBuffer[i].i >>= 4;
sampleBuffer[i].q >>= 4; sampleBuffer[i].q >>= 4;
i++; i++;
} }
} }
int sendStream = LMS_SendStream(&tx_stream, sampleBuffer, nSamples, NULL, 1000); int sendStream = LMS_SendStream(&tx_stream, sampleBuffer, nSamples, NULL, 1000);
if(sendStream < 0){ if(sendStream < 0){
printf("sendStream %d(%s)" "\n", sendStream, LMS_GetLastErrorMessage()); printf("sendStream %d(%s)" "\n", sendStream, LMS_GetLastErrorMessage());
} }
} }
}else if(8 == bits){ }else if(8 == bits){
// File contains interleaved signed 8-bit IQ values // File contains interleaved signed 8-bit IQ values
struct s8iq_sample_s { struct s8iq_sample_s {
signed char i; signed char i;
signed char q; signed char q;
}; };
struct s8iq_sample_s *fileSamples = (struct s8iq_sample_s*)malloc(sizeof(struct s8iq_sample_s) * nSamples); 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)){ while((0 == control_c_received) && fread(fileSamples, sizeof(struct s8iq_sample_s), nSamples, stdin)){
loop++; loop++;
if(0 == (loop % 100)){ if(0 == (loop % 100)){
struct timeval tv; struct timeval tv;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
printf("gettimeofday()=> %ld:%06ld ; ", tv.tv_sec, tv.tv_usec); printf("gettimeofday()=> %ld:%06ld ; ", tv.tv_sec, tv.tv_usec);
lms_stream_status_t status; lms_stream_status_t status;
LMS_GetStreamStatus(&tx_stream, &status); //Obtain TX stream stats LMS_GetStreamStatus(&tx_stream, &status); //Obtain TX stream stats
printf("TX rate:%lf MB/s" "\n", status.linkRate / 1e6); printf("TX rate:%lf MB/s" "\n", status.linkRate / 1e6);
} }
// Up-Scale to 12-bit // Up-Scale to 12-bit
int i = 0; int i = 0;
while(i < nSamples){ while(i < nSamples){
sampleBuffer[i].i = (fileSamples[i].i << 4); sampleBuffer[i].i = (fileSamples[i].i << 4);
sampleBuffer[i].q = (fileSamples[i].q << 4); sampleBuffer[i].q = (fileSamples[i].q << 4);
i++; i++;
} }
int sendStream = LMS_SendStream(&tx_stream, sampleBuffer, nSamples, NULL, 1000); int sendStream = LMS_SendStream(&tx_stream, sampleBuffer, nSamples, NULL, 1000);
if(sendStream < 0){ if(sendStream < 0){
printf("sendStream %d(%s)" "\n", sendStream, LMS_GetLastErrorMessage()); printf("sendStream %d(%s)" "\n", sendStream, LMS_GetLastErrorMessage());
} }
} }
free(fileSamples); free(fileSamples);
}else if(1 == bits){ }else if(1 == bits){
// File contains interleaved signed 1-bit IQ values // File contains interleaved signed 1-bit IQ values
// Each byte is IQIQIQIQ // Each byte is IQIQIQIQ
int16_t expand_lut[256][8]; int16_t expand_lut[256][8];
int i, j; int i, j;
for (i=0; i<256; i++){ for (i=0; i<256; i++){
for (j=0; j<8; j++){ for (j=0; j<8; j++){
expand_lut[i][j] = ((i>>(7-j))&0x1)?dynamic:-dynamic; expand_lut[i][j] = ((i>>(7-j))&0x1)?dynamic:-dynamic;
} }
} }
printf("1-bit mode: using dynamic=%d" "\n", 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])); // 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); int8_t *fileBuffer = (int8_t*)malloc(sizeof(int8_t) * nSamples);
while((0 == control_c_received) && fread(fileBuffer, sizeof(int8_t), nSamples / 4, stdin)){ while((0 == control_c_received) && fread(fileBuffer, sizeof(int8_t), nSamples / 4, stdin)){
loop++; loop++;
if(0 == (loop % 100)){ if(0 == (loop % 100)){
struct timeval tv; struct timeval tv;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
printf("gettimeofday()=> %ld:%06ld ; ", tv.tv_sec, tv.tv_usec); printf("gettimeofday()=> %ld:%06ld ; ", tv.tv_sec, tv.tv_usec);
lms_stream_status_t status; lms_stream_status_t status;
LMS_GetStreamStatus(&tx_stream, &status); //Obtain TX stream stats LMS_GetStreamStatus(&tx_stream, &status); //Obtain TX stream stats
printf("TX rate:%lf MB/s" "\n", status.linkRate / 1e6); printf("TX rate:%lf MB/s" "\n", status.linkRate / 1e6);
} }
// Expand // Expand
int src = 0; int src = 0;
int dst = 0; int dst = 0;
while(src < (nSamples / 4)){ while(src < (nSamples / 4)){
memcpy(sampleBuffer + dst, expand_lut + fileBuffer[src], sizeof(expand_lut[0])); memcpy(sampleBuffer + dst, expand_lut + fileBuffer[src], sizeof(expand_lut[0]));
dst += 4; dst += 4;
src++; src++;
} }
int sendStream = LMS_SendStream(&tx_stream, sampleBuffer, nSamples, NULL, 1000); int sendStream = LMS_SendStream(&tx_stream, sampleBuffer, nSamples, NULL, 1000);
if(sendStream < 0){ if(sendStream < 0){
printf("sendStream %d(%s)" "\n", sendStream, LMS_GetLastErrorMessage()); printf("sendStream %d(%s)" "\n", sendStream, LMS_GetLastErrorMessage());
} }
} }
free(fileBuffer); free(fileBuffer);
} }
LMS_StopStream(&tx_stream); LMS_StopStream(&tx_stream);
LMS_DestroyStream(device, &tx_stream); LMS_DestroyStream(device, &tx_stream);
free(sampleBuffer); free(sampleBuffer);
LMS_EnableChannel(device, LMS_CH_TX, channel, false); LMS_EnableChannel(device, LMS_CH_TX, channel, false);
LMS_Close(device); LMS_Close(device);
if(control_c_received){ if(control_c_received){
return(EXIT_CODE_CONTROL_C); return(EXIT_CODE_CONTROL_C);
} }
return(0); 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;
}