Skip to content

Commit 4117357

Browse files
authored
Merge pull request #1622 from DSheirer/dmr-cap-plus-identifier-updates
#1618 DMR Decoder Message Enhancements
2 parents 227c88c + 2ffb296 commit 4117357

File tree

64 files changed

+2039
-684
lines changed

Some content is hidden

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

64 files changed

+2039
-684
lines changed

.idea/misc.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* *****************************************************************************
3+
* Copyright (C) 2014-2023 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.edac;
21+
22+
import io.github.dsheirer.bits.BinaryMessage;
23+
import io.github.dsheirer.bits.CorrectedBinaryMessage;
24+
25+
/**
26+
* Block Product Turbo Code 16/2 for decoding a DMR Voice Frame F payload from the 32-bit EMB field.
27+
* <p>
28+
* See ETSI TS 102 361-1 B.2.2.1 and B.2.2.2
29+
*/
30+
public class BPTC_16_2
31+
{
32+
private static final int[] DEINTERLEAVE = new int[]{0, 24, 1, 25, 2, 26, 3, 27, 4, 28, 5, 29, 6, 30, 7, 31, 8, 16,
33+
9, 17, 10, 18, 11, 19, 12, 20, 13, 21, 14, 22, 15, 23};
34+
35+
/**
36+
* Unscramble and perform FEC checks per paragraph B.2.2.1 for Non-Reverse Channel Single Burst
37+
*
38+
* @param message with 32 interleaved bits.
39+
* @return descrambled and error checked message or null if the process fails or there are too many errors.
40+
*/
41+
public static CorrectedBinaryMessage decodeShortBurst(CorrectedBinaryMessage message)
42+
{
43+
CorrectedBinaryMessage deinterleaved = deinterleave(message);
44+
int fec = Hamming16.checkAndCorrect(deinterleaved, 0);
45+
46+
if(fec == 2) //0 or 1 is good, 2 = uncorrectable errors
47+
{
48+
return null;
49+
}
50+
51+
//Check for even parity. Bits 0-15 should be the same as bits 16-31.
52+
for(int x = 0; x < 16; x++)
53+
{
54+
if(deinterleaved.get(x) ^ deinterleaved.get(x + 16))
55+
{
56+
return null;
57+
}
58+
}
59+
60+
return deinterleaved;
61+
}
62+
63+
/**
64+
* Unscramble and perform FEC checks per paragraph B.2.2.2 for Reverse Channel Single Burst
65+
*
66+
* @param binaryMessage with 32 interleaved bits.
67+
* @return descrambled and error checked message or null if the process fails or there are too many errors.
68+
*/
69+
public static CorrectedBinaryMessage decodeReverseChannel(CorrectedBinaryMessage message)
70+
{
71+
CorrectedBinaryMessage deinterleaved = deinterleave(message);
72+
System.out.println(" DEINTER: " + deinterleaved.toHexString());
73+
int fec = Hamming16.checkAndCorrect(deinterleaved, 0);
74+
System.out.println(" DECODED: " + deinterleaved.toHexString());
75+
System.out.println("FEC:" + fec);
76+
if(fec == 2) //0 or 1 is good, 2 = uncorrectable errors
77+
{
78+
return null;
79+
}
80+
81+
//Check for odd parity. Bits 0-15 should be opposite of bits 16-31.
82+
for(int x = 0; x < 16; x++)
83+
{
84+
if(deinterleaved.get(x) == deinterleaved.get(x + 16))
85+
{
86+
return null;
87+
}
88+
}
89+
90+
return deinterleaved;
91+
}
92+
93+
/**
94+
* Performs deinterleave of the interleaved message.
95+
*
96+
* @param original to deinterleave
97+
* @return deinterleaved message
98+
*/
99+
public static CorrectedBinaryMessage deinterleave(CorrectedBinaryMessage original)
100+
{
101+
CorrectedBinaryMessage delinterleaved = new CorrectedBinaryMessage(32);
102+
for(int x = 0; x < 32; x++)
103+
{
104+
if(original.get(x))
105+
{
106+
delinterleaved.set(DEINTERLEAVE[x]);
107+
}
108+
}
109+
110+
return delinterleaved;
111+
}
112+
113+
public static void main(String[] args)
114+
{
115+
String[] msgs = new String[]{"05030A03", "35003A00", "1C6D2C9E"};
116+
117+
for(String msg : msgs)
118+
{
119+
CorrectedBinaryMessage original = new CorrectedBinaryMessage(BinaryMessage.loadHex(msg));
120+
System.out.println("ORIGINAL: " + original.toHexString());
121+
CorrectedBinaryMessage decoded = decodeReverseChannel(original);
122+
System.out.println("-------------------------");
123+
}
124+
}
125+
}

