Added prefixes to ft8/ft4/ftx functions and clang-formatted code

pull/16/merge
Karlis Goba 2021-11-17 10:31:01 +02:00
rodzic 550f3dc29c
commit 26decf92f7
22 zmienionych plików z 258 dodań i 225 usunięć

31
.clang-format 100644
Wyświetl plik

@ -0,0 +1,31 @@
BasedOnStyle: WebKit
# Cpp11BracedListStyle: false
# ColumnLimit: 120
IndentCaseLabels: false
IndentWidth: 4
TabWidth: 8
UseTab: Never
PointerAlignment: Left
SortIncludes: false
AlignConsecutiveMacros: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
BreakConstructorInitializers: BeforeColon
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 0
BreakBeforeBraces: Custom
BreakBeforeBinaryOperators: All
BraceWrapping:
AfterControlStatement: true
AfterClass: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeElse: true
BeforeCatch: true

Wyświetl plik

@ -1,6 +1,6 @@
CFLAGS = -O3
CFLAGS = -O3 -ggdb3 -fsanitize=address
CPPFLAGS = -std=c11 -I.
LDFLAGS = -lm
LDFLAGS = -lm -fsanitize=address
TARGETS = gen_ft8 decode_ft8 test

Wyświetl plik

@ -183,12 +183,13 @@ int main(int argc, char **argv)
.num_bins = num_bins,
.time_osr = kTime_osr,
.freq_osr = kFreq_osr,
.mag = mag_power};
.mag = mag_power
};
extract_power(signal, &power, block_size);
// Find top candidates by Costas sync score and localize them in time and frequency
candidate_t candidate_list[kMax_candidates];
int num_candidates = find_sync(&power, kMax_candidates, candidate_list, kMin_score);
int num_candidates = ft8_find_sync(&power, kMax_candidates, candidate_list, kMin_score);
// Hash table for decoded messages (to check for duplicates)
int num_decoded = 0;
@ -213,7 +214,7 @@ int main(int argc, char **argv)
message_t message;
decode_status_t status;
if (!decode(&power, cand, &message, kLDPC_iterations, &status))
if (!ft8_decode(&power, cand, &message, kLDPC_iterations, &status))
{
if (status.ldpc_errors > 0)
{

Wyświetl plik

@ -7,7 +7,7 @@
// Adapted from https://barrgroup.com/Embedded-Systems/How-To/CRC-Calculation-C-Code
// [IN] message - byte sequence (MSB first)
// [IN] num_bits - number of bits in the sequence
uint16_t ft8_crc(const uint8_t message[], int num_bits)
uint16_t ftx_compute_crc(const uint8_t message[], int num_bits)
{
uint16_t remainder = 0;
int idx_byte = 0;
@ -36,13 +36,13 @@ uint16_t ft8_crc(const uint8_t message[], int num_bits)
return remainder & ((TOPBIT << 1) - 1u);
}
uint16_t extract_crc(const uint8_t a91[])
uint16_t ftx_extract_crc(const uint8_t a91[])
{
uint16_t chksum = ((a91[9] & 0x07) << 11) | (a91[10] << 3) | (a91[11] >> 5);
return chksum;
}
void add_crc(const uint8_t payload[], uint8_t a91[])
void ftx_add_crc(const uint8_t payload[], uint8_t a91[])
{
// Copy 77 bits of payload data
for (int i = 0; i < 10; i++)
@ -54,7 +54,7 @@ void add_crc(const uint8_t payload[], uint8_t a91[])
// Calculate CRC of 82 bits (77 + 5 zeros)
// 'The CRC is calculated on the source-encoded message, zero-extended from 77 to 82 bits'
uint16_t checksum = ft8_crc(a91, 96 - 14);
uint16_t checksum = ftx_compute_crc(a91, 96 - 14);
// Store the CRC at the end of 77 bit message
a91[9] |= (uint8_t)(checksum >> 11);

Wyświetl plik

@ -4,19 +4,19 @@
#include <stdint.h>
#include <stdbool.h>
// Compute 14-bit CRC for a sequence of given number of bits
// Compute 14-bit CRC for a sequence of given number of bits using FT8/FT4 CRC polynomial
// [IN] message - byte sequence (MSB first)
// [IN] num_bits - number of bits in the sequence
uint16_t ft8_crc(const uint8_t message[], int num_bits);
uint16_t ftx_compute_crc(const uint8_t message[], int num_bits);
/// Extract the FT8 CRC of a packed message (during decoding)
/// Extract the FT8/FT4 CRC of a packed message (during decoding)
/// @param[in] a91 77 bits of payload data + CRC
/// @return Extracted CRC
uint16_t extract_crc(const uint8_t a91[]);
uint16_t ftx_extract_crc(const uint8_t a91[]);
/// Add the FT8 CRC to a packed message (during encoding)
/// Add FT8/FT4 CRC to a packed message (during encoding)
/// @param[in] payload 77 bits of payload data
/// @param[out] a91 91 bits of payload data + CRC
void add_crc(const uint8_t payload[], uint8_t a91[]);
void ftx_add_crc(const uint8_t payload[], uint8_t a91[]);
#endif // _INCLUDE_CRC_H_

Wyświetl plik

@ -12,7 +12,14 @@
/// @param[in] cand Candidate to extract the message from
/// @param[in] code_map Symbol encoding map
/// @param[out] log174 Output of decoded log likelihoods for each of the 174 message bits
static void extract_likelihood(const waterfall_t *power, const candidate_t *cand, float *log174);
static void ft8_extract_likelihood(const waterfall_t* power, const candidate_t* cand, float* log174);
/// Packs a string of bits each represented as a zero/non-zero byte in bit_array[],
/// as a string of packed bits starting from the MSB of the first byte of packed[]
/// @param[in] plain Array of bits (0 and nonzero values) with num_bits entires
/// @param[in] num_bits Number of bits (entries) passed in bit_array
/// @param[out] packed Byte-packed bits representing the data in bit_array
static void pack_bits(const uint8_t bit_array[], int num_bits, uint8_t packed[]);
static float max2(float a, float b);
static float max4(float a, float b, float c, float d);
@ -26,7 +33,7 @@ static int get_index(const waterfall_t *power, int block, int time_sub, int freq
return ((((block * power->time_osr) + time_sub) * power->freq_osr + freq_sub) * power->num_bins) + bin;
}
int find_sync(const waterfall_t *power, int num_candidates, candidate_t heap[], int min_score)
int ft8_find_sync(const waterfall_t* power, int num_candidates, candidate_t heap[], int min_score)
{
int heap_size = 0;
int sym_stride = power->time_osr * power->freq_osr * power->num_bins;
@ -143,7 +150,7 @@ int find_sync(const waterfall_t *power, int num_candidates, candidate_t heap[],
return heap_size;
}
void extract_likelihood(const waterfall_t *power, const candidate_t *cand, float *log174)
void ft8_extract_likelihood(const waterfall_t* power, const candidate_t* cand, float* log174)
{
int sym_stride = power->time_osr * power->freq_osr * power->num_bins;
int offset = get_index(power, cand->time_offset, cand->time_sub, cand->freq_sub, cand->freq_offset);
@ -193,10 +200,10 @@ void extract_likelihood(const waterfall_t *power, const candidate_t *cand, float
}
}
bool decode(const waterfall_t *power, const candidate_t *cand, message_t *message, int max_iterations, decode_status_t *status)
bool ft8_decode(const waterfall_t* power, const candidate_t* cand, message_t* message, int max_iterations, decode_status_t* status)
{
float log174[FT8_LDPC_N]; // message bits encoded as likelihood
extract_likelihood(power, cand, log174);
ft8_extract_likelihood(power, cand, log174);
uint8_t plain174[FT8_LDPC_N]; // message bits (0/1)
bp_decode(log174, max_iterations, plain174, &status->ldpc_errors);
@ -212,11 +219,11 @@ bool decode(const waterfall_t *power, const candidate_t *cand, message_t *messag
pack_bits(plain174, FT8_LDPC_K, a91);
// Extract CRC and check it
status->crc_extracted = extract_crc(a91);
status->crc_extracted = ftx_extract_crc(a91);
// [1]: 'The CRC is calculated on the source-encoded message, zero-extended from 77 to 82 bits.'
a91[9] &= 0xF8;
a91[10] &= 0x00;
status->crc_calculated = ft8_crc(a91, 96 - 14);
status->crc_calculated = ftx_compute_crc(a91, 96 - 14);
if (status->crc_extracted != status->crc_calculated)
{
@ -367,3 +374,30 @@ static void decode_multi_symbols(const uint8_t *power, int num_bins, int n_syms,
log174[bit_idx + i] = max_one - max_zero;
}
}
// Packs a string of bits each represented as a zero/non-zero byte in plain[],
// as a string of packed bits starting from the MSB of the first byte of packed[]
static void pack_bits(const uint8_t bit_array[], int num_bits, uint8_t packed[])
{
int num_bytes = (num_bits + 7) / 8;
for (int i = 0; i < num_bytes; ++i)
{
packed[i] = 0;
}
uint8_t mask = 0x80;
int byte_idx = 0;
for (int i = 0; i < num_bits; ++i)
{
if (bit_array[i])
{
packed[byte_idx] |= mask;
}
mask >>= 1;
if (!mask)
{
mask = 0x80;
++byte_idx;
}
}
}

Wyświetl plik

@ -4,7 +4,7 @@
#include <stdint.h>
#include <stdbool.h>
/// Input structure to find_sync() function. This structure describes stored waterfall data over the whole message slot.
/// Input structure to ft8_find_sync() function. This structure describes stored waterfall data over the whole message slot.
/// Fields time_osr and freq_osr specify additional oversampling rate for time and frequency resolution.
/// If time_osr=1, FFT magnitude data is collected once for every symbol transmitted, i.e. every 1/6.25 = 0.16 seconds.
/// Values time_osr > 1 mean each symbol is further subdivided in time.
@ -19,7 +19,7 @@ typedef struct
uint8_t* mag; ///< FFT magnitudes stored as uint8_t[blocks][time_osr][freq_osr][num_bins]
} waterfall_t;
/// Output structure of find_sync() and input structure of extract_likelihood().
/// Output structure of ft8_find_sync() and input structure of ft8_decode().
/// Holds the position of potential start of a message in time and frequency.
typedef struct
{
@ -55,7 +55,7 @@ typedef struct
/// @param[in,out] heap Array of candidate_t type entries (with num_candidates allocated entries)
/// @param[in] min_score Minimal score allowed for pruning unlikely candidates (can be zero for no effect)
/// @return Number of candidates filled in the heap
int find_sync(const waterfall_t *power, int num_candidates, candidate_t heap[], int min_score);
int ft8_find_sync(const waterfall_t* power, int num_candidates, candidate_t heap[], int min_score);
/// Attempt to decode a message candidate. Extracts the bit probabilities, runs LDPC decoder, checks CRC and unpacks the message in plain text.
/// @param[in] power Waterfall data collected during message slot
@ -64,6 +64,6 @@ int find_sync(const waterfall_t *power, int num_candidates, candidate_t heap[],
/// @param[in] max_iterations Maximum allowed LDPC iterations (lower number means faster decode, but less precise)
/// @param[out] status decode_status_t structure that will be filled with the status of various decoding steps
/// @return True if the decoding was successful, false otherwise (check status for details)
bool decode(const waterfall_t *power, const candidate_t *cand, message_t *message, int max_iterations, decode_status_t *status);
bool ft8_decode(const waterfall_t* power, const candidate_t* cand, message_t* message, int max_iterations, decode_status_t* status);
#endif // _INCLUDE_DECODE_H_

Wyświetl plik

@ -5,7 +5,7 @@
#include <stdio.h>
// Returns 1 if an odd number of bits are set in x, zero otherwise
uint8_t parity8(uint8_t x)
static uint8_t parity8(uint8_t x)
{
x ^= x >> 4; // a b c d ae bf cg dh
x ^= x >> 2; // a b ac bd cae dbf aecg bfdh
@ -13,13 +13,13 @@ uint8_t parity8(uint8_t x)
return x % 2; // modulo 2
}
// Encode a 91-bit message and return a 174-bit codeword.
// Encode via LDPC a 91-bit message and return a 174-bit codeword.
// The generator matrix has dimensions (87,87).
// The code is a (174,91) regular LDPC code with column weight 3.
// Arguments:
// [IN] message - array of 91 bits stored as 12 bytes (MSB first)
// [OUT] codeword - array of 174 bits stored as 22 bytes (MSB first)
void encode174(const uint8_t *message, uint8_t *codeword)
static void encode174(const uint8_t* message, uint8_t* codeword)
{
// This implementation accesses the generator bits straight from the packed binary representation in kFT8_LDPC_generator
@ -62,13 +62,13 @@ void encode174(const uint8_t *message, uint8_t *codeword)
}
}
void genft8(const uint8_t *payload, uint8_t *tones)
void ft8_encode(const uint8_t* payload, uint8_t* tones)
{
uint8_t a91[12]; // Store 77 bits of payload + 14 bits CRC
// Compute and add CRC at the end of the message
// a91 contains 77 bits of payload + 14 bits of CRC
add_crc(payload, a91);
ftx_add_crc(payload, a91);
uint8_t codeword[22];
encode174(a91, codeword);
@ -124,13 +124,13 @@ void genft8(const uint8_t *payload, uint8_t *tones)
}
}
void genft4(const uint8_t *payload, uint8_t *tones)
void ft4_encode(const uint8_t* payload, uint8_t* tones)
{
uint8_t a91[12]; // Store 77 bits of payload + 14 bits CRC
// Compute and add CRC at the end of the message
// a91 contains 77 bits of payload + 14 bits of CRC
add_crc(payload, a91);
ftx_add_crc(payload, a91);
uint8_t codeword[22];
encode174(a91, codeword); // 91 bits -> 174 bits

Wyświetl plik

@ -22,11 +22,11 @@
/// Generate FT8 tone sequence from payload data
/// @param[in] payload - 10 byte array consisting of 77 bit payload
/// @param[out] tones - array of FT8_NN (79) bytes to store the generated tones (encoded as 0..7)
void genft8(const uint8_t *payload, uint8_t *tones);
void ft8_encode(const uint8_t* payload, uint8_t* tones);
/// Generate FT4 tone sequence from payload data
/// @param[in] payload - 10 byte array consisting of 77 bit payload
/// @param[out] tones - array of FT4_NN (105) bytes to store the generated tones (encoded as 0..3)
void genft4(const uint8_t *payload, uint8_t *tones);
void ft4_encode(const uint8_t* payload, uint8_t* tones);
#endif // _INCLUDE_ENCODE_H_

Wyświetl plik

@ -21,33 +21,6 @@ static int ldpc_check(uint8_t codeword[]);
static float fast_tanh(float x);
static float fast_atanh(float x);
// Packs a string of bits each represented as a zero/non-zero byte in plain[],
// as a string of packed bits starting from the MSB of the first byte of packed[]
void pack_bits(const uint8_t plain[], int num_bits, uint8_t packed[])
{
int num_bytes = (num_bits + 7) / 8;
for (int i = 0; i < num_bytes; ++i)
{
packed[i] = 0;
}
uint8_t mask = 0x80;
int byte_idx = 0;
for (int i = 0; i < num_bits; ++i)
{
if (plain[i])
{
packed[byte_idx] |= mask;
}
mask >>= 1;
if (!mask)
{
mask = 0x80;
++byte_idx;
}
}
}
// codeword is 174 log-likelihoods.
// plain is a return value, 174 ints, to be 0 or 1.
// max_iters is how hard to try.

Wyświetl plik

@ -11,8 +11,4 @@ void ldpc_decode(float codeword[], int max_iters, uint8_t plain[], int *ok);
void bp_decode(float codeword[], int max_iters, uint8_t plain[], int* ok);
// Packs a string of bits each represented as a zero/non-zero byte in plain[],
// as a string of packed bits starting from the MSB of the first byte of packed[]
void pack_bits(const uint8_t plain[], int num_bits, uint8_t packed[]);
#endif // _INCLUDE_LDPC_H_

Wyświetl plik

@ -75,9 +75,7 @@ int32_t pack28(const char *callsign)
// Check for standard callsign
int i0, i1, i2, i3, i4, i5;
if ((i0 = char_index(A1, c6[0])) >= 0 && (i1 = char_index(A2, c6[1])) >= 0 &&
(i2 = char_index(A3, c6[2])) >= 0 && (i3 = char_index(A4, c6[3])) >= 0 &&
(i4 = char_index(A4, c6[4])) >= 0 && (i5 = char_index(A4, c6[5])) >= 0)
if ((i0 = char_index(A1, c6[0])) >= 0 && (i1 = char_index(A2, c6[1])) >= 0 && (i2 = char_index(A3, c6[2])) >= 0 && (i3 = char_index(A4, c6[3])) >= 0 && (i4 = char_index(A4, c6[4])) >= 0 && (i5 = char_index(A4, c6[5])) >= 0)
{
// This is a standard callsign
int32_t n28 = i0;
@ -138,9 +136,7 @@ uint16_t packgrid(const char *grid4)
return MAXGRID4 + 4;
// Check for standard 4 letter grid
if (in_range(grid4[0], 'A', 'R') &&
in_range(grid4[1], 'A', 'R') &&
is_digit(grid4[2]) && is_digit(grid4[3]))
if (in_range(grid4[0], 'A', 'R') && in_range(grid4[1], 'A', 'R') && is_digit(grid4[2]) && is_digit(grid4[3]))
{
uint16_t igrid4 = (grid4[0] - 'A');
igrid4 = igrid4 * 18 + (grid4[1] - 'A');
@ -321,7 +317,8 @@ bool test1()
"LL3JG",
"LL3AJG",
"CQ ",
0};
0
};
for (int i = 0; inputs[i]; ++i)
{
@ -341,7 +338,8 @@ bool test2()
"L0UAA LL3JG +02",
"L0UAA LL3JG RRR",
"L0UAA LL3JG 73",
0};
0
};
for (int i = 0; inputs[i]; ++i)
{

Wyświetl plik

@ -170,11 +170,11 @@ int main(int argc, char **argv)
uint8_t tones[num_tones]; // Array of 79 tones (symbols)
if (is_ft4)
{
genft4(packed, tones);
ft4_encode(packed, tones);
}
else
{
genft8(packed, tones);
ft8_encode(packed, tones);
}
printf("FSK tones: ");

2
test.c
Wyświetl plik

@ -96,7 +96,7 @@ void test2() {
void test3() {
uint8_t test_in2[10] = { 0x11, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x10, 0x04, 0x01, 0x00 };
uint16_t crc1 = ft8_crc(test_in2, 76); // Calculate CRC of 76 bits only
uint16_t crc1 = ftx_compute_crc(test_in2, 76); // Calculate CRC of 76 bits only
LOG(LOG_INFO, "CRC: %04x\n", crc1); // should be 0x0708
}
*/