Add basic sxceiver sdr module
This commit is contained in:
parent
159c3f1518
commit
eb03e6a661
276
impl/src/sdr/sdr_sxceiver.c
Normal file
276
impl/src/sdr/sdr_sxceiver.c
Normal file
|
@ -0,0 +1,276 @@
|
|||
#include <SoapySDR/Device.h>
|
||||
#include <SoapySDR/Formats.h>
|
||||
#include <SoapySDR/Logger.h>
|
||||
#include <liquid/liquid.h>
|
||||
#include <stdio.h> //printf
|
||||
#include <stdlib.h> //free
|
||||
#include <complex.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sdr.h"
|
||||
|
||||
void soapy_log_handler(const SoapySDRLogLevel logLevel, const char *message)
|
||||
{
|
||||
fprintf(stderr, "soapy [%d]: %s\n", logLevel, message);
|
||||
}
|
||||
|
||||
static void close_streams(sdr_sxceiver_ctx_t *ctx)
|
||||
{
|
||||
if(ctx->rx_stream) {
|
||||
SoapySDRDevice_deactivateStream(ctx->sdr, ctx->rx_stream, 0, 0);
|
||||
SoapySDRDevice_closeStream(ctx->sdr, ctx->rx_stream);
|
||||
}
|
||||
|
||||
if(ctx->tx_stream) {
|
||||
SoapySDRDevice_deactivateStream(ctx->sdr, ctx->tx_stream, 0, 0);
|
||||
SoapySDRDevice_closeStream(ctx->sdr, ctx->tx_stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
result_t sdr_sxceiver_init(sdr_sxceiver_ctx_t *ctx)
|
||||
{
|
||||
size_t length;
|
||||
|
||||
ctx->sdr = NULL;
|
||||
ctx->tx_stream = NULL;
|
||||
ctx->rx_stream = NULL;
|
||||
|
||||
ctx->tx_nco = nco_crcf_create(LIQUID_NCO);
|
||||
ctx->rx_nco = nco_crcf_create(LIQUID_NCO);
|
||||
|
||||
nco_crcf_set_frequency(ctx->tx_nco, 2 * M_PI * SDR_TX_IF_SHIFT / SDR_TX_SAMPLING_RATE);
|
||||
nco_crcf_set_frequency(ctx->rx_nco, 2 * M_PI * SDR_RX_IF_SHIFT / SDR_RX_SAMPLING_RATE);
|
||||
|
||||
// set up logging
|
||||
SoapySDR_registerLogHandler(soapy_log_handler);
|
||||
|
||||
//enumerate devices
|
||||
SoapySDRKwargs *results = SoapySDRDevice_enumerate(NULL, &length);
|
||||
for (size_t i = 0; i < length; i++)
|
||||
{
|
||||
fprintf(stderr, "sdr: Found device #%d:\n", (int)i);
|
||||
for (size_t j = 0; j < results[i].size; j++)
|
||||
{
|
||||
fprintf(stderr, "sdr: - %s=%s\n", results[i].keys[j], results[i].vals[j]);
|
||||
}
|
||||
fprintf(stderr, "sdr: \n");
|
||||
}
|
||||
SoapySDRKwargsList_clear(results, length);
|
||||
|
||||
//create device instance
|
||||
//args can be user defined or from the enumeration result
|
||||
SoapySDRKwargs args;
|
||||
memset(&args, 0, sizeof(args));
|
||||
SoapySDRKwargs_set(&args, "driver", "sx");
|
||||
ctx->sdr = SoapySDRDevice_make(&args);
|
||||
SoapySDRKwargs_clear(&args);
|
||||
|
||||
if (ctx->sdr == NULL)
|
||||
{
|
||||
fprintf(stderr, "sdr: SoapySDRDevice_make fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
//query device info
|
||||
char** names = SoapySDRDevice_listAntennas(ctx->sdr, SOAPY_SDR_RX, 0, &length);
|
||||
fprintf(stderr, "sdr: Rx antennas: ");
|
||||
for (size_t i = 0; i < length; i++) fprintf(stderr, "%s, ", names[i]);
|
||||
fprintf(stderr, "\n");
|
||||
SoapySDRStrings_clear(&names, length);
|
||||
|
||||
names = SoapySDRDevice_listGains(ctx->sdr, SOAPY_SDR_RX, 0, &length);
|
||||
fprintf(stderr, "sdr: Rx gains: ");
|
||||
for (size_t i = 0; i < length; i++) fprintf(stderr, "%s, ", names[i]);
|
||||
fprintf(stderr, "\n");
|
||||
SoapySDRStrings_clear(&names, length);
|
||||
|
||||
SoapySDRRange *ranges = SoapySDRDevice_getFrequencyRange(ctx->sdr, SOAPY_SDR_RX, 0, &length);
|
||||
fprintf(stderr, "sdr: Rx freq ranges: ");
|
||||
for (size_t i = 0; i < length; i++) fprintf(stderr, "[%g Hz -> %g Hz], ", ranges[i].minimum, ranges[i].maximum);
|
||||
fprintf(stderr, "\n");
|
||||
free(ranges);
|
||||
|
||||
char** names = SoapySDRDevice_listAntennas(ctx->sdr, SOAPY_SDR_TX, 0, &length);
|
||||
fprintf(stderr, "sdr: Tx antennas: ");
|
||||
for (size_t i = 0; i < length; i++) fprintf(stderr, "%s, ", names[i]);
|
||||
fprintf(stderr, "\n");
|
||||
SoapySDRStrings_clear(&names, length);
|
||||
|
||||
names = SoapySDRDevice_listGains(ctx->sdr, SOAPY_SDR_TX, 0, &length);
|
||||
fprintf(stderr, "sdr: Tx gains: ");
|
||||
for (size_t i = 0; i < length; i++) fprintf(stderr, "%s, ", names[i]);
|
||||
fprintf(stderr, "\n");
|
||||
SoapySDRStrings_clear(&names, length);
|
||||
|
||||
SoapySDRRange *ranges = SoapySDRDevice_getFrequencyRange(ctx->sdr, SOAPY_SDR_TX, 0, &length);
|
||||
fprintf(stderr, "sdr: Tx freq ranges: ");
|
||||
for (size_t i = 0; i < length; i++) fprintf(stderr, "[%g Hz -> %g Hz], ", ranges[i].minimum, ranges[i].maximum);
|
||||
fprintf(stderr, "\n");
|
||||
free(ranges);
|
||||
|
||||
//setup streams
|
||||
ctx->rx_stream = SoapySDRDevice_setupStream(ctx->sdr, SOAPY_SDR_RX, SOAPY_SDR_CF32, NULL, 0, NULL);
|
||||
|
||||
if(ctx->rx_stream == NULL) {
|
||||
fprintf(stderr, "sdr: setupStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
ctx->tx_stream = SoapySDRDevice_setupStream(ctx->sdr, SOAPY_SDR_TX, SOAPY_SDR_CF32, NULL, 0, NULL);
|
||||
|
||||
if(ctx->tx_stream == NULL) {
|
||||
fprintf(stderr, "sdr: setupStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
//apply settings
|
||||
if (SoapySDRDevice_setSampleRate(ctx->sdr, SOAPY_SDR_RX, 0, SDR_RX_SAMPLING_RATE) != 0) {
|
||||
fprintf(stderr, "sdr: setSampleRate fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
if (SoapySDRDevice_setFrequency(ctx->sdr, SOAPY_SDR_RX, 0, SDR_RX_FREQ - SDR_RX_IF_SHIFT, NULL) != 0) {
|
||||
fprintf(stderr, "sdr: setFrequency fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
if (SoapySDRDevice_setSampleRate(ctx->sdr, SOAPY_SDR_TX, 0, SDR_TX_SAMPLING_RATE) != 0) {
|
||||
fprintf(stderr, "sdr: setSampleRate fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
if (SoapySDRDevice_setFrequency(ctx->sdr, SOAPY_SDR_TX, 0, SDR_TX_FREQ, NULL) != 0) {
|
||||
fprintf(stderr, "sdr: setFrequency fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
result_t sdr_sxceiver_destroy(sdr_sxceiver_ctx_t *ctx)
|
||||
{
|
||||
close_streams(ctx);
|
||||
|
||||
nco_crcf_destroy(ctx->rx_nco);
|
||||
nco_crcf_destroy(ctx->tx_nco);
|
||||
|
||||
if(ctx->sdr) {
|
||||
SoapySDRDevice_unmake(ctx->sdr);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
result_t sdr_sxceiver_start_rx(sdr_sxceiver_ctx_t *ctx)
|
||||
{
|
||||
if(SoapySDRDevice_activateStream(ctx->sdr, ctx->rx_stream, 0, 0, 0) != 0) {
|
||||
fprintf(stderr, "sdr: activateStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
// set gains
|
||||
if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_RX, 0, "AMP", SDR_GAIN_RX_AMP) != 0) {
|
||||
fprintf(stderr, "sdr: setGainElement fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_RX, 0, "LNA", SDR_GAIN_RX_LNA) != 0) {
|
||||
fprintf(stderr, "sdr: setGainElement fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_RX, 0, "VGA", SDR_GAIN_RX_VGA) != 0) {
|
||||
fprintf(stderr, "sdr: setGainElement fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
result_t sdr_sxceiver_start_tx(sdr_sxceiver_ctx_t *ctx, size_t burst_size)
|
||||
{
|
||||
// set gain
|
||||
if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_TX, 0, "AMP", SDR_GAIN_TX_AMP) != 0) {
|
||||
fprintf(stderr, "sdr: setGainElement fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_TX, 0, "LNA", SDR_GAIN_TX_LNA) != 0) {
|
||||
fprintf(stderr, "sdr: setGainElement fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
if(SoapySDRDevice_activateStream(ctx->sdr, ctx->tx_stream, 0, 0, burst_size) != 0) {
|
||||
fprintf(stderr, "sdr: activateStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
result_t sdr_sxceiver_stop_rx(sdr_sxceiver_ctx_t *ctx)
|
||||
{
|
||||
if(SoapySDRDevice_deactivateStream(ctx->sdr, ctx->rx_stream, 0, 0) != 0) {
|
||||
fprintf(stderr, "sdr: activateStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
result_t sdr_sxceiver_stop_tx(sdr_sxceiver_ctx_t *ctx)
|
||||
{
|
||||
if(SoapySDRDevice_deactivateStream(ctx->sdr, ctx->tx_stream, 0, 0) != 0) {
|
||||
fprintf(stderr, "sdr: activateStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
result_t sdr_sxceiver_transmit(sdr_sxceiver_ctx_t *ctx, const float complex *samples, size_t nsamples, long timeout_us)
|
||||
{
|
||||
if(ctx->tx_stream == NULL) {
|
||||
return ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
void *buffs[] = {(void*)samples};
|
||||
|
||||
int ret = SoapySDRDevice_writeStream(ctx->sdr, ctx->tx_stream, (const void* const*)buffs, nsamples, 0, 0, timeout_us);
|
||||
|
||||
if(ret <= 0) {
|
||||
fprintf(stderr, "sdr: writeStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
result_t sdr_sxceiver_receive(sdr_sxceiver_ctx_t *ctx, float complex *samples, size_t *nsamples, long timeout_us)
|
||||
{
|
||||
if(ctx->rx_stream == NULL) {
|
||||
return ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
void *buffs[] = {(void*)samples};
|
||||
|
||||
int ret = SoapySDRDevice_readStream(ctx->sdr, ctx->rx_stream, (void* const*)buffs, *nsamples, 0, 0, timeout_us);
|
||||
|
||||
if(ret <= 0) {
|
||||
fprintf(stderr, "sdr: readStream fail: %s\n", SoapySDRDevice_lastError());
|
||||
return ERR_SOAPY;
|
||||
}
|
||||
|
||||
*nsamples = ret;
|
||||
|
||||
return OK;
|
||||
}
|
34
impl/src/sdr/sdr_sxceiver.h
Normal file
34
impl/src/sdr/sdr_sxceiver.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef SDR_SDR_H
|
||||
#define SDR_SDR_H
|
||||
|
||||
#include <complex.h>
|
||||
|
||||
#include <SoapySDR/Device.h>
|
||||
|
||||
#include <liquid/liquid.h>
|
||||
|
||||
#include "results.h"
|
||||
|
||||
typedef struct {
|
||||
SoapySDRDevice *sdr;
|
||||
|
||||
SoapySDRStream *rx_stream;
|
||||
SoapySDRStream *tx_stream;
|
||||
|
||||
nco_crcf tx_nco;
|
||||
nco_crcf rx_nco;
|
||||
} sdr_ctx_t;
|
||||
|
||||
result_t sdr_init(sdr_ctx_t *ctx);
|
||||
result_t sdr_destroy(sdr_ctx_t *ctx);
|
||||
|
||||
result_t sdr_start_rx(sdr_ctx_t *ctx);
|
||||
result_t sdr_start_tx(sdr_ctx_t *ctx, size_t burst_size);
|
||||
|
||||
result_t sdr_stop_rx(sdr_ctx_t *ctx);
|
||||
result_t sdr_stop_tx(sdr_ctx_t *ctx);
|
||||
|
||||
result_t sdr_transmit(sdr_ctx_t *ctx, const float complex *samples, size_t nsamples, long timeout_us);
|
||||
result_t sdr_receive(sdr_ctx_t *ctx, float complex *samples, size_t *nsamples, long timeout_us);
|
||||
|
||||
#endif // SDR_SDR_H
|
Loading…
Reference in a new issue