src/main/java/io/github/dsheirer/edac/CRCUtil.java

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* *****************************************************************************
3-
* Copyright (C) 2014-2022 Dennis Sheirer
3+
* Copyright (C) 2014-2023 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
@@ -226,17 +226,19 @@ public static void main(String[] args)
226226
{
227227
mLog.debug("Starting");
228228

229-
//DMR message
230-
// String raw = "100110010001000000001001000000001111011011010000011001010000000000000000000000001100001000001011";
231-
String raw = "101010000000000000110110100000101101011011010000011001111100000000000011100101001001111010001110";
232-
mLog.debug(raw);
233-
raw = "101010000000000000110110100000101101011011010000011001111100000000000011100101000000000000000000";
234-
BinaryMessage message = BinaryMessage.load(raw);
235-
mLog.debug(message.toString());
236-
237-
long polynomial = 0x11021l;
238-
decode(message, 0, 80, polynomial, 16);
239-
mLog.debug(message.toString());
240-
mLog.debug("Finished");
229+
long poly = 0x13l;
230+
long[] checksums = generate(32, 4, poly, 0, true);
231+
232+
StringBuilder sb = new StringBuilder();
233+
sb.append("private static int[] CHECKSUMS = new int[]{");
234+
for(long checksum: checksums)
235+
{
236+
sb.append("0x").append(Long.toHexString(checksum).toUpperCase());
237+
sb.append(",");
238+
}
239+
240+
sb.append("};");
241+
242+
System.out.println("Checksums:\n" + sb);
241243
}
242244
}

src/main/java/io/github/dsheirer/edac/Golay24.java

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,29 @@
1+
/*
2+
* *****************************************************************************
3+
* Copyright (C) 2014-2023 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+
120
package io.github.dsheirer.edac;
221

322
import io.github.dsheirer.bits.BinaryMessage;
423
import io.github.dsheirer.bits.CorrectedBinaryMessage;
524
import org.slf4j.Logger;
625
import org.slf4j.LoggerFactory;
726

8-
/*******************************************************************************
9-
* SDR Trunk
10-
* Copyright (C) 2014 Dennis Sheirer
11-
*
12-
* This program is free software: you can redistribute it and/or modify
13-
* it under the terms of the GNU General Public License as published by
14-
* the Free Software Foundation, either version 3 of the License, or
15-
* (at your option) any later version.
16-
*
17-
* This program is distributed in the hope that it will be useful,
18-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20-
* GNU General Public License for more details.
21-
*
22-
* You should have received a copy of the GNU General Public License
23-
* along with this program. If not, see <http://www.gnu.org/licenses/>
24-
* -----------------------------------------------------------------------
25-
* Galois24 decoder based on Hank Wallace's tutorial/algorithm located at:
26-
* http://www.aqdi.com/golay.htm
27-
******************************************************************************/
28-
2927
/**
3028
* Galois 24/12/7 decoder
3129
*/
@@ -160,4 +158,17 @@ private static int getSyndrome(BinaryMessage message, int startIndex)
160158

161159
return (checksum ^ calculated);
162160
}
161+
162+
public static void main(String[] args)
163+
{
164+
// CorrectedBinaryMessage bm = new CorrectedBinaryMessage(BinaryMessage.loadHex("F3BB20"));
165+
// CorrectedBinaryMessage bm = new CorrectedBinaryMessage(BinaryMessage.loadHex("F0C5C0"));
166+
CorrectedBinaryMessage bm = new CorrectedBinaryMessage(BinaryMessage.loadHex("AFAC00"));
167+
168+
System.out.println("M:" + bm.toHexString());
169+
int a = Golay24.checkAndCorrect(bm, 0);
170+
System.out.println("M:" + bm.toHexString());
171+
172+
System.out.println("A:" + a);
173+
}
163174
}

src/main/java/io/github/dsheirer/gui/dmr/DMRRecordingViewer.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,12 @@ private TextField getFindText()
459459
if(mFindText == null)
460460
{
461461
mFindText = new TextField();
462+
mFindText.setOnKeyPressed(event -> {
463+
if(event.getCode().equals(KeyCode.ENTER))
464+
{
465+
getFindButton().fire();
466+
}
467+
});
462468
mFindText.textProperty().addListener((observable, oldValue, newValue) -> updateFilters());
463469
}
464470

