#6 DMR Decoder (#947)

* #6 DMR decoder feature - work in progress

* #6 DMR Decoder.

* #6 DMR Decoder.  Code review updates.

Co-authored-by: Zhenyu Mao <maozhenyu@foxmail.com>
Co-authored-by: Denny <denny@denny-desktop>
This commit is contained in:
Denny Sheirer
2020-10-12 04:57:59 -04:00
committed by GitHub
parent b061db1189
commit 7eec82deee
436 changed files with 36258 additions and 2409 deletions

View File

@@ -1,17 +1,17 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
@@ -23,217 +23,219 @@ import org.slf4j.LoggerFactory;
public class CRCUtil
{
private final static Logger mLog = LoggerFactory.getLogger( CRCUtil.class );
private final static Logger mLog = LoggerFactory.getLogger(CRCUtil.class);
public static long[] generate( int messageSize,
int crcSize,
long polynomial,
long initialFill,
boolean includeCRCBitErrors )
{
long[] crcTable = new long[ messageSize +
( includeCRCBitErrors ? crcSize : 0 ) ];
int[] checksumIndexes = new int[ crcSize ];
for( int x = 0; x < crcSize; x++ )
{
checksumIndexes[ x ] = messageSize + x;
}
public static long[] generate(int messageSize,
int crcSize,
long polynomial,
long initialFill,
boolean includeCRCBitErrors)
{
long[] crcTable = new long[messageSize +
(includeCRCBitErrors ? crcSize : 0)];
for( int x = 0; x < messageSize; x++ )
{
BinaryMessage message = new BinaryMessage( messageSize + crcSize );
message.load( messageSize, crcSize, initialFill );
message.set( x );
message = decode( message, 0, messageSize, polynomial, crcSize );
long checksum = message.getLong( checksumIndexes );
crcTable[ x ] = checksum;
}
if( includeCRCBitErrors )
{
for( int x = 0; x < crcSize; x++ )
{
crcTable[ messageSize + x ] = Long.rotateLeft( 1, x );
}
}
return crcTable;
}
int[] checksumIndexes = new int[crcSize];
/**
* Generates the checksum table and treats the final bit of each check value
* as a parity bit that complies with the request parity argument.
*/
public static long[] generate( int messageSize,
int crcSize,
long polynomial,
long initialFill,
boolean includeCRCBitErrors,
Parity parity )
{
long[] table = generate( messageSize, crcSize, polynomial, initialFill,
includeCRCBitErrors );
for(int x = 0; x < crcSize; x++)
{
checksumIndexes[x] = messageSize + x;
}
if( parity == Parity.NONE )
{
return table;
}
else
{
for( int x = 0; x < table.length; x++ )
{
table[ x ] <<= 1;
if( parity( table[ x ] ) != parity )
{
table[ x ] ^= 0x1;
}
}
return table;
}
}
public enum Parity{ EVEN, ODD, NONE };
for(int x = 0; x < messageSize; x++)
{
BinaryMessage message = new BinaryMessage(messageSize + crcSize);
/* Determines the parity (number of 1 bits) for the value */
public static Parity parity( long value )
{
return Long.bitCount( value ) % 2 == 0 ? Parity.EVEN : Parity.ODD;
}
message.load(messageSize, crcSize, initialFill);
/**
* Performs binary division of the polynomial into the message for bits
* in index 0 to index messageLength - 1, leaving the results in the
* checksum filed following the message.
*
* IN: MMMMMMMMMMMMMMMMCCCCCCCCCCC
* OUT: 0000000000000000RRRRRRRRRRR
*
* M: Message
* C: Checksum
* R: Remainder
*
* @param message - message and crc
* @param polynomial - crc polynomial - must be 1 bit longer than the crc width
* @param messageSize - message length and start of the checksum
*
* @return message with all message bits zeroed out, and the remainder
* placed in the crc field which starts at index messageLength
*/
public static BinaryMessage decode( BinaryMessage message,
int messageStart,
int messageSize,
long polynomial,
int crcSize )
{
for (int i = message.nextSetBit( messageStart );
i >= messageStart && i < messageSize;
i = message.nextSetBit( i+1 ) )
{
BinaryMessage polySet = new BinaryMessage( crcSize + i + 1 );
polySet.load( i, crcSize + 1, polynomial );
message.xor( polySet );
}
return message;
}
public static void main( String[] args )
{
mLog.debug( "Starting" );
// String raw = "000000001010001000000000100010100000000000000000010000000011001001011100000000000000000011111110001000101001011100101110000101000110011101101001";
// BitSetBuffer message = BitSetBuffer.load( raw );
//
// long polynomial = 0x259l;
//
// decode( message, 0, 135, polynomial, 9 );
//
// mLog.debug( message.toString() );
message.set(x);
long[] table = CRCUtil.generate( 135, 9, 0x259l, 0x1FF, false, Parity.NONE );
mLog.debug( toCodeArray( table ) );
mLog.debug( "Finished" );
}
public static String toCodeArray( long[] values )
{
boolean integerArray = true;
message = decode(message, 0, messageSize, polynomial, crcSize);
/* Determine the correct primitive type: int or long */
for( long value: values )
{
if( value > Integer.MAX_VALUE || value < Integer.MIN_VALUE )
{
integerArray = false;
break;
}
}
long checksum = message.getLong(checksumIndexes);
StringBuilder sb = new StringBuilder();
crcTable[x] = checksum;
}
if( integerArray )
{
sb.append( "\npublic static final int[] CHECKSUMS = new int[]\n" );
}
else
{
sb.append( "\npublic static final long[] CHECKSUMS = new long[]\n" );
}
sb.append( "{\n" );
if(includeCRCBitErrors)
{
for(int x = 0; x < crcSize; x++)
{
crcTable[messageSize + x] = Long.rotateLeft(1, x);
}
}
StringBuilder row = new StringBuilder();
row.append( " " );
for( long value: values )
{
StringBuilder element = new StringBuilder();
element.append( "0x" );
element.append( Long.toHexString( value ).toUpperCase() );
if( !integerArray )
{
element.append( "l" );
}
element.append( ", " );
if( row.length() + element.length() <= 80 )
{
row.append( element.toString() );
}
else
{
sb.append( row.toString() );
sb.append( "\n" );
row = new StringBuilder();
row.append( " " );
row.append( element.toString() );
}
}
if( row.length() > 4 )
{
sb.append( row.toString() );
sb.append( "\n" );
}
sb.append( "};\n" );
return crcTable;
}
return sb.toString();
}
/**
* Generates the checksum table and treats the final bit of each check value
* as a parity bit that complies with the request parity argument.
*/
public static long[] generate(int messageSize,
int crcSize,
long polynomial,
long initialFill,
boolean includeCRCBitErrors,
Parity parity)
{
long[] table = generate(messageSize, crcSize, polynomial, initialFill,
includeCRCBitErrors);
if(parity == Parity.NONE)
{
return table;
}
else
{
for(int x = 0; x < table.length; x++)
{
table[x] <<= 1;
if(parity(table[x]) != parity)
{
table[x] ^= 0x1;
}
}
return table;
}
}
public enum Parity
{EVEN, ODD, NONE}
;
/* Determines the parity (number of 1 bits) for the value */
public static Parity parity(long value)
{
return Long.bitCount(value) % 2 == 0 ? Parity.EVEN : Parity.ODD;
}
/**
* Performs binary division of the polynomial into the message for bits
* in index 0 to index messageLength - 1, leaving the results in the
* checksum filed following the message.
*
* IN: MMMMMMMMMMMMMMMMCCCCCCCCCCC
* OUT: 0000000000000000RRRRRRRRRRR
*
* M: Message
* C: Checksum
* R: Remainder
*
* @param message - message and crc
* @param polynomial - crc polynomial - must be 1 bit longer than the crc width
* @param messageSize - message length and start of the checksum
* @return message with all message bits zeroed out, and the remainder
* placed in the crc field which starts at index messageLength
*/
public static BinaryMessage decode(BinaryMessage message,
int messageStart,
int messageSize,
long polynomial,
int crcSize)
{
for(int i = message.nextSetBit(messageStart);
i >= messageStart && i < messageSize;
i = message.nextSetBit(i + 1))
{
BinaryMessage polySet = new BinaryMessage(crcSize + i + 1);
polySet.load(i, crcSize + 1, polynomial);
message.xor(polySet);
System.out.println(message.toString());
}
return message;
}
public static String toCodeArray(long[] values)
{
boolean integerArray = true;
/* Determine the correct primitive type: int or long */
for(long value : values)
{
if(value > Integer.MAX_VALUE || value < Integer.MIN_VALUE)
{
integerArray = false;
break;
}
}
StringBuilder sb = new StringBuilder();
if(integerArray)
{
sb.append("\npublic static final int[] CHECKSUMS = new int[]\n");
}
else
{
sb.append("\npublic static final long[] CHECKSUMS = new long[]\n");
}
sb.append("{\n");
StringBuilder row = new StringBuilder();
row.append(" ");
for(long value : values)
{
StringBuilder element = new StringBuilder();
element.append("0x");
element.append(Long.toHexString(value).toUpperCase());
if(!integerArray)
{
element.append("l");
}
element.append(", ");
if(row.length() + element.length() <= 80)
{
row.append(element.toString());
}
else
{
sb.append(row.toString());
sb.append("\n");
row = new StringBuilder();
row.append(" ");
row.append(element.toString());
}
}
if(row.length() > 4)
{
sb.append(row.toString());
sb.append("\n");
}
sb.append("};\n");
return sb.toString();
}
public static void main(String[] args)
{
mLog.debug("Starting");
//DMR message
// String raw = "100110010001000000001001000000001111011011010000011001010000000000000000000000001100001000001011";
String raw = "101010000000000000110110100000101101011011010000011001111100000000000011100101001001111010001110";
mLog.debug(raw);
raw = "101010000000000000110110100000101101011011010000011001111100000000000011100101000000000000000000";
BinaryMessage message = BinaryMessage.load(raw);
mLog.debug(message.toString());
long polynomial = 0x11021l;
decode(message, 0, 80, polynomial, 16);
mLog.debug(message.toString());
mLog.debug("Finished");
}
}