Skip to content

Commit f1dd26c

Browse files
author
Dennis Sheirer
committed
#1304 P25 Phase 1/2 decoder enhancements.
* 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
1 parent f5938fa commit f1dd26c

File tree

430 files changed

+29914
-13088
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

430 files changed

+29914
-13088
lines changed

.idea/dictionaries/denny.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/java/io/github/dsheirer/alias/AliasList.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* *****************************************************************************
3-
* Copyright (C) 2014-2023 Dennis Sheirer
3+
* Copyright (C) 2014-2024 Dennis Sheirer
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -663,11 +663,13 @@ public TalkgroupAliasList()
663663

664664
public Alias getAlias(TalkgroupIdentifier identifier)
665665
{
666+
//Attempt to do a fully qualified identifier match first.
666667
if(identifier instanceof FullyQualifiedTalkgroupIdentifier fqti)
667668
{
668-
return mFullyQualifiedTalkgroupAliasMap.get(fqti.toString());
669+
return mFullyQualifiedTalkgroupAliasMap.get(fqti.getFullyQualifiedTalkgroupAddress());
669670
}
670671

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

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

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

781784
public Alias getAlias(RadioIdentifier identifier)
782785
{
786+
//Attempt to do a fully qualified identifier match first.
783787
if(identifier instanceof FullyQualifiedRadioIdentifier fqri)
784788
{
785-
return mFullyQualifiedRadioAliasMap.get(fqri.toString());
789+
return mFullyQualifiedRadioAliasMap.get(fqri.getFullyQualifiedRadioAddress());
786790
}
787791

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

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

801+
//Finally, attempt to match the locally assigned (temporary) address against any radio ranges.
796802
for(Map.Entry<RadioRange, Alias> entry : mRadioRangeAliasMap.entrySet())
797803
{
798804
if(entry.getKey().contains(value))

src/main/java/io/github/dsheirer/bits/BinaryMessage.java

Lines changed: 210 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* *****************************************************************************
3-
* Copyright (C) 2014-2023 Dennis Sheirer
3+
* Copyright (C) 2014-2024 Dennis Sheirer
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -451,6 +451,203 @@ public int getInt(int[] bits)
451451
return value;
452452
}
453453

454+
/**
455+
* Returns the integer value of the message field described by the field argument.
456+
* @param intField with start and end indices (inclusive).
457+
* @return integer field value.
458+
*/
459+
public int getInt(IntField intField)
460+
{
461+
int value = 0;
462+
463+
for(int index = intField.start(); index <= intField.end(); index++)
464+
{
465+
value = Integer.rotateLeft(value, 1);
466+
467+
if(get(index))
468+
{
469+
value++;
470+
}
471+
}
472+
473+
return value;
474+
}
475+
476+
/**
477+
* Returns the integer value of the message field described by the field argument.
478+
* @param fragmentedField with an array of message indices
479+
* @return integer field value.
480+
*/
481+
public int getInt(FragmentedIntField fragmentedField)
482+
{
483+
int value = 0;
484+
485+
for(int index: fragmentedField.indices())
486+
{
487+
value = Integer.rotateLeft(value, 1);
488+
489+
if(get(index))
490+
{
491+
value++;
492+
}
493+
}
494+
495+
return value;
496+
}
497+
498+
/**
499+
* Indicates if the message field contains a non-zero value indicated by any bits set in the int field indices.
500+
* @param intField to inspect
501+
* @return true if any of the bits are set, indicating a non-zero value.
502+
*/
503+
public boolean hasInt(IntField intField)
504+
{
505+
return nextSetBit(intField.start()) <= intField.end();
506+
}
507+
508+
/**
509+
* Indicates if the message field contains a non-zero value indicated by any bits set in the int field indices.
510+
* @param intField to inspect
511+
* @return true if any of the bits are set, indicating a non-zero value.
512+
*/
513+
public boolean hasInt(FragmentedIntField fragmentedField)
514+
{
515+
for(int index: fragmentedField.indices())
516+
{
517+
if(get(index))
518+
{
519+
return true;
520+
}
521+
}
522+
523+
return false;
524+
}
525+
526+
/**
527+
* Returns the integer value of the message field described by the field argument where the message start index is
528+
* offset within this binary message.
529+
* @param intField with start and end indices (inclusive).
530+
* @param offset to the start of the first message index.
531+
* @return integer field value.
532+
*/
533+
public int getInt(IntField intField, int offset)
534+
{
535+
int value = 0;
536+
537+
for(int index = intField.start() + offset; index <= intField.end() + offset; index++)
538+
{
539+
value = Integer.rotateLeft(value, 1);
540+
541+
if(get(index))
542+
{
543+
value++;
544+
}
545+
}
546+
547+
return value;
548+
}
549+
550+
/**
551+
* Returns the integer value of the message field described by the field argument where the message start index is
552+
* offset within this binary message.
553+
* @param fragmentedField with an array of field indices
554+
* @param offset to the start of the first message index.
555+
* @return integer field value.
556+
*/
557+
public int getInt(FragmentedIntField fragmentedField, int offset)
558+
{
559+
int value = 0;
560+
561+
for(int index: fragmentedField.indices())
562+
{
563+
value = Integer.rotateLeft(value, 1);
564+
565+
if(get(index + offset))
566+
{
567+
value++;
568+
}
569+
}
570+
571+
return value;
572+
}
573+
574+
/**
575+
* Indicates if the message field contains a non-zero value indicated by any bits set in the int field indices.
576+
* @param intField to inspect
577+
* @param offset to the first bit of the message.
578+
* @return true if any of the bits are set, indicating a non-zero value.
579+
*/
580+
public boolean hasInt(IntField intField, int offset)
581+
{
582+
return nextSetBit(intField.start() + offset) <= (intField.end() + offset);
583+
}
584+
585+
/**
586+
* Indicates if the message field contains a non-zero value indicated by any bits set in the int field indices.
587+
* @param intField to inspect
588+
* @param offset to the first bit of the message.
589+
* @return true if any of the bits are set, indicating a non-zero value.
590+
*/
591+
public boolean hasInt(FragmentedIntField fragmentedField, int offset)
592+
{
593+
for(int index: fragmentedField.indices())
594+
{
595+
if(get(index + offset))
596+
{
597+
return true;
598+
}
599+
}
600+
601+
return false;
602+
}
603+
604+
/**
605+
* Returns the long value of the message field described by the field argument.
606+
* @param intField with start and end indices (inclusive).
607+
* @return integer field value.
608+
*/
609+
public long getLong(LongField intField)
610+
{
611+
long value = 0;
612+
613+
for(int index = intField.start(); index <= intField.end(); index++)
614+
{
615+
value = Long.rotateLeft(value, 1);
616+
617+
if(get(index))
618+
{
619+
value++;
620+
}
621+
}
622+
623+
return value;
624+
}
625+
626+
/**
627+
* Returns the long value of the message field described by the field argument where the message start index is
628+
* offset within this binary message.
629+
* @param intField with start and end indices (inclusive).
630+
* @param offset to the start of the first message index.
631+
* @return field value.
632+
*/
633+
public long getLong(LongField intField, int offset)
634+
{
635+
long value = 0;
636+
637+
for(int index = intField.start() + offset; index <= intField.end() + offset; index++)
638+
{
639+
value = Long.rotateLeft(value, 1);
640+
641+
if(get(index))
642+
{
643+
value++;
644+
}
645+
}
646+
647+
return value;
648+
}
649+
650+
454651
/**
455652
* Returns the integer value represented by the bit array
456653
*
@@ -742,6 +939,18 @@ public String getHex(int start, int end)
742939
return sb.toString();
743940
}
744941

942+
/**
943+
* Returns the integer field formatted as a hex value using zero prefixes to pad the hex character count to fully
944+
* represent the size (width) of the field.
945+
* @param field to parse as hex
946+
* @return hex value.
947+
*/
948+
public String getHex(IntField field)
949+
{
950+
int width = Math.ceilDiv(field.width(), 4);
951+
return String.format("%0" + width + "X", getInt(field));
952+
}
953+
745954
/**
746955
* Format the byte value that starts at the specified index as hexadecimal. If the length of the message is less
747956
* than the start index plus 7 bits, then the value represents those bits as high-order bits with zero padding in

src/main/java/io/github/dsheirer/bits/CorrectedBinaryMessage.java

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11
/*
2+
* *****************************************************************************
3+
* Copyright (C) 2014-2024 Dennis Sheirer
24
*
3-
* * ******************************************************************************
4-
* * Copyright (C) 2014-2019 Dennis Sheirer
5-
* *
6-
* * This program is free software: you can redistribute it and/or modify
7-
* * it under the terms of the GNU General Public License as published by
8-
* * the Free Software Foundation, either version 3 of the License, or
9-
* * (at your option) any later version.
10-
* *
11-
* * This program is distributed in the hope that it will be useful,
12-
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
13-
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14-
* * GNU General Public License for more details.
15-
* *
16-
* * You should have received a copy of the GNU General Public License
17-
* * along with this program. If not, see <http://www.gnu.org/licenses/>
18-
* * *****************************************************************************
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
199
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
2014
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>
17+
* ****************************************************************************
2118
*/
2219
package io.github.dsheirer.bits;
2320

@@ -84,9 +81,9 @@ public void incrementCorrectedBitCount(int additionalCount)
8481
/**
8582
* Returns a new binary message containing the bits from (inclusive) to end (exclusive).
8683
*
87-
* @param start bit
88-
* @param end bit
89-
* @return message
84+
* @param start bit inclusive
85+
* @param end bit exclusive
86+
* @return message with sub message bits
9087
*/
9188
public CorrectedBinaryMessage getSubMessage(int start, int end)
9289
{
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* *****************************************************************************
3+
* Copyright (C) 2014-2024 Dennis Sheirer
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>
17+
* ****************************************************************************
18+
*/
19+
20+
package io.github.dsheirer.bits;
21+
22+
/**
23+
* Defines a fragmented or non-contiguous bit field within a binary message.
24+
* @param indices for the bits in the field.
25+
*/
26+
public record FragmentedIntField(int... indices)
27+
{
28+
public FragmentedIntField
29+
{
30+
if(indices.length > 32)
31+
{
32+
throw new IllegalArgumentException("Integer field indices size [" + indices.length + "] cannot exceed 32-bits for an integer");
33+
}
34+
}
35+
36+
/**
37+
* Utility constructor method.
38+
* @param indices (inclusive)
39+
* @return constructed fragmented integer field.
40+
*/
41+
public static FragmentedIntField of(int... indices)
42+
{
43+
return new FragmentedIntField(indices);
44+
}
45+
}

0 commit comments

Comments
 (0)