diff --git a/impl/CMakeLists.txt b/impl/CMakeLists.txt index e1aa0d8..ae88c11 100644 --- a/impl/CMakeLists.txt +++ b/impl/CMakeLists.txt @@ -25,6 +25,8 @@ set(sources 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 ) diff --git a/impl/src/layer1/rx.c b/impl/src/layer1/rx.c new file mode 100644 index 0000000..1a17bbf --- /dev/null +++ b/impl/src/layer1/rx.c @@ -0,0 +1,269 @@ +#include + +#include "correlator.h" +#include "preamble.h" +#include "freq_est.h" +#include "whitening.h" + +#include "config.h" + +#include "rx.h" + +#define HEADER_SIZE_BYTES 4 +#define FREQ_EST_L 8 + +static void update_nco_pll(nco_crcf nco, float phase_error) +{ + static const float pll_alpha = 0.05f; // phase adjustment factor + static const float pll_beta = (pll_alpha * pll_alpha) / 2.0f; // frequency adjustment factor + + nco_crcf_adjust_phase(nco, pll_alpha * phase_error); + nco_crcf_adjust_frequency(nco, pll_beta * phase_error); +} + + +static bool acquire_preamble(layer1_rx_t *rx, const float complex sample) +{ + static float complex freq_est_history[FREQ_EST_L]; + static unsigned int freq_est_history_write_idx = 0; + + // preamble search + float complex corr_out = correlator_step(&rx->preamble_correlator, sample); + + if(cabsf(corr_out) > 0.5f * preamble_get_symbol_count()) { + // Preamble found! + printf("Preamble found: %.3f > %.3f\n", cabsf(corr_out), 0.5f * preamble_get_symbol_count()); + + float phase_offset; + float mean_frequency_error = correlator_get_mean_frequency_deviation(&rx->preamble_correlator, FREQ_EST_L, &phase_offset); + + printf("Phase offset: %.6f rad\n", phase_offset); + printf("Preamble frequency deviation: %.6f rad/symbol\n", mean_frequency_error); + + // Set the fine carrier correction NCO to the values estimated from the preamble + nco_crcf_set_frequency(rx->carrier_fine_nco, mean_frequency_error / RRC_SPS * 0.5f); + nco_crcf_set_phase(rx->carrier_fine_nco, phase_offset); + + printf("New estimated carrier frequency: %.6f + %.6f\n", nco_crcf_get_frequency(rx->carrier_coarse_nco), nco_crcf_get_frequency(rx->carrier_fine_nco)); + + //float complex input_history[preamble_get_symbol_count()]; + //correlator_get_input_history(&rx->preamble_correlator, input_history); + + //printf("import numpy as np\n"); + //printf("import matplotlib.pyplot as pp\n"); + //print_complex_array("pre", preamble_get_symbols(), preamble_get_symbol_count()); + //print_complex_array("recv", input_history, preamble_get_symbol_count()); + //printf("pp.plot(np.angle(recv * pre.conj()))\n"); + //printf("pp.show()\n"); + + // start over with frequency estimation when preamble search restarts. + freq_est_history_write_idx = 0; + return true; // preamble found! + } else { + // preamble not found. + + // Run the frequency estimator in blocks of FREQ_EST_L samples. + // This is an implementation that works with unknown BPSK symbols + // and therefore can be used during ramp-up and preamble. + if(freq_est_history_write_idx == FREQ_EST_L) { + float freq_est = freq_est_unknown_bpsk(freq_est_history, FREQ_EST_L, NULL); + + float freq_adjustment = (freq_est / RRC_SPS) * 0.3f; + nco_crcf_adjust_frequency(rx->carrier_coarse_nco, freq_adjustment); + + printf("Frequency adjustment: %.6f - carrier frequency: %.6f\n", freq_adjustment, nco_crcf_get_frequency(rx->carrier_coarse_nco)); + + freq_est_history_write_idx = 0; + } + + freq_est_history[freq_est_history_write_idx] = sample; + freq_est_history_write_idx++; + + return false; // preamble not found + } +} + + +result_t layer1_rx_process(layer1_rx_t *rx, const float complex *samples, size_t sample_count) +{ + static size_t symbol_counter = 0; + static uint8_t symbols_int[1 << 12]; + + for(unsigned int i = 0; i < sample_count; i++) { + // Mix the input signal with the carrier NCO, which oscillates at the + // frequency coarsly estimated so far. + float complex mixed_sample; + nco_crcf_step(rx->carrier_coarse_nco); + nco_crcf_mix_down(rx->carrier_coarse_nco, samples[i], &mixed_sample); + + // run the timing synchronizer (works even with shifted frequency) + unsigned int out_len; + float complex symsync_out; + symsync_crcf_execute(rx->symsync, &mixed_sample, 1, &symsync_out, &out_len); + + if(out_len != 0) { + switch(rx->state) { + // Try to acquire packets by synchronizing the frequency + // (symbol-independent search) and correlating the preamble. + case RX_STATE_ACQUISITION: + if(acquire_preamble(rx, symsync_out)) { + // Preamble found and frequency corrected! + rx->callback(RX_EVT_PREAMBLE_FOUND, NULL, 0); + + // go on with decoding the header + rx->state = RX_STATE_HEADER; + symbol_counter = 0; + } + break; + + case RX_STATE_HEADER: + nco_crcf_mix_down(rx->carrier_fine_nco, symsync_out, &mixed_sample); + if(symbol_counter < rx->hdr_len_symbols) { + unsigned int sym_demod; + modem_demodulate(rx->hdr_demod, mixed_sample, &sym_demod); + + float phase_error = modem_get_demodulator_phase_error(rx->hdr_demod); + printf("Sym: %d; Phase error: %f\n", sym_demod, phase_error); + + update_nco_pll(rx->carrier_fine_nco, phase_error); + + symbols_int[symbol_counter] = sym_demod; + symbol_counter++; + } + + if(symbol_counter == rx->hdr_len_symbols) { + unsigned int nsyms; + uint8_t header_enc[rx->hdr_len_enc_bytes]; + uint8_t header[HEADER_SIZE_BYTES]; + + ERR_CHECK_LIQUID(liquid_repack_bytes( + symbols_int, modem_get_bps(rx->hdr_demod), rx->hdr_len_symbols, + header_enc, 8, sizeof(header_enc), &nsyms)); + + fec_decode(rx->hdr_fec, sizeof(header), header_enc, header); + + uint16_t payload_bps = modem_get_bps(rx->payload_demod); + + rx->payload_len_bytes = (((uint16_t)header[0] << 8) | header[1]) & 0x07FF; + rx->payload_crc = ((uint16_t)header[2] << 8) | header[3]; + + rx->payload_len_enc_bytes = fec_get_enc_msg_length(PAYLOAD_CHANNEL_CODE, rx->payload_len_bytes); + rx->payload_len_symbols = (rx->payload_len_enc_bytes * 8 + payload_bps - 1) / payload_bps; + + printf("=== DECODED HEADER ===\n"); + printf("Payload length: %u symbols, %u bytes encoded, %u bytes decoded\n", rx->payload_len_symbols, rx->payload_len_enc_bytes, rx->payload_len_bytes); + printf("CRC16: 0x%04x\n", rx->payload_crc); + printf("======================\n"); + + //dump_array_cf(symbols_cpx, symbol_counter, 1.0f, "/tmp/hdr.cpx"); + + rx->state = RX_STATE_DATA; + symbol_counter = 0; + } + break; + + case RX_STATE_DATA: + nco_crcf_mix_down(rx->carrier_fine_nco, symsync_out, &mixed_sample); + if(symbol_counter < rx->payload_len_symbols) { + unsigned int sym_demod; + modem_demodulate(rx->payload_demod, mixed_sample, &sym_demod); + + float phase_error = modem_get_demodulator_phase_error(rx->payload_demod); + printf("Sym: %d; Phase error: %f\n", sym_demod, phase_error); + + update_nco_pll(rx->carrier_fine_nco, phase_error); + + symbols_int[symbol_counter] = sym_demod; + symbol_counter++; + } + + if(symbol_counter == rx->payload_len_symbols) { + unsigned int nsyms; + unsigned char payload_enc[rx->payload_len_enc_bytes]; + unsigned char payload[rx->payload_len_bytes]; + + ERR_CHECK_LIQUID(liquid_repack_bytes( + symbols_int, modem_get_bps(rx->payload_demod), rx->payload_len_symbols, + payload_enc, 8, sizeof(payload_enc), &nsyms)); + + fec_decode(rx->payload_fec, rx->payload_len_bytes, payload_enc, payload); + + // de-whiten the data + whitening_apply_in_place(payload, rx->payload_len_bytes); + + int valid = crc_validate_message(PAYLOAD_CRC_SCHEME, payload, rx->payload_len_bytes, rx->payload_crc); + + payload[rx->payload_len_bytes] = '\0'; + + //dump_array_cf(symbols_cpx, symbol_counter, 1.0f, "/tmp/payload.cpx"); + if(valid) { + rx->callback(RX_EVT_PACKET_RECEIVED, payload, rx->payload_len_bytes); + } else { + rx->callback(RX_EVT_CHECKSUM_ERROR, payload, rx->payload_len_bytes); + } + rx->state = RX_STATE_ACQUISITION; + } + break; + } + } + } + + return OK; +} + + +result_t layer1_rx_init(layer1_rx_t *rx, rx_callback_t callback) +{ + rx->callback = callback; + + rx->state = RX_STATE_ACQUISITION; + + // create NCOs for carrier frequency compensation + rx->carrier_coarse_nco = nco_crcf_create(LIQUID_NCO); + nco_crcf_set_frequency(rx->carrier_coarse_nco, 0.00f); + nco_crcf_set_phase(rx->carrier_coarse_nco, 0.0f); + + rx->carrier_fine_nco = nco_crcf_create(LIQUID_NCO); + nco_crcf_set_frequency(rx->carrier_fine_nco, 0.00f); + nco_crcf_set_phase(rx->carrier_fine_nco, 0.0f); + + // forward error correction objects + rx->hdr_fec = fec_create(HEADER_CHANNEL_CODE, NULL); + rx->payload_fec = fec_create(PAYLOAD_CHANNEL_CODE, NULL); + + // demodulators + rx->hdr_demod = modem_create(HEADER_MODULATION); + rx->payload_demod = modem_create(PAYLOAD_MODULATION); + + // symbol timing synchronizer + rx->symsync = symsync_crcf_create_rnyquist(LIQUID_FIRFILT_RRC, RRC_SPS, RRC_DELAY, RRC_BETA, 32); + + // Correlator for preamble search + correlator_init(&rx->preamble_correlator, preamble_get_symbols(), preamble_get_symbol_count()); + + // precalculate encoded header length in symbols + unsigned int hdr_bps = modem_get_bps(rx->hdr_demod); + rx->hdr_len_enc_bytes = fec_get_enc_msg_length(HEADER_CHANNEL_CODE, HEADER_SIZE_BYTES); + rx->hdr_len_symbols = (rx->hdr_len_enc_bytes * 8 + hdr_bps - 1) / hdr_bps; + + return OK; +} + + +result_t layer1_rx_shutdown(layer1_rx_t *rx) +{ + nco_crcf_destroy(rx->carrier_coarse_nco); + nco_crcf_destroy(rx->carrier_fine_nco); + + fec_destroy(rx->hdr_fec); + fec_destroy(rx->payload_fec); + + modem_destroy(rx->hdr_demod); + modem_destroy(rx->payload_demod); + + symsync_crcf_destroy(rx->symsync); + + correlator_free(&rx->preamble_correlator); + + return OK; +} diff --git a/impl/src/layer1/rx.h b/impl/src/layer1/rx.h new file mode 100644 index 0000000..877f871 --- /dev/null +++ b/impl/src/layer1/rx.h @@ -0,0 +1,102 @@ +#ifndef LAYER1_RX_H +#define LAYER1_RX_H + +#include + +#include "correlator.h" + +#include "results.h" + +typedef enum { + RX_STATE_ACQUISITION, + RX_STATE_HEADER, + RX_STATE_DATA, +} rx_state_t; + + +typedef enum { + RX_EVT_PACKET_RECEIVED, + RX_EVT_PREAMBLE_FOUND, + RX_EVT_CHECKSUM_ERROR, +} rx_evt_t; + + +typedef void (*rx_callback_t)(rx_evt_t evt, uint8_t *packet_data, size_t packet_len); + + +typedef struct +{ + // NCOs for carrier frequency offset correction + nco_crcf carrier_coarse_nco; + nco_crcf carrier_fine_nco; + + // Forward error correction objects + fec hdr_fec; + fec payload_fec; + + // Demodulators + modem hdr_demod; + modem payload_demod; + + // symbol timing synchronizer + symsync_crcf symsync; + + // preamble correlator + correlator_ctx_t preamble_correlator; + + // Receiver state + rx_state_t state; + + // Callback function to notify user of certain events + rx_callback_t callback; + + // Precalcuated header lengths + unsigned int hdr_len_symbols; + unsigned int hdr_len_enc_bytes; + + // Information from the decoded header + uint16_t payload_len_symbols; + uint16_t payload_len_bytes; + uint16_t payload_crc; + uint16_t payload_len_enc_bytes; +} layer1_rx_t; + + +/*! + * \brief Initialize the receiver. + * + * \param tx Pointer to the receiver context. + * \param callback Function to be called on receiver events. + * \returns The result of the initialization. + */ +result_t layer1_rx_init(layer1_rx_t *rx, rx_callback_t callback); + + +/*! + * \brief Shut the receiver down. Frees all memory. + * + * \param tx Pointer to the receiver context. + * \returns The result of the shutdown. + */ +result_t layer1_rx_shutdown(layer1_rx_t *rx); + + +/*! + * \brief Process the given block of samples. + * + * Runs the whole receiver chain for the given samples. This includes timing- + * and frequency synchronization, preamble search, header demodulation and + * decoding and payload demodulation and decoding. + * + * On specific events, most notably when a packet is successfully decoded, the + * callback function passed to \ref layer1_rx_init() will be called. See \ref + * rx_evt_t for possible events. + * + * \param tx Pointer to the receiver context. + * \param samples Pointer to the samples to process. + * \param sample_count Number of samples to process. + * \returns The result of the shutdown. + */ +result_t layer1_rx_process(layer1_rx_t *rx, const float complex *samples, size_t sample_count); + +#endif // LAYER1_RX_H diff --git a/impl/src/main.c b/impl/src/main.c index 2d80848..ee109c9 100644 --- a/impl/src/main.c +++ b/impl/src/main.c @@ -5,13 +5,8 @@ #include #include "utils.h" -#include "layer1/results.h" -#include "layer1/config.h" -#include "layer1/preamble.h" -#include "layer1/correlator.h" -#include "layer1/freq_est.h" -#include "layer1/whitening.h" #include "layer1/tx.h" +#include "layer1/rx.h" #define RESULT_CHECK(stmt) { \ result_t res = stmt; \ @@ -21,13 +16,6 @@ } \ } -typedef enum { - RX_STATE_ACQUISITION, - RX_STATE_HEADER, - RX_STATE_DATA, -} rx_state_t; - - void print_complex_array(const char *varname, float complex const *array, size_t len) { printf("%s=np.array([%f%+fj", varname, crealf(array[0]), cimagf(array[0])); @@ -38,13 +26,24 @@ void print_complex_array(const char *varname, float complex const *array, size_t } -void update_nco_pll(nco_crcf nco, float phase_error) +void cb_rx(rx_evt_t evt, uint8_t *packet_data, size_t packet_len) { - static const float pll_alpha = 0.05f; // phase adjustment factor - static const float pll_beta = (pll_alpha * pll_alpha) / 2.0f; // frequency adjustment factor + switch(evt) + { + case RX_EVT_CHECKSUM_ERROR: + printf("Received a message of %zu bytes, but decoding failed.\n", packet_len); + break; - nco_crcf_adjust_phase(nco, pll_alpha * phase_error); - nco_crcf_adjust_frequency(nco, pll_beta * phase_error); + case RX_EVT_PACKET_RECEIVED: + printf("=== DECODED PAYLOAD ===\n"); + printf("%s\n", packet_data); + printf("=======================\n"); + break; + + case RX_EVT_PREAMBLE_FOUND: + printf("Found preamble!"); + break; + } } @@ -52,6 +51,8 @@ int main(void) { uint8_t msg_org[] = "Hello Liquid! This is the message to transmit. Hopefully it can be decoded correctly..."; + // ** Modulate packet ** + layer1_tx_t tx; RESULT_CHECK(layer1_tx_init(&tx)); @@ -63,28 +64,14 @@ int main(void) 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); - - modem hdr_demod = modem_create(HEADER_MODULATION); - modem payload_demod = modem_create(PAYLOAD_MODULATION); + // ** Apply channel distortions ** channel_cccf channel = channel_cccf_create(); - float snr = 7.0f; + float snr = 8.0f; channel_cccf_add_awgn(channel, -snr, snr); 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; - - - // channel float complex msg_received[burst_len]; @@ -93,248 +80,20 @@ int main(void) channel_cccf_execute_block(channel, whole_burst, burst_len, msg_received); dump_array_cf(msg_received, burst_len, 1.0f, "/tmp/rx.cpx"); - // create NCOs for carrier frequency compensation - nco_crcf carrier_nco = nco_crcf_create(LIQUID_NCO); - nco_crcf_set_frequency(carrier_nco, 0.00f); - nco_crcf_set_phase(carrier_nco, 0.0f); + // ** RX starts here ** - nco_crcf carrier_fine_nco = nco_crcf_create(LIQUID_NCO); - nco_crcf_set_frequency(carrier_fine_nco, 0.00f); - nco_crcf_set_phase(carrier_fine_nco, 0.0f); + layer1_rx_t rx; - // create symbol synchronizer - symsync_crcf symsync = symsync_crcf_create_rnyquist(LIQUID_FIRFILT_RRC, RRC_SPS, RRC_DELAY, RRC_BETA, 32); + RESULT_CHECK(layer1_rx_init(&rx, cb_rx)); - float complex symsync_out[burst_len]; - unsigned int symsync_out_len = 0; + RESULT_CHECK(layer1_rx_process(&rx, msg_received, burst_len)); - float complex symbols_cpx[16384]; - unsigned char symbols_int[16384]; - unsigned int symbol_counter = 0; // for demodulation - - uint16_t payload_len_symbols; - uint16_t payload_len_bytes; - uint16_t payload_crc; - uint16_t payload_len_enc_bytes; - uint16_t payload_bps = modem_get_bps(payload_demod); - -#define FREQ_EST_L 8 - // General receiver state - rx_state_t rx_state = RX_STATE_ACQUISITION; - - // Correlator for preamble search - correlator_ctx_t preamble_correlator; - correlator_init(&preamble_correlator, preamble_get_symbols(), preamble_get_symbol_count()); - - for(unsigned int i = 0; i < burst_len; i++) { - // Mix the input signal with the carrier NCO, which oscillates at the - // frequency estimated so far. - float complex mixed_sample; - nco_crcf_step(carrier_nco); - nco_crcf_mix_down(carrier_nco, msg_received[i], &mixed_sample); - - // run the timing synchronizer (works even with shifted frequency) - unsigned int out_len; - symsync_crcf_execute(symsync, &mixed_sample, 1, symsync_out + symsync_out_len, &out_len); - - if(out_len != 0) { - float complex corr_out; - switch(rx_state) { - // Try to acquire packets by synchronizing the frequency - // (symbol-independent search) and correlating the preamble. - case RX_STATE_ACQUISITION: - // preamble search - corr_out = correlator_step(&preamble_correlator, symsync_out[symsync_out_len]); - - if(cabsf(corr_out) > 0.5f * preamble_get_symbol_count()) { - // Preamble found! - printf("Preamble found at symbol %u: %.3f > %.3f\n", i/RRC_SPS, cabsf(corr_out), 0.5f * preamble_get_symbol_count()); - - float phase_offset; - float mean_frequency_error = correlator_get_mean_frequency_deviation(&preamble_correlator, FREQ_EST_L, &phase_offset); - - printf("Phase offset: %.6f rad\n", phase_offset); - printf("Preamble frequency deviation: %.6f rad/symbol\n", mean_frequency_error); - - // adjust the frequency and phase of the NCO with the estimations from the preamble - nco_crcf_set_frequency(carrier_fine_nco, mean_frequency_error / RRC_SPS * 0.5f); - nco_crcf_set_phase(carrier_fine_nco, phase_offset); - - printf("New estimated carrier frequency: %.6f + %.6f\n", nco_crcf_get_frequency(carrier_nco), nco_crcf_get_frequency(carrier_fine_nco)); - - float complex input_history[preamble_get_symbol_count()]; - correlator_get_input_history(&preamble_correlator, input_history); - - printf("import numpy as np\n"); - printf("import matplotlib.pyplot as pp\n"); - print_complex_array("pre", preamble_get_symbols(), preamble_get_symbol_count()); - print_complex_array("recv", input_history, preamble_get_symbol_count()); - printf("pp.plot(np.angle(recv * pre.conj()))\n"); - printf("pp.show()\n"); - - // receive and decode the header - rx_state = RX_STATE_HEADER; - symbol_counter = 0; - } else { - // preamble not found. - - // Run the frequency estimator in blocks of FREQ_EST_L samples. - // This is an implementation that works with unknown BPSK symbols - // and therefore can be used during ramp-up and preamble. - if(((i/RRC_SPS) % FREQ_EST_L) == 0) { - float freq_est = freq_est_unknown_bpsk(symsync_out + symsync_out_len - FREQ_EST_L, FREQ_EST_L, NULL); - - float freq_adjustment = (freq_est / RRC_SPS) * 0.3f; - nco_crcf_adjust_frequency(carrier_nco, freq_adjustment); - - printf("Frequency adjustment: %.6f - carrier frequency: %.6f\n", freq_adjustment, nco_crcf_get_frequency(carrier_nco)); - } - } - break; - - case RX_STATE_HEADER: - nco_crcf_mix_down(carrier_fine_nco, symsync_out[symsync_out_len], &mixed_sample); - if(symbol_counter < hdr_len_symbols) { - unsigned int sym_demod; - modem_demodulate(hdr_demod, mixed_sample, &sym_demod); - - float phase_error = modem_get_demodulator_phase_error(hdr_demod); - printf("Sym: %d; Phase error: %f\n", sym_demod, phase_error); - - update_nco_pll(carrier_fine_nco, phase_error); - - symbols_cpx[symbol_counter] = mixed_sample; - symbols_int[symbol_counter] = sym_demod; - symbol_counter++; - } - - if(symbol_counter == hdr_len_symbols) { - unsigned int nsyms; - unsigned char header_enc[4]; - - ERR_CHECK_LIQUID(liquid_repack_bytes( - symbols_int, modem_get_bps(hdr_demod), hdr_len_symbols, - header_enc, 8, sizeof(header_enc), &nsyms)); - - fec_decode(hdr_fec, sizeof(header), header_enc, header); - - payload_len_bytes = ((uint16_t)header[0] << 8) | header[1]; - payload_crc = ((uint16_t)header[2] << 8) | header[3]; - - payload_len_enc_bytes = fec_get_enc_msg_length(PAYLOAD_CHANNEL_CODE, payload_len_bytes); - payload_len_symbols = (payload_len_enc_bytes * 8 + payload_bps - 1) / payload_bps; - - printf("=== DECODED HEADER ===\n"); - printf("Payload length: %u symbols, %u bytes encoded, %u bytes decoded\n", payload_len_symbols, payload_len_enc_bytes, payload_len_bytes); - printf("CRC16: 0x%04x\n", payload_crc); - printf("======================\n"); - - dump_array_cf(symbols_cpx, symbol_counter, 1.0f, "/tmp/hdr.cpx"); - - rx_state = RX_STATE_DATA; - symbol_counter = 0; - } - break; - - case RX_STATE_DATA: - nco_crcf_mix_down(carrier_fine_nco, symsync_out[symsync_out_len], &mixed_sample); - if(symbol_counter < payload_len_symbols) { - unsigned int sym_demod; - modem_demodulate(payload_demod, mixed_sample, &sym_demod); - - float phase_error = modem_get_demodulator_phase_error(payload_demod); - printf("Sym: %d; Phase error: %f\n", sym_demod, phase_error); - - update_nco_pll(carrier_fine_nco, phase_error); - - symbols_cpx[symbol_counter] = mixed_sample; - symbols_int[symbol_counter] = sym_demod; - symbol_counter++; - } - - if(symbol_counter == payload_len_symbols) { - unsigned int nsyms; - unsigned char payload_enc[16384]; - unsigned char payload[16384]; - - ERR_CHECK_LIQUID(liquid_repack_bytes( - symbols_int, modem_get_bps(payload_demod), payload_len_symbols, - payload_enc, 8, sizeof(payload_enc), &nsyms)); - - fec_decode(payload_fec, payload_len_bytes, payload_enc, payload); - - // de-whiten the data - whitening_apply_in_place(payload, payload_len_bytes); - - int valid = crc_validate_message(PAYLOAD_CRC_SCHEME, payload, payload_len_bytes, payload_crc); - - payload[payload_len_bytes] = '\0'; - - printf("=== DECODED PAYLOAD (valid: %d) ===\n", valid); - printf("%s\n", payload); - printf("==================================\n"); - - dump_array_cf(symbols_cpx, symbol_counter, 1.0f, "/tmp/payload.cpx"); - rx_state = RX_STATE_ACQUISITION; - } - break; - } - } - - symsync_out_len += out_len; - } - - dump_array_cf(symsync_out, symsync_out_len, 1.0f, "/tmp/synced.cpx"); - -#if 0 - // demodulate - unsigned int bps = modem_get_bps(payload_demod); - - unsigned char msg_demod_syms[nsyms]; - unsigned char msg_demod[k+1]; - - for(size_t i = 0; i < nsyms; i++) { - unsigned int symbol; - - modem_demodulate(payload_demod, msg_received[i], &symbol); - msg_demod_syms[i] = symbol; - } - - unsigned int received_bytes; - liquid_repack_bytes(msg_demod_syms, bps, nsyms, msg_demod, 8, sizeof(msg_demod), &received_bytes); - - //assert(received_bytes == k); - - // decode - uint8_t msg_dec[sizeof(msg_org)]; - //memcpy(msg_dec, msg_enc, sizeof(msg_dec)); - fec_decode(q, sizeof(msg_dec), msg_demod, msg_dec); - - // compare original to decoded message - for(size_t i = 0; i < sizeof(msg_org); i++) - { - printf("%02x => %02x", msg_org[i], msg_dec[i]); - if(msg_org[i] != msg_dec[i]) { - printf(" <<< !!!\n"); - } else { - printf("\n"); - } - } - - unsigned int bit_errors = count_bit_errors_array(msg_org, msg_dec, sizeof(msg_org)); - printf("%u bit errors detected.\n", bit_errors); -#endif - - nco_crcf_destroy(carrier_nco); - - symsync_crcf_destroy(symsync); - - fec_destroy(hdr_fec); - - modem_destroy(payload_demod); - modem_destroy(hdr_demod); + // cleanup channel_cccf_destroy(channel); + layer1_tx_shutdown(&tx); + layer1_rx_shutdown(&rx); + printf("Done.\n"); }