#1304 P25 Phase 1/2 decoder enhancements. (#1898)

* 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:
Denny Sheirer
2024-04-26 13:55:17 -04:00
committed by GitHub
parent f5938fa8e2
commit 7e709d9d6f
430 changed files with 30098 additions and 13300 deletions

View File

@@ -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 */

View 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);
}
}

View File

@@ -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());
}
}

View File

@@ -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());
}
}