src/main/java/io/github/dsheirer/module/decode/dmr/DMRDecoderState.java

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@
6565
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.hytera.HyteraGroupVoiceChannelUser;
6666
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.hytera.HyteraUnitToUnitVoiceChannelUser;
6767
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusEncryptedVoiceChannelUser;
68-
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusGroupVoiceChannelUser;
6968
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusWideAreaVoiceChannelUser;
69+
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.MotorolaGroupVoiceChannelUser;
7070
import io.github.dsheirer.module.decode.dmr.message.data.lc.shorty.CapacityPlusRestChannel;
7171
import io.github.dsheirer.module.decode.dmr.message.data.packet.DMRPacketMessage;
7272
import io.github.dsheirer.module.decode.dmr.message.data.packet.UDTShortMessageService;
@@ -646,12 +646,12 @@ private void processCSBK(CSBKMessage csbk)
646646
}
647647
else
648648
{
649-
DecodeEvent event = mDetectedCallEventsMap.get(channel.getLogicalSlotNumber());
649+
DecodeEvent event = mDetectedCallEventsMap.get(channel.getValue());
650650

651651
if(isStale(event, csbk.getTimestamp(), csbk.getIdentifiers()))
652652
{
653653
event = getDecodeEvent(csbk, DecodeEventType.DATA_CALL, channel, mergedIdentifiers);
654-
mDetectedCallEventsMap.put(channel.getLogicalSlotNumber(), event);
654+
mDetectedCallEventsMap.put(channel.getValue(), event);
655655
}
656656
else
657657
{
@@ -679,12 +679,12 @@ private void processCSBK(CSBKMessage csbk)
679679
}
680680
else
681681
{
682-
DecodeEvent event = mDetectedCallEventsMap.get(channel.getLogicalSlotNumber());
682+
DecodeEvent event = mDetectedCallEventsMap.get(channel.getValue());
683683

684684
if(isStale(event, csbk.getTimestamp(), csbk.getIdentifiers()))
685685
{
686686
event = getDecodeEvent(csbk, DecodeEventType.CALL_GROUP, channel, mergedIdentifiers);
687-
mDetectedCallEventsMap.put(channel.getLogicalSlotNumber(), event);
687+
mDetectedCallEventsMap.put(channel.getValue(), event);
688688
}
689689
else
690690
{
@@ -711,12 +711,12 @@ private void processCSBK(CSBKMessage csbk)
711711
}
712712
else
713713
{
714-
DecodeEvent event = mDetectedCallEventsMap.get(channel.getLogicalSlotNumber());
714+
DecodeEvent event = mDetectedCallEventsMap.get(channel.getValue());
715715

716716
if(isStale(event, csbk.getTimestamp(), csbk.getIdentifiers()))
717717
{
718718
event = getDecodeEvent(csbk, DecodeEventType.CALL_UNIT_TO_UNIT, channel, mergedIdentifiers);
719-
mDetectedCallEventsMap.put(channel.getLogicalSlotNumber(), event);
719+
mDetectedCallEventsMap.put(channel.getValue(), event);
720720
}
721721
else
722722
{
@@ -756,12 +756,12 @@ private void processCSBK(CSBKMessage csbk)
756756
}
757757
else
758758
{
759-
DecodeEvent event = mDetectedCallEventsMap.get(channel.getLogicalSlotNumber());
759+
DecodeEvent event = mDetectedCallEventsMap.get(channel.getValue());
760760

761761
if(isStale(event, csbk.getTimestamp(), csbk.getIdentifiers()))
762762
{
763763
event = getDecodeEvent(csbk, DecodeEventType.DATA_CALL, channel, mergedIdentifiers);
764-
mDetectedCallEventsMap.put(channel.getLogicalSlotNumber(), event);
764+
mDetectedCallEventsMap.put(channel.getValue(), event);
765765
}
766766
else
767767
{
@@ -807,12 +807,12 @@ private void processCSBK(CSBKMessage csbk)
807807
}
808808
else
809809
{
810-
DecodeEvent detectedEvent = mDetectedCallEventsMap.get(channel.getLogicalSlotNumber());
810+
DecodeEvent detectedEvent = mDetectedCallEventsMap.get(channel.getValue());
811811

812812
if(isStale(detectedEvent, csbk.getTimestamp(), csbk.getIdentifiers()))
813813
{
814814
detectedEvent = getDecodeEvent(csbk, DecodeEventType.CALL_GROUP, channel, mergedIdentifiers);
815-
mDetectedCallEventsMap.put(channel.getLogicalSlotNumber(), detectedEvent);
815+
mDetectedCallEventsMap.put(channel.getValue(), detectedEvent);
816816
}
817817
else
818818
{
@@ -979,10 +979,8 @@ private void processLinkControl(LCMessage message, boolean isTerminator)
979979
}
980980
break;
981981
case FULL_CAPACITY_PLUS_GROUP_VOICE_CHANNEL_USER:
982-
if(message instanceof CapacityPlusGroupVoiceChannelUser cpgvcu)
982+
if(message instanceof MotorolaGroupVoiceChannelUser cpgvcu)
983983
{
984-
updateRestChannel(cpgvcu.getRestChannel());
985-
986984
if(isTerminator)
987985
{
988986
getIdentifierCollection().remove(Role.FROM);

0 commit comments

Comments
 (0)