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

@ -7,25 +7,25 @@
#include <stdint.h>
// Save signal in floating point format (-1 .. +1) as a WAVE file using 16-bit signed integers.
void save_wav(const float *signal, int num_samples, int sample_rate, const char *path)
void save_wav(const float* signal, int num_samples, int sample_rate, const char* path)
{
char subChunk1ID[4] = {'f', 'm', 't', ' '};
char subChunk1ID[4] = { 'f', 'm', 't', ' ' };
uint32_t subChunk1Size = 16; // 16 for PCM
uint16_t audioFormat = 1; // PCM = 1
uint16_t audioFormat = 1; // PCM = 1
uint16_t numChannels = 1;
uint16_t bitsPerSample = 16;
uint32_t sampleRate = sample_rate;
uint16_t blockAlign = numChannels * bitsPerSample / 8;
uint32_t byteRate = sampleRate * blockAlign;
char subChunk2ID[4] = {'d', 'a', 't', 'a'};
char subChunk2ID[4] = { 'd', 'a', 't', 'a' };
uint32_t subChunk2Size = num_samples * blockAlign;
char chunkID[4] = {'R', 'I', 'F', 'F'};
char chunkID[4] = { 'R', 'I', 'F', 'F' };
uint32_t chunkSize = 4 + (8 + subChunk1Size) + (8 + subChunk2Size);
char format[4] = {'W', 'A', 'V', 'E'};
char format[4] = { 'W', 'A', 'V', 'E' };
int16_t *raw_data = (int16_t *)malloc(num_samples * blockAlign);
int16_t* raw_data = (int16_t*)malloc(num_samples * blockAlign);
for (int i = 0; i < num_samples; i++)
{
float x = signal[i];
@ -36,7 +36,7 @@ void save_wav(const float *signal, int num_samples, int sample_rate, const char
raw_data[i] = (int)(0.5 + (x * 32767.0));
}
FILE *f = fopen(path, "wb");
FILE* f = fopen(path, "wb");
// NOTE: works only on little-endian architecture
fwrite(chunkID, sizeof(chunkID), 1, f);
@ -63,48 +63,48 @@ void save_wav(const float *signal, int num_samples, int sample_rate, const char
}
// Load signal in floating point format (-1 .. +1) as a WAVE file using 16-bit signed integers.
int load_wav(float *signal, int *num_samples, int *sample_rate, const char *path)
int load_wav(float* signal, int* num_samples, int* sample_rate, const char* path)
{
char subChunk1ID[4]; // = {'f', 'm', 't', ' '};
char subChunk1ID[4]; // = {'f', 'm', 't', ' '};
uint32_t subChunk1Size; // = 16; // 16 for PCM
uint16_t audioFormat; // = 1; // PCM = 1
uint16_t numChannels; // = 1;
uint16_t audioFormat; // = 1; // PCM = 1
uint16_t numChannels; // = 1;
uint16_t bitsPerSample; // = 16;
uint32_t sampleRate;
uint16_t blockAlign; // = numChannels * bitsPerSample / 8;
uint32_t byteRate; // = sampleRate * blockAlign;
uint32_t byteRate; // = sampleRate * blockAlign;
char subChunk2ID[4]; // = {'d', 'a', 't', 'a'};
char subChunk2ID[4]; // = {'d', 'a', 't', 'a'};
uint32_t subChunk2Size; // = num_samples * blockAlign;
char chunkID[4]; // = {'R', 'I', 'F', 'F'};
char chunkID[4]; // = {'R', 'I', 'F', 'F'};
uint32_t chunkSize; // = 4 + (8 + subChunk1Size) + (8 + subChunk2Size);
char format[4]; // = {'W', 'A', 'V', 'E'};
char format[4]; // = {'W', 'A', 'V', 'E'};
FILE *f = fopen(path, "rb");
FILE* f = fopen(path, "rb");
// NOTE: works only on little-endian architecture
fread((void *)chunkID, sizeof(chunkID), 1, f);
fread((void *)&chunkSize, sizeof(chunkSize), 1, f);
fread((void *)format, sizeof(format), 1, f);
fread((void*)chunkID, sizeof(chunkID), 1, f);
fread((void*)&chunkSize, sizeof(chunkSize), 1, f);
fread((void*)format, sizeof(format), 1, f);
fread((void *)subChunk1ID, sizeof(subChunk1ID), 1, f);
fread((void *)&subChunk1Size, sizeof(subChunk1Size), 1, f);
fread((void*)subChunk1ID, sizeof(subChunk1ID), 1, f);
fread((void*)&subChunk1Size, sizeof(subChunk1Size), 1, f);
if (subChunk1Size != 16)
return -1;
fread((void *)&audioFormat, sizeof(audioFormat), 1, f);
fread((void *)&numChannels, sizeof(numChannels), 1, f);
fread((void *)&sampleRate, sizeof(sampleRate), 1, f);
fread((void *)&byteRate, sizeof(byteRate), 1, f);
fread((void *)&blockAlign, sizeof(blockAlign), 1, f);
fread((void *)&bitsPerSample, sizeof(bitsPerSample), 1, f);
fread((void*)&audioFormat, sizeof(audioFormat), 1, f);
fread((void*)&numChannels, sizeof(numChannels), 1, f);
fread((void*)&sampleRate, sizeof(sampleRate), 1, f);
fread((void*)&byteRate, sizeof(byteRate), 1, f);
fread((void*)&blockAlign, sizeof(blockAlign), 1, f);
fread((void*)&bitsPerSample, sizeof(bitsPerSample), 1, f);
if (audioFormat != 1 || numChannels != 1 || bitsPerSample != 16)
return -1;
fread((void *)subChunk2ID, sizeof(subChunk2ID), 1, f);
fread((void *)&subChunk2Size, sizeof(subChunk2Size), 1, f);
fread((void*)subChunk2ID, sizeof(subChunk2ID), 1, f);
fread((void*)&subChunk2Size, sizeof(subChunk2Size), 1, f);
if (subChunk2Size / blockAlign > *num_samples)
return -2;
@ -112,9 +112,9 @@ int load_wav(float *signal, int *num_samples, int *sample_rate, const char *path
*num_samples = subChunk2Size / blockAlign;
*sample_rate = sampleRate;
int16_t *raw_data = (int16_t *)malloc(*num_samples * blockAlign);
int16_t* raw_data = (int16_t*)malloc(*num_samples * blockAlign);
fread((void *)raw_data, blockAlign, *num_samples, f);
fread((void*)raw_data, blockAlign, *num_samples, f);
for (int i = 0; i < *num_samples; i++)
{
signal[i] = raw_data[i] / 32768.0f;

Wyświetl plik

@ -2,9 +2,9 @@
#define _INCLUDE_WAVE_H_
// Save signal in floating point format (-1 .. +1) as a WAVE file using 16-bit signed integers.
void save_wav(const float *signal, int num_samples, int sample_rate, const char *path);
void save_wav(const float* signal, int num_samples, int sample_rate, const char* path);
// Load signal in floating point format (-1 .. +1) as a WAVE file using 16-bit signed integers.
int load_wav(float *signal, int *num_samples, int *sample_rate, const char *path);
int load_wav(float* signal, int* num_samples, int* sample_rate, const char* path);
#endif // _INCLUDE_WAVE_H_

Wyświetl plik

@ -68,7 +68,7 @@ static float max2(float a, float b)
}
// Compute FFT magnitudes (log power) for each timeslot in the signal
void extract_power(const float signal[], waterfall_t *power, int block_size)
void extract_power(const float signal[], waterfall_t* power, int block_size)
{
const int subblock_size = block_size / power->time_osr;
const int nfft = block_size * power->freq_osr;
@ -93,7 +93,7 @@ void extract_power(const float signal[], waterfall_t *power, int block_size)
LOG(LOG_INFO, "N_FFT = %d\n", nfft);
LOG(LOG_INFO, "FFT work area = %lu\n", fft_work_size);
void *fft_work = malloc(fft_work_size);
void* fft_work = malloc(fft_work_size);
kiss_fftr_cfg fft_cfg = kiss_fftr_alloc(nfft, 0, fft_work, &fft_work_size);
int offset = 0;
@ -146,7 +146,7 @@ void extract_power(const float signal[], waterfall_t *power, int block_size)
free(fft_work);
}
int main(int argc, char **argv)
int main(int argc, char** argv)
{
// Expect one command-line argument
if (argc < 2)
@ -155,7 +155,7 @@ int main(int argc, char **argv)
return -1;
}
const char *wav_path = argv[1];
const char* wav_path = argv[1];
int sample_rate = 12000;
int num_samples = 15 * sample_rate;
@ -169,7 +169,7 @@ int main(int argc, char **argv)
// Compute DSP parameters that depend on the sample rate
const int num_bins = (int)(sample_rate / (2 * kFSK_dev)); // number bins of FSK tone width that the spectrum can be divided into
const int block_size = (int)(sample_rate / kFSK_dev); // samples corresponding to one FSK symbol
const int block_size = (int)(sample_rate / kFSK_dev); // samples corresponding to one FSK symbol
const int subblock_size = block_size / kTime_osr;
const int nfft = block_size * kFreq_osr;
const int num_blocks = (num_samples - nfft + subblock_size) / block_size;
@ -183,17 +183,18 @@ 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;
message_t decoded[kMax_decoded_messages];
message_t *decoded_hashtable[kMax_decoded_messages];
message_t* decoded_hashtable[kMax_decoded_messages];
// Initialize hash table pointers
for (int i = 0; i < kMax_decoded_messages; ++i)
@ -204,7 +205,7 @@ int main(int argc, char **argv)
// Go over candidates and attempt to decode messages
for (int idx = 0; idx < num_candidates; ++idx)
{
const candidate_t *cand = &candidate_list[idx];
const candidate_t* cand = &candidate_list[idx];
if (cand->score < kMin_score)
continue;
@ -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

@ -9,21 +9,21 @@
#define FT8_NN (79) ///< Total channel symbols (FT8_NS + FT8_ND)
// Define FT4 symbol counts
#define FT4_ND (87) ///< Data symbols
#define FT4_NS (16) ///< Sync symbols (3 @ Costas 7x7)
#define FT4_NR (2) ///< Ramp symbols (beginning + end)
#define FT4_ND (87) ///< Data symbols
#define FT4_NS (16) ///< Sync symbols (3 @ Costas 7x7)
#define FT4_NR (2) ///< Ramp symbols (beginning + end)
#define FT4_NN (105) ///< Total channel symbols (FT4_NS + FT4_ND + FT4_NR)
// Define LDPC parameters
#define FT8_LDPC_N (174) ///< Number of bits in the encoded message (payload with LDPC checksum bits)
#define FT8_LDPC_K (91) ///< Number of payload bits (including CRC)
#define FT8_LDPC_M (83) ///< Number of LDPC checksum bits (FT8_LDPC_N - FT8_LDPC_K)
#define FT8_LDPC_N (174) ///< Number of bits in the encoded message (payload with LDPC checksum bits)
#define FT8_LDPC_K (91) ///< Number of payload bits (including CRC)
#define FT8_LDPC_M (83) ///< Number of LDPC checksum bits (FT8_LDPC_N - FT8_LDPC_K)
#define FT8_LDPC_N_BYTES ((FT8_LDPC_N + 7) / 8) ///< Number of whole bytes needed to store 174 bits (full message)
#define FT8_LDPC_K_BYTES ((FT8_LDPC_K + 7) / 8) ///< Number of whole bytes needed to store 91 bits (payload + CRC only)
// Define CRC parameters
#define FT8_CRC_POLYNOMIAL ((uint16_t)0x2757u) ///< CRC-14 polynomial without the leading (MSB) 1
#define FT8_CRC_WIDTH (14)
#define FT8_CRC_WIDTH (14)
/// Costas 7x7 tone pattern for synchronization
extern const uint8_t kFT8_Costas_pattern[7];

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,21 +12,28 @@
/// @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);
static void heapify_down(candidate_t heap[], int heap_size);
static void heapify_up(candidate_t heap[], int heap_size);
static void decode_symbol(const uint8_t *power, int bit_idx, float *log174);
static void decode_multi_symbols(const uint8_t *power, int num_bins, int n_syms, int bit_idx, float *log174);
static void decode_symbol(const uint8_t* power, int bit_idx, float* log174);
static void decode_multi_symbols(const uint8_t* power, int num_bins, int n_syms, int bit_idx, float* log174);
static int get_index(const waterfall_t *power, int block, int time_sub, int freq_sub, int bin)
static int get_index(const waterfall_t* power, int block, int time_sub, int freq_sub, int bin)
{
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;
@ -58,7 +65,7 @@ int find_sync(const waterfall_t *power, int num_candidates, candidate_t heap[],
break;
int offset = get_index(power, block, time_sub, freq_sub, freq_offset);
const uint8_t *p8 = power->mag + offset;
const uint8_t* p8 = power->mag + offset;
// Weighted difference between the expected and all other symbols
// Does not work as well as the alternative score below
@ -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);
@ -168,7 +175,7 @@ void extract_likelihood(const waterfall_t *power, const candidate_t *cand, float
else
{
// Pointer to 8 bins of the current symbol
const uint8_t *ps = power->mag + offset + (sym_idx * sym_stride);
const uint8_t* ps = power->mag + offset + (sym_idx * sym_stride);
decode_symbol(ps, bit_idx, log174);
}
@ -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)
{
@ -296,7 +303,7 @@ static void heapify_up(candidate_t heap[], int heap_size)
}
// Compute unnormalized log likelihood log(p(1) / p(0)) of 3 message bits (1 FSK symbol)
static void decode_symbol(const uint8_t *power, int bit_idx, float *log174)
static void decode_symbol(const uint8_t* power, int bit_idx, float* log174)
{
// Cleaned up code for the simple case of n_syms==1
float s2[8];
@ -312,7 +319,7 @@ static void decode_symbol(const uint8_t *power, int bit_idx, float *log174)
}
// Compute unnormalized log likelihood log(p(1) / p(0)) of bits corresponding to several FSK symbols at once
static void decode_multi_symbols(const uint8_t *power, int num_bins, int n_syms, int bit_idx, float *log174)
static void decode_multi_symbols(const uint8_t* power, int num_bins, int n_syms, int bit_idx, float* log174)
{
const int n_bits = 3 * n_syms;
const int n_tones = (1 << n_bits);
@ -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.
@ -13,21 +13,21 @@
typedef struct
{
int num_blocks; ///< number of total blocks (symbols) in terms of 160 ms time periods
int num_bins; ///< number of FFT bins in terms of 6.25 Hz
int time_osr; ///< number of time subdivisions
int freq_osr; ///< number of frequency subdivisions
uint8_t *mag; ///< FFT magnitudes stored as uint8_t[blocks][time_osr][freq_osr][num_bins]
int num_bins; ///< number of FFT bins in terms of 6.25 Hz
int time_osr; ///< number of time subdivisions
int freq_osr; ///< number of frequency subdivisions
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
{
int16_t score; ///< Candidate score (non-negative number; higher score means higher likelihood)
int16_t score; ///< Candidate score (non-negative number; higher score means higher likelihood)
int16_t time_offset; ///< Index of the time block
int16_t freq_offset; ///< Index of the frequency bin
uint8_t time_sub; ///< Index of the time subdivision used
uint8_t freq_sub; ///< Index of the frequency subdivision used
uint8_t time_sub; ///< Index of the time subdivision used
uint8_t freq_sub; ///< Index of the frequency subdivision used
} candidate_t;
/// Structure that holds the decoded message
@ -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,21 +5,21 @@
#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
x ^= x >> 1; // a ab bac acbd bdcae caedbf aecgbfdh
x ^= x >> 4; // a b c d ae bf cg dh
x ^= x >> 2; // a b ac bd cae dbf aecg bfdh
x ^= x >> 1; // a ab bac acbd bdcae caedbf aecgbfdh
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
@ -31,7 +31,7 @@ void encode174(const uint8_t *message, uint8_t *codeword)
// Compute the byte index and bit mask for the first checksum bit
uint8_t col_mask = (0x80u >> (FT8_LDPC_K % 8u)); // bitmask of current byte
uint8_t col_idx = FT8_LDPC_K_BYTES - 1; // index into byte array
uint8_t col_idx = FT8_LDPC_K_BYTES - 1; // index into byte array
// Compute the LDPC checksum bits and store them in codeword
for (int i = 0; i < FT8_LDPC_M; ++i)
@ -43,7 +43,7 @@ void encode174(const uint8_t *message, uint8_t *codeword)
for (int j = 0; j < FT8_LDPC_K_BYTES; ++j)
{
uint8_t bits = message[j] & kFT8_LDPC_generator[i][j]; // bitwise AND (bitwise multiplication)
nsum ^= parity8(bits); // bitwise XOR (addition modulo 2)
nsum ^= parity8(bits); // bitwise XOR (addition modulo 2)
}
// Set the current checksum bit in codeword if nsum is odd
@ -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);
@ -77,7 +77,7 @@ void genft8(const uint8_t *payload, uint8_t *tones)
// Total symbols: 79 (FT8_NN)
uint8_t mask = 0x80u; // Mask to extract 1 bit from codeword
int i_byte = 0; // Index of the current byte of the codeword
int i_byte = 0; // Index of the current byte of the codeword
for (int i_tone = 0; i_tone < FT8_NN; ++i_tone)
{
if ((i_tone >= 0) && (i_tone < 7))
@ -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
@ -139,7 +139,7 @@ void genft4(const uint8_t *payload, uint8_t *tones)
// Total symbols: 105 (FT4_NN)
uint8_t mask = 0x80u; // Mask to extract 1 bit from codeword
int i_byte = 0; // Index of the current byte of the codeword
int i_byte = 0; // Index of the current byte of the codeword
for (int i_tone = 0; i_tone < FT4_NN; ++i_tone)
{
if ((i_tone == 0) || (i_tone == 104))

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,38 +21,11 @@ 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.
// ok == 87 means success.
void ldpc_decode(float codeword[], int max_iters, uint8_t plain[], int *ok)
void ldpc_decode(float codeword[], int max_iters, uint8_t plain[], int* ok)
{
float m[FT8_LDPC_M][FT8_LDPC_N]; // ~60 kB
float e[FT8_LDPC_M][FT8_LDPC_N]; // ~60 kB
@ -154,7 +127,7 @@ static int ldpc_check(uint8_t codeword[])
return errors;
}
void bp_decode(float codeword[], int max_iters, uint8_t plain[], int *ok)
void bp_decode(float codeword[], int max_iters, uint8_t plain[], int* ok)
{
float tov[FT8_LDPC_N][3];
float toc[FT8_LDPC_M][7];

Wyświetl plik

@ -7,12 +7,8 @@
// plain is a return value, 174 ints, to be 0 or 1.
// iters is how hard to try.
// ok == 87 means success.
void ldpc_decode(float codeword[], int max_iters, uint8_t plain[], int *ok);
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[]);
void bp_decode(float codeword[], int max_iters, uint8_t plain[], int* ok);
#endif // _INCLUDE_LDPC_H_

Wyświetl plik

@ -6,8 +6,8 @@
#include <string.h>
#include <stdio.h>
#define NTOKENS ((uint32_t)2063592L)
#define MAX22 ((uint32_t)4194304L)
#define NTOKENS ((uint32_t)2063592L)
#define MAX22 ((uint32_t)4194304L)
#define MAXGRID4 ((uint16_t)32400)
// TODO: This is wasteful, should figure out something more elegant
@ -19,7 +19,7 @@ const char A4[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// Pack a special token, a 22-bit hash code, or a valid base call
// into a 28-bit integer.
int32_t pack28(const char *callsign)
int32_t pack28(const char* callsign)
{
// Check for special tokens first
if (starts_with(callsign, "DE "))
@ -38,7 +38,7 @@ int32_t pack28(const char *callsign)
// TODO: Check for <...> callsign
char c6[6] = {' ', ' ', ' ', ' ', ' ', ' '};
char c6[6] = { ' ', ' ', ' ', ' ', ' ', ' ' };
int length = 0; // strlen(callsign); // We will need it later
while (callsign[length] != ' ' && callsign[length] != 0)
@ -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;
@ -100,7 +98,7 @@ int32_t pack28(const char *callsign)
// Check if a string could be a valid standard callsign or a valid
// compound callsign.
// Return base call "bc" and a logical "cok" indicator.
bool chkcall(const char *call, char *bc)
bool chkcall(const char* call, char* bc)
{
int length = strlen(call); // n1=len_trim(w)
if (length > 11)
@ -121,7 +119,7 @@ bool chkcall(const char *call, char *bc)
return true;
}
uint16_t packgrid(const char *grid4)
uint16_t packgrid(const char* grid4)
{
if (grid4 == 0)
{
@ -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');
@ -168,15 +164,15 @@ uint16_t packgrid(const char *grid4)
}
// Pack Type 1 (Standard 77-bit message) and Type 2 (ditto, with a "/P" call)
int pack77_1(const char *msg, uint8_t *b77)
int pack77_1(const char* msg, uint8_t* b77)
{
// Locate the first delimiter
const char *s1 = strchr(msg, ' ');
const char* s1 = strchr(msg, ' ');
if (s1 == 0)
return -1;
const char *call1 = msg; // 1st call
const char *call2 = s1 + 1; // 2nd call
const char* call1 = msg; // 1st call
const char* call2 = s1 + 1; // 2nd call
int32_t n28a = pack28(call1);
int32_t n28b = pack28(call2);
@ -187,7 +183,7 @@ int pack77_1(const char *msg, uint8_t *b77)
uint16_t igrid4;
// Locate the second delimiter
const char *s2 = strchr(s1 + 1, ' ');
const char* s2 = strchr(s1 + 1, ' ');
if (s2 != 0)
{
igrid4 = packgrid(s2 + 1);
@ -221,7 +217,7 @@ int pack77_1(const char *msg, uint8_t *b77)
return 0;
}
void packtext77(const char *text, uint8_t *b77)
void packtext77(const char* text, uint8_t* b77)
{
int length = strlen(text);
@ -285,7 +281,7 @@ void packtext77(const char *text, uint8_t *b77)
b77[9] &= 0x00;
}
int pack77(const char *msg, uint8_t *c77)
int pack77(const char* msg, uint8_t* c77)
{
// Check Type 1 (Standard 77-bit message) or Type 2, with optional "/P"
if (0 == pack77_1(msg, c77))
@ -310,7 +306,7 @@ int pack77(const char *msg, uint8_t *c77)
bool test1()
{
const char *inputs[] = {
const char* inputs[] = {
"",
" ",
"ABC",
@ -321,7 +317,8 @@ bool test1()
"LL3JG",
"LL3AJG",
"CQ ",
0};
0
};
for (int i = 0; inputs[i]; ++i)
{
@ -334,14 +331,15 @@ bool test1()
bool test2()
{
const char *inputs[] = {
const char* inputs[] = {
"CQ LL3JG",
"CQ LL3JG KO26",
"L0UAA LL3JG KO26",
"L0UAA LL3JG +02",
"L0UAA LL3JG RRR",
"L0UAA LL3JG 73",
0};
0
};
for (int i = 0; inputs[i]; ++i)
{

Wyświetl plik

@ -6,6 +6,6 @@
// Pack FT8 text message into 72 bits
// [IN] msg - FT8 message (e.g. "CQ TE5T KN01")
// [OUT] c77 - 10 byte array to store the 77 bit payload (MSB first)
int pack77(const char *msg, uint8_t *c77);
int pack77(const char* msg, uint8_t* c77);
#endif // _INCLUDE_PACK_H_

Wyświetl plik

@ -2,7 +2,7 @@
#include <string.h>
const char *trim_front(const char *str)
const char* trim_front(const char* str)
{
// Skip leading whitespace
while (*str == ' ')
@ -12,7 +12,7 @@ const char *trim_front(const char *str)
return str;
}
void trim_back(char *str)
void trim_back(char* str)
{
// Skip trailing whitespace by replacing it with '\0' characters
int idx = strlen(str) - 1;
@ -24,9 +24,9 @@ void trim_back(char *str)
// 1) trims a string from the back by changing whitespaces to '\0'
// 2) trims a string from the front by skipping whitespaces
char *trim(char *str)
char* trim(char* str)
{
str = (char *)trim_front(str);
str = (char*)trim_front(str);
trim_back(str);
// return a pointer to the first non-whitespace character
return str;
@ -57,17 +57,17 @@ bool in_range(char c, char min, char max)
return (c >= min) && (c <= max);
}
bool starts_with(const char *string, const char *prefix)
bool starts_with(const char* string, const char* prefix)
{
return 0 == memcmp(string, prefix, strlen(prefix));
}
bool equals(const char *string1, const char *string2)
bool equals(const char* string1, const char* string2)
{
return 0 == strcmp(string1, string2);
}
int char_index(const char *string, char c)
int char_index(const char* string, char c)
{
for (int i = 0; *string; ++i, ++string)
{
@ -82,7 +82,7 @@ int char_index(const char *string, char c)
// Text message formatting:
// - replaces lowercase letters with uppercase
// - merges consecutive spaces into single space
void fmtmsg(char *msg_out, const char *msg_in)
void fmtmsg(char* msg_out, const char* msg_in)
{
char c;
char last_out = 0;
@ -100,7 +100,7 @@ void fmtmsg(char *msg_out, const char *msg_in)
}
// Parse a 2 digit integer from string
int dd_to_int(const char *str, int length)
int dd_to_int(const char* str, int length)
{
int result = 0;
bool negative;
@ -131,7 +131,7 @@ int dd_to_int(const char *str, int length)
}
// Convert a 2 digit integer to string
void int_to_dd(char *str, int value, int width, bool full_sign)
void int_to_dd(char* str, int value, int width, bool full_sign)
{
if (value < 0)
{

Wyświetl plik

@ -6,30 +6,30 @@
// Utility functions for characters and strings
const char *trim_front(const char *str);
void trim_back(char *str);
char *trim(char *str);
const char* trim_front(const char* str);
void trim_back(char* str);
char* trim(char* str);
char to_upper(char c);
bool is_digit(char c);
bool is_letter(char c);
bool is_space(char c);
bool in_range(char c, char min, char max);
bool starts_with(const char *string, const char *prefix);
bool equals(const char *string1, const char *string2);
bool starts_with(const char* string, const char* prefix);
bool equals(const char* string1, const char* string2);
int char_index(const char *string, char c);
int char_index(const char* string, char c);
// Text message formatting:
// - replaces lowercase letters with uppercase
// - merges consecutive spaces into single space
void fmtmsg(char *msg_out, const char *msg_in);
void fmtmsg(char* msg_out, const char* msg_in);
// Parse a 2 digit integer from string
int dd_to_int(const char *str, int length);
int dd_to_int(const char* str, int length);
// Convert a 2 digit integer to string
void int_to_dd(char *str, int value, int width, bool full_sign);
void int_to_dd(char* str, int value, int width, bool full_sign);
char charn(int c, int table_idx);
int nchar(char c, int table_idx);

Wyświetl plik

@ -1,18 +1,18 @@
#ifdef __linux__
#define _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "unpack.h"
#include "text.h"
#include <string.h>
#define MAX22 ((uint32_t)4194304L)
#define NTOKENS ((uint32_t)2063592L)
#define MAX22 ((uint32_t)4194304L)
#define NTOKENS ((uint32_t)2063592L)
#define MAXGRID4 ((uint16_t)32400L)
// n28 is a 28-bit integer, e.g. n28a or n28b, containing all the
// call sign bits from a packed message.
int unpack_callsign(uint32_t n28, uint8_t ip, uint8_t i3, char *result)
int unpack_callsign(uint32_t n28, uint8_t ip, uint8_t i3, char* result)
{
// Check for special tokens DE, QRZ, CQ, CQ_nnn, CQ_aaaa
if (n28 < NTOKENS)
@ -108,7 +108,7 @@ int unpack_callsign(uint32_t n28, uint8_t ip, uint8_t i3, char *result)
return 0; // Success
}
int unpack_type1(const uint8_t *a77, uint8_t i3, char *call_to, char *call_de, char *extra)
int unpack_type1(const uint8_t* a77, uint8_t i3, char* call_to, char* call_de, char* extra)
{
uint32_t n28a, n28b;
uint16_t igrid4;
@ -148,7 +148,7 @@ int unpack_type1(const uint8_t *a77, uint8_t i3, char *call_to, char *call_de, c
// save_hash_call(call_de)
// }
char *dst = extra;
char* dst = extra;
if (igrid4 <= MAXGRID4)
{
@ -205,7 +205,7 @@ int unpack_type1(const uint8_t *a77, uint8_t i3, char *call_to, char *call_de, c
return 0; // Success
}
int unpack_text(const uint8_t *a71, char *text)
int unpack_text(const uint8_t* a71, char* text)
{
// TODO: test
uint8_t b71[9];
@ -237,7 +237,7 @@ int unpack_text(const uint8_t *a71, char *text)
return 0; // Success
}
int unpack_telemetry(const uint8_t *a71, char *telemetry)
int unpack_telemetry(const uint8_t* a71, char* telemetry)
{
uint8_t b71[9];
@ -266,21 +266,21 @@ int unpack_telemetry(const uint8_t *a71, char *telemetry)
//none standard for wsjt-x 2.0
//by KD8CEC
int unpack_nonstandard(const uint8_t *a77, char *call_to, char *call_de, char *extra)
int unpack_nonstandard(const uint8_t* a77, char* call_to, char* call_de, char* extra)
{
uint32_t n12, iflip, nrpt, icq;
uint64_t n58;
n12 = (a77[0] << 4); //11 ~4 : 8
n12 = (a77[0] << 4); //11 ~4 : 8
n12 |= (a77[1] >> 4); //3~0 : 12
n58 = ((uint64_t)(a77[1] & 0x0F) << 54); //57 ~ 54 : 4
n58 |= ((uint64_t)a77[2] << 46); //53 ~ 46 : 12
n58 |= ((uint64_t)a77[3] << 38); //45 ~ 38 : 12
n58 |= ((uint64_t)a77[4] << 30); //37 ~ 30 : 12
n58 |= ((uint64_t)a77[5] << 22); //29 ~ 22 : 12
n58 |= ((uint64_t)a77[6] << 14); //21 ~ 14 : 12
n58 |= ((uint64_t)a77[7] << 6); //13 ~ 6 : 12
n58 |= ((uint64_t)a77[8] >> 2); //5 ~ 0 : 765432 10
n58 |= ((uint64_t)a77[2] << 46); //53 ~ 46 : 12
n58 |= ((uint64_t)a77[3] << 38); //45 ~ 38 : 12
n58 |= ((uint64_t)a77[4] << 30); //37 ~ 30 : 12
n58 |= ((uint64_t)a77[5] << 22); //29 ~ 22 : 12
n58 |= ((uint64_t)a77[6] << 14); //21 ~ 14 : 12
n58 |= ((uint64_t)a77[7] << 6); //13 ~ 6 : 12
n58 |= ((uint64_t)a77[8] >> 2); //5 ~ 0 : 765432 10
iflip = (a77[8] >> 1) & 0x01; //76543210
nrpt = ((a77[8] & 0x01) << 1);
@ -306,8 +306,8 @@ int unpack_nonstandard(const uint8_t *a77, char *call_to, char *call_de, char *e
// call_3[5] = '>';
// call_3[6] = '\0';
char *call_1 = (iflip) ? c11 : call_3;
char *call_2 = (iflip) ? call_3 : c11;
char* call_1 = (iflip) ? c11 : call_3;
char* call_2 = (iflip) ? call_3 : c11;
//save_hash_call(c11_trimmed);
if (icq == 0)
@ -334,7 +334,7 @@ int unpack_nonstandard(const uint8_t *a77, char *call_to, char *call_de, char *e
return 0;
}
int unpack77_fields(const uint8_t *a77, char *call_to, char *call_de, char *extra)
int unpack77_fields(const uint8_t* a77, char* call_to, char* call_de, char* extra)
{
call_to[0] = call_de[0] = extra[0] = '\0';
@ -390,7 +390,7 @@ int unpack77_fields(const uint8_t *a77, char *call_to, char *call_de, char *extr
return -1;
}
int unpack77(const uint8_t *a77, char *message)
int unpack77(const uint8_t* a77, char* message)
{
char call_to[14];
char call_de[14];
@ -401,7 +401,7 @@ int unpack77(const uint8_t *a77, char *message)
return rc;
// int msg_sz = strlen(call_to) + strlen(call_de) + strlen(extra) + 2;
char *dst = message;
char* dst = message;
dst[0] = '\0';

Wyświetl plik

@ -6,9 +6,9 @@
// field1 - at least 14 bytes
// field2 - at least 14 bytes
// field3 - at least 7 bytes
int unpack77_fields(const uint8_t *a77, char *field1, char *field2, char *field3);
int unpack77_fields(const uint8_t* a77, char* field1, char* field2, char* field3);
// message should have at least 35 bytes allocated (34 characters + zero terminator)
int unpack77(const uint8_t *a77, char *message);
int unpack77(const uint8_t* a77, char* message);
#endif // _INCLUDE_UNPACK_H_

Wyświetl plik

@ -13,13 +13,13 @@
#define LOG_LEVEL LOG_INFO
#define FT8_SLOT_TIME 15.0f // total length of output waveform in seconds
#define FT8_SLOT_TIME 15.0f // total length of output waveform in seconds
#define FT8_SYMBOL_RATE 6.25f // tone deviation (and symbol rate) in Hz
#define FT8_SYMBOL_BT 2.0f // symbol smoothing filter bandwidth factor (BT)
#define FT8_SYMBOL_BT 2.0f // symbol smoothing filter bandwidth factor (BT)
#define FT4_SLOT_TIME 7.5f // total length of output waveform in seconds
#define FT4_SLOT_TIME 7.5f // total length of output waveform in seconds
#define FT4_SYMBOL_RATE 20.833333f // tone deviation (and symbol rate) in Hz
#define FT4_SYMBOL_BT 1.0f // symbol smoothing filter bandwidth factor (BT)
#define FT4_SYMBOL_BT 1.0f // symbol smoothing filter bandwidth factor (BT)
#define GFSK_CONST_K 5.336446f // pi * sqrt(2 / log(2))
@ -30,7 +30,7 @@
/// @param[in] b Shape parameter (values defined for FT8/FT4)
/// @param[out] pulse Output array of pulse samples
///
void gfsk_pulse(int n_spsym, float symbol_bt, float *pulse)
void gfsk_pulse(int n_spsym, float symbol_bt, float* pulse)
{
for (int i = 0; i < 3 * n_spsym; ++i)
{
@ -51,10 +51,10 @@ void gfsk_pulse(int n_spsym, float symbol_bt, float *pulse)
/// @param[in] signal_rate Sample rate of synthesized signal, Hertz
/// @param[out] signal Output array of signal waveform samples (should have space for n_sym*n_spsym samples)
///
void synth_gfsk(const uint8_t *symbols, int n_sym, float f0, float symbol_bt, float symbol_rate, int signal_rate, float *signal)
void synth_gfsk(const uint8_t* symbols, int n_sym, float f0, float symbol_bt, float symbol_rate, int signal_rate, float* signal)
{
int n_spsym = (int)(0.5f + signal_rate / symbol_rate); // Samples per symbol
int n_wave = n_sym * n_spsym; // Number of output samples
int n_wave = n_sym * n_spsym; // Number of output samples
float hmod = 1.0f;
LOG(LOG_DEBUG, "n_spsym = %d\n", n_spsym);
@ -116,7 +116,7 @@ void usage()
printf("(Note that you might have to enclose your message in quote marks if it contains spaces)\n");
}
int main(int argc, char **argv)
int main(int argc, char** argv)
{
// Expect two command-line arguments
if (argc < 3)
@ -125,8 +125,8 @@ int main(int argc, char **argv)
return -1;
}
const char *message = argv[1];
const char *wav_path = argv[2];
const char* message = argv[1];
const char* wav_path = argv[2];
float frequency = 1000.0;
if (argc > 3)
{
@ -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: ");
@ -187,8 +187,8 @@ int main(int argc, char **argv)
// Third, convert the FSK tones into an audio signal
int sample_rate = 12000;
int num_samples = (int)(0.5f + num_tones / symbol_rate * sample_rate); // Number of samples in the data signal
int num_silence = (slot_time * sample_rate - num_samples) / 2; // Silence padding at both ends to make 15 seconds
int num_total_samples = num_silence + num_samples + num_silence; // Number of samples in the padded signal
int num_silence = (slot_time * sample_rate - num_samples) / 2; // Silence padding at both ends to make 15 seconds
int num_total_samples = num_silence + num_samples + num_silence; // Number of samples in the padded signal
float signal[num_total_samples];
for (int i = 0; i < num_silence; i++)
{

10
test.c
Wyświetl plik

@ -15,7 +15,7 @@
#define LOG_LEVEL LOG_INFO
void convert_8bit_to_6bit(uint8_t *dst, const uint8_t *src, int nBits)
void convert_8bit_to_6bit(uint8_t* dst, const uint8_t* src, int nBits)
{
// Zero-fill the destination array as we will only be setting bits later
for (int j = 0; j < (nBits + 5) / 6; ++j)
@ -96,17 +96,17 @@ 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
}
*/
void test_tones(float *log174)
void test_tones(float* log174)
{
// Just a test case
for (int i = 0; i < FT8_ND; ++i)
{
const uint8_t inv_map[8] = {0, 1, 3, 2, 6, 4, 5, 7};
const uint8_t inv_map[8] = { 0, 1, 3, 2, 6, 4, 5, 7 };
uint8_t tone = ("0000000011721762454112705354533170166234757420515470163426"[i]) - '0';
uint8_t b3 = inv_map[tone];
log174[3 * i] = (b3 & 4) ? +1.0 : -1.0;
@ -126,7 +126,7 @@ void test4()
printf("N_FFT = %d\n", nfft);
printf("FFT work area = %lu\n", fft_work_size);
void *fft_work = malloc(fft_work_size);
void* fft_work = malloc(fft_work_size);
kiss_fftr_cfg fft_cfg = kiss_fftr_alloc(nfft, 0, fft_work, &fft_work_size);
kiss_fft_scalar window[nfft];