61 Rotating Control Channel Support - P25 Decoder (#475)

* Initial work on add support for rotating control channels.

* Creates multiple frequency editor control.

* Updates channel source editor to allow user to select multi-frequency
configuration and add multiple frequencies.

* Adds full support for rotating control channels to the P25 channelizer.
Users define multiple frequencies in the channel source configuration.
The decoder monitors the state of the channel for a CONTROL state.  If
the state does not stay in the CONTROL state for a user-specified delay
value, then the decoder rotates to the next frequency in the list.  This
behavior continues until the decoder state once again changes to CONTROL.

This is NOT a 'scanner' feature.
This commit is contained in:
Denny Sheirer
2019-01-06 06:59:04 -05:00
committed by GitHub
parent 3a39ae76ba
commit 5481fb7d4d
44 changed files with 2502 additions and 634 deletions

View File

@@ -1,7 +1,7 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
* Copyright (C) 2014-2019 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
@@ -33,8 +33,8 @@ import io.github.dsheirer.identifier.configuration.DecoderTypeConfigurationIdent
import io.github.dsheirer.identifier.configuration.FrequencyConfigurationIdentifier;
import io.github.dsheirer.identifier.configuration.SiteConfigurationIdentifier;
import io.github.dsheirer.identifier.configuration.SystemConfigurationIdentifier;
import io.github.dsheirer.identifier.decoder.ChannelStateIdentifier;
import io.github.dsheirer.identifier.decoder.DecoderLogicalChannelNameIdentifier;
import io.github.dsheirer.identifier.decoder.DecoderStateIdentifier;
import io.github.dsheirer.sample.Listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -54,7 +54,7 @@ public class ChannelMetadata implements Listener<IdentifierUpdateNotification>,
private SiteConfigurationIdentifier mSiteConfigurationIdentifier;
private ChannelNameConfigurationIdentifier mChannelNameConfigurationIdentifier;
private FrequencyConfigurationIdentifier mFrequencyConfigurationIdentifier;
private DecoderStateIdentifier mDecoderStateIdentifier = DecoderStateIdentifier.IDLE;
private ChannelStateIdentifier mChannelStateIdentifier = ChannelStateIdentifier.IDLE;
private DecoderLogicalChannelNameIdentifier mDecoderLogicalChannelNameIdentifier;
private DecoderTypeConfigurationIdentifier mDecoderTypeConfigurationIdentifier;
private Identifier mFromIdentifier;
@@ -145,14 +145,14 @@ public class ChannelMetadata implements Listener<IdentifierUpdateNotification>,
/**
* Decoder state identifier
*/
public DecoderStateIdentifier getDecoderStateIdentifier()
public ChannelStateIdentifier getChannelStateIdentifier()
{
return mDecoderStateIdentifier;
return mChannelStateIdentifier;
}
public boolean hasDecoderStateIdentifier()
{
return mDecoderStateIdentifier != null;
return mChannelStateIdentifier != null;
}
/**
@@ -250,7 +250,7 @@ public class ChannelMetadata implements Listener<IdentifierUpdateNotification>,
switch(identifier.getForm())
{
case ALIAS_LIST:
if(update.isAdded())
if(update.isAdd())
{
mAliasList = mAliasModel.getAliasList((AliasListConfigurationIdentifier)identifier);
@@ -268,23 +268,58 @@ public class ChannelMetadata implements Listener<IdentifierUpdateNotification>,
}
break;
case CHANNEL:
mChannelNameConfigurationIdentifier = update.isAdded() ? (ChannelNameConfigurationIdentifier)identifier : null;
if(identifier instanceof ChannelNameConfigurationIdentifier && (update.isAdd() || update.isSilentAdd()))
{
mChannelNameConfigurationIdentifier = (ChannelNameConfigurationIdentifier)identifier;
}
else
{
mChannelNameConfigurationIdentifier = null;
}
broadcastUpdate(ChannelMetadataField.CONFIGURATION_CHANNEL);
break;
case CHANNEL_FREQUENCY:
mFrequencyConfigurationIdentifier = update.isAdded() ? (FrequencyConfigurationIdentifier)identifier : null;
if(identifier instanceof FrequencyConfigurationIdentifier && (update.isAdd() || update.isSilentAdd()))
{
mFrequencyConfigurationIdentifier = (FrequencyConfigurationIdentifier)identifier;
}
else
{
mFrequencyConfigurationIdentifier = null;
}
broadcastUpdate(ChannelMetadataField.CONFIGURATION_FREQUENCY);
break;
case DECODER_TYPE:
mDecoderTypeConfigurationIdentifier = update.isAdded() ? (DecoderTypeConfigurationIdentifier)identifier : null;
if(identifier instanceof DecoderTypeConfigurationIdentifier && (update.isAdd() || update.isSilentAdd()))
{
mDecoderTypeConfigurationIdentifier = (DecoderTypeConfigurationIdentifier)identifier;
}
else
{
mDecoderTypeConfigurationIdentifier = null;
}
broadcastUpdate(ChannelMetadataField.DECODER_TYPE);
break;
case SITE:
mSiteConfigurationIdentifier = update.isAdded() ? (SiteConfigurationIdentifier)identifier : null;
if(identifier instanceof SiteConfigurationIdentifier && (update.isAdd() || update.isSilentAdd()))
{
mSiteConfigurationIdentifier = (SiteConfigurationIdentifier)identifier;
}
else
{
mSiteConfigurationIdentifier = null;
}
broadcastUpdate(ChannelMetadataField.CONFIGURATION_SITE);
break;
case SYSTEM:
mSystemConfigurationIdentifier = update.isAdded() ? (SystemConfigurationIdentifier)identifier : null;
if(identifier instanceof SystemConfigurationIdentifier && (update.isAdd() || update.isSilentAdd()))
{
mSystemConfigurationIdentifier = (SystemConfigurationIdentifier)identifier;
}
else
{
mSystemConfigurationIdentifier = null;
}
broadcastUpdate(ChannelMetadataField.CONFIGURATION_SYSTEM);
break;
}
@@ -293,11 +328,25 @@ public class ChannelMetadata implements Listener<IdentifierUpdateNotification>,
switch(identifier.getForm())
{
case CHANNEL_NAME:
mDecoderLogicalChannelNameIdentifier = update.isAdded() ? (DecoderLogicalChannelNameIdentifier)identifier : null;
if(identifier instanceof DecoderLogicalChannelNameIdentifier && (update.isAdd() || update.isSilentAdd()))
{
mDecoderLogicalChannelNameIdentifier = (DecoderLogicalChannelNameIdentifier)identifier;
}
else
{
mDecoderLogicalChannelNameIdentifier = null;
}
broadcastUpdate(ChannelMetadataField.DECODER_CHANNEL_NAME);
break;
case STATE:
mDecoderStateIdentifier = update.isAdded() ? (DecoderStateIdentifier)identifier : null;
if(identifier instanceof ChannelStateIdentifier && (update.isAdd() || update.isSilentAdd()))
{
mChannelStateIdentifier = (ChannelStateIdentifier)identifier;
}
else
{
mChannelStateIdentifier = null;
}
broadcastUpdate(ChannelMetadataField.DECODER_STATE);
break;
}
@@ -305,7 +354,7 @@ public class ChannelMetadata implements Listener<IdentifierUpdateNotification>,
case USER:
if(identifier.getRole() == Role.FROM)
{
mFromIdentifier = update.isAdded() ? identifier : null;
mFromIdentifier = update.isAdd() ? identifier : null;
if(mAliasList != null && mFromIdentifier != null)
{
@@ -320,7 +369,7 @@ public class ChannelMetadata implements Listener<IdentifierUpdateNotification>,
}
else if(identifier.getRole() == Role.TO)
{
mToIdentifier = update.isAdded() ? identifier : null;
mToIdentifier = update.isAdd() ? identifier : null;
if(mAliasList != null && mToIdentifier != null)
{