kopia lustrzana https://github.com/jamescoxon/dl-fldigi
NAVTEX update
* change the distance between early, prompt, and late accumulators to be an integer number of samples. * noise and QSB processing - average the accumulator values over a longer time period - tighten bit tracking feedback loop .signal lock takes a little longer * make the AFC window a little wider to deal with some signals. * instead of requiring 5 consecutive correct characters to start decoding, store a stream of bit confidence values and require 9 good ones out of 14 total. FEC can take care of the rest. * add FEC calculations to do single bit permutations on bad characters, flipping the bit with the lowest confidence value. * code cleanup - remove unused variables.pull/4/head
rodzic
b1d12b8442
commit
9ed6cc3336
|
@ -547,6 +547,20 @@ public:
|
|||
return -code;
|
||||
}
|
||||
|
||||
int bytes_to_code(int *pos) {
|
||||
int code = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
code |= ((pos[i] > 0) << i);
|
||||
return code;
|
||||
}
|
||||
|
||||
int bytes_to_char(int *pos, int shift) {
|
||||
int code = bytes_to_code(pos);
|
||||
return code_to_char(code, shift);
|
||||
}
|
||||
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetNaive
|
||||
/// Counting set bits, Brian Kernighan's way
|
||||
static bool check_bits(int v) {
|
||||
|
@ -558,6 +572,19 @@ public:
|
|||
//printf("check_bits %d %d %c\n", bc, (int)code_to_ltrs[v], code_to_ltrs[v] );
|
||||
return bc == 4;
|
||||
}
|
||||
|
||||
// Is there a valid character in the next 7 ints?
|
||||
bool valid_char_at(int *pos) {
|
||||
int count = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
if (pos[i] > 0)
|
||||
count++;
|
||||
|
||||
return (count == 4);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// This is temporary, to manipulate a multi-line string.
|
||||
|
@ -800,15 +827,14 @@ class navtex ;
|
|||
class navtex_implementation {
|
||||
|
||||
enum State {
|
||||
NOSIGNAL, SYNC_SETUP, SYNC1, SYNC2, READ_DATA
|
||||
NOSIGNAL, SYNC_SETUP, SYNC, READ_DATA
|
||||
};
|
||||
|
||||
static const char * state_to_str( State s ) {
|
||||
switch( s ) {
|
||||
case NOSIGNAL : return "NOSIGNAL";
|
||||
case SYNC_SETUP: return "SYNC_SETUP";
|
||||
case SYNC1 : return "SYNC1";
|
||||
case SYNC2 : return "SYNC2";
|
||||
case SYNC : return "SYNC";
|
||||
case READ_DATA : return "READ_DATA";
|
||||
default : return "Unknown" ;
|
||||
}
|
||||
|
@ -832,13 +858,8 @@ class navtex_implementation {
|
|||
|
||||
CCIR476 m_ccir476;
|
||||
typedef std::list<int> sync_chrs_type ;
|
||||
sync_chrs_type m_sync_chrs;
|
||||
ccir_message m_curr_msg ;
|
||||
|
||||
int m_c1, m_c2, m_c3;
|
||||
static const int m_zero_crossings_divisor = 4;
|
||||
std::vector<int> m_zero_crossings ;
|
||||
long m_zero_crossing_count;
|
||||
double m_message_time ;
|
||||
double m_early_accumulator ;
|
||||
double m_prompt_accumulator ;
|
||||
|
@ -850,16 +871,14 @@ class navtex_implementation {
|
|||
double m_time_sec;
|
||||
|
||||
double m_baud_rate ;
|
||||
double m_baud_error;
|
||||
int m_sample_rate ;
|
||||
bool m_averaged_mark_state;
|
||||
int m_averaged_mark_state;
|
||||
int m_bit_duration ;
|
||||
bool m_old_mark_state;
|
||||
fftfilt *m_mark_lowpass;
|
||||
fftfilt *m_space_lowpass;
|
||||
double m_mark_phase;
|
||||
double m_space_phase;
|
||||
double m_bit_sample_count, m_half_bit_sample_count, m_quarter_bit_sample_count;
|
||||
double m_bit_sample_count, m_half_bit_sample_count;
|
||||
State m_state;
|
||||
int m_sample_count;
|
||||
double m_next_early_event;
|
||||
|
@ -868,13 +887,11 @@ class navtex_implementation {
|
|||
double m_average_early_signal;
|
||||
double m_average_prompt_signal;
|
||||
double m_average_late_signal;
|
||||
int m_bit_count;
|
||||
int m_code_bits;
|
||||
std::vector<int> m_bit_values;
|
||||
int m_bit_cursor;
|
||||
bool m_shift ;
|
||||
bool m_pulse_edge_event;
|
||||
int m_error_count;
|
||||
int m_valid_count;
|
||||
double m_sync_delta;
|
||||
bool m_alpha_phase ;
|
||||
bool m_header_found ;
|
||||
char snrmsg[80];
|
||||
|
@ -911,21 +928,23 @@ public:
|
|||
double m_bit_duration_seconds = 1.0 / m_baud_rate;
|
||||
m_bit_sample_count = m_sample_rate * m_bit_duration_seconds;
|
||||
m_half_bit_sample_count = m_bit_sample_count / 2;
|
||||
m_quarter_bit_sample_count = m_bit_sample_count / 4;
|
||||
// A narrower spread between signals allows the modem to
|
||||
// center on the pulses better, but a wider spread makes
|
||||
// more robust under noisy conditions. 1/6 seems to work.
|
||||
// more robust under noisy conditions. 1/5 seems to work.
|
||||
m_next_early_event = 0;
|
||||
m_next_prompt_event = m_bit_sample_count / 6;
|
||||
m_next_late_event = m_bit_sample_count * 2 / 6;
|
||||
m_next_prompt_event = m_bit_sample_count / 5;
|
||||
m_next_late_event = m_bit_sample_count * 2 / 5;
|
||||
m_average_early_signal = 0;
|
||||
m_average_prompt_signal = 0;
|
||||
m_average_late_signal = 0;
|
||||
m_error_count = 0;
|
||||
m_valid_count = 0;
|
||||
m_sample_count = 0;
|
||||
m_old_mark_state = false;
|
||||
m_averaged_mark_state = false ;
|
||||
// keep 1 second worth of bit values for decoding
|
||||
m_bit_values.resize(m_baud_rate);
|
||||
m_bit_cursor = 0;
|
||||
|
||||
m_mark_lowpass = 0;
|
||||
m_space_lowpass = 0;
|
||||
|
||||
set_filter_values();
|
||||
configure_filters();
|
||||
|
@ -948,11 +967,11 @@ private:
|
|||
|
||||
void configure_filters() {
|
||||
const int filtlen = 512;
|
||||
delete m_mark_lowpass;
|
||||
if (m_mark_lowpass) delete m_mark_lowpass;
|
||||
m_mark_lowpass = new fftfilt(m_baud_rate/m_sample_rate, filtlen);
|
||||
m_mark_lowpass->rtty_filter(m_baud_rate/m_sample_rate);
|
||||
|
||||
delete m_space_lowpass;
|
||||
if (m_space_lowpass) delete m_space_lowpass;
|
||||
m_space_lowpass = new fftfilt(m_baud_rate/m_sample_rate, filtlen);
|
||||
m_space_lowpass->rtty_filter(m_baud_rate/m_sample_rate);
|
||||
}
|
||||
|
@ -1029,74 +1048,273 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
// two phases: alpha and rep
|
||||
// marked during sync by code_alpha and code_rep
|
||||
// then for data: rep phase character is sent first,
|
||||
// then, three chars later, same char is sent in alpha phase
|
||||
bool process_char(int code) {
|
||||
bool success = CCIR476::check_bits(code);
|
||||
int chr = -1;
|
||||
// force phasing with the two phasing characters
|
||||
if (code == code_rep) {
|
||||
m_alpha_phase = false;
|
||||
} else if (code == code_alpha) {
|
||||
m_alpha_phase = true;
|
||||
// The rep character is transmitted 5 characters (35 bits) ahead of
|
||||
// the alpha character.
|
||||
int fec_offset(int offset) {
|
||||
return offset - 35;
|
||||
}
|
||||
|
||||
// Flip the sign of the smallest (least certain) bit in a character;
|
||||
// hopefully this will result in the right valid character.
|
||||
void flip_smallest_bit(int *pos) {
|
||||
int minimum = INT_MAX;
|
||||
int smallest_bit = -1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
if (abs(pos[i]) < minimum) {
|
||||
minimum = abs(pos[i]);
|
||||
smallest_bit = i;
|
||||
}
|
||||
}
|
||||
if (!m_alpha_phase) {
|
||||
m_c1 = m_c2;
|
||||
m_c2 = m_c3;
|
||||
m_c3 = code;
|
||||
} else { // alpha channel
|
||||
bool strict = false ;
|
||||
if (strict) {
|
||||
if (success && m_c1 == code) {
|
||||
chr = code;
|
||||
}
|
||||
} else {
|
||||
if (success) {
|
||||
chr = code;
|
||||
} else if (CCIR476::check_bits(m_c1)) {
|
||||
chr = m_c1;
|
||||
LOG_DEBUG("FEC replacement: %x -> %x", code, m_c1);
|
||||
|
||||
pos[smallest_bit] = -pos[smallest_bit];
|
||||
}
|
||||
|
||||
// Try to find a position in the bit stream with:
|
||||
// - the largest number of valid characters, and
|
||||
// - with rep (duplicate) characters in the right locations
|
||||
// This way the code can sync up with an incoming signal after
|
||||
// the initial alpha/rep synchronisation
|
||||
//
|
||||
// http://www.arachnoid.com/JNX/index.html
|
||||
// "NAUTICAL" becomes:
|
||||
// rep alpha rep alpha N alpha A alpha U N T A I U C T A I L C blank A blank L
|
||||
int find_alpha_characters(void) {
|
||||
int best_offset = 0;
|
||||
int best_score = 0;
|
||||
int offset, i;
|
||||
|
||||
// With 7 bits per character, and interleaved rep & alpha
|
||||
// characters, the first alpha character with a corresponding
|
||||
// rep in the stream can be in any of 14 locations
|
||||
for (offset = 35; offset < (35 + 14); offset++) {
|
||||
int score = 0;
|
||||
int reps = 0;
|
||||
int limit = m_bit_values.size() - 7;
|
||||
|
||||
// Search for the largest sequence of valid characters
|
||||
for (i = offset; i < limit; i += 7) {
|
||||
if (m_ccir476.valid_char_at(&m_bit_values[i])) {
|
||||
int ri = fec_offset(i);
|
||||
int code = m_ccir476.bytes_to_code(&m_bit_values[i]);
|
||||
int rep = m_ccir476.bytes_to_code(&m_bit_values[ri]);
|
||||
|
||||
// This character is valid
|
||||
score++;
|
||||
|
||||
// Does it match its rep?
|
||||
if (code == rep) {
|
||||
// This offset is wrong, rep
|
||||
// and alpha are spaced odd
|
||||
if (code == code_alpha ||
|
||||
code == code_rep) {
|
||||
score = 0;
|
||||
break;
|
||||
}
|
||||
reps++;
|
||||
} else if (code == code_alpha) {
|
||||
// Is there a matching rep to
|
||||
// this alpha?
|
||||
int ri = i - 7;
|
||||
int rep = m_ccir476.bytes_to_code(&m_bit_values[ri]);
|
||||
if (rep == code_rep) {
|
||||
reps++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chr == -1) {
|
||||
LOG_DEBUG("Fail all options: %x %x", code, m_c1);
|
||||
} else {
|
||||
switch (chr) {
|
||||
case code_rep:
|
||||
break;
|
||||
case code_alpha:
|
||||
break;
|
||||
case code_beta:
|
||||
break;
|
||||
case code_char32:
|
||||
break;
|
||||
case code_ltrs:
|
||||
m_shift = false;
|
||||
break;
|
||||
case code_figs:
|
||||
m_shift = true;
|
||||
break;
|
||||
default:
|
||||
chr = m_ccir476.code_to_char(chr, m_shift);
|
||||
if (chr < 0) {
|
||||
LOG_INFO(_("Missed this code: %x"), abs(chr));
|
||||
} else {
|
||||
filter_print(chr);
|
||||
process_messages(chr);
|
||||
}
|
||||
break;
|
||||
} // switch
|
||||
|
||||
} // if test != -1
|
||||
} // alpha channel
|
||||
// the most valid characters, with at least 3 FEC reps
|
||||
if (reps > 3 && score + reps > best_score) {
|
||||
best_score = score + reps;
|
||||
best_offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
// alpha/rep phasing
|
||||
m_alpha_phase = !m_alpha_phase;
|
||||
// m_bit_values fits 14 characters; if there are at least
|
||||
// 9 good ones, tell the caller where they start
|
||||
if (best_score > 8)
|
||||
return best_offset;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Turns accumulator values (estimates of whether a bit is 1 or 0)
|
||||
// into navtex messages
|
||||
void handle_bit_value(int accumulator) {
|
||||
int buffersize = m_bit_values.size();
|
||||
int i, offset = 0;
|
||||
|
||||
// Store the received value in the bit stream
|
||||
for (i = 0; i < buffersize - 1; i++) {
|
||||
m_bit_values[i] = m_bit_values[i+1];
|
||||
}
|
||||
m_bit_values[buffersize - 1] = accumulator;
|
||||
if (m_bit_cursor > 0)
|
||||
m_bit_cursor--;
|
||||
|
||||
// Find the most likely location where the message starts
|
||||
if (m_state == SYNC) {
|
||||
offset = find_alpha_characters();
|
||||
if (offset >= 0) {
|
||||
set_state(READ_DATA);
|
||||
m_bit_cursor = offset;
|
||||
m_alpha_phase = true;
|
||||
} else
|
||||
set_state(SYNC_SETUP);
|
||||
}
|
||||
|
||||
// Process 7-bit characters as they come in,
|
||||
// skipping rep (duplicate) characters
|
||||
if (m_state == READ_DATA) {
|
||||
if (m_bit_cursor < buffersize - 7) {
|
||||
if (m_alpha_phase) {
|
||||
int ret = process_bytes(m_bit_cursor);
|
||||
m_error_count -= ret;
|
||||
if (m_error_count > 5)
|
||||
set_state(SYNC_SETUP);
|
||||
if (m_error_count < 0)
|
||||
m_error_count = 0;
|
||||
}
|
||||
m_alpha_phase = !m_alpha_phase;
|
||||
m_bit_cursor += 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Turn a series of 7 bit confidence values into a character
|
||||
//
|
||||
// 1 on successful decode of the alpha character
|
||||
// 0 on unmodified FEC replacement
|
||||
// -1 on soft failure (FEC calculation)
|
||||
// -2 on hard failure
|
||||
int process_bytes(int m_bit_cursor) {
|
||||
int code = m_ccir476.bytes_to_code(&m_bit_values[m_bit_cursor]);
|
||||
int success = 0;
|
||||
|
||||
if (m_ccir476.check_bits(code)) {
|
||||
LOG_DEBUG("valid code : %x (%c)", code, m_ccir476.code_to_char(code, m_shift));
|
||||
success = 1;
|
||||
goto decode;
|
||||
}
|
||||
|
||||
if (fec_offset(m_bit_cursor) < 0)
|
||||
return -1;
|
||||
|
||||
// The alpha (primary) character received was not correct.
|
||||
// Try the rep (duplicate) copy of the character, and some
|
||||
// permutations to see if the correct character can be found.
|
||||
{
|
||||
int i, calc, avg[7];
|
||||
// Rep is 5 characters before alpha.
|
||||
int reppos = fec_offset(m_bit_cursor);
|
||||
int rep = m_ccir476.bytes_to_code(&m_bit_values[reppos]);
|
||||
if (CCIR476::check_bits(rep)) {
|
||||
// Current code is probably code_alpha.
|
||||
// Skip decoding to avoid switching phase.
|
||||
if (rep == code_rep)
|
||||
return 0;
|
||||
LOG_DEBUG("FEC replacement: %x -> %x (%c)", code, rep, m_ccir476.code_to_char(rep, m_shift));
|
||||
code = rep;
|
||||
goto decode;
|
||||
}
|
||||
|
||||
// Neither alpha or rep are valid. Check whether
|
||||
// the average of the two is a valid character.
|
||||
for (i = 0; i < 7; i++) {
|
||||
int a = m_bit_values[m_bit_cursor + i];
|
||||
int r = m_bit_values[rep + i];
|
||||
avg[i] = a + r;
|
||||
}
|
||||
|
||||
calc = m_ccir476.bytes_to_code(avg);
|
||||
if (CCIR476::check_bits(calc)) {
|
||||
LOG_DEBUG("FEC calculation: %x & %x -> %x (%c)", code, rep, calc, m_ccir476.code_to_char(calc, m_shift));
|
||||
code = calc;
|
||||
success = -1;
|
||||
goto decode;
|
||||
}
|
||||
|
||||
// Flip the lowest confidence bit in alpha.
|
||||
flip_smallest_bit(&m_bit_values[m_bit_cursor]);
|
||||
calc = m_ccir476.bytes_to_code(&m_bit_values[m_bit_cursor]);
|
||||
if (CCIR476::check_bits(calc)) {
|
||||
LOG_DEBUG("FEC calculation: %x & %x -> %x (%c)", code, rep, calc, m_ccir476.code_to_char(calc, m_shift));
|
||||
code = calc;
|
||||
success = -1;
|
||||
goto decode;
|
||||
}
|
||||
|
||||
// Flip the lowest confidence bit in rep.
|
||||
flip_smallest_bit(&m_bit_values[reppos]);
|
||||
calc = m_ccir476.bytes_to_code(&m_bit_values[reppos]);
|
||||
if (CCIR476::check_bits(calc)) {
|
||||
LOG_DEBUG("FEC calculation: %x & %x -> %x (%c)", code, rep, calc, m_ccir476.code_to_char(calc, m_shift));
|
||||
code = calc;
|
||||
success = -1;
|
||||
goto decode;
|
||||
}
|
||||
|
||||
// Try flipping the bit with the lowest confidence
|
||||
// in the average of alpha & rep.
|
||||
flip_smallest_bit(avg);
|
||||
calc = m_ccir476.bytes_to_code(avg);
|
||||
if (CCIR476::check_bits(calc)) {
|
||||
LOG_DEBUG("FEC calculation: %x & %x -> %x (%c)", code, rep, calc, m_ccir476.code_to_char(calc, m_shift));
|
||||
code = calc;
|
||||
success = -1;
|
||||
goto decode;
|
||||
}
|
||||
|
||||
LOG_DEBUG("decode fail %x, %x", code, rep);
|
||||
return -2;
|
||||
}
|
||||
|
||||
decode:
|
||||
process_char(code);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool process_char(int chr) {
|
||||
static int last_char = 0;
|
||||
switch (chr) {
|
||||
case code_rep:
|
||||
// This code should run in alpha phase, but
|
||||
// it just received two rep characters. Fix
|
||||
// the rep/alpha phase, so FEC works again.
|
||||
if (last_char == code_rep) {
|
||||
LOG_DEBUG("fixing rep/alpha sync");
|
||||
m_alpha_phase = false;
|
||||
}
|
||||
break;
|
||||
case code_alpha:
|
||||
break;
|
||||
case code_beta:
|
||||
break;
|
||||
case code_char32:
|
||||
break;
|
||||
case code_ltrs:
|
||||
m_shift = false;
|
||||
break;
|
||||
case code_figs:
|
||||
m_shift = true;
|
||||
break;
|
||||
default:
|
||||
chr = m_ccir476.code_to_char(chr, m_shift);
|
||||
if (chr < 0) {
|
||||
LOG_INFO(_("Missed this code: %x"), abs(chr));
|
||||
} else {
|
||||
filter_print(chr);
|
||||
process_messages(chr);
|
||||
}
|
||||
break;
|
||||
} // switch
|
||||
|
||||
last_char = chr;
|
||||
return true;
|
||||
}
|
||||
|
||||
void filter_print(int c) {
|
||||
if (c == char_bell) {
|
||||
/// TODO: It should be a beep, but French navtex displays a quote.
|
||||
|
@ -1141,8 +1359,8 @@ private:
|
|||
static int cnt_read_data = 0 ;
|
||||
/// This centers the carrier where the activity is the strongest.
|
||||
static const int bw[][2] = {
|
||||
{ -deviation_f - 5, -deviation_f + 5 },
|
||||
{ deviation_f - 5, deviation_f + 5 } };
|
||||
{ -deviation_f - 10, -deviation_f + 5 },
|
||||
{ deviation_f - 5, deviation_f + 10 } };
|
||||
double max_carrier = wf->powerDensityMaximum( 2, bw );
|
||||
|
||||
/// Do not change the frequency too quickly if an image is received.
|
||||
|
@ -1175,8 +1393,7 @@ private:
|
|||
case SYNC_SETUP:
|
||||
next_carr = max_carrier ;
|
||||
break;
|
||||
case SYNC1:
|
||||
case SYNC2:
|
||||
case SYNC:
|
||||
next_carr = decayavg( m_center_frequency_f, max_carrier, 1 );
|
||||
break;
|
||||
case READ_DATA:
|
||||
|
@ -1205,8 +1422,8 @@ private:
|
|||
// late are only used to adjust the time of the sampling to match
|
||||
// the incoming signal.
|
||||
//
|
||||
// The early event happens 1/6 bit period before the prompt event,
|
||||
// and the late event 1/6 bit period later. If the incoming signal
|
||||
// The early event happens 1/5 bit period before the prompt event,
|
||||
// and the late event 1/5 bit period later. If the incoming signal
|
||||
// peaks early, it means the decoder is late. That is, if the early
|
||||
// signal is "too large", decoding should to happen earlier.
|
||||
//
|
||||
|
@ -1226,18 +1443,19 @@ private:
|
|||
if (m_average_prompt_signal < m_average_early_signal &&
|
||||
m_average_prompt_signal < m_average_late_signal)
|
||||
// At a signal minimum. Get out quickly.
|
||||
slope *= 2;
|
||||
slope /= 2;
|
||||
else if (m_average_prompt_signal > m_average_late_signal &&
|
||||
m_average_prompt_signal > m_average_late_signal)
|
||||
// Limit the adjustment, to ride out noise
|
||||
slope /= 8;
|
||||
slope /= 128;
|
||||
else
|
||||
slope /= 4;
|
||||
slope /= 32;
|
||||
|
||||
if (slope) {
|
||||
m_next_early_event += slope;
|
||||
m_next_prompt_event += slope;
|
||||
m_next_late_event += slope;
|
||||
LOG_DEBUG("adjusting by %1.2f, early %1.1f, prompt %1.1f, late %1.1f", slope, m_average_early_signal, m_average_prompt_signal, m_average_late_signal);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1367,7 +1585,7 @@ private:
|
|||
if (m_sample_count >= m_next_early_event) {
|
||||
m_average_early_signal = decayavg(
|
||||
m_average_early_signal,
|
||||
fabs(m_early_accumulator), 16);
|
||||
fabs(m_early_accumulator), 64);
|
||||
m_next_early_event += m_bit_sample_count;
|
||||
m_early_accumulator = 0;
|
||||
}
|
||||
|
@ -1375,7 +1593,7 @@ private:
|
|||
if (m_sample_count >= m_next_late_event) {
|
||||
m_average_late_signal = decayavg(
|
||||
m_average_late_signal,
|
||||
fabs(m_late_accumulator), 16);
|
||||
fabs(m_late_accumulator), 64);
|
||||
m_next_late_event += m_bit_sample_count;
|
||||
m_late_accumulator = 0;
|
||||
}
|
||||
|
@ -1386,10 +1604,11 @@ private:
|
|||
if (m_pulse_edge_event) {
|
||||
m_average_prompt_signal = decayavg(
|
||||
m_average_prompt_signal,
|
||||
fabs(m_prompt_accumulator), 16);
|
||||
fabs(m_prompt_accumulator), 64);
|
||||
m_next_prompt_event += m_bit_sample_count;
|
||||
|
||||
m_averaged_mark_state = (m_prompt_accumulator > 0) ^ m_ptr_navtex->get_reverse();
|
||||
m_averaged_mark_state = m_prompt_accumulator;
|
||||
if (m_ptr_navtex->get_reverse())
|
||||
m_averaged_mark_state = -m_averaged_mark_state;
|
||||
m_prompt_accumulator = 0;
|
||||
}
|
||||
|
||||
|
@ -1402,79 +1621,14 @@ private:
|
|||
switch (m_state) {
|
||||
case NOSIGNAL: break;
|
||||
case SYNC_SETUP:
|
||||
m_bit_count = -1;
|
||||
m_code_bits = 0;
|
||||
m_error_count = 0;
|
||||
m_valid_count = 0;
|
||||
m_shift = false;
|
||||
m_sync_chrs.clear();
|
||||
set_state(SYNC1);
|
||||
break;
|
||||
// scan indefinitely for valid bit pattern
|
||||
case SYNC1:
|
||||
if (m_pulse_edge_event) {
|
||||
m_code_bits = (m_code_bits >> 1) | ( m_averaged_mark_state ? 64 : 0);
|
||||
if (CCIR476::check_bits(m_code_bits)) {
|
||||
m_sync_chrs.push_back(m_code_bits);
|
||||
m_bit_count = 0;
|
||||
m_code_bits = 0;
|
||||
set_state(SYNC2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
// sample and validate bits in groups of 7
|
||||
case SYNC2:
|
||||
// find any bit alignment that produces a valid character
|
||||
// then test that synchronization in subsequent groups of 7 bits
|
||||
if (m_pulse_edge_event) {
|
||||
m_code_bits = (m_code_bits >> 1) | ( m_averaged_mark_state ? 64 : 0);
|
||||
m_bit_count++;
|
||||
if (m_bit_count == 7) {
|
||||
if (CCIR476::check_bits(m_code_bits)) {
|
||||
m_sync_chrs.push_back(m_code_bits);
|
||||
m_code_bits = 0;
|
||||
m_bit_count = 0;
|
||||
m_valid_count++;
|
||||
// successfully read 4 characters?
|
||||
if (m_valid_count == 4) {
|
||||
for( sync_chrs_type::const_iterator it = m_sync_chrs.begin(), en = m_sync_chrs.end(); it != en; ++it ) {
|
||||
process_char(*it);
|
||||
}
|
||||
set_state(READ_DATA);
|
||||
}
|
||||
} else { // failed subsequent bit test
|
||||
m_code_bits = 0;
|
||||
m_bit_count = 0;
|
||||
// LOG_INFO("restarting sync");
|
||||
set_state(SYNC_SETUP);
|
||||
}
|
||||
}
|
||||
}
|
||||
set_state(SYNC);
|
||||
break;
|
||||
case SYNC:
|
||||
case READ_DATA:
|
||||
if (m_pulse_edge_event) {
|
||||
m_code_bits = (m_code_bits >> 1) | ( m_averaged_mark_state ? 64 : 0);
|
||||
m_bit_count++;
|
||||
if (m_bit_count == 7) {
|
||||
if (m_error_count > 0) {
|
||||
LOG_DEBUG("Error count: %d", m_error_count);
|
||||
}
|
||||
if (process_char(m_code_bits)) {
|
||||
if (m_error_count > 0) {
|
||||
m_error_count--;
|
||||
}
|
||||
} else {
|
||||
m_error_count++;
|
||||
if (m_error_count > 2) {
|
||||
LOG_DEBUG("Returning to sync");
|
||||
set_state(SYNC_SETUP);
|
||||
}
|
||||
}
|
||||
m_bit_count = 0;
|
||||
m_code_bits = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
if (m_pulse_edge_event)
|
||||
handle_bit_value(m_averaged_mark_state);
|
||||
}
|
||||
|
||||
m_sample_count++;
|
||||
|
|
Ładowanie…
Reference in New Issue