Naming consistency + time slot display in decode_ft8

pull/37/head
Karlis Goba 2022-06-28 09:07:52 +03:00
rodzic 7dc84b972a
commit a28593682e
4 zmienionych plików z 37 dodań i 37 usunięć

Wyświetl plik

@ -32,7 +32,7 @@ void usage(const char* error_msg)
{ {
fprintf(stderr, "ERROR: %s\n", error_msg); fprintf(stderr, "ERROR: %s\n", error_msg);
} }
fprintf(stderr, "Usage: decode_ft8 [-list|-ft4] INPUT\n\n"); fprintf(stderr, "Usage: decode_ft8 [-list|([-ft4] [INPUT|-dev DEVICE])]\n\n");
fprintf(stderr, "Decode a 15-second (or slighly shorter) WAV file.\n"); fprintf(stderr, "Decode a 15-second (or slighly shorter) WAV file.\n");
} }
@ -40,8 +40,8 @@ void usage(const char* error_msg)
static struct static struct
{ {
char callsign[12]; char callsign[12]; ///> Up to 11 symbols of callsign + trailing zeros (always filled)
uint32_t hash; uint32_t hash; ///> 8 MSBs contain the age of callsign; 22 LSBs contain hash value
} callsign_hashtable[CALLSIGN_HASHTABLE_SIZE]; } callsign_hashtable[CALLSIGN_HASHTABLE_SIZE];
static int callsign_hashtable_size; static int callsign_hashtable_size;
@ -105,7 +105,7 @@ void hashtable_add(const char* callsign, uint32_t hash)
bool hashtable_lookup(ftx_callsign_hash_type_t hash_type, uint32_t hash, char* callsign) bool hashtable_lookup(ftx_callsign_hash_type_t hash_type, uint32_t hash, char* callsign)
{ {
uint8_t hash_shift = (hash_type == FTX_CALLSIGN_HASH_10_BITS) ? 12 : (hash_type == FTX_CALLSIGN_HASH_12_BITS ? 10 : 0); uint8_t hash_shift = (hash_type == FTX_CALLSIGN_HASH_10_BITS) ? 12 : (hash_type == FTX_CALLSIGN_HASH_12_BITS ? 10 : 0);
uint16_t hash10 = (hash >> (12 - hash_shift)) & 0x3FF; uint16_t hash10 = (hash >> (12 - hash_shift)) & 0x3FFu;
int idx_hash = (hash10 * 23) % CALLSIGN_HASHTABLE_SIZE; int idx_hash = (hash10 * 23) % CALLSIGN_HASHTABLE_SIZE;
while (callsign_hashtable[idx_hash].callsign[0] != '\0') while (callsign_hashtable[idx_hash].callsign[0] != '\0')
{ {
@ -126,12 +126,12 @@ ftx_callsign_hash_interface_t hash_if = {
.save_hash = hashtable_add .save_hash = hashtable_add
}; };
void decode(const monitor_t* mon) void decode(const monitor_t* mon, struct tm* tm_slot_start)
{ {
const ftx_waterfall_t* wf = &mon->wf; const ftx_waterfall_t* wf = &mon->wf;
// Find top candidates by Costas sync score and localize them in time and frequency // Find top candidates by Costas sync score and localize them in time and frequency
ftx_candidate_t candidate_list[kMax_candidates]; ftx_candidate_t candidate_list[kMax_candidates];
int num_candidates = ft8_find_sync(wf, kMax_candidates, candidate_list, kMin_score); int num_candidates = ftx_find_candidates(wf, kMax_candidates, candidate_list, kMin_score);
// Hash table for decoded messages (to check for duplicates) // Hash table for decoded messages (to check for duplicates)
int num_decoded = 0; int num_decoded = 0;
@ -154,10 +154,8 @@ void decode(const monitor_t* mon)
ftx_message_t message; ftx_message_t message;
ftx_decode_status_t status; ftx_decode_status_t status;
if (!ft8_decode(wf, cand, kLDPC_iterations, &message, &status)) if (!ftx_decode_candidate(wf, cand, kLDPC_iterations, &message, &status))
{ {
// float snr = cand->score * 0.5f; // TODO: compute better approximation of SNR
// printf("000000 %2.1f %+4.2f %4.0f ~ %s\n", snr, time_sec, freq_hz, "---");
if (status.ldpc_errors > 0) if (status.ldpc_errors > 0)
{ {
LOG(LOG_DEBUG, "LDPC decode: %d errors\n", status.ldpc_errors); LOG(LOG_DEBUG, "LDPC decode: %d errors\n", status.ldpc_errors);
@ -201,25 +199,17 @@ void decode(const monitor_t* mon)
++num_decoded; ++num_decoded;
char text[FTX_MAX_MESSAGE_LENGTH]; char text[FTX_MAX_MESSAGE_LENGTH];
// int unpack_status = unpack77(message.payload, text, NULL); ftx_message_rc_t unpack_status = ftx_message_decode(&message, &hash_if, text);
int unpack_status = ftx_message_decode(&message, &hash_if, text); if (unpack_status != FTX_MESSAGE_RC_OK)
if (unpack_status != 0)
{ {
strcpy(text, "Error while unpacking!"); snprintf(text, sizeof(text), "Error [%d] while unpacking!", (int)unpack_status);
} }
// uint8_t i3 = ftx_message_get_i3(&message);
// if (i3 == 0)
// {
// uint8_t n3 = ftx_message_get_n3(&message);
// printf("000000 %02d %+4.2f %4.0f [%d.%d] ~ %s\n", cand->score, time_sec, freq_hz, i3, n3, text);
// }
// else
// printf("000000 %02d %+4.2f %4.0f [%d ] ~ %s\n", cand->score, time_sec, freq_hz, i3, text);
// Fake WSJT-X-like output for now // Fake WSJT-X-like output for now
float snr = cand->score * 0.5f; // TODO: compute better approximation of SNR float snr = cand->score * 0.5f; // TODO: compute better approximation of SNR
printf("000000 %+05.1f %+4.2f %4.0f ~ %s\n", snr, time_sec, freq_hz, text); printf("%02d%02d%02d %+05.1f %+4.2f %4.0f ~ %s\n",
tm_slot_start->tm_hour, tm_slot_start->tm_min, tm_slot_start->tm_sec,
snr, time_sec, freq_hz, text);
} }
} }
LOG(LOG_INFO, "Decoded %d messages, callsign hashtable size %d\n", num_decoded, callsign_hashtable_size); LOG(LOG_INFO, "Decoded %d messages, callsign hashtable size %d\n", num_decoded, callsign_hashtable_size);
@ -292,9 +282,9 @@ int main(int argc, char** argv)
return -1; return -1;
} }
float slot_time = ((protocol == FTX_PROTOCOL_FT8) ? FT8_SLOT_TIME : FT4_SLOT_TIME); float slot_period = ((protocol == FTX_PROTOCOL_FT8) ? FT8_SLOT_TIME : FT4_SLOT_TIME);
int sample_rate = 12000; int sample_rate = 12000;
int num_samples = slot_time * sample_rate; int num_samples = slot_period * sample_rate;
float signal[num_samples]; float signal[num_samples];
bool isContinuous = false; bool isContinuous = false;
@ -312,7 +302,7 @@ int main(int argc, char** argv)
{ {
audio_init(); audio_init();
audio_open(dev_name); audio_open(dev_name);
num_samples = (slot_time - 0.4f) * sample_rate; num_samples = (slot_period - 0.4f) * sample_rate;
isContinuous = true; isContinuous = true;
} }
@ -334,6 +324,7 @@ int main(int argc, char** argv)
do do
{ {
struct tm tm_slot_start = { 0 };
if (dev_name != NULL) if (dev_name != NULL)
{ {
// Wait for the start of time slot // Wait for the start of time slot
@ -341,12 +332,18 @@ int main(int argc, char** argv)
{ {
struct timespec spec; struct timespec spec;
clock_gettime(CLOCK_REALTIME, &spec); clock_gettime(CLOCK_REALTIME, &spec);
float time_within_slot = fmod((double)spec.tv_sec + (spec.tv_nsec * 1e-9) - time_shift, slot_time); double time = (double)spec.tv_sec + (spec.tv_nsec / 1e9);
if (time_within_slot > slot_time / 3) double time_within_slot = fmod(time - time_shift, slot_period);
if (time_within_slot > slot_period / 4)
{
audio_read(signal, mon.block_size); audio_read(signal, mon.block_size);
}
else else
{ {
LOG(LOG_INFO, "Time within slot: %.3f s\n", time_within_slot); time_t time_slot_start = (time_t)(time - time_within_slot);
gmtime_r(&time_slot_start, &tm_slot_start);
LOG(LOG_INFO, "Time within slot %02d%02d%02d: %.3f s\n", tm_slot_start.tm_hour,
tm_slot_start.tm_min, tm_slot_start.tm_sec, time_within_slot);
break; break;
} }
} }
@ -369,7 +366,7 @@ int main(int argc, char** argv)
LOG(LOG_INFO, "Max magnitude: %.1f dB\n", mon.max_mag); LOG(LOG_INFO, "Max magnitude: %.1f dB\n", mon.max_mag);
// Decode accumulated data (containing slightly less than a full time slot) // Decode accumulated data (containing slightly less than a full time slot)
decode(&mon); decode(&mon, &tm_slot_start);
// Reset internal variables for the next time slot // Reset internal variables for the next time slot
monitor_reset(&mon); monitor_reset(&mon);

Wyświetl plik

@ -229,7 +229,7 @@ static int ft4_sync_score(const ftx_waterfall_t* wf, const ftx_candidate_t* cand
return score; return score;
} }
int ft8_find_sync(const ftx_waterfall_t* wf, int num_candidates, ftx_candidate_t heap[], int min_score) int ftx_find_candidates(const ftx_waterfall_t* wf, int num_candidates, ftx_candidate_t heap[], int min_score)
{ {
int heap_size = 0; int heap_size = 0;
ftx_candidate_t candidate; ftx_candidate_t candidate;
@ -377,7 +377,7 @@ static void ftx_normalize_logl(float* log174)
} }
} }
bool ft8_decode(const ftx_waterfall_t* wf, const ftx_candidate_t* cand, int max_iterations, ftx_message_t* message, ftx_decode_status_t* status) bool ftx_decode_candidate(const ftx_waterfall_t* wf, const ftx_candidate_t* cand, int max_iterations, ftx_message_t* message, ftx_decode_status_t* status)
{ {
float log174[FTX_LDPC_N]; // message bits encoded as likelihood float log174[FTX_LDPC_N]; // message bits encoded as likelihood
if (wf->protocol == FTX_PROTOCOL_FT4) if (wf->protocol == FTX_PROTOCOL_FT4)

Wyświetl plik

@ -59,7 +59,7 @@ typedef struct
/// @param[in,out] heap Array of ftx_candidate_t type entries (with num_candidates allocated entries) /// @param[in,out] heap Array of ftx_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) /// @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 /// @return Number of candidates filled in the heap
int ft8_find_sync(const ftx_waterfall_t* power, int num_candidates, ftx_candidate_t heap[], int min_score); int ftx_find_candidates(const ftx_waterfall_t* power, int num_candidates, ftx_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. /// 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 /// @param[in] power Waterfall data collected during message slot
@ -68,7 +68,7 @@ int ft8_find_sync(const ftx_waterfall_t* power, int num_candidates, ftx_candidat
/// @param[out] message ftx_message_t structure that will receive the decoded message /// @param[out] message ftx_message_t structure that will receive the decoded message
/// @param[out] status ftx_decode_status_t structure that will be filled with the status of various decoding steps /// @param[out] status ftx_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) /// @return True if the decoding was successful, false otherwise (check status for details)
bool ft8_decode(const ftx_waterfall_t* power, const ftx_candidate_t* cand, int max_iterations, ftx_message_t* message, ftx_decode_status_t* status); bool ftx_decode_candidate(const ftx_waterfall_t* power, const ftx_candidate_t* cand, int max_iterations, ftx_message_t* message, ftx_decode_status_t* status);
#ifdef __cplusplus #ifdef __cplusplus
} }

Wyświetl plik

@ -78,9 +78,12 @@ typedef enum
FTX_MESSAGE_RC_ERROR_TYPE FTX_MESSAGE_RC_ERROR_TYPE
} ftx_message_rc_t; } ftx_message_rc_t;
// Basecall - 1-2 letter/digit prefix (at least one letter), 1 digit area code, 1-3 letter suffix, total 3-6 chars (except for 7 char 3DA0- and 3X- calls) // Callsign types and sizes:
// Ext. basecall - basecall followed by /R or /P // * Std. call (basecall) - 1-2 letter/digit prefix (at least one letter), 1 digit area code, 1-3 letter suffix,
// Nonstd. call - all the rest, limited to 3-11 characters either alphanumeric or stroke (/) // total 3-6 chars (exception: 7 character calls with prefixes 3DA0- and 3XA..3XZ-)
// * Ext. std. call - basecall followed by /R or /P
// * Nonstd. call - all the rest, limited to 3-11 characters either alphanumeric or stroke (/)
// In case a call is looked up from its hash value, the call is enclosed in angular brackets (<CA0LL>).
void ftx_message_init(ftx_message_t* msg); void ftx_message_init(ftx_message_t* msg);