Skip to content

Commit 9d03c15

Browse files
DSheirersheirerd
andauthored
#1787 DMR Decoder enhancements for RAS enabled systems. Adds support for CSBKO:33 and FLCO:16 (#1794)
Co-authored-by: sheirerd <[email protected]>
1 parent 3c18bfd commit 9d03c15

File tree

10 files changed

+351
-29
lines changed

10 files changed

+351
-29
lines changed

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

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.UnitToUnitVoiceChannelUser;
6767
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.hytera.HyteraGroupVoiceChannelUser;
6868
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.hytera.HyteraUnitToUnitVoiceChannelUser;
69+
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityMaxVoiceChannelUser;
6970
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusEncryptedVoiceChannelUser;
7071
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusWideAreaVoiceChannelUser;
7172
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.MotorolaGroupVoiceChannelUser;
@@ -142,6 +143,16 @@ public DMRDecoderState(Channel channel, int timeslot, DMRTrafficChannelManager t
142143
}
143144
}
144145

146+
/**
147+
* Indicates if the message is valid or if the Ignore CRC Checksums feature is enabled.
148+
* @param message to check
149+
* @return true if ignore CRC checksums or if the message is valid, meaning the message has passed CRC check.
150+
*/
151+
private boolean isValid(IMessage message)
152+
{
153+
return mIgnoreCRCChecksums || message.isValid();
154+
}
155+
145156
/**
146157
* Indicates if this decoder state has an (optional) traffic channel manager.
147158
*/
@@ -206,21 +217,21 @@ public void receive(IMessage message)
206217
{
207218
if(message.getTimeslot() == getTimeslot())
208219
{
209-
if(message instanceof VoiceMessage)
220+
if(message instanceof VoiceMessage voice)
210221
{
211-
processVoice((VoiceMessage)message);
222+
processVoice(voice);
212223
}
213-
else if(message instanceof DataMessage)
224+
else if(message instanceof DataMessage data)
214225
{
215-
processData((DataMessage)message);
226+
processData(data);
216227
}
217-
else if((message.isValid() || mIgnoreCRCChecksums) && message instanceof LCMessage)
228+
else if(isValid(message) && message instanceof LCMessage lcMessage)
218229
{
219-
processLinkControl((LCMessage)message, false);
230+
processLinkControl(lcMessage, false);
220231
}
221-
else if(message.isValid() && message instanceof DMRPacketMessage)
232+
else if(isValid(message) && message instanceof DMRPacketMessage packet)
222233
{
223-
processPacket((DMRPacketMessage)message);
234+
processPacket(packet);
224235
}
225236
else if(message instanceof UDTShortMessageService sms)
226237
{
@@ -232,16 +243,15 @@ else if(message instanceof DMRMessage)
232243
}
233244
}
234245
//SLCO messages on timeslot 0 to catch capacity plus rest channel events
235-
else if((message.isValid() || mIgnoreCRCChecksums) && message.getTimeslot() == 0 && message instanceof LCMessage)
246+
else if(isValid(message) && message.getTimeslot() == 0 && message instanceof LCMessage lcMessage)
236247
{
237-
processLinkControl((LCMessage)message, false);
248+
processLinkControl(lcMessage, false);
238249
}
239250

240251
//Pass the message to the network configuration monitor, if this decoder state has a non-null instance
241-
if(mNetworkConfigurationMonitor != null && (message.isValid() || mIgnoreCRCChecksums) &&
242-
message instanceof DMRMessage)
252+
if(mNetworkConfigurationMonitor != null && isValid(message) && message instanceof DMRMessage dmrMessage)
243253
{
244-
mNetworkConfigurationMonitor.process((DMRMessage)message);
254+
mNetworkConfigurationMonitor.process(dmrMessage);
245255
}
246256
}
247257

@@ -503,7 +513,7 @@ private void processHeader(HeaderMessage header)
503513
//Process the link control message to get the identifiers
504514
LCMessage lc = header.getLCMessage();
505515

