Skip to content

Commit

Permalink
#1787 DMR Decoder enhancements for RAS enabled systems. Adds support …
Browse files Browse the repository at this point in the history
…for CSBKO:33 and FLCO:16
  • Loading branch information
sheirerd committed Jan 13, 2024
1 parent 3c18bfd commit 10ed02f
Show file tree
Hide file tree
Showing 10 changed files with 351 additions and 29 deletions.
Expand Up @@ -66,6 +66,7 @@
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.UnitToUnitVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.hytera.HyteraGroupVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.hytera.HyteraUnitToUnitVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityMaxVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusEncryptedVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.CapacityPlusWideAreaVoiceChannelUser;
import io.github.dsheirer.module.decode.dmr.message.data.lc.full.motorola.MotorolaGroupVoiceChannelUser;
Expand Down Expand Up @@ -142,6 +143,16 @@ public DMRDecoderState(Channel channel, int timeslot, DMRTrafficChannelManager t
}
}

/**
* Indicates if the message is valid or if the Ignore CRC Checksums feature is enabled.
* @param message to check
* @return true if ignore CRC checksums or if the message is valid, meaning the message has passed CRC check.
*/
private boolean isValid(IMessage message)
{
return mIgnoreCRCChecksums || message.isValid();
}

/**
* Indicates if this decoder state has an (optional) traffic channel manager.
*/
Expand Down Expand Up @@ -206,21 +217,21 @@ public void receive(IMessage message)
{
if(message.getTimeslot() == getTimeslot())
{
if(message instanceof VoiceMessage)
if(message instanceof VoiceMessage voice)
{
processVoice((VoiceMessage)message);
processVoice(voice);
}
else if(message instanceof DataMessage)
else if(message instanceof DataMessage data)
{
processData((DataMessage)message);
processData(data);
}
else if((message.isValid() || mIgnoreCRCChecksums) && message instanceof LCMessage)
else if(isValid(message) && message instanceof LCMessage lcMessage)
{
processLinkControl((LCMessage)message, false);
processLinkControl(lcMessage, false);
}
else if(message.isValid() && message instanceof DMRPacketMessage)
else if(isValid(message) && message instanceof DMRPacketMessage packet)
{
processPacket((DMRPacketMessage)message);
processPacket(packet);
}
else if(message instanceof UDTShortMessageService sms)
{
Expand All @@ -232,16 +243,15 @@ else if(message instanceof DMRMessage)
}
}
//SLCO messages on timeslot 0 to catch capacity plus rest channel events
else if((message.isValid() || mIgnoreCRCChecksums) && message.getTimeslot() == 0 && message instanceof LCMessage)
else if(isValid(message) && message.getTimeslot() == 0 && message instanceof LCMessage lcMessage)
{
processLinkControl((LCMessage)message, false);
processLinkControl(lcMessage, false);
}

//Pass the message to the network configuration monitor, if this decoder state has a non-null instance
if(mNetworkConfigurationMonitor != null && (message.isValid() || mIgnoreCRCChecksums) &&
message instanceof DMRMessage)
if(mNetworkConfigurationMonitor != null && isValid(message) && message instanceof DMRMessage dmrMessage)
{
mNetworkConfigurationMonitor.process((DMRMessage)message);
mNetworkConfigurationMonitor.process(dmrMessage);
}
}

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

