From d9707ac4a9072dae10148d57adf4ed5987e22ad7 Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Sat, 30 Mar 2024 21:56:00 +0100 Subject: [PATCH] test: add test_rx_file --- impl/test/CMakeLists.txt | 30 ++++++ impl/test/layer1/test_rx_file.c | 156 ++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 impl/test/layer1/test_rx_file.c diff --git a/impl/test/CMakeLists.txt b/impl/test/CMakeLists.txt index 9e45084..1fc43a6 100644 --- a/impl/test/CMakeLists.txt +++ b/impl/test/CMakeLists.txt @@ -61,3 +61,33 @@ target_link_libraries( m liquid ) + +#------------------------------------ + +add_executable( + test_rx_file + ../src/layer1/correlator.c + ../src/layer1/correlator.h + ../src/layer1/freq_est.c + ../src/layer1/freq_est.h + ../src/layer1/rx.c + ../src/layer1/rx.h + ../src/layer1/whitening.c + ../src/layer1/whitening.h + ../src/layer1/modcod.c + ../src/layer1/modcod.h + ../src/layer1/preamble.c + ../src/layer1/preamble.h + ../src/utils.c + ../src/utils.h + ../src/config.h + layer1/test_rx_file.c +) + +target_link_libraries( + test_rx_file + fec + fftw3f + m + liquid +) diff --git a/impl/test/layer1/test_rx_file.c b/impl/test/layer1/test_rx_file.c new file mode 100644 index 0000000..201864b --- /dev/null +++ b/impl/test/layer1/test_rx_file.c @@ -0,0 +1,156 @@ +#include +#include +#include + +#include + +#include "layer1/rx.h" + +#include "config.h" + +#define RESULT_CHECK(stmt) { \ + result_t res = stmt; \ + if(res != OK) { \ + fprintf(stderr, "Error %d in %s:%d!\n", res, __FILE__, __LINE__); \ + exit(1); \ + } \ +} + +#define CHUNKSIZE_INPUT 8000 +#define CHUNKSIZE_RF (CHUNKSIZE_INPUT/2) +#define CHUNKSIZE_BB (CHUNKSIZE_RF/SDR_OVERSAMPLING) + +static struct { + size_t preambles_found; + size_t successful_decodes; + size_t failed_decodes; + size_t header_errors; +} m_stats; + + +static result_t sdr_rf_to_baseband(nco_crcf nco, firdecim_crcf decim, + const float complex *rf_samples, size_t nrf, + float complex *bb_samples, size_t *nbb) +{ + if((*nbb * SDR_OVERSAMPLING) < nrf) { + fprintf(stderr, "sdr_rf_to_baseband: result would not fit in output: %zd * %d < %zd\n", *nbb, SDR_OVERSAMPLING, nrf); + return ERR_SIZE; + } + + *nbb = nrf / SDR_OVERSAMPLING; + + for(size_t i = 0; i < *nbb; i++) { + float complex tmp[SDR_OVERSAMPLING]; + + assert(i*SDR_OVERSAMPLING < nrf); + + nco_crcf_mix_block_down(nco, + (complex float*)(rf_samples + i * SDR_OVERSAMPLING), + tmp, + SDR_OVERSAMPLING); + + firdecim_crcf_execute(decim, tmp, bb_samples + i); + } + + return OK; +} + + +void cb_rx(rx_evt_t evt, uint8_t *packet_data, size_t packet_len) +{ + switch(evt) + { + case RX_EVT_CHECKSUM_ERROR: + //fprintf(stderr, "Received a message of %zu bytes, but decoding failed.\n", packet_len); + //fprintf(stderr, "=== FAILED PAYLOAD ===\n"); + //hexdump(packet_data, packet_len); + //fprintf(stderr, "=======================\n"); + m_stats.failed_decodes++; + break; + + case RX_EVT_HEADER_ERROR: + m_stats.header_errors++; + break; + + case RX_EVT_PACKET_RECEIVED: + //fprintf(stderr, "A message of %zu bytes was decoded successfully.\n", packet_len); + //fprintf(stderr, "=== DECODED PAYLOAD (%4zu bytes) ===\n", packet_len); + //hexdump(packet_data, packet_len < 64 ? packet_len : 64); + //fprintf(stderr, "====================================\n"); + + m_stats.successful_decodes++; + break; + + case RX_EVT_PREAMBLE_FOUND: + //fprintf(stderr, "Found preamble!\n"); + m_stats.preambles_found++; + break; + } +} + + +int main(int argc, char **argv) +{ + if(argc < 2) { + fprintf(stderr, "Not enough arguments!\n"); + fprintf(stderr, "usage: %s \n\n", argv[0]); + fprintf(stderr, "dump-file: HackRF dump in 8-bit signed interleaved I/Q format.\n"); + return 1; + } + + layer1_rx_t rx; + FILE *inputfile; + int8_t rbuf[CHUNKSIZE_INPUT]; + + // ** Initialize ** + + firdecim_crcf decim = firdecim_crcf_create_kaiser(SDR_OVERSAMPLING, 9, 60.0f); + nco_crcf rx_nco = nco_crcf_create(LIQUID_NCO); + + inputfile = fopen(argv[1], "rb"); + if(!inputfile) { + fprintf(stderr, "Could not open input file!\n"); + return 1; + } + + RESULT_CHECK(layer1_rx_init(&rx, cb_rx)); + + // ** Process packets ** + + size_t nread; + while((nread = fread(rbuf, 1, sizeof(rbuf), inputfile)) != 0) { + assert(nread % 2 == 0); + + // ** Receive signal ** + + float complex rf_samples[CHUNKSIZE_RF]; + float complex bb_samples[CHUNKSIZE_BB]; + + size_t n_rf_samples = CHUNKSIZE_RF; + size_t n_bb_samples = CHUNKSIZE_BB; + + for(size_t iout = 0; iout < CHUNKSIZE_RF; iout++) { + rf_samples[iout] = 0.0078125f * (rbuf[2*iout + 0] + I * rbuf[2*iout + 1]); + } + + RESULT_CHECK(sdr_rf_to_baseband(rx_nco, decim, rf_samples, n_rf_samples, bb_samples, &n_bb_samples)); + + RESULT_CHECK(layer1_rx_process(&rx, bb_samples, n_bb_samples)); + + fprintf(stderr, "Receiver statistics:\n"); + fprintf(stderr, " Preambles found: %8zd\n", m_stats.preambles_found); + fprintf(stderr, " Successful decodes: %8zd (%6.2f %%)\n", + m_stats.successful_decodes, m_stats.successful_decodes * 100.0f / m_stats.preambles_found); + fprintf(stderr, " Header errors: %8zd (%6.2f %%)\n", + m_stats.header_errors, m_stats.header_errors * 100.0f / m_stats.preambles_found); + fprintf(stderr, " Failed decodes: %8zd (%6.2f %%)\n", + m_stats.failed_decodes, m_stats.failed_decodes * 100.0f / m_stats.preambles_found); + + } + + // ** Cleanup ** + + layer1_rx_shutdown(&rx); + + fprintf(stderr, "Done.\n"); +}