diff options
| author | drowe67 <[email protected]> | 2023-07-14 12:36:50 +0930 |
|---|---|---|
| committer | David Rowe <[email protected]> | 2023-07-14 12:36:50 +0930 |
| commit | b86e88413d4c6ec428aaedb147f7675f28882fe4 (patch) | |
| tree | ce360925856e25d4343d59a37e2e6bac142d3752 /src/reliable_text.c | |
| parent | 0c2e969cfbe85548801eeb20ad8113969604892a (diff) | |
clang-format -i applied to src unittest misc
Diffstat (limited to 'src/reliable_text.c')
| -rw-r--r-- | src/reliable_text.c | 783 |
1 files changed, 388 insertions, 395 deletions
diff --git a/src/reliable_text.c b/src/reliable_text.c index 375ca32..8a5ba21 100644 --- a/src/reliable_text.c +++ b/src/reliable_text.c @@ -20,17 +20,19 @@ // //========================================================================== +#include "reliable_text.h" + +#include <assert.h> +#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <ctype.h> -#include <assert.h> + #include "freedv_api.h" #include "freedv_api_internal.h" -#include "reliable_text.h" +#include "gp_interleaver.h" #include "ldpc_codes.h" #include "ofdm_internal.h" -#include "gp_interleaver.h" #define LDPC_TOTAL_SIZE_BITS (112) @@ -39,31 +41,36 @@ #define RELIABLE_TEXT_MAX_LENGTH (8) #define RELIABLE_TEXT_CRC_LENGTH (1) -#define RELIABLE_TEXT_MAX_RAW_LENGTH (RELIABLE_TEXT_MAX_LENGTH + RELIABLE_TEXT_CRC_LENGTH) +#define RELIABLE_TEXT_MAX_RAW_LENGTH \ + (RELIABLE_TEXT_MAX_LENGTH + RELIABLE_TEXT_CRC_LENGTH) /* Two bytes of text/CRC equal four bytes of LDPC(112,56). */ #define RELIABLE_TEXT_BYTES_PER_ENCODED_SEGMENT (8) /* Internal definition of reliable_text_t. */ -typedef struct -{ - on_text_rx_t text_rx_callback; - void* callback_state; - - char tx_text[LDPC_TOTAL_SIZE_BITS + RELIABLE_TEXT_UW_LENGTH_BITS]; - int tx_text_index; - int tx_text_length; - - char inbound_pending_bits[RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS]; - _Complex float inbound_pending_syms[(RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS) / 2]; - float inbound_pending_amps[(RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS) / 2]; - int bit_index; - int sym_index; - - int has_successfully_decoded; - - struct LDPC ldpc; - struct freedv* fdv; +typedef struct { + on_text_rx_t text_rx_callback; + void* callback_state; + + char tx_text[LDPC_TOTAL_SIZE_BITS + RELIABLE_TEXT_UW_LENGTH_BITS]; + int tx_text_index; + int tx_text_length; + + char + inbound_pending_bits[RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS]; + _Complex float inbound_pending_syms[(RELIABLE_TEXT_UW_LENGTH_BITS + + LDPC_TOTAL_SIZE_BITS) / + 2]; + float inbound_pending_amps[(RELIABLE_TEXT_UW_LENGTH_BITS + + LDPC_TOTAL_SIZE_BITS) / + 2]; + int bit_index; + int sym_index; + + int has_successfully_decoded; + + struct LDPC ldpc; + struct freedv* fdv; } reliable_text_impl_t; // 6 bit character set for text field use: @@ -72,416 +79,402 @@ typedef struct // 10-19: ASCII '0'-'9' // 20-46: ASCII 'A'-'Z' // 47: ASCII ' ' -static void convert_callsign_to_ota_string_(const char* input, char* output, int maxLength) -{ - assert(input != NULL); - assert(output != NULL); - assert(maxLength >= 0); - - int outidx = 0; - for (size_t index = 0; index < maxLength; index++) - { - if (input[index] == 0) break; - - if (input[index] >= 38 && input[index] <= 47) - { - output[outidx++] = input[index] - 37; - } - else if (input[index] >= '0' && input[index] <= '9') - { - output[outidx++] = input[index] - '0' + 10; - } - else if (input[index] >= 'A' && input[index] <= 'Z') - { - output[outidx++] = input[index] - 'A' + 20; - } - else if (input[index] >= 'a' && input[index] <= 'z') - { - output[outidx++] = toupper(input[index]) - 'A' + 20; - } +static void convert_callsign_to_ota_string_(const char* input, char* output, + int maxLength) { + assert(input != NULL); + assert(output != NULL); + assert(maxLength >= 0); + + int outidx = 0; + for (size_t index = 0; index < maxLength; index++) { + if (input[index] == 0) break; + + if (input[index] >= 38 && input[index] <= 47) { + output[outidx++] = input[index] - 37; + } else if (input[index] >= '0' && input[index] <= '9') { + output[outidx++] = input[index] - '0' + 10; + } else if (input[index] >= 'A' && input[index] <= 'Z') { + output[outidx++] = input[index] - 'A' + 20; + } else if (input[index] >= 'a' && input[index] <= 'z') { + output[outidx++] = toupper(input[index]) - 'A' + 20; } - output[outidx] = 0; + } + output[outidx] = 0; } -static void convert_ota_string_to_callsign_(const char* input, char* output, int maxLength) -{ - assert(input != NULL); - assert(output != NULL); - assert(maxLength >= 0); - - int outidx = 0; - for (size_t index = 0; index < maxLength; index++) - { - if (input[index] == 0) break; - - if (input[index] >= 1 && input[index] <= 9) - { - output[outidx++] = input[index] + 37; - } - else if (input[index] >= 10 && input[index] <= 19) - { - output[outidx++] = input[index] - 10 + '0'; - } - else if (input[index] >= 20 && input[index] <= 46) - { - output[outidx++] = input[index] - 20 + 'A'; - } +static void convert_ota_string_to_callsign_(const char* input, char* output, + int maxLength) { + assert(input != NULL); + assert(output != NULL); + assert(maxLength >= 0); + + int outidx = 0; + for (size_t index = 0; index < maxLength; index++) { + if (input[index] == 0) break; + + if (input[index] >= 1 && input[index] <= 9) { + output[outidx++] = input[index] + 37; + } else if (input[index] >= 10 && input[index] <= 19) { + output[outidx++] = input[index] - 10 + '0'; + } else if (input[index] >= 20 && input[index] <= 46) { + output[outidx++] = input[index] - 20 + 'A'; } - output[outidx] = 0; + } + output[outidx] = 0; } -static char calculateCRC8_(char* input, int length) -{ - assert(input != NULL); - assert(length >= 0); - - unsigned char generator = 0x1D; - unsigned char crc = 0x00; /* start with 0 so first byte can be 'xored' in */ - - while (length > 0) - { - unsigned char ch = *input++; - length--; - - // Break out if we see a null. - if (ch == 0) break; - - crc ^= ch; /* XOR-in the next input byte */ - - for (int i = 0; i < 8; i++) - { - if ((crc & 0x80) != 0) - { - crc = (unsigned char)((crc << 1) ^ generator); - } - else - { - crc <<= 1; - } - } +static char calculateCRC8_(char* input, int length) { + assert(input != NULL); + assert(length >= 0); + + unsigned char generator = 0x1D; + unsigned char crc = 0x00; /* start with 0 so first byte can be 'xored' in */ + + while (length > 0) { + unsigned char ch = *input++; + length--; + + // Break out if we see a null. + if (ch == 0) break; + + crc ^= ch; /* XOR-in the next input byte */ + + for (int i = 0; i < 8; i++) { + if ((crc & 0x80) != 0) { + crc = (unsigned char)((crc << 1) ^ generator); + } else { + crc <<= 1; + } } + } - return crc; + return crc; } -static int reliable_text_ldpc_decode(reliable_text_impl_t* obj, char* dest) -{ - assert(obj != NULL); - assert(dest != NULL); - - char* src = &obj->inbound_pending_bits[RELIABLE_TEXT_UW_LENGTH_BITS]; - char deinterleavedBits[LDPC_TOTAL_SIZE_BITS]; - _Complex float deinterleavedSyms[LDPC_TOTAL_SIZE_BITS / 2]; - float deinterleavedAmps[LDPC_TOTAL_SIZE_BITS / 2]; - float incomingData[LDPC_TOTAL_SIZE_BITS]; - float llr[LDPC_TOTAL_SIZE_BITS]; - unsigned char output[LDPC_TOTAL_SIZE_BITS]; - int parityCheckCount = 0; - - if (obj->bit_index == obj->sym_index * 2) - { - // Use soft decision for the LDPC decoder. - - int Npayloadsymsperpacket = LDPC_TOTAL_SIZE_BITS / 2; - - // Deinterleave symbols - gp_deinterleave_comp ((COMP*)deinterleavedSyms, (COMP*)&obj->inbound_pending_syms[RELIABLE_TEXT_UW_LENGTH_BITS/2], Npayloadsymsperpacket); - gp_deinterleave_float(deinterleavedAmps, &obj->inbound_pending_amps[RELIABLE_TEXT_UW_LENGTH_BITS/2], Npayloadsymsperpacket); - - float EsNo = 3.0; // note: constant from freedv_700.c - - symbols_to_llrs(llr, (COMP*)deinterleavedSyms, deinterleavedAmps, - EsNo, obj->fdv->ofdm->mean_amp, Npayloadsymsperpacket); +static int reliable_text_ldpc_decode(reliable_text_impl_t* obj, char* dest) { + assert(obj != NULL); + assert(dest != NULL); + + char* src = &obj->inbound_pending_bits[RELIABLE_TEXT_UW_LENGTH_BITS]; + char deinterleavedBits[LDPC_TOTAL_SIZE_BITS]; + _Complex float deinterleavedSyms[LDPC_TOTAL_SIZE_BITS / 2]; + float deinterleavedAmps[LDPC_TOTAL_SIZE_BITS / 2]; + float incomingData[LDPC_TOTAL_SIZE_BITS]; + float llr[LDPC_TOTAL_SIZE_BITS]; + unsigned char output[LDPC_TOTAL_SIZE_BITS]; + int parityCheckCount = 0; + + if (obj->bit_index == obj->sym_index * 2) { + // Use soft decision for the LDPC decoder. + + int Npayloadsymsperpacket = LDPC_TOTAL_SIZE_BITS / 2; + + // Deinterleave symbols + gp_deinterleave_comp( + (COMP*)deinterleavedSyms, + (COMP*)&obj->inbound_pending_syms[RELIABLE_TEXT_UW_LENGTH_BITS / 2], + Npayloadsymsperpacket); + gp_deinterleave_float( + deinterleavedAmps, + &obj->inbound_pending_amps[RELIABLE_TEXT_UW_LENGTH_BITS / 2], + Npayloadsymsperpacket); + + float EsNo = 3.0; // note: constant from freedv_700.c + + symbols_to_llrs(llr, (COMP*)deinterleavedSyms, deinterleavedAmps, EsNo, + obj->fdv->ofdm->mean_amp, Npayloadsymsperpacket); + } else { + // Deinterlace the received bits. + gp_deinterleave_bits(deinterleavedBits, src, LDPC_TOTAL_SIZE_BITS / 2); + + // We don't have symbol data (likely due to incorrect mode), so we fall back + // to hard decision. + for (int bitIndex = 0; bitIndex < LDPC_TOTAL_SIZE_BITS; bitIndex++) { + // fprintf(stderr, "rx bit %d: %d\n", bitIndex, + // deinterleavedBits[bitIndex]); + + // Map to value expected by sd_to_llr() + incomingData[bitIndex] = 1.0 - 2.0 * deinterleavedBits[bitIndex]; } - else - { - // Deinterlace the received bits. - gp_deinterleave_bits(deinterleavedBits, src, LDPC_TOTAL_SIZE_BITS / 2); - - // We don't have symbol data (likely due to incorrect mode), so we fall back - // to hard decision. - for (int bitIndex = 0; bitIndex < LDPC_TOTAL_SIZE_BITS; bitIndex++) - { - //fprintf(stderr, "rx bit %d: %d\n", bitIndex, deinterleavedBits[bitIndex]); - - // Map to value expected by sd_to_llr() - incomingData[bitIndex] = 1.0 - 2.0 * deinterleavedBits[bitIndex]; - } - - sd_to_llr(llr, incomingData, LDPC_TOTAL_SIZE_BITS); + + sd_to_llr(llr, incomingData, LDPC_TOTAL_SIZE_BITS); + } + run_ldpc_decoder(&obj->ldpc, output, llr, &parityCheckCount); + + // Data is valid if BER < 0.2 + float ber_est = (float)(obj->ldpc.NumberParityBits - parityCheckCount) / + obj->ldpc.NumberParityBits; + int result = (ber_est < 0.2); + + // fprintf(stderr, "BER est: %f\n", ber_est); + if (result) { + memset(dest, 0, RELIABLE_TEXT_BYTES_PER_ENCODED_SEGMENT); + + for (int bitIndex = 0; bitIndex < 8; bitIndex++) { + if (output[bitIndex]) dest[0] |= 1 << bitIndex; } - run_ldpc_decoder(&obj->ldpc, output, llr, &parityCheckCount); - - // Data is valid if BER < 0.2 - float ber_est = (float)(obj->ldpc.NumberParityBits - parityCheckCount)/obj->ldpc.NumberParityBits; - int result = (ber_est < 0.2); - - //fprintf(stderr, "BER est: %f\n", ber_est); - if (result) - { - memset(dest, 0, RELIABLE_TEXT_BYTES_PER_ENCODED_SEGMENT); - - for (int bitIndex = 0; bitIndex < 8; bitIndex++) - { - if (output[bitIndex]) - dest[0] |= 1 << bitIndex; - } - for (int bitIndex = 8; bitIndex < (LDPC_TOTAL_SIZE_BITS / 2); bitIndex++) - { - int bitsSinceCrc = bitIndex - 8; - if (output[bitIndex]) - dest[1 + (bitsSinceCrc / 6)] |= (1 << (bitsSinceCrc % 6)); - } + for (int bitIndex = 8; bitIndex < (LDPC_TOTAL_SIZE_BITS / 2); bitIndex++) { + int bitsSinceCrc = bitIndex - 8; + if (output[bitIndex]) + dest[1 + (bitsSinceCrc / 6)] |= (1 << (bitsSinceCrc % 6)); } - - return result; + } + + return result; } -static void reliable_text_freedv_callback_rx_sym(void *state, _Complex float sym, float amp) -{ - reliable_text_impl_t* obj = (reliable_text_impl_t*)state; - assert(obj != NULL); - - // Save the symbol. We'll use it during the bit handling below. - obj->inbound_pending_syms[obj->sym_index] = (complex float)sym; - obj->inbound_pending_amps[obj->sym_index++] = amp; - - //fprintf(stderr, "Got sym: %f, amp: %f\n", sym, amp); +static void reliable_text_freedv_callback_rx_sym(void* state, + _Complex float sym, + float amp) { + reliable_text_impl_t* obj = (reliable_text_impl_t*)state; + assert(obj != NULL); + + // Save the symbol. We'll use it during the bit handling below. + obj->inbound_pending_syms[obj->sym_index] = (complex float)sym; + obj->inbound_pending_amps[obj->sym_index++] = amp; + + // fprintf(stderr, "Got sym: %f, amp: %f\n", sym, amp); } -static int check_uw(reliable_text_impl_t* obj) -{ - assert(obj != NULL); - - // Count number of errors in UW. - int num_zeroes = 0; - for (int bit = 0; bit < RELIABLE_TEXT_UW_LENGTH_BITS; bit++) - { - if (obj->inbound_pending_bits[bit] ^ 1) - { - num_zeroes++; - } +static int check_uw(reliable_text_impl_t* obj) { + assert(obj != NULL); + + // Count number of errors in UW. + int num_zeroes = 0; + for (int bit = 0; bit < RELIABLE_TEXT_UW_LENGTH_BITS; bit++) { + if (obj->inbound_pending_bits[bit] ^ 1) { + num_zeroes++; } - return num_zeroes <= RELIABLE_TEXT_MAX_ZEROES_IN_UW; + } + return num_zeroes <= RELIABLE_TEXT_MAX_ZEROES_IN_UW; } -static void reliable_text_freedv_callback_rx(void *state, char chr) -{ - //fprintf(stderr, "char: %d\n", (chr & 0x3F)); - - reliable_text_impl_t* obj = (reliable_text_impl_t*)state; - assert(obj != NULL); - - // No need to further process if we got a valid string already. - if (obj->has_successfully_decoded) - { - return; - } - - // Append character to the end of the symbol list. - obj->inbound_pending_bits[obj->bit_index++] = chr; - - // Verify UW and data. - if (obj->bit_index >= RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS) - { - int uw_bits_valid = check_uw(obj); - - // Only verify data if UW is valid. - int resync = !uw_bits_valid; - if (uw_bits_valid) - { - // We have all the bits we need, so we're ready to decode. - char decodedStr[RELIABLE_TEXT_MAX_RAW_LENGTH + 1]; - char rawStr[RELIABLE_TEXT_MAX_RAW_LENGTH + 1]; - memset(rawStr, 0, RELIABLE_TEXT_MAX_RAW_LENGTH + 1); - memset(decodedStr, 0, RELIABLE_TEXT_MAX_RAW_LENGTH + 1); - - if (reliable_text_ldpc_decode(obj, rawStr) != 0) - { - // BER is under limits. - convert_ota_string_to_callsign_(&rawStr[RELIABLE_TEXT_CRC_LENGTH], &decodedStr[RELIABLE_TEXT_CRC_LENGTH], RELIABLE_TEXT_MAX_LENGTH); - decodedStr[0] = rawStr[0]; // CRC - - // Get expected and actual CRC. - unsigned char receivedCRC = decodedStr[0]; - unsigned char calcCRC = calculateCRC8_(&rawStr[RELIABLE_TEXT_CRC_LENGTH], RELIABLE_TEXT_MAX_LENGTH); - - //fprintf(stderr, "rxCRC: %d, calcCRC: %d, decodedStr: %s\n", receivedCRC, calcCRC, &decodedStr[RELIABLE_TEXT_CRC_LENGTH]); - if (receivedCRC == calcCRC) - { - // We got a valid string. Call assigned callback. - obj->has_successfully_decoded = 1; - obj->text_rx_callback(obj, &decodedStr[RELIABLE_TEXT_CRC_LENGTH], strlen(&decodedStr[RELIABLE_TEXT_CRC_LENGTH]), obj->callback_state); - } - - // Reset UW decoding for next callsign. - obj->bit_index = 0; - obj->sym_index = 0; - memset(&obj->inbound_pending_syms, 0, sizeof(complex float)*LDPC_TOTAL_SIZE_BITS/2); - memset(&obj->inbound_pending_amps, 0, sizeof(float)*LDPC_TOTAL_SIZE_BITS/2); - memset(&obj->inbound_pending_bits, 0, LDPC_TOTAL_SIZE_BITS + RELIABLE_TEXT_UW_LENGTH_BITS); - } - else - { - // It's possible that we didn't actually sync on UW after all. - // Shift existing UW back 1 bit (or 2 if OFDM), add the bit(s) - // from the data portion to UW, and try again next bit(s) we receive. - resync = 1; - } - } - - if (resync) - { - obj->bit_index--; - memmove(&obj->inbound_pending_bits[0], &obj->inbound_pending_bits[1], RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS - 1); - if (obj->sym_index > 0) - { - memmove(&obj->inbound_pending_bits[0], &obj->inbound_pending_bits[1], RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS - 1); - memmove(&obj->inbound_pending_syms[0], &obj->inbound_pending_syms[1], sizeof(_Complex float)*((RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS)/2 - 1)); - memmove(&obj->inbound_pending_amps[0], &obj->inbound_pending_amps[1], sizeof(float)*((RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS)/2 - 1)); - obj->bit_index--; - obj->sym_index--; - } +static void reliable_text_freedv_callback_rx(void* state, char chr) { + // fprintf(stderr, "char: %d\n", (chr & 0x3F)); + + reliable_text_impl_t* obj = (reliable_text_impl_t*)state; + assert(obj != NULL); + + // No need to further process if we got a valid string already. + if (obj->has_successfully_decoded) { + return; + } + + // Append character to the end of the symbol list. + obj->inbound_pending_bits[obj->bit_index++] = chr; + + // Verify UW and data. + if (obj->bit_index >= RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS) { + int uw_bits_valid = check_uw(obj); + + // Only verify data if UW is valid. + int resync = !uw_bits_valid; + if (uw_bits_valid) { + // We have all the bits we need, so we're ready to decode. + char decodedStr[RELIABLE_TEXT_MAX_RAW_LENGTH + 1]; + char rawStr[RELIABLE_TEXT_MAX_RAW_LENGTH + 1]; + memset(rawStr, 0, RELIABLE_TEXT_MAX_RAW_LENGTH + 1); + memset(decodedStr, 0, RELIABLE_TEXT_MAX_RAW_LENGTH + 1); + + if (reliable_text_ldpc_decode(obj, rawStr) != 0) { + // BER is under limits. + convert_ota_string_to_callsign_(&rawStr[RELIABLE_TEXT_CRC_LENGTH], + &decodedStr[RELIABLE_TEXT_CRC_LENGTH], + RELIABLE_TEXT_MAX_LENGTH); + decodedStr[0] = rawStr[0]; // CRC + + // Get expected and actual CRC. + unsigned char receivedCRC = decodedStr[0]; + unsigned char calcCRC = calculateCRC8_( + &rawStr[RELIABLE_TEXT_CRC_LENGTH], RELIABLE_TEXT_MAX_LENGTH); + + // fprintf(stderr, "rxCRC: %d, calcCRC: %d, decodedStr: %s\n", + // receivedCRC, calcCRC, &decodedStr[RELIABLE_TEXT_CRC_LENGTH]); + if (receivedCRC == calcCRC) { + // We got a valid string. Call assigned callback. + obj->has_successfully_decoded = 1; + obj->text_rx_callback(obj, &decodedStr[RELIABLE_TEXT_CRC_LENGTH], + strlen(&decodedStr[RELIABLE_TEXT_CRC_LENGTH]), + obj->callback_state); } + + // Reset UW decoding for next callsign. + obj->bit_index = 0; + obj->sym_index = 0; + memset(&obj->inbound_pending_syms, 0, + sizeof(complex float) * LDPC_TOTAL_SIZE_BITS / 2); + memset(&obj->inbound_pending_amps, 0, + sizeof(float) * LDPC_TOTAL_SIZE_BITS / 2); + memset(&obj->inbound_pending_bits, 0, + LDPC_TOTAL_SIZE_BITS + RELIABLE_TEXT_UW_LENGTH_BITS); + } else { + // It's possible that we didn't actually sync on UW after all. + // Shift existing UW back 1 bit (or 2 if OFDM), add the bit(s) + // from the data portion to UW, and try again next bit(s) we receive. + resync = 1; + } } + + if (resync) { + obj->bit_index--; + memmove(&obj->inbound_pending_bits[0], &obj->inbound_pending_bits[1], + RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS - 1); + if (obj->sym_index > 0) { + memmove(&obj->inbound_pending_bits[0], &obj->inbound_pending_bits[1], + RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS - 1); + memmove(&obj->inbound_pending_syms[0], &obj->inbound_pending_syms[1], + sizeof(_Complex float) * + ((RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS) / 2 - + 1)); + memmove(&obj->inbound_pending_amps[0], &obj->inbound_pending_amps[1], + sizeof(float) * + ((RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS) / 2 - + 1)); + obj->bit_index--; + obj->sym_index--; + } + } + } } -static char reliable_text_freedv_callback_tx(void *state) -{ - reliable_text_impl_t* obj = (reliable_text_impl_t*)state; - assert(obj != NULL); - - char ret = obj->tx_text[obj->tx_text_index]; - obj->tx_text_index = (obj->tx_text_index + 1) % (obj->tx_text_length); - - //fprintf(stderr, "char: %d\n", ret); - return ret; +static char reliable_text_freedv_callback_tx(void* state) { + reliable_text_impl_t* obj = (reliable_text_impl_t*)state; + assert(obj != NULL); + + char ret = obj->tx_text[obj->tx_text_index]; + obj->tx_text_index = (obj->tx_text_index + 1) % (obj->tx_text_length); + + // fprintf(stderr, "char: %d\n", ret); + return ret; } -reliable_text_t reliable_text_create() -{ - reliable_text_impl_t* ret = calloc(1, sizeof(reliable_text_impl_t)); - assert(ret != NULL); - - // Load LDPC code into memory. - int code_index = ldpc_codes_find("HRA_56_56"); - memcpy(&ret->ldpc, &ldpc_codes[code_index], sizeof(struct LDPC)); - - return (reliable_text_t)ret; +reliable_text_t reliable_text_create() { + reliable_text_impl_t* ret = calloc(1, sizeof(reliable_text_impl_t)); + assert(ret != NULL); + + // Load LDPC code into memory. + int code_index = ldpc_codes_find("HRA_56_56"); + memcpy(&ret->ldpc, &ldpc_codes[code_index], sizeof(struct LDPC)); + + return (reliable_text_t)ret; } -void reliable_text_destroy(reliable_text_t ptr) -{ - assert(ptr != NULL); - - reliable_text_unlink_from_freedv(ptr); - free(ptr); +void reliable_text_destroy(reliable_text_t ptr) { + assert(ptr != NULL); + + reliable_text_unlink_from_freedv(ptr); + free(ptr); } -void reliable_text_reset(reliable_text_t ptr) -{ - reliable_text_impl_t* impl = (reliable_text_impl_t*)ptr; - assert(impl != NULL); - - impl->bit_index = 0; - impl->sym_index = 0; - impl->has_successfully_decoded = 0; - memset(&impl->inbound_pending_syms, 0, sizeof(complex float)*LDPC_TOTAL_SIZE_BITS/2); - memset(&impl->inbound_pending_amps, 0, sizeof(float)*LDPC_TOTAL_SIZE_BITS/2); - memset(&impl->inbound_pending_bits, 0, LDPC_TOTAL_SIZE_BITS + RELIABLE_TEXT_UW_LENGTH_BITS); +void reliable_text_reset(reliable_text_t ptr) { + reliable_text_impl_t* impl = (reliable_text_impl_t*)ptr; + assert(impl != NULL); + + impl->bit_index = 0; + impl->sym_index = 0; + impl->has_successfully_decoded = 0; + memset(&impl->inbound_pending_syms, 0, + sizeof(complex float) * LDPC_TOTAL_SIZE_BITS / 2); + memset(&impl->inbound_pending_amps, 0, + sizeof(float) * LDPC_TOTAL_SIZE_BITS / 2); + memset(&impl->inbound_pending_bits, 0, + LDPC_TOTAL_SIZE_BITS + RELIABLE_TEXT_UW_LENGTH_BITS); } -void reliable_text_set_string(reliable_text_t ptr, const char* str, int strlength) -{ - reliable_text_impl_t* impl = (reliable_text_impl_t*)ptr; - assert(impl != NULL); - - char tmp[RELIABLE_TEXT_MAX_RAW_LENGTH + 1]; - memset(tmp, 0, RELIABLE_TEXT_MAX_RAW_LENGTH + 1); - - convert_callsign_to_ota_string_(str, &tmp[RELIABLE_TEXT_CRC_LENGTH], strlength < RELIABLE_TEXT_MAX_LENGTH ? strlength : RELIABLE_TEXT_MAX_LENGTH); - - int txt_length = strlen(&tmp[RELIABLE_TEXT_CRC_LENGTH]); - if (txt_length >= RELIABLE_TEXT_MAX_LENGTH) - { - txt_length = RELIABLE_TEXT_MAX_LENGTH; - } - impl->tx_text_length = RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS; - impl->tx_text_index = 0; - unsigned char crc = calculateCRC8_(&tmp[RELIABLE_TEXT_CRC_LENGTH], txt_length); - tmp[0] = crc; - - // Encode block of text using LDPC(112,56). - unsigned char ibits[LDPC_TOTAL_SIZE_BITS / 2]; - unsigned char pbits[LDPC_TOTAL_SIZE_BITS / 2]; - memset(ibits, 0, LDPC_TOTAL_SIZE_BITS / 2); - memset(pbits, 0, LDPC_TOTAL_SIZE_BITS / 2); - for (int index = 0; index < 8; index++) - { - if (tmp[0] & (1 << index)) ibits[index] = 1; - } +void reliable_text_set_string(reliable_text_t ptr, const char* str, + int strlength) { + reliable_text_impl_t* impl = (reliable_text_impl_t*)ptr; + assert(impl != NULL); - // Pack 6 bit characters into single LDPC block. - for (int ibitsBitIndex = 8; ibitsBitIndex < (LDPC_TOTAL_SIZE_BITS / 2); ibitsBitIndex++) - { - int bitsFromCrc = ibitsBitIndex - 8; - unsigned int byte = tmp[RELIABLE_TEXT_CRC_LENGTH + bitsFromCrc / 6]; - unsigned int bitToCheck = bitsFromCrc % 6; - //fprintf(stderr, "bit index: %d, byte: %x, bit to check: %d, result: %d\n", ibitsBitIndex, byte, bitToCheck, (byte & (1 << bitToCheck)) != 0); - - if (byte & (1 << bitToCheck)) - { - ibits[ibitsBitIndex] = 1; - } + char tmp[RELIABLE_TEXT_MAX_RAW_LENGTH + 1]; + memset(tmp, 0, RELIABLE_TEXT_MAX_RAW_LENGTH + 1); + + convert_callsign_to_ota_string_(str, &tmp[RELIABLE_TEXT_CRC_LENGTH], + strlength < RELIABLE_TEXT_MAX_LENGTH + ? strlength + : RELIABLE_TEXT_MAX_LENGTH); + + int txt_length = strlen(&tmp[RELIABLE_TEXT_CRC_LENGTH]); + if (txt_length >= RELIABLE_TEXT_MAX_LENGTH) { + txt_length = RELIABLE_TEXT_MAX_LENGTH; + } + impl->tx_text_length = RELIABLE_TEXT_UW_LENGTH_BITS + LDPC_TOTAL_SIZE_BITS; + impl->tx_text_index = 0; + unsigned char crc = + calculateCRC8_(&tmp[RELIABLE_TEXT_CRC_LENGTH], txt_length); + tmp[0] = crc; + + // Encode block of text using LDPC(112,56). + unsigned char ibits[LDPC_TOTAL_SIZE_BITS / 2]; + unsigned char pbits[LDPC_TOTAL_SIZE_BITS / 2]; + memset(ibits, 0, LDPC_TOTAL_SIZE_BITS / 2); + memset(pbits, 0, LDPC_TOTAL_SIZE_BITS / 2); + for (int index = 0; index < 8; index++) { + if (tmp[0] & (1 << index)) ibits[index] = 1; + } + + // Pack 6 bit characters into single LDPC block. + for (int ibitsBitIndex = 8; ibitsBitIndex < (LDPC_TOTAL_SIZE_BITS / 2); + ibitsBitIndex++) { + int bitsFromCrc = ibitsBitIndex - 8; + unsigned int byte = tmp[RELIABLE_TEXT_CRC_LENGTH + bitsFromCrc / 6]; + unsigned int bitToCheck = bitsFromCrc % 6; + // fprintf(stderr, "bit index: %d, byte: %x, bit to check: %d, result: + // %d\n", ibitsBitIndex, byte, bitToCheck, (byte & (1 << bitToCheck)) != 0); + + if (byte & (1 << bitToCheck)) { + ibits[ibitsBitIndex] = 1; } - - encode(&impl->ldpc, ibits, pbits); - - // Split LDPC encoded bits into individual bits, with the first RELIABLE_TEXT_UW_LENGTH_BITS being UW. - char tmpbits[LDPC_TOTAL_SIZE_BITS]; - - memset(impl->tx_text, 1, RELIABLE_TEXT_UW_LENGTH_BITS); - memset(impl->tx_text + RELIABLE_TEXT_UW_LENGTH_BITS, 0, LDPC_TOTAL_SIZE_BITS); - memcpy(&tmpbits[0], &ibits[0], LDPC_TOTAL_SIZE_BITS / 2); - memcpy(&tmpbits[LDPC_TOTAL_SIZE_BITS / 2], &pbits[0], LDPC_TOTAL_SIZE_BITS / 2); - - // Interleave the bits together to enhance fading performance. - gp_interleave_bits(&impl->tx_text[RELIABLE_TEXT_UW_LENGTH_BITS], tmpbits, LDPC_TOTAL_SIZE_BITS / 2); + } + + encode(&impl->ldpc, ibits, pbits); + + // Split LDPC encoded bits into individual bits, with the first + // RELIABLE_TEXT_UW_LENGTH_BITS being UW. + char tmpbits[LDPC_TOTAL_SIZE_BITS]; + + memset(impl->tx_text, 1, RELIABLE_TEXT_UW_LENGTH_BITS); + memset(impl->tx_text + RELIABLE_TEXT_UW_LENGTH_BITS, 0, LDPC_TOTAL_SIZE_BITS); + memcpy(&tmpbits[0], &ibits[0], LDPC_TOTAL_SIZE_BITS / 2); + memcpy(&tmpbits[LDPC_TOTAL_SIZE_BITS / 2], &pbits[0], + LDPC_TOTAL_SIZE_BITS / 2); + + // Interleave the bits together to enhance fading performance. + gp_interleave_bits(&impl->tx_text[RELIABLE_TEXT_UW_LENGTH_BITS], tmpbits, + LDPC_TOTAL_SIZE_BITS / 2); } -void reliable_text_use_with_freedv(reliable_text_t ptr, struct freedv* fdv, on_text_rx_t text_rx_fn, void* state) -{ - reliable_text_impl_t* impl = (reliable_text_impl_t*)ptr; - assert(impl != NULL); - - impl->callback_state = state; - impl->text_rx_callback = text_rx_fn; - impl->fdv = fdv; - freedv_set_callback_txt(fdv, reliable_text_freedv_callback_rx, reliable_text_freedv_callback_tx, impl); - freedv_set_callback_txt_sym(fdv, reliable_text_freedv_callback_rx_sym, impl); - - // Use code 3 for varicode en/decode and handle all framing at this level. - varicode_set_code_num(&fdv->varicode_dec_states, 3); +void reliable_text_use_with_freedv(reliable_text_t ptr, struct freedv* fdv, + on_text_rx_t text_rx_fn, void* state) { + reliable_text_impl_t* impl = (reliable_text_impl_t*)ptr; + assert(impl != NULL); + + impl->callback_state = state; + impl->text_rx_callback = text_rx_fn; + impl->fdv = fdv; + freedv_set_callback_txt(fdv, reliable_text_freedv_callback_rx, + reliable_text_freedv_callback_tx, impl); + freedv_set_callback_txt_sym(fdv, reliable_text_freedv_callback_rx_sym, impl); + + // Use code 3 for varicode en/decode and handle all framing at this level. + varicode_set_code_num(&fdv->varicode_dec_states, 3); } -struct freedv* reliable_text_get_freedv_obj(reliable_text_t ptr) -{ - reliable_text_impl_t* impl = (reliable_text_impl_t*)ptr; - assert(impl != NULL); +struct freedv* reliable_text_get_freedv_obj(reliable_text_t ptr) { + reliable_text_impl_t* impl = (reliable_text_impl_t*)ptr; + assert(impl != NULL); - return impl->fdv; + return impl->fdv; } -void reliable_text_unlink_from_freedv(reliable_text_t ptr) -{ - reliable_text_impl_t* impl = (reliable_text_impl_t*)ptr; - assert(impl != NULL); - - if (impl->fdv) - { - freedv_set_callback_txt(impl->fdv, NULL, NULL, NULL); - freedv_set_callback_txt_sym(impl->fdv, NULL, NULL); - varicode_set_code_num(&impl->fdv->varicode_dec_states, 1); - impl->fdv = NULL; - } +void reliable_text_unlink_from_freedv(reliable_text_t ptr) { + reliable_text_impl_t* impl = (reliable_text_impl_t*)ptr; + assert(impl != NULL); + + if (impl->fdv) { + freedv_set_callback_txt(impl->fdv, NULL, NULL, NULL); + freedv_set_callback_txt_sym(impl->fdv, NULL, NULL); + varicode_set_code_num(&impl->fdv->varicode_dec_states, 1); + impl->fdv = NULL; + } } |