if(lc.isValid())
if(isValid(lc))
{
processLinkControl(lc, false);
}
Expand All @@ -520,15 +530,15 @@ private void processData(DataMessage message)
switch(message.getSlotType().getDataType())
{
case CSBK:
if((message.isValid() || mIgnoreCRCChecksums) && message instanceof CSBKMessage)
if(isValid(message) && message instanceof CSBKMessage csbk)
{
processCSBK((CSBKMessage)message);
processCSBK(csbk);
}
break;
case VOICE_HEADER:
if(message instanceof HeaderMessage)
if(message instanceof HeaderMessage header)
{
processVoiceHeader((HeaderMessage)message);
processVoiceHeader(header);
}
break;
case USB_DATA:
Expand All @@ -539,9 +549,9 @@ private void processData(DataMessage message)
case MBC_ENC_HEADER:
case DATA_ENC_HEADER:
case CHANNEL_CONTROL_ENC_HEADER:
if(message instanceof HeaderMessage)
if(message instanceof HeaderMessage header)
{
processHeader((HeaderMessage)message);
processHeader(header);
}
break;
case SLOT_IDLE:
Expand Down Expand Up @@ -579,7 +589,7 @@ private void processTerminator(Terminator terminator)

LCMessage lcMessage = terminator.getLCMessage();

if(lcMessage.isValid())
if(isValid(lcMessage))
{
processLinkControl(lcMessage, true);
}
Expand All @@ -592,7 +602,7 @@ private void processVoiceHeader(HeaderMessage voiceHeader)
{
LCMessage lcMessage = voiceHeader.getLCMessage();

if(lcMessage.isValid())
if(isValid(lcMessage))
{
processLinkControl(lcMessage, false);
}
Expand Down Expand Up @@ -1133,6 +1143,23 @@ private void processLinkControl(LCMessage message, boolean isTerminator)
}
}
break;
case FULL_CAPACITY_MAX_GROUP_VOICE_CHANNEL_USER:
if(message instanceof CapacityMaxVoiceChannelUser cmvcu)
{
if(isTerminator)
{
getIdentifierCollection().remove(Role.FROM);
getIdentifierCollection().update(cmvcu.getTalkgroup());
}
else
{
getIdentifierCollection().update(message.getIdentifiers());
ServiceOptions serviceOptions = cmvcu.getServiceOptions();
updateCurrentCall(serviceOptions.isEncrypted() ? DecodeEventType.CALL_GROUP_ENCRYPTED :
DecodeEventType.CALL_GROUP, serviceOptions.toString(), message.getTimestamp());
}
}
break;
case FULL_CAPACITY_PLUS_WIDE_AREA_VOICE_CHANNEL_USER:
if(message instanceof CapacityPlusWideAreaVoiceChannelUser)
{
Expand Down
Expand Up @@ -66,20 +66,23 @@ public class DMRMessageProcessor implements Listener<IMessage>
private VoiceSuperFrameProcessor mSuperFrameProcessor2 = new VoiceSuperFrameProcessor();
private FLCAssembler mFLCAssemblerTimeslot1 = new FLCAssembler(1);
private FLCAssembler mFLCAssemblerTimeslot2 = new FLCAssembler(2);
private MBCAssembler mMBCAssembler = new MBCAssembler();
private MBCAssembler mMBCAssembler;
private PacketSequenceAssembler mPacketSequenceAssembler;
private SLCAssembler mSLCAssembler = new SLCAssembler();
private TalkerAliasAssembler mTalkerAliasAssembler = new TalkerAliasAssembler();
private Listener<IMessage> mMessageListener;
private Map<Integer,TimeslotFrequency> mTimeslotFrequencyMap = new TreeMap<>();
private DmrCrcMaskManager mCrcMaskManager = new DmrCrcMaskManager();
private boolean mIgnoreCrcChecksums;

/**
* Constructs an instance
*/
public DMRMessageProcessor(DecodeConfigDMR config)
{
mConfigDMR = config;
mIgnoreCrcChecksums = config.getIgnoreCRCChecksums();
mMBCAssembler = new MBCAssembler(mIgnoreCrcChecksums);

for(TimeslotFrequency timeslotFrequency: config.getTimeslotMap())
{
Expand All @@ -89,6 +92,17 @@ public DMRMessageProcessor(DecodeConfigDMR config)
mPacketSequenceAssembler = new PacketSequenceAssembler();
}

/**
* Indicates if the message is valid or if the Ignore CRC Checksums feature is enabled.
*
* @param message to check
* @return true if ignore CRC checksums or if the message is valid.
*/
private boolean isValid(IMessage message)
{
return mIgnoreCrcChecksums || message.isValid();
}

/**
* Primary message processing
*/
Expand Down Expand Up @@ -128,7 +142,7 @@ else if(message instanceof VoiceMessage voiceMessage)
mSuperFrameProcessor2.process(voiceMessage);
}
}
else if(message instanceof DMRBurst dmrBurst && dmrBurst.isValid())
else if(message instanceof DMRBurst dmrBurst && isValid(dmrBurst))
{
if(dmrBurst.getTimeslot() == 1)
{
Expand Down Expand Up @@ -243,14 +257,14 @@ else if((message instanceof IDLEMessage || message instanceof Aloha || message i
}

//Reset talker alias assembler on Idle or Terminator
if(message.isValid() && (message instanceof IDLEMessage || message instanceof Terminator))
if(isValid(message) && (message instanceof IDLEMessage || message instanceof Terminator))
{
mTalkerAliasAssembler.reset(message.getTimeslot());
}
}

//Assemble Talker Alias from FLC message fragments (header & blocks 1-3)
if(message instanceof FullLCMessage flc && flc.getOpcode().isTalkerAliasOpcode() && message.isValid())
if(message instanceof FullLCMessage flc && flc.getOpcode().isTalkerAliasOpcode() && isValid(message))
{
dispatch(mTalkerAliasAssembler.process(flc));
}
Expand Down
Expand Up @@ -34,6 +34,7 @@
import io.github.dsheirer.module.decode.dmr.message.data.csbk.hytera.HyteraXPTPreamble;
import io.github.dsheirer.module.decode.dmr.message.data.csbk.hytera.HyteraXPTSiteState;
import io.github.dsheirer.module.decode.dmr.message.data.csbk.motorola.CapacityMaxAloha;
import io.github.dsheirer.module.decode.dmr.message.data.csbk.motorola.CapacityMaxGroupVoiceChannelUpdate;
import io.github.dsheirer.module.decode.dmr.message.data.csbk.motorola.CapacityPlusCSBKO_60;
import io.github.dsheirer.module.decode.dmr.message.data.csbk.motorola.CapacityPlusDataRevertWindowAnnouncement;
import io.github.dsheirer.module.decode.dmr.message.data.csbk.motorola.CapacityPlusDataRevertWindowGrant;
Expand Down Expand Up @@ -277,7 +278,9 @@ public static CSBKMessage create(DMRSyncPattern pattern, CorrectedBinaryMessage
case MOTOROLA_CAPPLUS_DATA_WINDOW_GRANT:
csbk = new CapacityPlusDataRevertWindowGrant(pattern, message, cach, slotType, timestamp, timeslot);
break;

case MOTOROLA_CAPMAX_GROUP_VOICE_CHANNEL_UPDATE:
csbk = new CapacityMaxGroupVoiceChannelUpdate(pattern, message, cach, slotType, timestamp, timeslot);
break;
case MOTOROLA_CONPLUS_CSBKO_10:
csbk = new ConnectPlusOTAAnnouncement(pattern, message, cach, slotType, timestamp, timeslot);
break;
Expand Down
Expand Up @@ -77,7 +77,9 @@ public enum Opcode
MOTOROLA_CONPLUS_DATA_WINDOW_ANNOUNCEMENT(Vendor.MOTOROLA_CONNECT_PLUS, 28, "ENHANCED DATA REVERT WINDOW ANNOUNCEMENT"),
MOTOROLA_CONPLUS_DATA_WINDOW_GRANT(Vendor.MOTOROLA_CONNECT_PLUS, 29, "ENHANCED DATA REVERT WINDOW GRANT"),

MOTOROLA_CAPMAX_GROUP_CHANNEL_USER(Vendor.MOTOROLA_CAPACITY_PLUS, 16, "GROUP CHANNEL USER"),
MOTOROLA_CAPMAX_ALOHA(Vendor.MOTOROLA_CAPACITY_PLUS, 25, "ALOHA"),
MOTOROLA_CAPMAX_GROUP_VOICE_CHANNEL_UPDATE(Vendor.MOTOROLA_CAPACITY_PLUS, 33, "TALKGROUP ACTIVE"),

MOTOROLA_CAPPLUS_CALL_ALERT(Vendor.MOTOROLA_CAPACITY_PLUS, 31, "CALL ALERT"),
MOTOROLA_CAPPLUS_CALL_ALERT_ACK(Vendor.MOTOROLA_CAPACITY_PLUS, 32, "CALL ALERT ACK"),
Expand Down

0 comments on commit 10ed02f

Please sign in to comment.