Move the transmission chain to a separate "tx" module

This commit is contained in:
Thomas Kolb 2022-02-13 21:29:35 +01:00
parent 97772fa12b
commit a5634ed736
6 changed files with 341 additions and 46 deletions

View file

@ -23,6 +23,8 @@ set(sources
src/layer1/results.h src/layer1/results.h
src/layer1/transmission.c src/layer1/transmission.c
src/layer1/transmission.h src/layer1/transmission.h
src/layer1/tx.c
src/layer1/tx.h
src/layer1/whitening.c src/layer1/whitening.c
src/layer1/whitening.h src/layer1/whitening.h
) )

View file

@ -96,3 +96,24 @@ result_t transmission_filter_packet(
return OK; 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;
}

View file

@ -76,4 +76,29 @@ result_t transmission_filter_packet(
size_t *output_size); 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 #endif // LAYER1_TRANSMISSION_H

168
impl/src/layer1/tx.c Normal file
View file

@ -0,0 +1,168 @@
#include <stdbool.h>
#include <malloc.h>
#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;
}

103
impl/src/layer1/tx.h Normal file
View file

@ -0,0 +1,103 @@
#ifndef LAYER1_TX_H
#define LAYER1_TX_H
#include <complex.h>
#include <stddef.h>
#include <stdint.h>
#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 packets 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

View file

@ -6,13 +6,20 @@
#include "utils.h" #include "utils.h"
#include "layer1/results.h" #include "layer1/results.h"
#include "layer1/packet_mod.h"
#include "layer1/config.h" #include "layer1/config.h"
#include "layer1/preamble.h" #include "layer1/preamble.h"
#include "layer1/transmission.h"
#include "layer1/correlator.h" #include "layer1/correlator.h"
#include "layer1/freq_est.h" #include "layer1/freq_est.h"
#include "layer1/whitening.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 { typedef enum {
RX_STATE_ACQUISITION, 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 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 hdr_fec = fec_create(HEADER_CHANNEL_CODE, NULL);
fec payload_fec = fec_create(PAYLOAD_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); channel_cccf_add_carrier_offset(channel, 0.20f, 1.00f);
// precalculate encoded header length in symbols // 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_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_bps = modem_get_bps(hdr_demod);
unsigned int hdr_len_symbols = (hdr_len_enc_bytes * 8 + hdr_bps - 1) / hdr_bps; 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 // channel
float complex msg_received[burst_len]; float complex msg_received[burst_len];