Files
dsd-fme/src/p25_12.c
2023-10-02 08:58:03 -04:00

168 lines
4.3 KiB
C

/*-------------------------------------------------------------------------------
* p25_12.c
* P25p1 1/2 Rate Simple Trellis Decoder
*
* LWVMOBILE
* 2023-10 DSD-FME Florida Man Edition
*-----------------------------------------------------------------------------*/
#include "dsd.h"
uint8_t p25_interleave[98] = {
0, 1, 8, 9, 16, 17, 24, 25, 32, 33, 40, 41, 48, 49, 56, 57, 64, 65, 72, 73, 80, 81, 88, 89, 96, 97,
2, 3, 10, 11, 18, 19, 26, 27, 34, 35, 42, 43, 50, 51, 58, 59, 66, 67, 74, 75, 82, 83, 90, 91,
4, 5, 12, 13, 20, 21, 28, 29, 36, 37, 44, 45, 52, 53, 60, 61, 68, 69, 76, 77, 84, 85, 92, 93,
6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55, 62, 63, 70, 71, 78, 79, 86, 87, 94, 95};
//this is a convertion table for converting the dibit pairs into constellation points
uint8_t p25_constellation_map[16] = {
11, 12, 0, 7, 14, 9, 5, 2, 10, 13, 1, 6, 15, 8, 4, 3
};
//digitized dibit to OTA symbol conversion for reference
//0 = +1; 1 = +3;
//2 = -1; 3 = -3;
//finite state machine values
uint8_t p25_fsm[16] = {
0,15,12,3,
4,11,8,7,
13,2,1,14,
9,6,5,10 };
//this is a dibit-pair to trellis dibit transition matrix (SDRTrunk and Ossmann)
//when evaluating hamming distance, we want to use this xor the dibit-pair nib,
//and not the fsm xor the constellation point
uint8_t p25_dtm[16] = {
2,12,1,15,
14,0,13,3,
9,7,10,4,
5,11,6,8 };
int count_bits(uint8_t b, int slen)
{
int i = 0; int j = 0;
for (j = 0; j < slen; j++)
{
if ( (b & 1) == 1) i++;
b = b >> 1;
}
return i;
}
uint8_t find_min(uint8_t list[4], int len)
{
int min = list[0];
uint8_t index = 0;
int i;
for (i = 1; i < len; i++)
{
if (list[i] < min)
{
min = list[i];
index = (uint8_t)i;
}
//NOTE: Disqualifying result on uniqueness can impact decoding
//let the CRC determine if the result is good or bad
//its not uncommon for two values of the same min
//distance to emerge, so its 50/50 each time
}
return index;
}
int p25_12(uint8_t * input, uint8_t treturn[12])
{
int i, j;
int irr_err = 0;
uint8_t deinterleaved_dibits[98];
memset (deinterleaved_dibits, 0, sizeof(deinterleaved_dibits));
//deinterleave our input dibits
for (i = 0; i < 98; i++)
deinterleaved_dibits[p25_interleave[i]] = input[i];
//pack the input into nibbles (dibit pairs)
uint8_t nibs[49];
memset (nibs, 0, sizeof(nibs));
for (i = 0; i < 49; i++)
nibs[i] = (deinterleaved_dibits[i*2+0] << 2) | (deinterleaved_dibits[i*2+1] << 0);
//convert our dibit pairs into constellation point values
uint8_t point[49];
memset (point, 0xFF, sizeof(point));
for (i = 0; i < 49; i++)
point[i] = p25_constellation_map[nibs[i]];
//debug view points
// fprintf (stderr, "\n P =");
// for (i = 0; i < 49; i++)
// fprintf (stderr, " %02d", point[i]);
//convert constellation points into tdibit values using the FSM
uint8_t state = 0;
uint8_t tdibits[49]; //trellis dibits 1/2 rate
memset (tdibits, 0xF, sizeof(tdibits));
uint8_t hd[4]; //array of the four fsm words hamming distance
memset (hd, 0, sizeof(hd));
uint8_t min = 0;
for (i = 0; i < 49; i++)
{
for (j = 0; j < 4; j++)
{
if ( p25_fsm[(state*4)+j] == point[i] )
{
//return our tdibit value and state for the next point
tdibits[i] = state = (uint8_t)j;
break;
}
}
//if tdibit value is greater than 3, then we have a decoding error
if (tdibits[i] == 0xF)
{
irr_err++; //increment number of errors
//debug position of error and state value
// fprintf (stderr, " %d:%d;", i, state);
//this method only seems to be reliable up to 1-2 bit errors...sometimes
for (j = 0; j < 4; j++)
hd[j] = count_bits ( ((nibs[i] ^ p25_dtm[(state*4)+j]) & 0xF ), 4 );
min = find_min (hd, 4);
tdibits[i] = state = min;
memset (hd, 0, sizeof(hd));
min = 0;
}
}
//debug view tdibits/states
// fprintf (stderr, "\n T =");
// for (i = 0; i < 49; i++)
// fprintf (stderr, " %02d", tdibits[i]);
//pack tdibits into return payload bytes
for (i = 0; i < 12; i++)
treturn[i] = (tdibits[(i*4)+0] << 6) | (tdibits[(i*4)+1] << 4) | (tdibits[(i*4)+2] << 2) | tdibits[(i*4)+3];
//trellis point/state err tally
// if (irr_err != 0)
// fprintf (stderr, " P_ERR = %d", irr_err);
return (irr_err);
}