From 7d5b67a257eb18ed4b5ac4c0efedc54cdfb23a13 Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Fri, 12 May 2023 13:46:02 +0200 Subject: [PATCH] Add layer 1 software loopback test --- impl/test/CMakeLists.txt | 32 ++++++ impl/test/layer1/test_loopback.c | 161 +++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 impl/test/layer1/test_loopback.c diff --git a/impl/test/CMakeLists.txt b/impl/test/CMakeLists.txt index 6068eca..e9532ad 100644 --- a/impl/test/CMakeLists.txt +++ b/impl/test/CMakeLists.txt @@ -12,3 +12,35 @@ target_link_libraries( m liquid ) + +#------------------------------------ + +add_executable( + test_layer1_loopback + ../src/layer1/correlator.c + ../src/layer1/correlator.h + ../src/layer1/freq_est.c + ../src/layer1/freq_est.h + ../src/layer1/packet_mod.c + ../src/layer1/packet_mod.h + ../src/layer1/preamble.c + ../src/layer1/preamble.h + ../src/layer1/transmission.c + ../src/layer1/transmission.h + ../src/layer1/tx.c + ../src/layer1/tx.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/utils.c + layer1/test_loopback.c +) + +target_link_libraries( + test_layer1_loopback + m + liquid +) diff --git a/impl/test/layer1/test_loopback.c b/impl/test/layer1/test_loopback.c new file mode 100644 index 0000000..917ce2c --- /dev/null +++ b/impl/test/layer1/test_loopback.c @@ -0,0 +1,161 @@ +#include +#include +#include +#include +#include + +#include + +#include "layer1/tx.h" +#include "layer1/rx.h" + +#include "utils.h" + +#include "sdr/sdr.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); \ + } \ +} + + +void print_complex_array(const char *varname, float complex const *array, size_t len) +{ + fprintf(stderr, "%s=np.array([%f%+fj", varname, crealf(array[0]), cimagf(array[0])); + for(size_t k = 1; k < len; k++) { + fprintf(stderr, ", %f%+fj", crealf(array[k]), cimagf(array[k])); + } + fprintf(stderr, "])\n"); +} + + +void hexdump(const uint8_t *data, size_t len) +{ + static const char lut[16] = "0123456789ABCDEF"; + static const size_t BYTES_PER_LINE = 16; + + size_t pos = 0; + + while(pos < len) { + size_t bytes_in_line = len - pos; + if(bytes_in_line > BYTES_PER_LINE) { + bytes_in_line = BYTES_PER_LINE; + } + + for(size_t i = 0; i < BYTES_PER_LINE; i++) { + if(i >= bytes_in_line) { + fputs(" ", stderr); + } else { + uint8_t byte = data[pos+i]; + + fprintf(stderr, "%c%c ", lut[byte >> 4], lut[byte & 0x0F]); + } + } + + fputs(" ", stderr); + + for(size_t i = 0; i < bytes_in_line; i++) { + uint8_t byte = data[pos+i]; + + if(isprint(byte)) { + putc(byte, stderr); + } else { + putc('.', stderr); + } + } + + putc('\n', stderr); + pos += bytes_in_line; + } +} + + +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"); + 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"); + break; + + case RX_EVT_PREAMBLE_FOUND: + fprintf(stderr, "Found preamble!\n"); + break; + } +} + + +int main(void) +{ + layer1_tx_t tx; + layer1_rx_t rx; + + // ** Initialize ** + + RESULT_CHECK(layer1_tx_init(&tx)); + RESULT_CHECK(layer1_rx_init(&rx, cb_rx)); + + + + // ** Generate packets ** + + RESULT_CHECK(layer1_tx_reset(&tx)); + + uint8_t packetbuf1[] = "Hello World! 1234567890"; + size_t l = sizeof(packetbuf1); + + fprintf(stderr, "Transmitting packet with %zd bytes.\n", l); + + RESULT_CHECK(layer1_tx_add_packet_to_burst(&tx, packetbuf1, l)); + + uint8_t packetbuf2[] = "This is just a test message. Just writing some stuff here to create a longer packet."; + l = sizeof(packetbuf2); + + fprintf(stderr, "Transmitting packet with %zd bytes.\n", l); + + RESULT_CHECK(layer1_tx_add_packet_to_burst(&tx, packetbuf2, l)); + + RESULT_CHECK(layer1_tx_finalize_burst(&tx)); + + size_t burst_len = layer1_tx_get_sample_count(&tx); + const float complex *whole_burst = layer1_tx_get_sample_data(&tx); + + dump_array_cf(whole_burst, burst_len, 10e-6f, "/tmp/tx.cpx"); + + // ** Simulate channel effects ** + channel_cccf ch = channel_cccf_create(); + //channel_cccf_add_awgn(ch, -30, 15); + channel_cccf_add_carrier_offset(ch, 0.01f, 1.23f); + + float complex whole_burst_ch[burst_len]; + channel_cccf_execute_block(ch, (float complex*)whole_burst, burst_len, whole_burst_ch); + + dump_array_cf(whole_burst_ch, burst_len, 10e-6f, "/tmp/rx.cpx"); + + + // ** Receive signal ** + + RESULT_CHECK(layer1_rx_process(&rx, whole_burst_ch, burst_len)); + + // ** Cleanup ** + + layer1_tx_shutdown(&tx); + layer1_rx_shutdown(&rx); + + fprintf(stderr, "Done.\n"); +}