#1304 P25 Phase 1/2 decoder enhancements. (#1898)

* 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

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
Denny Sheirer
2024-04-26 13:55:17 -04:00
committed by GitHub
parent f5938fa8e2
commit 7e709d9d6f
430 changed files with 30098 additions and 13300 deletions

View File

@@ -26,6 +26,7 @@ import io.github.dsheirer.message.IMessageListener;
import io.github.dsheirer.module.Module;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.event.ActivitySummaryProvider;
import io.github.dsheirer.module.decode.event.DecodeEventDuplicateDetector;
import io.github.dsheirer.module.decode.event.IDecodeEvent;
import io.github.dsheirer.module.decode.event.IDecodeEventProvider;
import io.github.dsheirer.sample.Broadcaster;
@@ -44,6 +45,7 @@ public abstract class AbstractDecoderState extends Module implements ActivitySum
protected Broadcaster<IDecodeEvent> mDecodeEventBroadcaster = new Broadcaster<>();
protected Listener<DecoderStateEvent> mDecoderStateListener;
private DecoderStateEventListener mDecoderStateEventListener = new DecoderStateEventListener();
private static final DecodeEventDuplicateDetector mDuplicateEventDetector = new DecodeEventDuplicateDetector();
private boolean mRunning;
public abstract DecoderType getDecoderType();
@@ -105,7 +107,10 @@ public abstract class AbstractDecoderState extends Module implements ActivitySum
*/
protected void broadcast(IDecodeEvent event)
{
mDecodeEventBroadcaster.broadcast(event);
if(!mDuplicateEventDetector.isDuplicate(event, System.currentTimeMillis()))
{
mDecodeEventBroadcaster.broadcast(event);
}
}
/**
@@ -161,6 +166,9 @@ public abstract class AbstractDecoderState extends Module implements ActivitySum
mDecoderStateListener = null;
}
/**
* Wrapper that implements the IDecoderStateEventListener interface
*/
private class DecoderStateEventListener implements Listener<DecoderStateEvent>
{
@Override
@@ -169,23 +177,4 @@ public abstract class AbstractDecoderState extends Module implements ActivitySum
receiveDecoderStateEvent(event);
}
}
/**
* Message listener that only passes messages while we're running. This is important because each of the decoders
* can process blocks of samples and that can result in additional messages being generated even after shutdown
* and so we shut off the processing of decoded messages when we're commanded to stop. The sample processing thread
* cannot be shutdown or forcefully interrupted because downstream decoder and channel states may have acquired
* locks that have to be properly released.
*/
private class MessageListener implements Listener<IMessage>
{
@Override
public void receive(IMessage message)
{
if(isRunning())
{
receive(message);
}
}
}
}

View File

@@ -25,6 +25,7 @@ import io.github.dsheirer.identifier.IdentifierUpdateNotification;
import io.github.dsheirer.identifier.MutableIdentifierCollection;
import io.github.dsheirer.identifier.configuration.ChannelDescriptorConfigurationIdentifier;
import io.github.dsheirer.identifier.configuration.DecoderTypeConfigurationIdentifier;
import io.github.dsheirer.identifier.configuration.FrequencyConfigurationIdentifier;
import io.github.dsheirer.sample.Listener;
/**
@@ -38,13 +39,21 @@ public abstract class DecoderState extends AbstractDecoderState
private MutableIdentifierCollection mIdentifierCollection;
protected Listener<IdentifierUpdateNotification> mConfigurationIdentifierListener;
protected IChannelDescriptor mCurrentChannel;
private long mCurrentFrequency;
/**
* Constructs an instance
* @param mutableIdentifierCollection to preload into this decoder state
*/
public DecoderState(MutableIdentifierCollection mutableIdentifierCollection)
{
mIdentifierCollection = mutableIdentifierCollection;
mIdentifierCollection.update(new DecoderTypeConfigurationIdentifier(getDecoderType()));
}
/**
* Constructs an instance using an empty identifier collection.
*/
public DecoderState()
{
this(new MutableIdentifierCollection());
@@ -59,6 +68,23 @@ public abstract class DecoderState extends AbstractDecoderState
mIdentifierCollection.broadcastIdentifiers();
}
/**
* Current frequency for this channel.
*/
public long getCurrentFrequency()
{
return mCurrentFrequency;
}
/**
* Sets the current frequency for this channel.
* @param frequency to set.
*/
public void setCurrentFrequency(long frequency)
{
mCurrentFrequency = frequency;
}
/**
* Registers the listener to receive identifier update notifications
*/
@@ -153,9 +179,13 @@ public abstract class DecoderState extends AbstractDecoderState
{
getIdentifierCollection().receive(identifierUpdateNotification);
if(identifierUpdateNotification.getIdentifier() instanceof ChannelDescriptorConfigurationIdentifier)
if(identifierUpdateNotification.getIdentifier() instanceof ChannelDescriptorConfigurationIdentifier cdci)
{
setCurrentChannel(((ChannelDescriptorConfigurationIdentifier)identifierUpdateNotification.getIdentifier()).getValue());
setCurrentChannel(cdci.getValue());
}
else if(identifierUpdateNotification.getIdentifier() instanceof FrequencyConfigurationIdentifier fci)
{
setCurrentFrequency(fci.getValue());
}
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2024 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
@@ -26,12 +26,20 @@ import io.github.dsheirer.identifier.IdentifierClass;
import io.github.dsheirer.identifier.IdentifierUpdateNotification;
import io.github.dsheirer.identifier.MutableIdentifierCollection;
import io.github.dsheirer.identifier.configuration.ChannelDescriptorConfigurationIdentifier;
import io.github.dsheirer.identifier.configuration.FrequencyConfigurationIdentifier;
import io.github.dsheirer.sample.Listener;
/**
* Base decoder state implementation for a multi-timeslot protocol that tracks the state for a single timeslot.
*/
public abstract class TimeslotDecoderState extends DecoderState
{
private int mTimeslot;
/**
* Constructs an instance
* @param timeslot to monitor/maintain state.
*/
public TimeslotDecoderState(int timeslot)
{
super(new MutableIdentifierCollection(timeslot));
@@ -39,6 +47,9 @@ public abstract class TimeslotDecoderState extends DecoderState
mConfigurationIdentifierListener = new TimeslotConfigurationIdentifierListener();
}
/**
* Monitored timeslot for this decoder state instance.
*/
protected int getTimeslot()
{
return mTimeslot;
@@ -82,6 +93,10 @@ public abstract class TimeslotDecoderState extends DecoderState
{
setCurrentChannel((IChannelDescriptor)identifier);
}
else if(identifier instanceof FrequencyConfigurationIdentifier fci)
{
setCurrentFrequency(fci.getValue());
}
}
}
}