mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 01:07:24 -05:00
215 lines
6.2 KiB
C
215 lines
6.2 KiB
C
/*-------------------------------------------------------------------------------
|
|
* dmr_34.c
|
|
* DMR (and P25) 3/4 Rate Simple Trellis Decoder
|
|
*
|
|
* LWVMOBILE
|
|
* 2023-12 DSD-FME Florida Man Edition
|
|
*-----------------------------------------------------------------------------*/
|
|
|
|
#include "dsd.h"
|
|
|
|
uint8_t 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 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 fsm[64] = {
|
|
0, 8, 4, 12, 2, 10, 6, 14,
|
|
4, 12, 2, 10, 6, 14, 0, 8,
|
|
1, 9, 5, 13, 3, 11, 7, 15,
|
|
5, 13, 3, 11, 7, 15, 1, 9,
|
|
3, 11, 7, 15, 1, 9, 5, 13,
|
|
7, 15, 1, 9, 5, 13, 3, 11,
|
|
2, 10, 6, 14, 0, 8, 4, 12,
|
|
6, 14, 0, 8, 4, 12, 2, 10};
|
|
|
|
//attempt to find the surviving path, or the 'best' path available (most positions gained)
|
|
uint8_t fix_34(uint8_t * p, uint8_t state, int position)
|
|
{
|
|
int i, j, k, counter, best_p, best_v, survivors;
|
|
uint8_t temp_s, tri, t;
|
|
|
|
//status of surviving paths -- debug
|
|
int s[8];
|
|
memset (s, 0, 8*sizeof(int));
|
|
|
|
//assign all potentially correct points to temporary storage
|
|
uint8_t temp_p[8];
|
|
temp_p[0] = (p[position] ^ 1) & 0xF;
|
|
temp_p[1] = (p[position] ^ 3) & 0xF;
|
|
temp_p[2] = (p[position] ^ 5) & 0xF;
|
|
temp_p[3] = (p[position] ^ 7) & 0xF;
|
|
temp_p[4] = (p[position] ^ 9) & 0xF;
|
|
temp_p[5] = (p[position] ^ 11) & 0xF;
|
|
temp_p[6] = (p[position] ^ 13) & 0xF;
|
|
temp_p[7] = (p[position] ^ 15) & 0xF;
|
|
|
|
best_p = 0; //best position
|
|
best_v = 0; //best path value
|
|
|
|
for (k = 0; k < 8; k++)
|
|
{
|
|
temp_s = state;
|
|
counter = 0;
|
|
tri = 0;
|
|
for (i = position; i < 49; i++)
|
|
{
|
|
//assign temp t either as our temp_p, or next point of i
|
|
if (i == position) t = temp_p[k];
|
|
else t = p[i];
|
|
|
|
if (tri != 0xFF) //while the path survives
|
|
{
|
|
tri = 0xFF;
|
|
for (j = 0; j < 8; j++)
|
|
{
|
|
if ( fsm[(temp_s*8)+j] == t )
|
|
{
|
|
//return our tribit value and state for the next point
|
|
tri = temp_s = (uint8_t)j;
|
|
counter++;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (counter > best_p)
|
|
{
|
|
best_p = counter;
|
|
best_v = k; //if we make it further on current path, assign as best path
|
|
}
|
|
|
|
// surviving path -- made it to 49
|
|
if (i == 48) s[k] = 1;
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//NOTE: If there are no surviving paths, then that means there is another bit/point err
|
|
//Ideally, at the end of a single or multiple fixes, there should only be one survivor, but in practice,
|
|
//I've seen up to 4 surviving paths and somehow, get a good CRC and a good LRRP or LOCN decode
|
|
//multiple survivors seems common when the starting err position is very close to 49
|
|
|
|
//tally number of surviving paths
|
|
survivors = 0;
|
|
for (k = 0; k < 8; k++)
|
|
{
|
|
if (s[k] == 1) survivors++;
|
|
}
|
|
|
|
//debug
|
|
// fprintf (stderr, "START: %d; BEST_P: %d; BEST_V: %d; Survivors: %d; Point: %d; ", position, best_p, best_v, survivors, temp_p[best_v]);
|
|
|
|
return temp_p[best_v]; //return the point value of the best path's starting point value
|
|
}
|
|
|
|
uint32_t dmr_34(uint8_t * input, uint8_t treturn[18])
|
|
{
|
|
int i, j;
|
|
uint32_t irr_err = 0; //irrecoverable errors
|
|
|
|
uint8_t deinterleaved_dibits[98];
|
|
memset (deinterleaved_dibits, 0, sizeof(deinterleaved_dibits));
|
|
|
|
//deinterleave our input dibits
|
|
for (i = 0; i < 98; i++)
|
|
deinterleaved_dibits[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] = 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 tribit values using the FSM
|
|
uint8_t state = 0;
|
|
uint32_t tribits[49];
|
|
memset (tribits, 0xF, sizeof(tribits));
|
|
|
|
for (i = 0; i < 49; i++)
|
|
{
|
|
|
|
for (j = 0; j < 8; j++)
|
|
{
|
|
if ( fsm[(state*8)+j] == point[i] )
|
|
{
|
|
//return our tribit value and state for the next point
|
|
tribits[i] = state = (uint8_t)j;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//if tribit value is greater than 7, then we have a decoding error
|
|
if (tribits[i] > 7)
|
|
{
|
|
irr_err++; //tally number of errors
|
|
|
|
//debug point, position of error, and state value
|
|
// fprintf (stderr, "\n P: %d, %d:%d; ", point[i], i, state);
|
|
|
|
//attempt to fix point by looking for the best path from here
|
|
point[i] = fix_34(point, state, i);
|
|
|
|
//Make a hard decision and flip point to fit in current state
|
|
// point[i] ^= 7; //lucky number 7 (0111) //fallback
|
|
|
|
//decrement one and resume decoding
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//debug view tribits/states
|
|
// fprintf (stderr, "\n T =");
|
|
// for (i = 0; i < 49; i++)
|
|
// fprintf (stderr, " %02d", tribits[i]);
|
|
|
|
//convert tribits into a return payload
|
|
uint32_t temp = 0;
|
|
|
|
//break into chunks of 24 bit values and shuffle into 8-bit (byte) treturn values
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
temp = (tribits[(i*8)+0] << 21) + (tribits[(i*8)+1] << 18) + (tribits[(i*8)+2] << 15) + (tribits[(i*8)+3] << 12) +
|
|
(tribits[(i*8)+4] << 9) + (tribits[(i*8)+5] << 6) + (tribits[(i*8)+6] << 3) + (tribits[(i*8)+7] << 0);
|
|
|
|
treturn[(i*3)+0] = (temp >> 16) & 0xFF;
|
|
treturn[(i*3)+1] = (temp >> 8) & 0xFF;
|
|
treturn[(i*3)+2] = (temp >> 0) & 0xFF;
|
|
}
|
|
|
|
//trellis point/state err tally
|
|
// if (irr_err != 0)
|
|
// fprintf (stderr, " P_ERR = %d", irr_err);
|
|
|
|
return (0);
|
|
}
|
|
|