kopia lustrzana https://github.com/kgoba/ft8_lib
Naming consistency + time slot display in decode_ft8
rodzic
7dc84b972a
commit
a28593682e
|
@ -32,7 +32,7 @@ void usage(const char* 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");
|
||||
}
|
||||
|
||||
|
@ -40,8 +40,8 @@ void usage(const char* error_msg)
|
|||
|
||||
static struct
|
||||
{
|
||||
char callsign[12];
|
||||
uint32_t hash;
|
||||
char callsign[12]; ///> Up to 11 symbols of callsign + trailing zeros (always filled)
|
||||
uint32_t hash; ///> 8 MSBs contain the age of callsign; 22 LSBs contain hash value
|
||||
} callsign_hashtable[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)
|
||||
{
|
||||
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;
|
||||
while (callsign_hashtable[idx_hash].callsign[0] != '\0')
|
||||
{
|
||||
|
@ -126,12 +126,12 @@ ftx_callsign_hash_interface_t hash_if = {
|
|||
.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;
|
||||
// Find top candidates by Costas sync score and localize them in time and frequency
|
||||
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)
|
||||
int num_decoded = 0;
|
||||
|
@ -154,10 +154,8 @@ void decode(const monitor_t* mon)
|
|||
|
||||
ftx_message_t message;
|
||||
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)
|
||||
{
|
||||
LOG(LOG_DEBUG, "LDPC decode: %d errors\n", status.ldpc_errors);
|
||||
|
@ -201,25 +199,17 @@ void decode(const monitor_t* mon)
|
|||
++num_decoded;
|
||||
|
||||
char text[FTX_MAX_MESSAGE_LENGTH];
|
||||
// int unpack_status = unpack77(message.payload, text, NULL);
|
||||
int unpack_status = ftx_message_decode(&message, &hash_if, text);
|
||||
if (unpack_status != 0)
|
||||
ftx_message_rc_t unpack_status = ftx_message_decode(&message, &hash_if, text);
|
||||
if (unpack_status != FTX_MESSAGE_RC_OK)
|
||||
{
|
||||
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
|
||||
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);
|
||||
|
@ -292,9 +282,9 @@ int main(int argc, char** argv)
|
|||
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 num_samples = slot_time * sample_rate;
|
||||
int num_samples = slot_period * sample_rate;
|
||||
float signal[num_samples];
|
||||
bool isContinuous = false;
|
||||
|
||||
|
@ -312,7 +302,7 @@ int main(int argc, char** argv)
|
|||
{
|
||||
audio_init();
|
||||
audio_open(dev_name);
|
||||
num_samples = (slot_time - 0.4f) * sample_rate;
|
||||
num_samples = (slot_period - 0.4f) * sample_rate;
|
||||
isContinuous = true;
|
||||
}
|
||||
|
||||
|
@ -334,6 +324,7 @@ int main(int argc, char** argv)
|
|||
|
||||
do
|
||||
{
|
||||
struct tm tm_slot_start = { 0 };
|
||||
if (dev_name != NULL)
|
||||
{
|
||||
// Wait for the start of time slot
|
||||
|
@ -341,12 +332,18 @@ int main(int argc, char** argv)
|
|||
{
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_REALTIME, &spec);
|
||||
float time_within_slot = fmod((double)spec.tv_sec + (spec.tv_nsec * 1e-9) - time_shift, slot_time);
|
||||
if (time_within_slot > slot_time / 3)
|
||||
double time = (double)spec.tv_sec + (spec.tv_nsec / 1e9);
|
||||
double time_within_slot = fmod(time - time_shift, slot_period);
|
||||
if (time_within_slot > slot_period / 4)
|
||||
{
|
||||
audio_read(signal, mon.block_size);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -369,7 +366,7 @@ int main(int argc, char** argv)
|
|||
LOG(LOG_INFO, "Max magnitude: %.1f dB\n", mon.max_mag);
|
||||
|
||||
// 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
|
||||
monitor_reset(&mon);
|
||||
|
|
|
@ -229,7 +229,7 @@ static int ft4_sync_score(const ftx_waterfall_t* wf, const ftx_candidate_t* cand
|
|||
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;
|
||||
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
|
||||
if (wf->protocol == FTX_PROTOCOL_FT4)
|
||||
|
|
|
@ -59,7 +59,7 @@ typedef struct
|
|||
/// @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)
|
||||
/// @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.
|
||||
/// @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] 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)
|
||||
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
|
||||
}
|
||||
|
|
|
@ -78,9 +78,12 @@ typedef enum
|
|||
FTX_MESSAGE_RC_ERROR_TYPE
|
||||
} 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)
|
||||
// Ext. basecall - basecall followed by /R or /P
|
||||
// Nonstd. call - all the rest, limited to 3-11 characters either alphanumeric or stroke (/)
|
||||
// Callsign types and sizes:
|
||||
// * Std. call (basecall) - 1-2 letter/digit prefix (at least one letter), 1 digit area code, 1-3 letter suffix,
|
||||
// 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);
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue