diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/DMRDecoderState.java b/src/main/java/io/github/dsheirer/module/decode/dmr/DMRDecoderState.java
index b6adfd90..48525a82 100644
--- a/src/main/java/io/github/dsheirer/module/decode/dmr/DMRDecoderState.java
+++ b/src/main/java/io/github/dsheirer/module/decode/dmr/DMRDecoderState.java
@@ -1,23 +1,20 @@
/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 Dennis Sheirer
*
- * * ******************************************************************************
- * * Copyright (C) 2014-2020 Dennis Sheirer, Zhenyu Mao
- * *
- * * 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
- * * *****************************************************************************
+ * 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
+ * ****************************************************************************
*/
package io.github.dsheirer.module.decode.dmr;
@@ -40,6 +37,7 @@ import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.dmr.channel.DMRChannel;
import io.github.dsheirer.module.decode.dmr.event.DMRDecodeEvent;
+import io.github.dsheirer.module.decode.dmr.identifier.DMRTalkgroup;
import io.github.dsheirer.module.decode.dmr.message.DMRMessage;
import io.github.dsheirer.module.decode.dmr.message.data.DataMessage;
import io.github.dsheirer.module.decode.dmr.message.data.csbk.CSBKMessage;
@@ -307,7 +305,17 @@ public class DMRDecoderState extends TimeslotDecoderState
*/
private void processVoice(VoiceMessage message)
{
- broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL, getTimeslot()));
+ if(message.getSyncPattern().isDirectMode())
+ {
+ updateCurrentCall(DecodeEventType.CALL, "DIRECT MODE", message.getTimestamp());
+
+ //Use the timeslot as the talkgroup identifier since DCDM mode doesn't use talkgroups
+ getIdentifierCollection().update(DMRTalkgroup.create(getTimeslot()));
+ }
+ else
+ {
+ broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL, getTimeslot()));
+ }
}
/**
diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/DMRSyncPattern.java b/src/main/java/io/github/dsheirer/module/decode/dmr/DMRSyncPattern.java
index 60d94792..79a7ff10 100644
--- a/src/main/java/io/github/dsheirer/module/decode/dmr/DMRSyncPattern.java
+++ b/src/main/java/io/github/dsheirer/module/decode/dmr/DMRSyncPattern.java
@@ -1,7 +1,6 @@
/*
- * ******************************************************************************
- * sdrtrunk
- * Copyright (C) 2014-2020 Dennis Sheirer, Zhenyu Mao
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 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
@@ -15,7 +14,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
- * *****************************************************************************
+ * ****************************************************************************
*/
package io.github.dsheirer.module.decode.dmr;
@@ -34,10 +33,10 @@ public enum DMRSyncPattern
MOBILE_STATION_DATA(0xD5D7F77FD757l, 0xBFBEAEEABEFEl, 0x404151154101l, 0x2A28088028A8l, "MS DATA"),
MOBILE_STATION_VOICE(0x7F7D5DD57DFDl, 0xEAEBFBBFEBABl, 0x151404401454l, 0x8082A22A8202l, "MS VOICE A"),
- DIRECT_MODE_DATA_TIMESLOT_1(0xF7FDD5DDFD55l, 0xAEABBFBBABFFl, 0x515440445400l, 0x08022A2202AAl, "DM DAT0"),
- DIRECT_MODE_DATA_TIMESLOT_2(0xD7557F5FF7F5l, 0xBEFFEAFAAEAFl, 0x410015055150l, 0x28AA80A0080Al, "DM DAT1"),
- DIRECT_MODE_VOICE_TIMESLOT_1(0x5D577F7757FFl, 0xFBFEEAEEFEAAl, 0x040115110155l, 0xA2A88088A800l, "DM VOX0"),
- DIRECT_MODE_VOICE_TIMESLOT_2(0x7DFFD5F55D5Fl, 0xEBAABFAFFBFAl, 0x145540500405l, 0x82002A0AA2A0l, "DM VOX1"),
+ DIRECT_MODE_DATA_TIMESLOT_1(0xF7FDD5DDFD55l, 0xAEABBFBBABFFl, 0x515440445400l, 0x08022A2202AAl, "MS DATA - DUAL CAPACITY DIRECT MODE"),
+ DIRECT_MODE_DATA_TIMESLOT_2(0xD7557F5FF7F5l, 0xBEFFEAFAAEAFl, 0x410015055150l, 0x28AA80A0080Al, "MS DATA - DUAL CAPACITY DIRECT MODE"),
+ DIRECT_MODE_VOICE_TIMESLOT_1(0x5D577F7757FFl, 0xFBFEEAEEFEAAl, 0x040115110155l, 0xA2A88088A800l, "MS VOICE A - DUAL CAPACITY DIRECT MODE"),
+ DIRECT_MODE_VOICE_TIMESLOT_2(0x7DFFD5F55D5Fl, 0xEBAABFAFFBFAl, 0x145540500405l, 0x82002A0AA2A0l, "MS VOICE A - DUAL CAPACITY DIRECT MODE"),
MOBILE_STATION_REVERSE_CHANNEL(0x77D55F7DFD77l, 0xEEBFFAEBABEEl, 0x114005145411l, 0x882AA0820288l, "MS RVRS"),
RESERVED(0xDD7FF5D757DDl, 0xBBEAAFBEFEBBl, 0x441550410144l, 0x22800A28A822l, "RESERVED"),
diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/audio/DMRAudioModule.java b/src/main/java/io/github/dsheirer/module/decode/dmr/audio/DMRAudioModule.java
index 1007554d..fdc3fa78 100644
--- a/src/main/java/io/github/dsheirer/module/decode/dmr/audio/DMRAudioModule.java
+++ b/src/main/java/io/github/dsheirer/module/decode/dmr/audio/DMRAudioModule.java
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
- * Copyright (C) 2014-2021 Dennis Sheirer
+ * Copyright (C) 2014-2022 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
@@ -102,11 +102,22 @@ public class DMRAudioModule extends AmbeAudioModule implements IdentifierUpdateP
{
if(hasAudioCodec() && message.getTimeslot() == getTimeslot())
{
+ //DCDM doesn't provide FLCs or EMBs ... assume that the call is unencrypted.
+ if(!mEncryptedCallStateEstablished && message instanceof VoiceMessage vm &&
+ vm.getSyncPattern().isDirectMode())
+ {
+ mEncryptedCallStateEstablished = true;
+ mEncryptedCall = false;
+ List frames = vm.getAMBEFrames();
+ for(byte[] frame: frames)
+ {
+ processAudio(frame);
+ }
+ }
//Both Motorola and Hytera signal their Basic Privacy (BP) scrambling in some of the Voice B-F frames
//in the EMB field.
- if(!mEncryptedCallStateEstablished && message instanceof VoiceEMBMessage)
+ else if(!mEncryptedCallStateEstablished && message instanceof VoiceEMBMessage voiceMessage)
{
- VoiceEMBMessage voiceMessage = (VoiceEMBMessage)message;
if(voiceMessage.getEMB().isValid())
{
mEncryptedCallStateEstablished = true;
@@ -119,23 +130,20 @@ public class DMRAudioModule extends AmbeAudioModule implements IdentifierUpdateP
processAudio(frame);
}
}
- else if(message instanceof VoiceMessage)
+ else if(message instanceof VoiceMessage voiceMessage)
{
- VoiceMessage voiceMessage = (VoiceMessage)message;
List frames = voiceMessage.getAMBEFrames();
for(byte[] frame: frames)
{
processAudio(frame);
}
}
- else if(!mEncryptedCallStateEstablished && message instanceof VoiceHeader)
+ else if(!mEncryptedCallStateEstablished && message instanceof VoiceHeader voiceHeader)
{
- LCMessage lc = ((VoiceHeader)message).getLCMessage();
+ LCMessage lc = voiceHeader.getLCMessage();
- if(lc instanceof FullLCMessage) //We know it is, but this null checks as well
+ if(lc instanceof FullLCMessage flc) //We know it is, but this null checks as well
{
- FullLCMessage flc = (FullLCMessage)lc;
-
if(flc.isValid())
{
mEncryptedCallStateEstablished = true;
@@ -146,9 +154,9 @@ public class DMRAudioModule extends AmbeAudioModule implements IdentifierUpdateP
//Note: the DMRMessageProcess extracts Full Link Control messages from Voice Frames B-C and sends them
// independent of any DMR Burst messaging. When encountered, it can be assumed that they are part of
// an ongoing call and can be used to establish encryption state when the FLC is a voice channel user.
- else if(!mEncryptedCallStateEstablished && message instanceof AbstractVoiceChannelUser)
+ else if(!mEncryptedCallStateEstablished && message instanceof AbstractVoiceChannelUser avcu)
{
- ServiceOptions serviceOptions = ((AbstractVoiceChannelUser)message).getServiceOptions();
+ ServiceOptions serviceOptions = avcu.getServiceOptions();
mEncryptedCallStateEstablished = true;
mEncryptedCall = serviceOptions.isEncrypted();
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/DMRMessageFactory.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/DMRMessageFactory.java
index cfd84c77..96d04b0e 100644
--- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/DMRMessageFactory.java
+++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/DMRMessageFactory.java
@@ -1,3 +1,22 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 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
+ * ****************************************************************************
+ */
+
package io.github.dsheirer.module.decode.dmr.message;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
@@ -33,6 +52,12 @@ public class DMRMessageFactory
case BS_VOICE_FRAME_D:
case BS_VOICE_FRAME_E:
case BS_VOICE_FRAME_F:
+
+ case MS_VOICE_FRAME_B:
+ case MS_VOICE_FRAME_C:
+ case MS_VOICE_FRAME_D:
+ case MS_VOICE_FRAME_E:
+ case MS_VOICE_FRAME_F:
return createVoiceMessage(syncPattern, binaryMessage, cach, timestamp, timeslot);
case DIRECT_MODE_VOICE_TIMESLOT_1:
return createVoiceMessage(syncPattern, binaryMessage, cach, timestamp, 1);
diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/voice/VoiceAMessage.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/voice/VoiceAMessage.java
index 45188ce6..2f77ec6a 100644
--- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/voice/VoiceAMessage.java
+++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/voice/VoiceAMessage.java
@@ -1,3 +1,22 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 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
+ * ****************************************************************************
+ */
+
package io.github.dsheirer.module.decode.dmr.message.voice;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
@@ -29,7 +48,16 @@ public class VoiceAMessage extends VoiceMessage
public String toString()
{
StringBuilder sb = new StringBuilder();
- sb.append(" ").append(getSyncPattern());
+
+ if(getSyncPattern().isDirectMode())
+ {
+ sb.append(getSyncPattern());
+ }
+ else
+ {
+ sb.append(" ").append(getSyncPattern());
+ }
+
return sb.toString();
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/dmr/message/voice/VoiceEMBMessage.java b/src/main/java/io/github/dsheirer/module/decode/dmr/message/voice/VoiceEMBMessage.java
index b6e8387a..aebe3c07 100644
--- a/src/main/java/io/github/dsheirer/module/decode/dmr/message/voice/VoiceEMBMessage.java
+++ b/src/main/java/io/github/dsheirer/module/decode/dmr/message/voice/VoiceEMBMessage.java
@@ -1,3 +1,22 @@
+/*
+ * *****************************************************************************
+ * Copyright (C) 2014-2022 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
+ * ****************************************************************************
+ */
+
package io.github.dsheirer.module.decode.dmr.message.voice;
import io.github.dsheirer.bits.BinaryMessage;
@@ -37,25 +56,14 @@ public class VoiceEMBMessage extends VoiceMessage
if(getEMB().isValid())
{
- sb.append("CC:").append(getEMB().getColorCode());
- }
- else
- {
- sb.append("CC:?");
+ sb.append("CC:").append(getEMB().getColorCode()).append(" ");
}
- sb.append(" ").append(getSyncPattern().toString());
+ sb.append(getSyncPattern().toString());
- if(getEMB().isValid())
+ if(getEMB().isValid() && getEMB().isEncrypted())
{
- if(getEMB().isEncrypted())
- {
- sb.append(" ENCRYPTED");
- }
- }
- else
- {
- sb.append(" [EMB CRC-ERROR]");
+ sb.append(" ENCRYPTED");
}
return sb.toString();