From a5634ed736a7597bbbf8e73e5da6130df01042c9 Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Sun, 13 Feb 2022 21:29:35 +0100 Subject: [PATCH] Move the transmission chain to a separate "tx" module --- impl/CMakeLists.txt | 2 + impl/src/layer1/transmission.c | 21 +++++ impl/src/layer1/transmission.h | 25 +++++ impl/src/layer1/tx.c | 168 +++++++++++++++++++++++++++++++++ impl/src/layer1/tx.h | 103 ++++++++++++++++++++ impl/src/main.c | 68 +++++-------- 6 files changed, 341 insertions(+), 46 deletions(-) create mode 100644 impl/src/layer1/tx.c create mode 100644 impl/src/layer1/tx.h diff --git a/impl/CMakeLists.txt b/impl/CMakeLists.txt index 3570236..e1aa0d8 100644 --- a/impl/CMakeLists.txt +++ b/impl/CMakeLists.txt @@ -23,6 +23,8 @@ set(sources src/layer1/results.h src/layer1/transmission.c src/layer1/transmission.h + src/layer1/tx.c + src/layer1/tx.h src/layer1/whitening.c src/layer1/whitening.h ) diff --git a/impl/src/layer1/transmission.c b/impl/src/layer1/transmission.c index 79dde55..bbab6af 100644 --- a/impl/src/layer1/transmission.c +++ b/impl/src/layer1/transmission.c @@ -96,3 +96,24 @@ result_t transmission_filter_packet( return OK; } + + +size_t transmission_calculate_ramp_up_length(transmission_ctx_t *ctx) +{ + (void)ctx; + return RRC_SPS * TRANSMISSION_RAMP_UP_LEN; +} + + +size_t transmission_calculate_ramp_down_length(transmission_ctx_t *ctx) +{ + (void)ctx; + return RRC_SPS * TRANSMISSION_RAMP_DOWN_LEN; +} + + +size_t transmission_calculate_packet_length(transmission_ctx_t *ctx, size_t symbol_count) +{ + (void)ctx; + return RRC_SPS * symbol_count; +} diff --git a/impl/src/layer1/transmission.h b/impl/src/layer1/transmission.h index 3a7948d..9a6a426 100644 --- a/impl/src/layer1/transmission.h +++ b/impl/src/layer1/transmission.h @@ -76,4 +76,29 @@ result_t transmission_filter_packet( size_t *output_size); +/*!\brief Calculate the number of samples required for ramp-up. + * + * \param ctx Pointer to the transmission context. + * \returns The number of samples required. + */ +size_t transmission_calculate_ramp_up_length(transmission_ctx_t *ctx); + + +/*!\brief Calculate the number of samples required for ramp-down. + * + * \param ctx Pointer to the transmission context. + * \returns The number of samples required. + */ +size_t transmission_calculate_ramp_down_length(transmission_ctx_t *ctx); + + +/*!\brief Calculate the number of samples required for the given number of packet symbols. + * + * \param ctx Pointer to the transmission context. + * \param symbol_count Size of the packet in symbols. + * \returns The number of samples required. + */ +size_t transmission_calculate_packet_length(transmission_ctx_t *ctx, size_t symbol_count); + + #endif // LAYER1_TRANSMISSION_H diff --git a/impl/src/layer1/tx.c b/impl/src/layer1/tx.c new file mode 100644 index 0000000..0a4f2d0 --- /dev/null +++ b/impl/src/layer1/tx.c @@ -0,0 +1,168 @@ +#include +#include + +#include "layer1/results.h" +#include "tx.h" + +static inline bool resize_buffer(layer1_tx_t *tx, size_t new_size) +{ + void *tmpptr = realloc(tx->samples, new_size * sizeof(*(tx->samples))); + if(tmpptr) { + tx->samples = tmpptr; + tx->samples_allocated = new_size; + return true; + } else { + return false; + } +} + + +static inline bool can_append_n_samples(layer1_tx_t *tx, size_t samples) +{ + return (tx->samples_used + samples) <= tx->samples_allocated; +} + + +static inline size_t get_free_space(layer1_tx_t *tx) +{ + return tx->samples_allocated - tx->samples_used; +} + + +static inline float complex* get_write_ptr(layer1_tx_t *tx) +{ + return tx->samples + tx->samples_used; +} + + +result_t layer1_tx_init(layer1_tx_t *tx) +{ + tx->samples = NULL; + tx->samples_allocated = 0; + tx->samples_used = 0; + + transmission_init(&tx->transmission); + packet_mod_init(&tx->pmod); + return OK; +} + + +result_t layer1_tx_shutdown(layer1_tx_t *tx) +{ + if(tx->samples) { + free(tx->samples); + tx->samples = NULL; + } + + tx->samples_allocated = 0; + tx->samples_used = 0; + + transmission_free(&tx->transmission); + packet_mod_free(&tx->pmod); + + return OK; +} + + +result_t layer1_tx_reset(layer1_tx_t *tx) +{ + tx->samples_used = 0; + return OK; +} + + +result_t layer1_tx_add_packet_to_burst(layer1_tx_t *tx, const uint8_t *data, size_t length) +{ + if(tx->samples_used == 0) { + if(!resize_buffer(tx, 4096 + transmission_calculate_ramp_up_length(&tx->transmission))) { + return ERR_NO_MEM; + } + + // nothing is in the buffer yet, so we must first generate a ramp-up. + size_t len = get_free_space(tx); + result_t res = transmission_ramp_up(&tx->transmission, get_write_ptr(tx), &len); + + if(res != OK) { + printf("Ramp-up requires %zd samples at offset %zd.\n", len, tx->samples_used); + return res; + } + + tx->samples_used += len; + } + + // encode and modulate the packet + packet_mod_set_data(&tx->pmod, data, length); + packet_mod_encode(&tx->pmod); + packet_mod_modulate(&tx->pmod); + packet_mod_add_header(&tx->pmod); + packet_mod_add_preamble(&tx->pmod); + + // determine number of symbols in the packet + size_t nsyms; + packet_mod_get_result_cf(&tx->pmod, NULL, &nsyms); + + // calculate the number of filtered samples + size_t filtered_size = transmission_calculate_packet_length(&tx->transmission, nsyms); + + // resize the buffer if necessary (and add some reserve) + if(!can_append_n_samples(tx, filtered_size)) { + if(!resize_buffer(tx, tx->samples_allocated + 2*filtered_size)) { + return ERR_NO_MEM; + } + } + + // store the packet symbols into a temporary buffer + float complex msg_mod[nsyms]; + packet_mod_get_result_cf(&tx->pmod, msg_mod, &nsyms); + + // filter the packet and append it to the output buffer + size_t len = get_free_space(tx); + result_t res = transmission_filter_packet(&tx->transmission, msg_mod, nsyms, get_write_ptr(tx), &len); + + if(res != OK) { + printf("Packet requires %zd samples at offset %zd.\n", len, tx->samples_used); + return res; + } + + tx->samples_used += len; + + return OK; +} + + +result_t layer1_tx_finalize_burst(layer1_tx_t *tx) +{ + // calculate the number of samples for the ramp down + size_t len = transmission_calculate_ramp_down_length(&tx->transmission); + + // resize the buffer if necessary + if(!can_append_n_samples(tx, len)) { + if(!resize_buffer(tx, tx->samples_allocated + len)) { + return ERR_NO_MEM; + } + } + + // generate the ramp-down + len = get_free_space(tx); + result_t res = transmission_ramp_down(&tx->transmission, get_write_ptr(tx), &len); + + if(res != OK) { + printf("Ramp-down requires %zd samples at offset %zd.\n", len, tx->samples_used); + return res; + } + + tx->samples_used += len; + return OK; +} + + +size_t layer1_tx_get_sample_count(const layer1_tx_t *tx) +{ + return tx->samples_used; +} + + +const float complex* layer1_tx_get_sample_data(const layer1_tx_t *tx) +{ + return tx->samples; +} diff --git a/impl/src/layer1/tx.h b/impl/src/layer1/tx.h new file mode 100644 index 0000000..7f62c5e --- /dev/null +++ b/impl/src/layer1/tx.h @@ -0,0 +1,103 @@ +#ifndef LAYER1_TX_H +#define LAYER1_TX_H + +#include + +#include +#include + +#include "results.h" +#include "transmission.h" +#include "packet_mod.h" + +typedef struct +{ + float complex *samples; + size_t samples_allocated; + size_t samples_used; + + transmission_ctx_t transmission; + packet_mod_ctx_t pmod; +} layer1_tx_t; + + +/*! + * \brief Initialize the transmitter. + * + * \param tx Pointer to the transmitter context. + * \returns The result of the initialization. + */ +result_t layer1_tx_init(layer1_tx_t *tx); + + +/*! + * \brief Shut the transmitter down. Frees all memory. + * + * \param tx Pointer to the transmitter context. + * \returns The result of the shutdown. + */ +result_t layer1_tx_shutdown(layer1_tx_t *tx); + + +/*! + * \brief Reset the transmitter. + * + * Logically removes all internal data, but does not free memory. + * + * \param tx Pointer to the transmitter context. + * \returns The result of the reset. + */ +result_t layer1_tx_reset(layer1_tx_t *tx); + + +/*! + * \brief Add a packet to the burst. + * + * Encodes the raw data, modulates it, applies pulse filtering and appends the + * result to the internal buffer. + * + * If the buffer is empty (after init or reset), it first generates a ramp-up + * sequence. + * + * You can add arbitrarily many packets, the only limit is the available memory. + * + * \param tx Pointer to the transmitter context. + * \param data Pointer to the packet’s raw data. + * \param length The number of bytes in the data array. + * \returns The result of the operation. + */ +result_t layer1_tx_add_packet_to_burst(layer1_tx_t *tx, const uint8_t *data, size_t length); + + +/*! + * \brief Generate the ramp-down sequence. + * + * The burst is considered complete after calling this function. You should + * retrieve the generated samples and call \ref layer1_tx_reset() before adding + * further packets. + * + * \param tx Pointer to the transmitter context. + * \returns The result of the finalization. + */ +result_t layer1_tx_finalize_burst(layer1_tx_t *tx); + + +/*! + * \brief Retrieve the number of generated samples. + * + * \param tx Pointer to the transmitter context. + * \returns The number of samples returned by \ref layer1_tx_get_sample_data(). + */ +size_t layer1_tx_get_sample_count(const layer1_tx_t *tx); + +/*! + * \brief Retrieve the generated samples. + * + * Calling this after \ref layer1_tx_finalize_burst() returns the complete burst ready for transmission. + * + * \param tx Pointer to the transmitter context. + * \returns A pointer to the generated samples. + */ +const float complex* layer1_tx_get_sample_data(const layer1_tx_t *tx); + +#endif // LAYER1_TX_H diff --git a/impl/src/main.c b/impl/src/main.c index e190484..2d80848 100644 --- a/impl/src/main.c +++ b/impl/src/main.c @@ -6,13 +6,20 @@ #include "utils.h" #include "layer1/results.h" -#include "layer1/packet_mod.h" #include "layer1/config.h" #include "layer1/preamble.h" -#include "layer1/transmission.h" #include "layer1/correlator.h" #include "layer1/freq_est.h" #include "layer1/whitening.h" +#include "layer1/tx.h" + +#define RESULT_CHECK(stmt) { \ + result_t res = stmt; \ + if(res != OK) { \ + printf("Error %d in %s:%d!", res, __FILE__, __LINE__); \ + exit(1); \ + } \ +} typedef enum { RX_STATE_ACQUISITION, @@ -45,7 +52,18 @@ int main(void) { uint8_t msg_org[] = "Hello Liquid! This is the message to transmit. Hopefully it can be decoded correctly..."; - uint8_t header[4]; + layer1_tx_t tx; + + RESULT_CHECK(layer1_tx_init(&tx)); + RESULT_CHECK(layer1_tx_add_packet_to_burst(&tx, msg_org, sizeof(msg_org))); + 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, 1.0f, "/tmp/tx.cpx"); + + // ** RX starts here ** fec hdr_fec = fec_create(HEADER_CHANNEL_CODE, NULL); fec payload_fec = fec_create(PAYLOAD_CHANNEL_CODE, NULL); @@ -60,54 +78,12 @@ int main(void) channel_cccf_add_carrier_offset(channel, 0.20f, 1.00f); // precalculate encoded header length in symbols + uint8_t header[4]; unsigned int hdr_len_enc_bytes = fec_get_enc_msg_length(HEADER_CHANNEL_CODE, sizeof(header)); unsigned int hdr_bps = modem_get_bps(hdr_demod); unsigned int hdr_len_symbols = (hdr_len_enc_bytes * 8 + hdr_bps - 1) / hdr_bps; - packet_mod_ctx_t pmod; - packet_mod_init(&pmod); - packet_mod_set_data(&pmod, msg_org, sizeof(msg_org)); - packet_mod_encode(&pmod); - packet_mod_modulate(&pmod); - packet_mod_add_header(&pmod); - packet_mod_add_preamble(&pmod); - - size_t nsyms; - packet_mod_get_result_cf(&pmod, NULL, &nsyms); // determine number of symbols for allocation - - float complex msg_mod[nsyms]; - packet_mod_get_result_cf(&pmod, msg_mod, &nsyms); // get the data - - size_t burst_len = 0; - float complex whole_burst[65536]; - size_t len; - - transmission_ctx_t transm; - transmission_init(&transm); - - len = 65536-burst_len; - if(transmission_ramp_up(&transm, whole_burst+burst_len, &len) != OK) { - printf("Ramp-up requires %zd symbols at offset %zd.\n", len, burst_len); - return 1; - } - burst_len += len; - - len = 65536-burst_len; - if(transmission_filter_packet(&transm, msg_mod, nsyms, whole_burst+burst_len, &len) != OK) { - printf("Packet requires %zd symbols at offset %zd.\n", len, burst_len); - return 1; - } - burst_len += len; - - len = 65536-burst_len; - if(transmission_ramp_down(&transm, whole_burst+burst_len, &len) != OK) { - printf("Ramp-down requires %zd symbols at offset %zd.\n", len, burst_len); - return 1; - } - burst_len += len; - - dump_array_cf(whole_burst, burst_len, 1.0f, "/tmp/tx.cpx"); // channel float complex msg_received[burst_len];