mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 01:07:24 -05:00
168 lines
4.3 KiB
C
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);
|
|
}
|
|
|
|
|
|
|