mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
* P25 Phase 2 now supports control channel decoding and decoder was enhanced to improve decodes. * Radio reference site editor updated for phase 2 sites to allow user to select FDMA or TDMA control. * Decode events are now minimized and de-duplicated. * Fully parsing all phase 1/2 messages from the latest ICD. * Vendor specific messaging recoveries (Moto & Harris). * Patch group management enhancements with stale patch detection. * Tuner editor now fully resets the min/max frequency values * Default traffic channel count increased to 20 (from 3). * ISSI roaming radio and talkgroup values now displayed and aliasable as fully qualified values (e.g. 1234(123.456.7890) * Moto emergency alarm activation messaging support * Expanded list of P25 encryption algorithms * Message (bits) viewer enhanced for P25 phase 1 and phase 2 * IPV4 addresses and UDP ports no longer classified as user values - won't display in event views. * New framework for describing message binary fields that should reduce overall memory footprint and enhance code readability Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2023 Dennis Sheirer
|
||||
* Copyright (C) 2014-2024 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
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
package io.github.dsheirer.edac;
|
||||
|
||||
import io.github.dsheirer.log.LoggingSuppressor;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
import org.slf4j.Logger;
|
||||
@@ -32,6 +33,7 @@ import org.slf4j.LoggerFactory;
|
||||
public class BerlekempMassey
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(BerlekempMassey.class);
|
||||
private static final LoggingSuppressor LOGGING_SUPPRESSOR = new LoggingSuppressor(mLog);
|
||||
|
||||
/* Golay field size GF( 2 ** MM ) */
|
||||
private int MM;
|
||||
@@ -234,7 +236,16 @@ public class BerlekempMassey
|
||||
/* put recd[i] into index form (ie as powers of alpha) */
|
||||
for(int i = 0; i < NN; i++)
|
||||
{
|
||||
output[i] = index_of[input[i]];
|
||||
try
|
||||
{
|
||||
output[i] = index_of[input[i]];
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOGGING_SUPPRESSOR.error(getClass().toString(), 2, "Reed Solomon Decoder error for " +
|
||||
"class [" + getClass() + "] there may be an issue with the message parser class indices - " +
|
||||
"ensure the hex bit values are not larger 63", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* first form the syndromes */
|
||||
|
||||
285
src/main/java/io/github/dsheirer/edac/Binary40_9_16.java
Normal file
285
src/main/java/io/github/dsheirer/edac/Binary40_9_16.java
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 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/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.edac;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.IntField;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* P25 Phase 2 Binary (40, 9, 16) Code for IISCH in the Super Frame Fragment.
|
||||
*/
|
||||
public class Binary40_9_16
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(Binary40_9_16.class);
|
||||
private static final long[] CHECKSUMS = {0x8816CE36D7l, 0x201DFD4F64l, 0x100F4B1758l, 0x0C00DED18El, 0x020807F7FFl,
|
||||
0x09048D9B72l, 0x009DA3A171l, 0x0058CBAA4El, 0x00343D8597l};
|
||||
private static final long CODE_WORD_OFFSET = 0x184229d461l;
|
||||
private static final Map<Long,BinaryMessage> CODEWORD_MAP_TS1 = new TreeMap<>();
|
||||
private static final Map<Long,BinaryMessage> CODEWORD_MAP_TS2 = new TreeMap<>();
|
||||
private static final IntField CHANNEL_NUMBER = IntField.range(2, 3);
|
||||
private static final IntField ISCH_LOCATION = IntField.range(4, 5);
|
||||
private static final IntField WORD = IntField.range(0, 8);
|
||||
|
||||
public Binary40_9_16()
|
||||
{
|
||||
for(int x = 0; x < 512; x++)
|
||||
{
|
||||
BinaryMessage message = new BinaryMessage(9);
|
||||
message.load(0, 9, x);
|
||||
|
||||
int channelNumber = message.getInt(CHANNEL_NUMBER) + 1;
|
||||
int ischLocation = message.getInt(ISCH_LOCATION);
|
||||
|
||||
long codeword = getCodeWord(message);
|
||||
codeword ^= CODE_WORD_OFFSET;
|
||||
|
||||
if(ischLocation != 3)
|
||||
{
|
||||
if(channelNumber == 1)
|
||||
{
|
||||
CODEWORD_MAP_TS1.put(codeword, message);
|
||||
}
|
||||
else if(channelNumber == 2)
|
||||
{
|
||||
CODEWORD_MAP_TS2.put(codeword, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Long> keys = new ArrayList<>(CODEWORD_MAP_TS1.keySet());
|
||||
Collections.sort(keys);
|
||||
for(Long key: keys)
|
||||
{
|
||||
BinaryMessage message = CODEWORD_MAP_TS1.get(key);
|
||||
int distance = getDistance(key, keys);
|
||||
}
|
||||
List<Long> keys2 = new ArrayList<>(CODEWORD_MAP_TS2.keySet());
|
||||
Collections.sort(keys2);
|
||||
for(Long key: keys2)
|
||||
{
|
||||
BinaryMessage message = CODEWORD_MAP_TS2.get(key);
|
||||
int distance = getDistance(key, keys);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the closest distance between the value and the values in the value set.
|
||||
* @param value to test
|
||||
* @param valueSet to test against
|
||||
* @return closest distance of the value to the values in the value set, ignoring any equivalent values.
|
||||
*/
|
||||
public static int getDistance(long value, List<Long> valueSet)
|
||||
{
|
||||
int distance = 40;
|
||||
|
||||
for(Long candidate: valueSet)
|
||||
{
|
||||
if(candidate != value)
|
||||
{
|
||||
long syndrome = candidate ^ value;
|
||||
int candidateDistance = Long.bitCount(syndrome);
|
||||
if(candidateDistance < distance)
|
||||
{
|
||||
distance = candidateDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a codeword from the binary message where each set bit in the binary message corresponds to one of the
|
||||
* words in the generator and we XOR the words together.
|
||||
* @param message for generating a codeword
|
||||
* @return codeword
|
||||
*/
|
||||
public static long getCodeWord(BinaryMessage message)
|
||||
{
|
||||
long codeword = 0;
|
||||
|
||||
for(int x = 0; x < message.length(); x++)
|
||||
{
|
||||
if(message.get(x))
|
||||
{
|
||||
codeword ^= CHECKSUMS[x];
|
||||
}
|
||||
}
|
||||
|
||||
return codeword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the checksum (ie codeword) from the set bits in the message.
|
||||
* @param message with set bits, 0-8
|
||||
* @return
|
||||
*/
|
||||
private static long calculateChecksum(BinaryMessage message)
|
||||
{
|
||||
long calculated = 0; //Starting value
|
||||
|
||||
/* Iterate the set bits and XOR running checksum with lookup value */
|
||||
for(int i = message.nextSetBit(0); i < 9; i = message.nextSetBit(i + 1))
|
||||
{
|
||||
calculated ^= CHECKSUMS[i];
|
||||
}
|
||||
|
||||
return calculated;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Performs error detection and returns a corrected copy of the 24-bit
|
||||
// * message that starts at the start index.
|
||||
// *
|
||||
// * @param message - source message containing startIndex + 24 bits length
|
||||
// * @return - corrected 24-bit galois value
|
||||
// */
|
||||
// public static int checkAndCorrect(CorrectedBinaryMessage message)
|
||||
// {
|
||||
// boolean parityError = message.cardinality() % 2 != 0;
|
||||
//
|
||||
// long syndrome = getSyndrome(message);
|
||||
//
|
||||
// /* No errors */
|
||||
// if(syndrome == 0)
|
||||
// {
|
||||
// if(parityError)
|
||||
// {
|
||||
// message.flip(23);
|
||||
// message.incrementCorrectedBitCount(1);
|
||||
// return 1;
|
||||
// }
|
||||
//
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// /* Get original message value */
|
||||
// int original = message.getInt(0, 22);
|
||||
//
|
||||
// int index = -1;
|
||||
// int syndromeWeight = 3;
|
||||
// int errors = 0;
|
||||
//
|
||||
// while(index < 23)
|
||||
// {
|
||||
// if(index != -1)
|
||||
// {
|
||||
// /* restore the previous flipped bit */
|
||||
// if(index > 0)
|
||||
// {
|
||||
// message.flip(index - 1);
|
||||
// }
|
||||
//
|
||||
// message.flip(index);
|
||||
//
|
||||
// syndromeWeight = 2;
|
||||
// }
|
||||
//
|
||||
// syndrome = getSyndrome(message);
|
||||
//
|
||||
// if(syndrome > 0)
|
||||
// {
|
||||
// for(int i = 0; i < 23; i++)
|
||||
// {
|
||||
//
|
||||
// errors = Long.bitCount(syndrome);
|
||||
//
|
||||
// if(errors <= syndromeWeight)
|
||||
// {
|
||||
// message.xor(12, 11, syndrome);
|
||||
//
|
||||
// message.rotateRight(i, 0, 22);
|
||||
//
|
||||
// if(index >= 0)
|
||||
// {
|
||||
// errors++;
|
||||
// }
|
||||
//
|
||||
// int corrected = message.getInt(0, 22);
|
||||
//
|
||||
// if(Integer.bitCount(original ^ corrected) > 3)
|
||||
// {
|
||||
// return 2;
|
||||
// }
|
||||
//
|
||||
// return 1;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// message.rotateLeft(0, 22);
|
||||
// syndrome = getSyndrome(message);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// index++;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return 2;
|
||||
// }
|
||||
|
||||
private static long getSyndrome(BinaryMessage message)
|
||||
{
|
||||
long calculated = calculateChecksum(message);
|
||||
long checksum = message.getInt(12, 22);
|
||||
return (checksum ^ calculated);
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
// Binary40_9_16 edac = new Binary40_9_16();
|
||||
|
||||
long mask = 0xFFFFFFFFFFl;
|
||||
long sync = 0x575D57F7FFl;
|
||||
long syncLeft = Long.rotateLeft(sync, 2) & mask;
|
||||
long syncRight = Long.rotateRight(sync, 2) & mask;
|
||||
System.out.println("Mask: " + Long.toBinaryString(sync));
|
||||
System.out.println("Left: " + Long.toBinaryString(syncLeft));
|
||||
System.out.println("Right: " + Long.toBinaryString(syncRight));
|
||||
|
||||
int distanceLeft = Long.bitCount(sync ^ syncLeft);
|
||||
int distanceRight = Long.bitCount( sync ^ syncRight);
|
||||
|
||||
System.out.println("Left: " + distanceLeft);
|
||||
System.out.println("Right: " + distanceRight);
|
||||
|
||||
System.out.println("Finished!");
|
||||
|
||||
|
||||
// CorrectedBinaryMessage bm = new CorrectedBinaryMessage(BinaryMessage.loadHex("F3BB20"));
|
||||
// CorrectedBinaryMessage bm = new CorrectedBinaryMessage(BinaryMessage.loadHex("F0C5C0"));
|
||||
// CorrectedBinaryMessage bm = new CorrectedBinaryMessage(BinaryMessage.loadHex("AFAC00"));
|
||||
//
|
||||
// System.out.println("M:" + bm.toHexString());
|
||||
// int a = Binary40_9_16.checkAndCorrect(bm);
|
||||
// System.out.println("M:" + bm.toHexString());
|
||||
//
|
||||
// System.out.println("A:" + a);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,26 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2024 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 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.
|
||||
* 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/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.edac;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import java.util.Arrays;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -216,6 +220,63 @@ public class CRCP25
|
||||
0x20000000l, 0x40000000l, 0x80000000l
|
||||
};
|
||||
|
||||
/**
|
||||
* CRC-12 checksums for P25 Phase 2 MAC PDU Contents. This is used for a 144-bit message and 12-bits of checksum
|
||||
* using a polynomial of 0x1897 and generated by:
|
||||
* <p>
|
||||
* long[] checksums = CRCUtil.generate(144, 12, 0x1897l, 0x0l, false);
|
||||
*/
|
||||
private static int[] CRC_12_FACCH = new int[]{0x256, 0x12B, 0xCDE, 0x66F, 0xF7C, 0x7BE, 0x3DF, 0xDA4, 0x6D2, 0x369,
|
||||
0xDFF, 0xAB4, 0x55A, 0x2AD, 0xD1D, 0xAC5, 0x929, 0x8DF, 0x824, 0x412, 0x209, 0xD4F, 0xAEC, 0x576, 0x2BB,
|
||||
0xD16, 0x68B, 0xF0E, 0x787, 0xF88, 0x7C4, 0x3E2, 0x1F1, 0xCB3, 0xA12, 0x509, 0xECF, 0xB2C, 0x596, 0x2CB,
|
||||
0xD2E, 0x697, 0xF00, 0x780, 0x3C0, 0x1E0, 0xF0, 0x78, 0x3C, 0x1E, 0xF, 0xC4C, 0x626, 0x313, 0xDC2, 0x6E1,
|
||||
0xF3B, 0xBD6, 0x5EB, 0xEBE, 0x75F, 0xFE4, 0x7F2, 0x3F9, 0xDB7, 0xA90, 0x548, 0x2A4, 0x152, 0xA9, 0xC1F,
|
||||
0xA44, 0x522, 0x291, 0xD03, 0xACA, 0x565, 0xEF9, 0xB37, 0x9D0, 0x4E8, 0x274, 0x13A, 0x9D, 0xC05, 0xA49,
|
||||
0x96F, 0x8FC, 0x47E, 0x23F, 0xD54, 0x6AA, 0x355, 0xDE1, 0xABB, 0x916, 0x48B, 0xE0E, 0x707, 0xFC8, 0x7E4,
|
||||
0x3F2, 0x1F9, 0xCB7, 0xA10, 0x508, 0x284, 0x142, 0xA1, 0xC1B, 0xA46, 0x523, 0xEDA, 0x76D, 0xFFD, 0xBB5,
|
||||
0x991, 0x883, 0x80A, 0x405, 0xE49, 0xB6F, 0x9FC, 0x4FE, 0x27F, 0xD74, 0x6BA, 0x35D, 0xDE5, 0xAB9, 0x917,
|
||||
0x8C0, 0x460, 0x230, 0x118, 0x8C, 0x46, 0x23, 0xC5A, 0x62D, 0xF5D, 0xBE5, 0x9B9, 0x897};
|
||||
|
||||
/**
|
||||
* CRC-12 checksums for P25 Phase 2 MAC PDU Contents. This is used for a 168-bit message and 12-bits of checksum
|
||||
* using a polynomial of 0x1897 and generated by:
|
||||
* <p>
|
||||
* long[] checksums = CRCUtil.generate(168, 12, 0x1897l, 0x0l, false);
|
||||
*/
|
||||
private static int[] CRC_12_SACCH = new int[]{0x47B, 0xE76, 0x73B, 0xFD6, 0x7EB, 0xFBE, 0x7DF, 0xFA4, 0x7D2, 0x3E9,
|
||||
0xDBF, 0xA94, 0x54A, 0x2A5, 0xD19, 0xAC7, 0x928, 0x494, 0x24A, 0x125, 0xCD9, 0xA27, 0x958, 0x4AC, 0x256,
|
||||
0x12B, 0xCDE, 0x66F, 0xF7C, 0x7BE, 0x3DF, 0xDA4, 0x6D2, 0x369, 0xDFF, 0xAB4, 0x55A, 0x2AD, 0xD1D, 0xAC5,
|
||||
0x929, 0x8DF, 0x824, 0x412, 0x209, 0xD4F, 0xAEC, 0x576, 0x2BB, 0xD16, 0x68B, 0xF0E, 0x787, 0xF88, 0x7C4,
|
||||
0x3E2, 0x1F1, 0xCB3, 0xA12, 0x509, 0xECF, 0xB2C, 0x596, 0x2CB, 0xD2E, 0x697, 0xF00, 0x780, 0x3C0, 0x1E0,
|
||||
0xF0, 0x78, 0x3C, 0x1E, 0xF, 0xC4C, 0x626, 0x313, 0xDC2, 0x6E1, 0xF3B, 0xBD6, 0x5EB, 0xEBE, 0x75F, 0xFE4,
|
||||
0x7F2, 0x3F9, 0xDB7, 0xA90, 0x548, 0x2A4, 0x152, 0xA9, 0xC1F, 0xA44, 0x522, 0x291, 0xD03, 0xACA, 0x565,
|
||||
0xEF9, 0xB37, 0x9D0, 0x4E8, 0x274, 0x13A, 0x9D, 0xC05, 0xA49, 0x96F, 0x8FC, 0x47E, 0x23F, 0xD54, 0x6AA,
|
||||
0x355, 0xDE1, 0xABB, 0x916, 0x48B, 0xE0E, 0x707, 0xFC8, 0x7E4, 0x3F2, 0x1F9, 0xCB7, 0xA10, 0x508, 0x284,
|
||||
0x142, 0xA1, 0xC1B, 0xA46, 0x523, 0xEDA, 0x76D, 0xFFD, 0xBB5, 0x991, 0x883, 0x80A, 0x405, 0xE49, 0xB6F,
|
||||
0x9FC, 0x4FE, 0x27F, 0xD74, 0x6BA, 0x35D, 0xDE5, 0xAB9, 0x917, 0x8C0, 0x460, 0x230, 0x118, 0x8C, 0x46, 0x23,
|
||||
0xC5A, 0x62D, 0xF5D, 0xBE5, 0x9B9, 0x897,};
|
||||
|
||||
/**
|
||||
* CRC-16 checksums for P25 Phase 2 LCCH MAC PDU Contents. This is used for a 164-bit message and 16-bits of
|
||||
* checksum using a polynomial of 0x11021 and generated by:
|
||||
* <p>
|
||||
* long[] checksums = CRCUtil.generate(164, 16, 0x11021l, 0x0l, true);
|
||||
*/
|
||||
private static int[] CRC_16_LCCH = new int[]{0xCF76, 0x67BB, 0xBBCD, 0xD5F6, 0x6AFB, 0xBD6D, 0xD6A6, 0x6B53, 0xBDB9,
|
||||
0xD6CC, 0x6B66, 0x35B3, 0x92C9, 0xC174, 0x60BA, 0x305D, 0x903E, 0x481F, 0xAC1F, 0xDE1F, 0xE71F, 0xFB9F,
|
||||
0xF5DF, 0xF2FF, 0xF16F, 0xF0A7, 0xF043, 0xF031, 0xF008, 0x7804, 0x3C02, 0x1E01, 0x8710, 0x4388, 0x21C4,
|
||||
0x10E2, 0x871, 0x8C28, 0x4614, 0x230A, 0x1185, 0x80D2, 0x4069, 0xA824, 0x5412, 0x2A09, 0x9D14, 0x4E8A,
|
||||
0x2745, 0x9BB2, 0x4DD9, 0xAEFC, 0x577E, 0x2BBF, 0x9DCF, 0xC6F7, 0xEB6B, 0xFDA5, 0xF6C2, 0x7B61, 0xB5A0,
|
||||
0x5AD0, 0x2D68, 0x16B4, 0xB5A, 0x5AD, 0x8AC6, 0x4563, 0xAAA1, 0xDD40, 0x6EA0, 0x3750, 0x1BA8, 0xDD4, 0x6EA,
|
||||
0x375, 0x89AA, 0x44D5, 0xAA7A, 0x553D, 0xA28E, 0x5147, 0xA0B3, 0xD849, 0xE434, 0x721A, 0x390D, 0x9496,
|
||||
0x4A4B, 0xAD35, 0xDE8A, 0x6F45, 0xBFB2, 0x5FD9, 0xA7FC, 0x53FE, 0x29FF, 0x9CEF, 0xC667, 0xEB23, 0xFD81,
|
||||
0xF6D0, 0x7B68, 0x3DB4, 0x1EDA, 0xF6D, 0x8FA6, 0x47D3, 0xABF9, 0xDDEC, 0x6EF6, 0x377B, 0x93AD, 0xC1C6,
|
||||
0x60E3, 0xB861, 0xD420, 0x6A10, 0x3508, 0x1A84, 0xD42, 0x6A1, 0x8B40, 0x45A0, 0x22D0, 0x1168, 0x8B4, 0x45A,
|
||||
0x22D, 0x8906, 0x4483, 0xAA51, 0xDD38, 0x6E9C, 0x374E, 0x1BA7, 0x85C3, 0xCAF1, 0xED68, 0x76B4, 0x3B5A,
|
||||
0x1DAD, 0x86C6, 0x4363, 0xA9A1, 0xDCC0, 0x6E60, 0x3730, 0x1B98, 0xDCC, 0x6E6, 0x373, 0x89A9, 0xCCC4, 0x6662,
|
||||
0x3331, 0x9188, 0x48C4, 0x2462, 0x1231, 0x8108, 0x4084, 0x2042, 0x1021, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20,
|
||||
0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000};
|
||||
|
||||
/**
|
||||
* Performs error detection and single-bit error correction against the
|
||||
* data blocks of a PDU1 message.
|
||||
@@ -402,11 +463,8 @@ public class CRCP25
|
||||
}
|
||||
|
||||
int checksum = message.getInt(messageStart + 7, messageStart + 15);
|
||||
|
||||
int residual = calculated ^ checksum;
|
||||
|
||||
// mLog.debug( "CALC:" + calculated + " CHECK:" + checksum + " RESID:" + residual );
|
||||
|
||||
if(residual == 0 || residual == 0x1FF)
|
||||
{
|
||||
return CRC.PASSED;
|
||||
@@ -441,12 +499,80 @@ public class CRCP25
|
||||
return passes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the CRC-12 checksum for the P25 Phase 2 MAC PDU Contents for S-OEMI/FACCH and compares it to the
|
||||
* transmitted checksum to verify that the message is correct.
|
||||
* Note: this uses the pre-calculated checksums in the CRC_12_FACCH array.
|
||||
*
|
||||
* @param message to verify
|
||||
* @return true if the message passes the CRC-12 check.
|
||||
*/
|
||||
public static boolean crc12_FACCH(CorrectedBinaryMessage message)
|
||||
{
|
||||
int calculated = 0xFFF; //Initial fill of all ones.
|
||||
|
||||
//Iterate the set bits and XOR the running checksum with pre-calculated lookup value
|
||||
for(int i = message.nextSetBit(0); i >= 0 && i < 144; i = message.nextSetBit(i + 1))
|
||||
{
|
||||
calculated ^= CRC_12_FACCH[i];
|
||||
}
|
||||
|
||||
int checksum = message.getInt(144, 155); //12-bit transmitted checksum
|
||||
int residual = calculated ^ checksum;
|
||||
return residual == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the CRC-12 checksum for the P25 Phase 2 MAC PDU Contents for I-OEMI/SACCH and compares it to the
|
||||
* transmitted checksum to verify that the message is correct.
|
||||
* Note: this uses the pre-calculated checksums in the CRC_12_SACCH array.
|
||||
*
|
||||
* @param message to verify
|
||||
* @return true if the message passes the CRC-12 check.
|
||||
*/
|
||||
public static boolean crc12_SACCH(CorrectedBinaryMessage message)
|
||||
{
|
||||
int calculated = 0xFFF; //Initial fill of all ones.
|
||||
|
||||
//Iterate the set bits and XOR the running checksum with pre-calculated lookup value
|
||||
for(int i = message.nextSetBit(0); i >= 0 && i < 168; i = message.nextSetBit(i + 1))
|
||||
{
|
||||
calculated ^= CRC_12_SACCH[i];
|
||||
}
|
||||
|
||||
int checksum = message.getInt(168, 179); //12-bit transmitted checksum
|
||||
int residual = calculated ^ checksum;
|
||||
return residual == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the CRC-16 checksum for the P25 Phase 2 MAC PDU Contents for I-OECI/LCCH and compares it to the
|
||||
* transmitted checksum to verify that the message is correct.
|
||||
* Note: this uses the pre-calculated checksums in the CRC_16_LCCH array.
|
||||
*
|
||||
* @param message to verify
|
||||
* @return true if the message passes the CRC-16 check.
|
||||
*/
|
||||
public static boolean crc16_LCCH(CorrectedBinaryMessage message)
|
||||
{
|
||||
int calculated = 0xFFFF; //Initial fill of all ones.
|
||||
|
||||
//Iterate the set bits and XOR the running checksum with pre-calculated lookup value
|
||||
for(int i = message.nextSetBit(0); i >= 0 && i < 164; i = message.nextSetBit(i + 1))
|
||||
{
|
||||
calculated ^= CRC_16_LCCH[i];
|
||||
}
|
||||
|
||||
int checksum = message.getInt(164, 179); //16-bit transmitted checksum
|
||||
int residual = calculated ^ checksum;
|
||||
return residual == 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the value of the message checksum as a long
|
||||
*/
|
||||
public static long getLongChecksum(BinaryMessage message,
|
||||
int crcStart, int crcLength)
|
||||
public static long getLongChecksum(BinaryMessage message, int crcStart, int crcLength)
|
||||
{
|
||||
return message.getLong(crcStart, crcStart + crcLength - 1);
|
||||
}
|
||||
@@ -454,8 +580,7 @@ public class CRCP25
|
||||
/**
|
||||
* Calculates the value of the message checksum as an integer
|
||||
*/
|
||||
public static int getIntChecksum(BinaryMessage message,
|
||||
int crcStart, int crcLength)
|
||||
public static int getIntChecksum(BinaryMessage message, int crcStart, int crcLength)
|
||||
{
|
||||
return message.getInt(crcStart, crcStart + crcLength - 1);
|
||||
}
|
||||
@@ -494,16 +619,19 @@ public class CRCP25
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
String raw = "000000001000001100000001010001111011000100001010010001111100000000000101000000000000000001000000000000110000000000000001101010101010101010101010";
|
||||
long[] checksums = CRCUtil.generate(144, 12, 0x1897l, 0x0l, false);
|
||||
System.out.println("Checksums:" + Arrays.toString(checksums));
|
||||
|
||||
BinaryMessage message = BinaryMessage.load(raw);
|
||||
String hex12 = "7C0000000000000000000000000000000000CA7";
|
||||
|
||||
mLog.debug("MSG:" + message.toString());
|
||||
|
||||
CRC results = checkCRC9(message, 0);
|
||||
|
||||
mLog.debug("COR:" + message.toString());
|
||||
|
||||
mLog.debug("Results: " + results.getDisplayText());
|
||||
// BinaryMessage message = BinaryMessage.load(raw);
|
||||
//
|
||||
// mLog.debug("MSG:" + message.toString());
|
||||
//
|
||||
// CRC results = checkCRC9(message, 0);
|
||||
//
|
||||
// mLog.debug("COR:" + message.toString());
|
||||
//
|
||||
// mLog.debug("Results: " + results.getDisplayText());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2023 Dennis Sheirer
|
||||
* Copyright (C) 2014-2024 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
|
||||
@@ -19,6 +19,7 @@
|
||||
package io.github.dsheirer.edac;
|
||||
|
||||
import io.github.dsheirer.bits.BinaryMessage;
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -32,8 +33,7 @@ public class CRCUtil
|
||||
long initialFill,
|
||||
boolean includeCRCBitErrors)
|
||||
{
|
||||
long[] crcTable = new long[messageSize +
|
||||
(includeCRCBitErrors ? crcSize : 0)];
|
||||
long[] crcTable = new long[messageSize + (includeCRCBitErrors ? crcSize : 0)];
|
||||
|
||||
int[] checksumIndexes = new int[crcSize];
|
||||
|
||||
@@ -132,20 +132,12 @@ public class CRCUtil
|
||||
* @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)
|
||||
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))
|
||||
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());
|
||||
}
|
||||
@@ -226,8 +218,11 @@ public class CRCUtil
|
||||
{
|
||||
mLog.debug("Starting");
|
||||
|
||||
long poly = 0x13l;
|
||||
long[] checksums = generate(32, 4, poly, 0, true);
|
||||
int messageSize = 164;
|
||||
int crcSize = 16;
|
||||
long poly = 0x11021l;
|
||||
long initialFill = 0x0l;
|
||||
long[] checksums = CRCUtil.generate(messageSize, crcSize, poly, initialFill, true);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("private static int[] CHECKSUMS = new int[]{");
|
||||
@@ -238,7 +233,29 @@ public class CRCUtil
|
||||
}
|
||||
|
||||
sb.append("};");
|
||||
|
||||
System.out.println("Checksums:\n" + sb);
|
||||
|
||||
String hex = "7CFC0039420170452A4F9970000000000000000000D05";
|
||||
CorrectedBinaryMessage message = new CorrectedBinaryMessage(BinaryMessage.loadHex(hex));
|
||||
|
||||
|
||||
int calculated = 0xFFF; //Initial fill of all ones
|
||||
|
||||
int messageStart = 0;
|
||||
/* Iterate the set bits and XOR running checksum with lookup value */
|
||||
for(int i = message.nextSetBit(messageStart);
|
||||
i >= messageStart && i < messageSize;
|
||||
i = message.nextSetBit(i + 1))
|
||||
{
|
||||
System.out.println("Bit [" + i + "] is set");
|
||||
calculated ^= checksums[i];
|
||||
}
|
||||
|
||||
int checksum = message.getInt(messageSize, messageSize + crcSize - 1);
|
||||
int residual = calculated ^ checksum;
|
||||
|
||||
mLog.debug("CALC:" + Integer.toHexString(calculated).toUpperCase() +
|
||||
" CHECK:" + Integer.toHexString(checksum).toUpperCase() +
|
||||
" RESIDUAL:" + Integer.toHexString(residual).toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user