Files
dsd-fme/p25p1_ldu.c
EdFuentetaja 9e6b3b7978 Included error correction on P25 TDULC.
Added a new "heuristics" module for P25 that improves the estimation of the symbol (dibit) that corresponds to a given analog signal value.
Added a BER (bit error reate) estimation for P25.
2014-05-11 08:14:29 +08:00

270 lines
6.4 KiB
C

#include "dsd.h"
#include "p25p1_const.h"
#include "p25p1_hdu.h"
#include "p25p1_check_ldu.h"
#include "p25p1_heuristics.h"
#ifdef TRACE_DSD
static void
debug_write_label_imbe(dsd_state* state, unsigned int cc, int bitindex, char bit)
{
float left, right;
if (state->debug_label_imbe_file == NULL)
{
state->debug_label_imbe_file = fopen ("pp_label_imbe.txt", "w");
}
left = (state->debug_sample_index-10) / 48000.0F;
right = (state->debug_sample_index) / 48000.0F;
fprintf(state->debug_label_imbe_file, "%f\t%f\tC_%i[%i]=%c\n", left, right, cc, bitindex, (bit + '0'));
}
#endif
/**
* Logs the IMBE's c0-c6 words.
*/
static void
debug_log_imbe(char imbe_fr[8][23])
{
int i, j;
printf(" ");
for (j=0; j<4; j++)
{
printf("{");
for (i=0; i<23; i++)
{
if (i>0)
{
printf(", ");
}
printf("%c", (imbe_fr[j][i] + '0'));
}
printf("}; ");
}
for (j=4; j<7; j++)
{
printf("{");
for (i=0; i<15; i++)
{
if (i>0)
{
printf(", ");
}
printf("%c", (imbe_fr[j][i] + '0'));
}
printf("}; ");
}
printf("\n");
}
void
process_IMBE (dsd_opts* opts, dsd_state* state, int* status_count)
{
int j, dibit, status;
char imbe_fr[8][23];
const int *w, *x, *y, *z;
w = iW;
x = iX;
y = iY;
z = iZ;
#ifdef TRACE_DSD
state->debug_prefix = 'I';
#endif
for (j = 0; j < 72; j++)
{
if (*status_count == 35)
{
// Skip the status symbol
#ifdef TRACE_DSD
state->debug_prefix = 's';
#endif
status = getDibit (opts, state);
// TODO: do something useful with the status bits...
*status_count = 1;
#ifdef TRACE_DSD
state->debug_prefix = 'I';
#endif
}
else
{
(*status_count)++;
}
dibit = getDibit (opts, state);
imbe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
imbe_fr[*y][*z] = (1 & dibit); // bit 0
#ifdef TRACE_DSD
if (*w == 0) {
debug_write_label_imbe(state, 0, *x, (1 & (dibit >> 1)));
}
if (*y == 0) {
debug_write_label_imbe(state, 0, *z, (1 & dibit));
}
#endif
w++;
x++;
y++;
z++;
}
#ifdef TRACE_DSD
state->debug_prefix = '\0';
#endif
if (state->p25kid == 0 || opts->unmute_encrypted_p25 == 1)
{
{
// Check for a non-standard c0 transmitted
// This is explained here: https://github.com/szechyjs/dsd/issues/24
char non_standard_word[23] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0};
int match = 1;
unsigned int i;
for (i=0; i<23; i++) {
if (imbe_fr[0][i] != non_standard_word[i]) {
match = 0;
break;
}
}
if (match) {
// Skip this particular value. If we let it pass it will be signaled as an erroneus IMBE
printf("(Non-standard IMBE c0 detected, skipped)");
} else {
processMbeFrame (opts, state, imbe_fr, NULL, NULL);
}
}
}
}
// Uncomment this line for verbose information on the error correction of the LDU bits.
//#define LDU_DEBUG
void
read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* status_count,
AnalogSignal* analog_signal_array, int* analog_signal_index)
{
char parity[4];
int error_count;
// Read the hex word
read_word (opts, state, hex, 6, status_count, analog_signal_array, analog_signal_index);
// Read the parity
read_hamm_parity (opts, state, parity, status_count, analog_signal_array, analog_signal_index);
#ifdef LDU_DEBUG
printf("[");
for (i = 0; i < 6; i++)
{
printf("%c", (hex[i] == 1)? 'X' : ' ');
}
printf("-");
for (i = 0; i < 4; i++)
{
printf("%c", (parity[i] == 1)? 'X' : ' ');
}
printf("]");
#endif
// Use Hamming to error correct the hex word
error_count = check_and_fix_hamming_10_6_3(hex, parity);
if (error_count == 1)
{
state->debug_header_errors++;
}
else if (error_count ==2)
{
state->debug_header_critical_errors++;
}
#ifdef LDU_DEBUG
printf(" -> [");
for (i = 0; i < 6; i++)
{
printf("%c", (hex[i] == 1)? 'X' : ' ');
}
printf("]");
if (error_count == 1)
{
printf(" fixed!");
}
else if (error_count ==2)
{
printf(" IRRECOVERABLE");
}
printf("\n");
#endif
}
void
correct_hamming_dibits(char* data, int count, AnalogSignal* analog_signal_array)
{
char parity[4];
int i, j;
int analog_signal_index;
analog_signal_index = 0;
for (i=count-1; i>=0; i--)
{
// Take the next 3 dibits (1 hex word) as they are
for (j=0; j<6; j+=2) // 3 iterations -> 3 dibits
{
int dibit = (data[i*6+j] << 1) | data[i*6+j+1];
// This dibit is the correct value we should have read in the first place
analog_signal_array[analog_signal_index].corrected_dibit = dibit;
#ifdef HEURISTICS_DEBUG
if (analog_signal_array[analog_signal_index].dibit != dibit)
{
printf("LDU word corrected from %i to %i, analog value %i\n",
analog_signal_array[analog_signal_index].dibit, dibit, analog_signal_array[analog_signal_index].value);
}
#endif
analog_signal_index++;
}
// The next two dibits are calculated has the hamming parity of the hex word
encode_hamming_10_6_3(data+i*6, parity);
for (j=0; j<4; j+=2) // 2 iterations -> 2 dibits
{
int dibit = (parity[j] << 1) | parity[j+1];
// Again, this dibit is the correct value we should have read in the first place
analog_signal_array[analog_signal_index].corrected_dibit = dibit;
#ifdef HEURISTICS_DEBUG
if (analog_signal_array[analog_signal_index].dibit != dibit)
{
printf("LDU-HM parity corrected from %i to %i, analog value %i\n",
analog_signal_array[analog_signal_index].dibit, dibit, analog_signal_array[analog_signal_index].value);
}
#endif
analog_signal_index++;
}
}
}
void
debug_ldu_header(dsd_state* state)
{
#ifdef TRACE_DSD
float s = state->debug_sample_index / 48000.0F;
printf("Start of LDU at sample %f\n", s);
#endif
debug_print_heuristics(&state->p25_heuristics);
}