#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
@@ -451,6 +451,203 @@ public class BinaryMessage extends BitSet
return value;
}
/**
* Returns the integer value of the message field described by the field argument.
* @param intField with start and end indices (inclusive).
* @return integer field value.
*/
public int getInt(IntField intField)
{
int value = 0;
for(int index = intField.start(); index <= intField.end(); index++)
{
value = Integer.rotateLeft(value, 1);
if(get(index))
{
value++;
}
}
return value;
}
/**
* Returns the integer value of the message field described by the field argument.
* @param fragmentedField with an array of message indices
* @return integer field value.
*/
public int getInt(FragmentedIntField fragmentedField)
{
int value = 0;
for(int index: fragmentedField.indices())
{
value = Integer.rotateLeft(value, 1);
if(get(index))
{
value++;
}
}
return value;
}
/**
* Indicates if the message field contains a non-zero value indicated by any bits set in the int field indices.
* @param intField to inspect
* @return true if any of the bits are set, indicating a non-zero value.
*/
public boolean hasInt(IntField intField)
{
return nextSetBit(intField.start()) <= intField.end();
}
/**
* Indicates if the message field contains a non-zero value indicated by any bits set in the int field indices.
* @param intField to inspect
* @return true if any of the bits are set, indicating a non-zero value.
*/
public boolean hasInt(FragmentedIntField fragmentedField)
{
for(int index: fragmentedField.indices())
{
if(get(index))
{
return true;
}
}
return false;
}
/**
* Returns the integer value of the message field described by the field argument where the message start index is
* offset within this binary message.
* @param intField with start and end indices (inclusive).
* @param offset to the start of the first message index.
* @return integer field value.
*/
public int getInt(IntField intField, int offset)
{
int value = 0;
for(int index = intField.start() + offset; index <= intField.end() + offset; index++)
{
value = Integer.rotateLeft(value, 1);
if(get(index))
{
value++;
}
}
return value;
}
/**
* Returns the integer value of the message field described by the field argument where the message start index is
* offset within this binary message.
* @param fragmentedField with an array of field indices
* @param offset to the start of the first message index.
* @return integer field value.
*/
public int getInt(FragmentedIntField fragmentedField, int offset)
{
int value = 0;
for(int index: fragmentedField.indices())
{
value = Integer.rotateLeft(value, 1);
if(get(index + offset))
{
value++;
}
}
return value;
}
/**
* Indicates if the message field contains a non-zero value indicated by any bits set in the int field indices.
* @param intField to inspect
* @param offset to the first bit of the message.
* @return true if any of the bits are set, indicating a non-zero value.
*/
public boolean hasInt(IntField intField, int offset)
{
return nextSetBit(intField.start() + offset) <= (intField.end() + offset);
}
/**
* Indicates if the message field contains a non-zero value indicated by any bits set in the int field indices.
* @param intField to inspect
* @param offset to the first bit of the message.
* @return true if any of the bits are set, indicating a non-zero value.
*/
public boolean hasInt(FragmentedIntField fragmentedField, int offset)
{
for(int index: fragmentedField.indices())
{
if(get(index + offset))
{
return true;
}
}
return false;
}
/**
* Returns the long value of the message field described by the field argument.
* @param intField with start and end indices (inclusive).
* @return integer field value.
*/
public long getLong(LongField intField)
{
long value = 0;
for(int index = intField.start(); index <= intField.end(); index++)
{
value = Long.rotateLeft(value, 1);
if(get(index))
{
value++;
}
}
return value;
}
/**
* Returns the long value of the message field described by the field argument where the message start index is
* offset within this binary message.
* @param intField with start and end indices (inclusive).
* @param offset to the start of the first message index.
* @return field value.
*/
public long getLong(LongField intField, int offset)
{
long value = 0;
for(int index = intField.start() + offset; index <= intField.end() + offset; index++)
{
value = Long.rotateLeft(value, 1);
if(get(index))
{
value++;
}
}
return value;
}
/**
* Returns the integer value represented by the bit array
*
@@ -742,6 +939,18 @@ public class BinaryMessage extends BitSet
return sb.toString();
}
/**
* Returns the integer field formatted as a hex value using zero prefixes to pad the hex character count to fully
* represent the size (width) of the field.
* @param field to parse as hex
* @return hex value.
*/
public String getHex(IntField field)
{
int width = Math.ceilDiv(field.width(), 4);
return String.format("%0" + width + "X", getInt(field));
}
/**
* Format the byte value that starts at the specified index as hexadecimal. If the length of the message is less
* than the start index plus 7 bits, then the value represents those bits as high-order bits with zero padding in