From a520b3232dd142180c73897eb3b694a0a8b5d4ec Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Sun, 13 Oct 2024 18:43:17 +0100 Subject: [PATCH] sdr/sx: implement timed transmission --- impl/src/main.c | 8 ++- impl/src/sdr/sdr_sxceiver.c | 137 ++++++++++++++++++++++++------------ impl/src/sdr/sdr_sxceiver.h | 2 +- 3 files changed, 99 insertions(+), 48 deletions(-) diff --git a/impl/src/main.c b/impl/src/main.c index ff42625..cb051c4 100644 --- a/impl/src/main.c +++ b/impl/src/main.c @@ -50,6 +50,8 @@ static int m_tunfd = -1; static bool m_running = true; +static double m_tstart = 0.0; + static double next_tx_switch_time = 0.0; static rx_stats_t m_rx_stats; @@ -149,7 +151,8 @@ void cb_rx(rx_evt_t evt, const struct layer1_rx_s *rx, uint8_t *packet_data, siz static result_t transmit(sdr_ctx_t *sdr, const float complex *samples, size_t len) { - result_t result = sdr_transmit(sdr, samples, len, 100000); + int64_t tx_time_ns = (int64_t)((get_hires_time() - m_tstart + 0.1) * 1e9); + result_t result = sdr_transmit(sdr, samples, len, tx_time_ns, 100000); fprintf(stderr, "t"); return result; @@ -223,10 +226,11 @@ int main(int argc, char **argv) // start in TX mode to work around SoapyHackRF not setting the correct frequency. RESULT_CHECK(sdr_start_tx(&sdr, 1)); + m_tstart = get_hires_time(); unsigned rx_retries = 0; - double old = get_hires_time(); + double old = m_tstart; size_t total_samples = 0; double next_stats_print_time = old + 0.5; diff --git a/impl/src/sdr/sdr_sxceiver.c b/impl/src/sdr/sdr_sxceiver.c index 6326740..62beb16 100644 --- a/impl/src/sdr/sdr_sxceiver.c +++ b/impl/src/sdr/sdr_sxceiver.c @@ -11,12 +11,43 @@ #include "logger.h" #include "config.h" +#include "utils.h" +#include "results.h" #include "sdr_sxceiver.h" void soapy_log_handler(const SoapySDRLogLevel logLevel, const char *message) { - LOG(LVL_ERR, "soapy [%d]: %s", logLevel, message); + int level; + + switch(logLevel) { + case SOAPY_SDR_CRITICAL: + case SOAPY_SDR_FATAL: + level = LVL_FATAL; + break; + + case SOAPY_SDR_ERROR: + level = LVL_ERR; + break; + + case SOAPY_SDR_WARNING: + level = LVL_WARN; + break; + + case SOAPY_SDR_INFO: + level = LVL_INFO; + break; + + case SOAPY_SDR_DEBUG: + level = LVL_DEBUG; + break; + + default: + level = LVL_DUMP; + break; + } + + LOG(level, "soapy [%d]: %s", logLevel, message); } static void close_streams(sdr_ctx_t *ctx) @@ -49,6 +80,7 @@ result_t sdr_init(sdr_ctx_t *ctx) // set up logging SoapySDR_registerLogHandler(soapy_log_handler); + //SoapySDR_setLogLevel(SOAPY_SDR_DEBUG); //enumerate devices SoapySDRKwargs *results = SoapySDRDevice_enumerate(NULL, &length); @@ -155,6 +187,55 @@ result_t sdr_init(sdr_ctx_t *ctx) return ERR_SOAPY; } +#if 0 + // PA always on + if (SoapySDRDevice_writeSetting(ctx->sdr, "PA", "ON") != 0) { + LOG(LVL_ERR, "writeSetting fail: %s", SoapySDRDevice_lastError()); + return ERR_SOAPY; + } +#endif + + // set up and start RX + + // set gains + if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_RX, 0, "PGA", SDR_GAIN_RX_PGA) != 0) { + LOG(LVL_ERR, "setGainElement fail: %s", SoapySDRDevice_lastError()); + return ERR_SOAPY; + } + + if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_RX, 0, "LNA", SDR_GAIN_RX_LNA) != 0) { + LOG(LVL_ERR, "setGainElement fail: %s", SoapySDRDevice_lastError()); + return ERR_SOAPY; + } + + if(SoapySDRDevice_activateStream(ctx->sdr, ctx->rx_stream, 0, 0, 0) != 0) { + LOG(LVL_ERR, "activateStream fail: %s", SoapySDRDevice_lastError()); + return ERR_SOAPY; + } + + // set up and start TX + + // set gain + /*if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_TX, 0, "DAC", SDR_GAIN_TX_DAC) != 0) { + LOG(LVL_ERR, "setGainElement fail: %s", SoapySDRDevice_lastError()); + return ERR_SOAPY; + } + + if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_TX, 0, "MIXER", SDR_GAIN_TX_MIXER) != 0) { + LOG(LVL_ERR, "setGainElement fail: %s", SoapySDRDevice_lastError()); + return ERR_SOAPY; + }*/ + + if(SoapySDRDevice_setGain(ctx->sdr, SOAPY_SDR_TX, 0, SDR_GAIN_TX) != 0) { + LOG(LVL_ERR, "setGain fail: %s", SoapySDRDevice_lastError()); + return ERR_SOAPY; + } + + if(SoapySDRDevice_activateStream(ctx->sdr, ctx->tx_stream, 0, 0, 0) != 0) { + LOG(LVL_ERR, "activateStream fail: %s", SoapySDRDevice_lastError()); + return ERR_SOAPY; + } + return OK; } @@ -176,21 +257,6 @@ result_t sdr_destroy(sdr_ctx_t *ctx) result_t sdr_start_rx(sdr_ctx_t *ctx) { - // set gains - if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_RX, 0, "PGA", SDR_GAIN_RX_PGA) != 0) { - LOG(LVL_ERR, "setGainElement fail: %s", SoapySDRDevice_lastError()); - return ERR_SOAPY; - } - - if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_RX, 0, "LNA", SDR_GAIN_RX_LNA) != 0) { - LOG(LVL_ERR, "setGainElement fail: %s", SoapySDRDevice_lastError()); - return ERR_SOAPY; - } - - if(SoapySDRDevice_activateStream(ctx->sdr, ctx->rx_stream, 0, 0, 0) != 0) { - LOG(LVL_ERR, "activateStream fail: %s", SoapySDRDevice_lastError()); - return ERR_SOAPY; - } return OK; } @@ -198,21 +264,6 @@ result_t sdr_start_rx(sdr_ctx_t *ctx) result_t sdr_start_tx(sdr_ctx_t *ctx, size_t burst_size) { - // set gain - if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_TX, 0, "DAC", SDR_GAIN_TX_DAC) != 0) { - LOG(LVL_ERR, "setGainElement fail: %s", SoapySDRDevice_lastError()); - return ERR_SOAPY; - } - - if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_TX, 0, "MIXER", SDR_GAIN_TX_MIXER) != 0) { - LOG(LVL_ERR, "setGainElement fail: %s", SoapySDRDevice_lastError()); - return ERR_SOAPY; - } - - if(SoapySDRDevice_activateStream(ctx->sdr, ctx->tx_stream, 0, 0, burst_size) != 0) { - LOG(LVL_ERR, "activateStream fail: %s", SoapySDRDevice_lastError()); - return ERR_SOAPY; - } return OK; } @@ -220,40 +271,36 @@ result_t sdr_start_tx(sdr_ctx_t *ctx, size_t burst_size) result_t sdr_stop_rx(sdr_ctx_t *ctx) { - if(SoapySDRDevice_deactivateStream(ctx->sdr, ctx->rx_stream, 0, 0) != 0) { - LOG(LVL_ERR, "activateStream fail: %s", SoapySDRDevice_lastError()); - return ERR_SOAPY; - } - return OK; } result_t sdr_stop_tx(sdr_ctx_t *ctx) { - if(SoapySDRDevice_deactivateStream(ctx->sdr, ctx->tx_stream, 0, 0) != 0) { - LOG(LVL_ERR, "activateStream fail: %s", SoapySDRDevice_lastError()); - return ERR_SOAPY; - } - return OK; } -result_t sdr_transmit(sdr_ctx_t *ctx, const float complex *samples, size_t nsamples, long timeout_us) +result_t sdr_transmit(sdr_ctx_t *ctx, const float complex *samples, size_t nsamples, int64_t time_ns, long timeout_us) { if(ctx->tx_stream == NULL) { return ERR_INVALID_STATE; } - void *buffs[] = {(void*)samples}; - int flags = 0; - int ret = SoapySDRDevice_writeStream(ctx->sdr, ctx->tx_stream, (const void* const*)buffs, nsamples, &flags, 0, timeout_us); + if(time_ns != 0) { + flags |= SOAPY_SDR_HAS_TIME; + } + + void *buffs[] = {(void*)(samples)}; + + int ret = SoapySDRDevice_writeStream(ctx->sdr, ctx->tx_stream, (const void* const*)buffs, nsamples, &flags, time_ns, timeout_us); if(ret <= 0) { LOG(LVL_ERR, "writeStream fail: %s", SoapySDRDevice_lastError()); return ERR_SOAPY; + } else if(ret != nsamples) { + LOG(LVL_WARN, "writeStream() did not transmit all samples: %i/%zu", ret, nsamples); } return OK; diff --git a/impl/src/sdr/sdr_sxceiver.h b/impl/src/sdr/sdr_sxceiver.h index 91ac994..c29b242 100644 --- a/impl/src/sdr/sdr_sxceiver.h +++ b/impl/src/sdr/sdr_sxceiver.h @@ -28,7 +28,7 @@ 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_transmit(sdr_ctx_t *ctx, const float complex *samples, size_t nsamples, int64_t time_ns, long timeout_us); result_t sdr_receive(sdr_ctx_t *ctx, float complex *samples, size_t *nsamples, long timeout_us); #endif // SDR_SDR_H