506-
if(lc.isValid())
516+
if(isValid(lc))
507517
{
508518
processLinkControl(lc, false);
509519
}
@@ -520,15 +530,15 @@ private void processData(DataMessage message)
520530
switch(message.getSlotType().getDataType())
521531
{
522532
case CSBK:
523-
if((message.isValid() || mIgnoreCRCChecksums) && message instanceof CSBKMessage)
533+
if(isValid(message) && message instanceof CSBKMessage csbk)
524534
{
525-
processCSBK((CSBKMessage)message);
535+
processCSBK(csbk);
526536
}
527537
break;
528538
case VOICE_HEADER:
529-
if(message instanceof HeaderMessage)
539+
if(message instanceof HeaderMessage header)
530540
{
531-
processVoiceHeader((HeaderMessage)message);
541+
processVoiceHeader(header);
532542
}
533543
break;
534544
case USB_DATA:
@@ -539,9 +549,9 @@ private void processData(DataMessage message)
539549
case MBC_ENC_HEADER:
540550
case DATA_ENC_HEADER:
541551
case CHANNEL_CONTROL_ENC_HEADER:
542-
if(message instanceof HeaderMessage)
552+
if(message instanceof HeaderMessage header)
543553
{
544-
processHeader((HeaderMessage)message);
554+
processHeader(header);
545555
}
546556
break;
547557
case SLOT_IDLE:
@@ -579,7 +589,7 @@ private void processTerminator(Terminator terminator)
579589

580590
LCMessage lcMessage = terminator.getLCMessage();
581591

582-
if(lcMessage.isValid())
592+
if(isValid(lcMessage))
583593
{
584594
processLinkControl(lcMessage, true);
585595
}
@@ -592,7 +602,7 @@ private void processVoiceHeader(HeaderMessage voiceHeader)
592602
{
593603
LCMessage lcMessage = voiceHeader.getLCMessage();
594604

595-
if(lcMessage.isValid())
605+
if(isValid(lcMessage))
596606
{
597607
processLinkControl(lcMessage, false);
598608
}
@@ -1133,6 +1143,23 @@ private void processLinkControl(LCMessage message, boolean isTerminator)
11331143
}
11341144
}
11351145
break;
1146+
case FULL_CAPACITY_MAX_GROUP_VOICE_CHANNEL_USER:
1147+
if(message instanceof CapacityMaxVoiceChannelUser cmvcu)
1148+
{
1149+
if(isTerminator)
1150+
{
1151+
getIdentifierCollection().remove(Role.FROM);
1152+
getIdentifierCollection().update(cmvcu.getTalkgroup());
1153+
}
1154+
else
1155+
{
1156+
getIdentifierCollection().update(message.getIdentifiers());
1157+
ServiceOptions serviceOptions = cmvcu.getServiceOptions();
1158+
updateCurrentCall(serviceOptions.isEncrypted() ? DecodeEventType.CALL_GROUP_ENCRYPTED :
1159+
DecodeEventType.CALL_GROUP, serviceOptions.toString(), message.getTimestamp());
1160+
}
1161+
}
1162+
break;
11361163
case FULL_CAPACITY_PLUS_WIDE_AREA_VOICE_CHANNEL_USER:
11371164
if(message instanceof CapacityPlusWideAreaVoiceChannelUser)
11381165
{

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,20 +66,23 @@ public class DMRMessageProcessor implements Listener<IMessage>
6666
private VoiceSuperFrameProcessor mSuperFrameProcessor2 = new VoiceSuperFrameProcessor();
6767
private FLCAssembler mFLCAssemblerTimeslot1 = new FLCAssembler(1);
6868
private FLCAssembler mFLCAssemblerTimeslot2 = new FLCAssembler(2);
69-
private MBCAssembler mMBCAssembler = new MBCAssembler();
69+
private MBCAssembler mMBCAssembler;
7070
private PacketSequenceAssembler mPacketSequenceAssembler;
7171
private SLCAssembler mSLCAssembler = new SLCAssembler();
7272
private TalkerAliasAssembler mTalkerAliasAssembler = new TalkerAliasAssembler();
7373
private Listener<IMessage> mMessageListener;
7474
private Map<Integer,TimeslotFrequency> mTimeslotFrequencyMap = new TreeMap<>();
7575
private DmrCrcMaskManager mCrcMaskManager = new DmrCrcMaskManager();
76+
private boolean mIgnoreCrcChecksums;
7677

7778
/**
7879
* Constructs an instance
7980
*/
8081
public DMRMessageProcessor(DecodeConfigDMR config)
8182
{
8283
mConfigDMR = config;
84+
mIgnoreCrcChecksums = config.getIgnoreCRCChecksums();
85+
mMBCAssembler = new MBCAssembler(mIgnoreCrcChecksums);
8386

8487
for(TimeslotFrequency timeslotFrequency: config.getTimeslotMap())
8588
{
@@ -89,6 +92,17 @@ public DMRMessageProcessor(DecodeConfigDMR config)
8992
mPacketSequenceAssembler = new PacketSequenceAssembler();
9093
}
9194

95+
/**
96+
* Indicates if the message is valid or if the Ignore CRC Checksums feature is enabled.
97+
*
98+
* @param message to check
99+
* @return true if ignore CRC checksums or if the message is valid.
100+
*/
101+
private boolean isValid(IMessage message)
102+
{
103+
return mIgnoreCrcChecksums || message.isValid();
104+
}
105+
92106
/**
93107
* Primary message processing
94108
*/
@@ -128,7 +142,7 @@ else if(message instanceof VoiceMessage voiceMessage)
128142
mSuperFrameProcessor2.process(voiceMessage);
129143
}
130144
}
131-
else if(message instanceof DMRBurst dmrBurst && dmrBurst.isValid())
145+
else if(message instanceof DMRBurst dmrBurst && isValid(dmrBurst))
132146
{
133147
if(dmrBurst.getTimeslot() == 1)
134148
{
@@ -243,14 +257,14 @@ else if((message instanceof IDLEMessage || message instanceof Aloha || message i
243257
}
244258

245259
//Reset talker alias assembler on Idle or Terminator
246-
if(message.isValid() && (message instanceof IDLEMessage || message instanceof Terminator))
260+
if(isValid(message) && (message instanceof IDLEMessage || message instanceof Terminator))
247261
{
248262
mTalkerAliasAssembler.reset(message.getTimeslot());
249263
}
250264
}
251265

252266
//Assemble Talker Alias from FLC message fragments (header & blocks 1-3)
253-
if(message instanceof FullLCMessage flc && flc.getOpcode().isTalkerAliasOpcode() && message.isValid())
267+
if(message instanceof FullLCMessage flc && flc.getOpcode().isTalkerAliasOpcode() && isValid(message))
254268
{
255269
dispatch(mTalkerAliasAssembler.process(flc));
256270
}

src/main/java/io/github/dsheirer/module/decode/dmr/message/data/csbk/CSBKMessageFactory.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import io.github.dsheirer.module.decode.dmr.message.data.csbk.hytera.HyteraXPTPreamble;
3535
import io.github.dsheirer.module.decode.dmr.message.data.csbk.hytera.HyteraXPTSiteState;
3636
import io.github.dsheirer.module.decode.dmr.message.data.csbk.motorola.CapacityMaxAloha;
37+
import io.github.dsheirer.module.decode.dmr.message.data.csbk.motorola.CapacityMaxGroupVoiceChannelUpdate;
3738
import io.github.dsheirer.module.decode.dmr.message.data.csbk.motorola.CapacityPlusCSBKO_60;
3839
import io.github.dsheirer.module.decode.dmr.message.data.csbk.motorola.CapacityPlusDataRevertWindowAnnouncement;
3940
import io.github.dsheirer.module.decode.dmr.message.data.csbk.motorola.CapacityPlusDataRevertWindowGrant;
@@ -277,7 +278,9 @@ public static CSBKMessage create(DMRSyncPattern pattern, CorrectedBinaryMessage
277278
case MOTOROLA_CAPPLUS_DATA_WINDOW_GRANT:
278279
csbk = new CapacityPlusDataRevertWindowGrant(pattern, message, cach, slotType, timestamp, timeslot);
279280
break;
280-
281+
case MOTOROLA_CAPMAX_GROUP_VOICE_CHANNEL_UPDATE:
282+
csbk = new CapacityMaxGroupVoiceChannelUpdate(pattern, message, cach, slotType, timestamp, timeslot);
283+
break;
281284
case MOTOROLA_CONPLUS_CSBKO_10:
282285
csbk = new ConnectPlusOTAAnnouncement(pattern, message, cach, slotType, timestamp, timeslot);
283286
break;

src/main/java/io/github/dsheirer/module/decode/dmr/message/data/csbk/Opcode.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ public enum Opcode
7777
MOTOROLA_CONPLUS_DATA_WINDOW_ANNOUNCEMENT(Vendor.MOTOROLA_CONNECT_PLUS, 28, "ENHANCED DATA REVERT WINDOW ANNOUNCEMENT"),
7878
MOTOROLA_CONPLUS_DATA_WINDOW_GRANT(Vendor.MOTOROLA_CONNECT_PLUS, 29, "ENHANCED DATA REVERT WINDOW GRANT"),
7979

80+
MOTOROLA_CAPMAX_GROUP_CHANNEL_USER(Vendor.MOTOROLA_CAPACITY_PLUS, 16, "GROUP CHANNEL USER"),
8081
MOTOROLA_CAPMAX_ALOHA(Vendor.MOTOROLA_CAPACITY_PLUS, 25, "ALOHA"),
82+
MOTOROLA_CAPMAX_GROUP_VOICE_CHANNEL_UPDATE(Vendor.MOTOROLA_CAPACITY_PLUS, 33, "TALKGROUP ACTIVE"),
8183

8284
MOTOROLA_CAPPLUS_CALL_ALERT(Vendor.MOTOROLA_CAPACITY_PLUS, 31, "CALL ALERT"),
8385
MOTOROLA_CAPPLUS_CALL_ALERT_ACK(Vendor.MOTOROLA_CAPACITY_PLUS, 32, "CALL ALERT ACK"),

0 commit comments

Comments
 (0)