hamnet70/impl/src/packet_mod.c

252 lines
5.6 KiB
C
Raw Normal View History

#include <string.h>
#include "preamble.h"
#include "config.h"
#include "packet_mod.h"
result_t packet_mod_init(packet_mod_ctx_t *ctx)
{
ctx->pkt_bytes = NULL;
ctx->pkt_symbols = NULL;
ctx->length = 0;
ctx->fec = fec_create(CHANNEL_CODE, NULL);
ctx->modem = modem_create(MODULATION);
ctx->state = NOT_STARTED;
return OK;
}
result_t packet_mod_free(packet_mod_ctx_t *ctx)
{
switch(ctx->state) {
case DATA_RAW:
case DATA_CODED:
free(ctx->pkt_bytes);
ctx->pkt_bytes = NULL;
break;
case DATA_MODULATED:
case HEADER_ADDED:
case PREAMBLE_ADDED:
free(ctx->pkt_symbols);
ctx->pkt_symbols = NULL;
break;
case NOT_STARTED:
// nothing to do
break;
}
ctx->state = NOT_STARTED;
ctx->length = 0;
fec_destroy(ctx->fec);
modem_destroy(ctx->modem);
return OK;
}
result_t packet_mod_set_data(packet_mod_ctx_t *ctx, const unsigned char *data, size_t length)
{
if(ctx->state != NOT_STARTED) {
return ERR_INVALID_STATE;
}
ctx->pkt_bytes = malloc(length);
if(!ctx->pkt_bytes) {
return ERR_NO_MEM;
}
memcpy(ctx->pkt_bytes, data, length);
ctx->length = length;
ctx->state = DATA_RAW;
return OK;
}
result_t packet_mod_encode(packet_mod_ctx_t *ctx)
{
if(ctx->state != DATA_RAW) {
return ERR_INVALID_STATE;
}
unsigned int enc_length = fec_get_enc_msg_length(CHANNEL_CODE, ctx->length);
unsigned char *enc_msg = malloc(enc_length);
if(!enc_msg) {
return ERR_NO_MEM;
}
ERR_CHECK_LIQUID(fec_encode(ctx->fec, ctx->length, ctx->pkt_bytes, enc_msg));
free(ctx->pkt_bytes);
ctx->pkt_bytes = enc_msg;
ctx->length = enc_length;
ctx->state = DATA_CODED;
return OK;
}
result_t packet_mod_modulate(packet_mod_ctx_t *ctx)
{
if(!((ctx->state == DATA_RAW) || (ctx->state == DATA_CODED))) {
return ERR_INVALID_STATE;
}
unsigned int bps = modem_get_bps(ctx->modem);
unsigned int nsyms = (ctx->length * 8 + bps/2) / bps;
unsigned char msg_sym_idcs[nsyms];
float complex *msg_mod = malloc(sizeof(float complex) * nsyms);
if(!msg_mod) {
return ERR_NO_MEM;
}
ERR_CHECK_LIQUID(liquid_repack_bytes(ctx->pkt_bytes, 8, ctx->length, msg_sym_idcs, bps, nsyms, &nsyms));
for(size_t i = 0; i < nsyms; i++) {
ERR_CHECK_LIQUID(modem_modulate(ctx->modem, msg_sym_idcs[i], &msg_mod[i]));
}
free(ctx->pkt_bytes);
ctx->pkt_bytes = NULL;
ctx->pkt_symbols = msg_mod;
ctx->length = nsyms;
ctx->state = DATA_MODULATED;
return OK;
}
result_t packet_mod_add_header(packet_mod_ctx_t *ctx)
{
if(ctx->state != DATA_MODULATED) {
return ERR_INVALID_STATE;
}
if(ctx->length >= (1 << 16)) {
// packet length cannot be stored in the uint16_t in the header.
return ERR_SIZE;
}
// build the header. All field are transferred in network byte order (big endian).
uint8_t header[4];
// set length
header[0] = (ctx->length >> 8) & 0xFF;
header[1] = (ctx->length >> 0) & 0xFF;
// set raw data CRC
header[2] = (ctx->raw_data_crc >> 8) & 0xFF;
header[3] = (ctx->raw_data_crc >> 0) & 0xFF;
// the header is coded and modulated differently than the data.
fec hdr_fec = fec_create(HEADER_CHANNEL_CODE, NULL);
modem hdr_modem = modem_create(HEADER_MODULATION);
// encode the header
unsigned int hdr_enc_length = fec_get_enc_msg_length(HEADER_CHANNEL_CODE, sizeof(header));
unsigned char header_encoded[hdr_enc_length];
ERR_CHECK_LIQUID(fec_encode(hdr_fec, sizeof(header), header, header_encoded));
// modulate the header
unsigned int bps = modem_get_bps(hdr_modem);
unsigned int nsyms = (hdr_enc_length * 8 + bps/2) / bps;
unsigned char header_sym_idcs[nsyms];
float complex header_mod[nsyms];
ERR_CHECK_LIQUID(liquid_repack_bytes(header_encoded, 8, hdr_enc_length, header_sym_idcs, bps, nsyms, &nsyms));
for(size_t i = 0; i < nsyms; i++) {
ERR_CHECK_LIQUID(modem_modulate(hdr_modem, header_sym_idcs[i], &header_mod[i]));
}
// concatenate the modulated header and message
size_t packet_length_with_header = ctx->length + nsyms;
float complex *packet_with_header = malloc(sizeof(float complex) * packet_length_with_header);
if(!packet_with_header) {
return ERR_NO_MEM;
}
memcpy(packet_with_header, header_mod, sizeof(float complex) * nsyms);
memcpy(packet_with_header+nsyms, ctx->pkt_symbols, sizeof(float complex) * ctx->length);
// replace the data in the context struct
free(ctx->pkt_symbols);
ctx->pkt_symbols = packet_with_header;
ctx->length = packet_length_with_header;
ctx->state = HEADER_ADDED;
return OK;
}
result_t packet_mod_add_preamble(packet_mod_ctx_t *ctx)
{
if(ctx->state != HEADER_ADDED) {
return ERR_INVALID_STATE;
}
// concatenate the preamble with the message
size_t pre_length = preamble_get_symbol_count();
size_t packet_length_with_preamble = ctx->length + pre_length;
float complex *packet_with_preamble = malloc(sizeof(float complex) * packet_length_with_preamble);
if(!packet_with_preamble) {
return ERR_NO_MEM;
}
memcpy(packet_with_preamble, preamble_get_symbols(), sizeof(float complex) * pre_length);
memcpy(packet_with_preamble+pre_length, ctx->pkt_symbols, sizeof(float complex) * ctx->length);
// replace the data in the context struct
free(ctx->pkt_symbols);
ctx->pkt_symbols = packet_with_preamble;
ctx->length = packet_length_with_preamble;
ctx->state = PREAMBLE_ADDED;
return OK;
}
result_t packet_mod_get_result_cf(packet_mod_ctx_t *ctx, float complex *data, size_t *length)
{
if(!((ctx->state == DATA_MODULATED) || (ctx->state == HEADER_ADDED) || (ctx->state == PREAMBLE_ADDED))) {
return ERR_INVALID_STATE;
}
if(!data) {
// data is NULL, so we only return the required length
*length = ctx->length;
return OK;
}
if(*length < ctx->length) {
return ERR_NO_MEM;
}
*length = ctx->length;
memcpy(data, ctx->pkt_symbols, *length * sizeof(float complex));
return OK;
}