hamnet70/impl/src/layer1/tx.c

203 lines
4.7 KiB
C

#include <liquid/liquid.h>
#include <stdbool.h>
#include <malloc.h>
#include "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;
tx->carrier_frequency_offset = 0.0f;
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((tx->samples_allocated == 0)
&& !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) {
fprintf(stderr, "Ramp-up requires %zd samples at offset %zd.\n", len, tx->samples_used);
return res;
}
tx->samples_used += len;
}
// encode and modulate the packet
ERR_CHECK(packet_mod_reset(&tx->pmod));
ERR_CHECK(packet_mod_set_data(&tx->pmod, data, length));
ERR_CHECK(packet_mod_encode(&tx->pmod));
ERR_CHECK(packet_mod_modulate(&tx->pmod));
ERR_CHECK(packet_mod_add_header(&tx->pmod));
ERR_CHECK(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) {
fprintf(stderr, "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) {
fprintf(stderr, "Ramp-down requires %zd samples at offset %zd.\n", len, tx->samples_used);
return res;
}
tx->samples_used += len;
// mix the signal up to the carrier offset frequency
// allocate a temporary buffer
float complex *tmp = malloc(sizeof(float complex) * tx->samples_used);
if(!tmp) {
fprintf(stderr, "Could not allocate buffer for TX frequency correction.\n", len, tx->samples_used);
return ERR_NO_MEM;
}
nco_crcf carrier_nco = nco_crcf_create(LIQUID_NCO);
nco_crcf_set_frequency(carrier_nco, tx->carrier_frequency_offset);
nco_crcf_mix_block_up(carrier_nco, tx->samples, tmp, tx->samples_used);
nco_crcf_destroy(carrier_nco);
// swap the buffers
free(tx->samples);
tx->samples = tmp;
tx->samples_allocated = tx->samples_used;
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;
}
void layer1_tx_set_carrier_frequency_offset(layer1_tx_t *tx, float freq)
{
tx->carrier_frequency_offset = freq;
}