Skip to content

Commit

Permalink
#1304 P25 Phase 1/2 decoder enhancements.
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Dennis Sheirer committed Apr 26, 2024
1 parent f5938fa commit 48c4a86
Show file tree
Hide file tree
Showing 430 changed files with 29,889 additions and 13,091 deletions.
1 change: 1 addition & 0 deletions .idea/dictionaries/denny.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 9 additions & 3 deletions src/main/java/io/github/dsheirer/alias/AliasList.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -663,11 +663,13 @@ public TalkgroupAliasList()

public Alias getAlias(TalkgroupIdentifier identifier)
{
//Attempt to do a fully qualified identifier match first.
if(identifier instanceof FullyQualifiedTalkgroupIdentifier fqti)
{
return mFullyQualifiedTalkgroupAliasMap.get(fqti.toString());
return mFullyQualifiedTalkgroupAliasMap.get(fqti.getFullyQualifiedTalkgroupAddress());
}

//Then try to match it by it's locally assigned (temporary) address.
int value = identifier.getValue();

Alias mapValue = mTalkgroupAliasMap.get(value);
Expand All @@ -676,6 +678,7 @@ public Alias getAlias(TalkgroupIdentifier identifier)
return mapValue;
}

//Finally, match the locally assigned address against any talkgroup ranges
for(Map.Entry<TalkgroupRange, Alias> entry : mTalkgroupRangeAliasMap.entrySet())
{
if(entry.getKey().contains(value))
Expand Down Expand Up @@ -780,11 +783,13 @@ public RadioAliasList()

public Alias getAlias(RadioIdentifier identifier)
{
//Attempt to do a fully qualified identifier match first.
if(identifier instanceof FullyQualifiedRadioIdentifier fqri)
{
return mFullyQualifiedRadioAliasMap.get(fqri.toString());
return mFullyQualifiedRadioAliasMap.get(fqri.getFullyQualifiedRadioAddress());
}

//Then match against the locally assigned (temporary) address
int value = identifier.getValue();

Alias mapValue = mRadioAliasMap.get(value);
Expand All @@ -793,6 +798,7 @@ public Alias getAlias(RadioIdentifier identifier)
return mapValue;
}

//Finally, attempt to match the locally assigned (temporary) address against any radio ranges.
for(Map.Entry<RadioRange, Alias> entry : mRadioRangeAliasMap.entrySet())
{
if(entry.getKey().contains(value))
Expand Down
211 changes: 210 additions & 1 deletion src/main/java/io/github/dsheirer/bits/BinaryMessage.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -451,6 +451,203 @@ public int getInt(int[] bits)
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
*
Expand Down Expand Up @@ -742,6 +939,18 @@ public String getHex(int start, int end)
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
Expand Down
35 changes: 16 additions & 19 deletions src/main/java/io/github/dsheirer/bits/CorrectedBinaryMessage.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 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/>
* * *****************************************************************************
* 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.bits;

Expand Down Expand Up @@ -84,9 +81,9 @@ public void incrementCorrectedBitCount(int additionalCount)
/**
* Returns a new binary message containing the bits from (inclusive) to end (exclusive).
*
* @param start bit
* @param end bit
* @return message
* @param start bit inclusive
* @param end bit exclusive
* @return message with sub message bits
*/
public CorrectedBinaryMessage getSubMessage(int start, int end)
{
Expand Down
45 changes: 45 additions & 0 deletions src/main/java/io/github/dsheirer/bits/FragmentedIntField.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* *****************************************************************************
* 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.bits;

/**
* Defines a fragmented or non-contiguous bit field within a binary message.
* @param indices for the bits in the field.
*/
public record FragmentedIntField(int... indices)
{
public FragmentedIntField
{
if(indices.length > 32)
{
throw new IllegalArgumentException("Integer field indices size [" + indices.length + "] cannot exceed 32-bits for an integer");
}
}

/**
* Utility constructor method.
* @param indices (inclusive)
* @return constructed fragmented integer field.
*/
public static FragmentedIntField of(int... indices)
{
return new FragmentedIntField(indices);
}
}

0 comments on commit 48c4a86

Please sign in to comment.