Merges #34 Major redesign of Tuner, Channel and Alias management.

Changes to model, view and controller components and updates all gui
editors.  Removes the configuration panel and tree and replaces with 3
new panels.  Updates playlist.xml to a new playlist_v2.xml format.
This commit is contained in:
denny
2016-04-01 08:23:49 -04:00
450 changed files with 19560 additions and 22805 deletions

View File

@@ -1,110 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import javax.swing.JCheckBox;
import javax.swing.SwingUtilities;
import module.decode.config.AuxDecodeConfiguration;
import controller.channel.AbstractChannelEditor;
import controller.channel.ChannelNode;
public class AuxDecodeComponentEditor extends AbstractChannelEditor
{
private static final long serialVersionUID = 1L;
private HashMap<DecoderType,AuxDecoderCheckBox> mControls =
new HashMap<DecoderType,AuxDecoderCheckBox>();
public AuxDecodeComponentEditor( ChannelNode channelNode )
{
super( channelNode );
List<DecoderType> decoders = DecoderType.getAuxDecoders();
Collections.sort( decoders );
for( DecoderType decoder: decoders )
{
AuxDecoderCheckBox control = new AuxDecoderCheckBox( decoder );
if( getConfig().getAuxDecoders().contains( decoder ) )
{
control.setSelected( true );
}
add( control, "wrap" );
mControls.put( decoder, control );
}
}
public AuxDecodeConfiguration getConfig()
{
return getChannelNode().getChannel().getAuxDecodeConfiguration();
}
@Override
public void save()
{
getConfig().clearAuxDecoders();
for( DecoderType decoder: mControls.keySet() )
{
if( mControls.get( decoder ) .isSelected() )
{
getConfig().addAuxDecoder( decoder );
}
}
}
@Override
public void reset()
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
for( DecoderType decoder: mControls.keySet() )
{
mControls.get( decoder ).setSelected(
getConfig().getAuxDecoders().contains( decoder ) );
}
}
});
}
public class AuxDecoderCheckBox extends JCheckBox
{
private static final long serialVersionUID = 1L;
private DecoderType mDecoderType;
public AuxDecoderCheckBox( DecoderType decoder )
{
super( decoder.getDisplayString() );
mDecoderType = decoder;
}
}
}

View File

@@ -0,0 +1,153 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode;
import gui.editor.Editor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JCheckBox;
import module.decode.config.AuxDecodeConfiguration;
import net.miginfocom.swing.MigLayout;
import controller.channel.Channel;
public class AuxDecodeConfigurationEditor extends Editor<Channel>
{
private static final long serialVersionUID = 1L;
private List<AuxDecoderCheckBox> mControls = new ArrayList<>();
public AuxDecodeConfigurationEditor()
{
init();
}
public AuxDecodeConfiguration getConfiguration()
{
return hasItem() ? getItem().getAuxDecodeConfiguration() : null;
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 4", "", "[][grow]" ) );
List<DecoderType> decoders = DecoderType.getAuxDecoders();
Collections.sort( decoders );
for( DecoderType decoder: decoders )
{
AuxDecoderCheckBox control = new AuxDecoderCheckBox( decoder );
control.setEnabled( false );
control.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( control );
mControls.add( control );
}
}
@Override
public void save()
{
if( hasItem() )
{
AuxDecodeConfiguration config = getItem().getAuxDecodeConfiguration();
config.clearAuxDecoders();
for( AuxDecoderCheckBox checkBox: mControls )
{
if( checkBox.isSelected() )
{
config.addAuxDecoder( checkBox.getDecoderType() );
}
}
}
setModified( false );
}
private void setControlsEnabled( boolean enabled )
{
for( AuxDecoderCheckBox box: mControls )
{
if( box.isEnabled() != enabled )
{
box.setEnabled( enabled );
}
}
}
public class AuxDecoderCheckBox extends JCheckBox
{
private static final long serialVersionUID = 1L;
private DecoderType mDecoderType;
public AuxDecoderCheckBox( DecoderType decoder )
{
super( decoder.getDisplayString() );
mDecoderType = decoder;
}
public DecoderType getDecoderType()
{
return mDecoderType;
}
}
@Override
public void setItem( Channel channel )
{
super.setItem( channel );
if( hasItem() )
{
setControlsEnabled( true );
for( AuxDecoderCheckBox cb: mControls )
{
if( getItem().getAuxDecodeConfiguration().getAuxDecoders().contains( cb.getDecoderType() ) )
{
cb.setSelected( true );
}
else
{
cb.setSelected( false );
}
}
}
else
{
setControlsEnabled( false );
}
}
}

View File

@@ -1,172 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import module.decode.config.DecodeConfigFactory;
import module.decode.config.DecodeConfiguration;
import net.miginfocom.swing.MigLayout;
import playlist.PlaylistManager;
import controller.Editor;
import controller.channel.AbstractChannelEditor;
import controller.channel.Channel;
import controller.channel.ChannelNode;
import controller.channel.ChannelValidationException;
public class DecodeComponentEditor extends AbstractChannelEditor
{
private static final long serialVersionUID = 1L;
private JComboBox<DecoderType> mComboDecoders;
private DecodeEditor mEditor;
private PlaylistManager mPlaylistManager;
public DecodeComponentEditor( PlaylistManager playlistManager )
{
this( new ChannelNode( new Channel() ), playlistManager );
}
public DecodeComponentEditor( ChannelNode channelNode,
PlaylistManager playlistMangager )
{
super( channelNode );
mPlaylistManager = playlistMangager;
setLayout( new MigLayout( "fill,wrap 2", "[right,grow][grow]", "[][][grow]" ) );
/**
* ComboBox: Decoders
*/
mComboDecoders = new JComboBox<DecoderType>();
DefaultComboBoxModel<DecoderType> model =
new DefaultComboBoxModel<DecoderType>();
for( DecoderType type: DecoderType.getPrimaryDecoders() )
{
model.addElement( type );
}
mComboDecoders.setModel( model );
mComboDecoders.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
DecoderType selected = mComboDecoders
.getItemAt( mComboDecoders.getSelectedIndex() );
if( selected != null )
{
DecodeConfiguration config;
if( mChannelNode.getChannel()
.getDecodeConfiguration().getDecoderType() ==
selected )
{
config = mChannelNode.getChannel()
.getDecodeConfiguration();
}
else
{
config = DecodeConfigFactory
.getDecodeConfiguration( selected );
}
//Remove the existing one
if( mEditor != null )
{
remove( mEditor );
}
//Change to the new one
mEditor = DecoderFactory.getEditorPanel( config,
mChannelNode, mPlaylistManager );
add( mEditor, "span 2,center" );
revalidate();
repaint();
}
}
});
add( new JLabel( "Decoder:" ) );
add( mComboDecoders, "wrap" );
reset();
}
public void reset()
{
final DecoderType decoder = mChannelNode.getChannel()
.getDecodeConfiguration().getDecoderType();
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run() {
mComboDecoders.setSelectedItem( decoder );
mComboDecoders.requestFocus();
mComboDecoders.requestFocusInWindow();
}
});
}
public DecodeConfiguration getDecodeConfig()
{
return mEditor.getConfig();
}
@Override
public void save()
{
if( mEditor != null )
{
mEditor.save();
}
//The component that calls save will invoke the change broadcast
mChannelNode.getChannel()
.setDecodeConfiguration( mEditor.getConfig(), false );
}
/**
* Validates the editor against the current decode editor
*/
@Override
public void validate( Editor editor ) throws ChannelValidationException
{
super.validate( editor );
mEditor.validate( editor );
}
}

View File

@@ -0,0 +1,137 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode;
import gui.editor.Editor;
import gui.editor.EditorValidationException;
import gui.editor.EmptyValidatingEditor;
import gui.editor.ValidatingEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import net.miginfocom.swing.MigLayout;
import controller.channel.Channel;
import controller.channel.map.ChannelMapModel;
public class DecodeConfigurationEditor extends ValidatingEditor<Channel>
{
private static final long serialVersionUID = 1L;
private JComboBox<DecoderType> mComboDecoders;
private ValidatingEditor<Channel> mCurrentEditor = new EmptyValidatingEditor<>( "a decoder" );
private ChannelMapModel mChannelMapModel;
public DecodeConfigurationEditor( final ChannelMapModel channelMapModel )
{
mChannelMapModel = channelMapModel;
init();
}
private void init()
{
setLayout( new MigLayout( "wrap 2", "[][grow,fill]", "[align top][grow,fill]" ) );
mComboDecoders = new JComboBox<DecoderType>();
mComboDecoders.setEnabled( false );
DefaultComboBoxModel<DecoderType> model = new DefaultComboBoxModel<DecoderType>();
for( DecoderType type: DecoderType.getPrimaryDecoders() )
{
model.addElement( type );
}
mComboDecoders.setModel( model );
mComboDecoders.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
DecoderType selected = mComboDecoders.getItemAt( mComboDecoders.getSelectedIndex() );
ValidatingEditor<Channel> editor = DecoderFactory.getEditor( selected, mChannelMapModel );
setEditor( editor );
}
});
add( mComboDecoders );
add( mCurrentEditor );
}
private void setEditor( ValidatingEditor<Channel> editor )
{
if( mCurrentEditor != editor )
{
//Set channel to null in current editor to force a save prompt as required
if( mCurrentEditor.isModified() )
{
mCurrentEditor.setItem( null );
}
remove( mCurrentEditor );
mCurrentEditor = editor;
mCurrentEditor.setSaveRequestListener( this );
mCurrentEditor.setItem( getItem() );
add( mCurrentEditor );
revalidate();
repaint();
}
}
@Override
public void save()
{
if( hasItem() )
{
mCurrentEditor.save();
}
setModified( false );
}
@Override
public void setItem( Channel channel )
{
super.setItem( channel );
if( hasItem() )
{
mComboDecoders.setEnabled( true );
mComboDecoders.setSelectedItem( channel.getDecodeConfiguration().getDecoderType() );
mCurrentEditor.setItem( channel );
}
else
{
mComboDecoders.setEnabled( false );
}
setModified( false );
}
@Override
public void validate( Editor<Channel> editor ) throws EditorValidationException
{
mCurrentEditor.validate( editor );
}
}

View File

@@ -1,116 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JSpinner;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import module.decode.config.DecodeConfiguration;
import net.miginfocom.swing.MigLayout;
import controller.Editor;
public class DecodeEditor extends Editor
{
private static final long serialVersionUID = 1L;
protected DecodeConfiguration mConfig;
protected JCheckBox mAFC;
protected JSpinner mAFCMaximumCorrection;
public DecodeEditor( DecodeConfiguration config )
{
setLayout( new MigLayout( "fill,wrap 2", "[right,grow][grow]", "[][][][][grow]" ) );
mConfig = config;
if( config.supportsAFC() )
{
mAFC = new JCheckBox( "Automatic Frequency Control" );
mAFC.setSelected( mConfig.isAFCEnabled() );
mAFC.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
mConfig.setAFC( mAFC.isSelected() );
}
} );
mAFC.setToolTipText( "AFC automatically adjusts the center "
+ "frequency of the channel to correct/compensate for "
+ "inaccuracies and frequency drift in the tuner" );
add( mAFC, "span" );
int initial = mConfig.getAFCMaximumCorrection();
SpinnerModel model = new SpinnerNumberModel( initial, 0, 15000, 1 );
mAFCMaximumCorrection = new JSpinner( model );
JSpinner.NumberEditor editor =
(JSpinner.NumberEditor)mAFCMaximumCorrection.getEditor();
editor.getTextField().setHorizontalAlignment( SwingConstants.CENTER );
mAFCMaximumCorrection.setToolTipText( "Sets the maximum frequency "
+ "correction value in hertz, 0 - 15kHz" );
mAFCMaximumCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
int value = ((SpinnerNumberModel)mAFCMaximumCorrection
.getModel()).getNumber().intValue();
mConfig.setAFCMaximumCorrection( value );
save();
}
} );
add( new JLabel( "Correction Limit Hz:" ) );
add( mAFCMaximumCorrection, "wrap" );
}
}
public DecodeConfiguration getConfig()
{
return mConfig;
}
@Override
public void save()
{
}
@Override
public void reset()
{
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014,2015 Dennis Sheirer
* Copyright (C) 2014-2016 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
@@ -20,13 +20,13 @@ package module.decode;
import message.IMessageProvider;
import message.Message;
import module.Module;
import sample.Broadcaster;
import sample.Listener;
public abstract class Decoder extends Module implements IMessageProvider
public abstract class Decoder extends Module
implements IMessageProvider, Listener<Message>
{
/* This has to be a broadcaster in order for references to persist */
protected Broadcaster<Message> mMessageBroadcaster = new Broadcaster<>();
protected Listener<Message> mMessageListener;
/**
* Decoder - parent class for all decoders, demodulators and components.
@@ -38,8 +38,7 @@ public abstract class Decoder extends Module implements IMessageProvider
@Override
public void dispose()
{
mMessageBroadcaster.dispose();
mMessageBroadcaster = null;
mMessageListener = null;
}
/**
@@ -52,9 +51,9 @@ public abstract class Decoder extends Module implements IMessageProvider
* Adds a listener for receiving decoded messages from this decoder
*/
@Override
public void addMessageListener( Listener<Message> listener )
public void setMessageListener( Listener<Message> listener )
{
mMessageBroadcaster.addListener( listener );
mMessageListener = listener;
}
/**
@@ -62,8 +61,25 @@ public abstract class Decoder extends Module implements IMessageProvider
* decoders
*/
@Override
public void removeMessageListener( Listener<Message> listener )
public void removeMessageListener()
{
mMessageBroadcaster.removeListener( listener );
mMessageListener = null;
}
/**
* Broadcasts the message to the registered message listener
*/
public void broadcast( Message message )
{
if( mMessageListener != null )
{
mMessageListener.receive( message );
}
}
@Override
public void receive( Message message )
{
broadcast( message );
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 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
@@ -25,7 +25,9 @@ import message.Message;
import message.MessageDirection;
import module.Module;
import module.decode.am.AMDecoder;
import module.decode.am.AMDecoderEditor;
import module.decode.am.AMDecoderPanel;
import module.decode.am.DecodeConfigAM;
import module.decode.config.AuxDecodeConfiguration;
import module.decode.config.DecodeConfiguration;
import module.decode.fleetsync2.Fleetsync2Decoder;
@@ -38,43 +40,45 @@ import module.decode.lj1200.LJ1200DecoderState;
import module.decode.lj1200.LJ1200MessageFilter;
import module.decode.ltrnet.DecodeConfigLTRNet;
import module.decode.ltrnet.LTRNetDecoder;
import module.decode.ltrnet.LTRNetDecoderEditor;
import module.decode.ltrnet.LTRNetDecoderPanel;
import module.decode.ltrnet.LTRNetDecoderState;
import module.decode.ltrnet.LTRNetEditor;
import module.decode.ltrnet.LTRNetMessageFilter;
import module.decode.ltrstandard.DecodeConfigLTRStandard;
import module.decode.ltrstandard.LTRStandardDecoder;
import module.decode.ltrstandard.LTRStandardDecoderEditor;
import module.decode.ltrstandard.LTRStandardDecoderPanel;
import module.decode.ltrstandard.LTRStandardDecoderState;
import module.decode.ltrstandard.LTRStandardEditor;
import module.decode.ltrstandard.LTRStandardMessageFilter;
import module.decode.mdc1200.MDCDecoder;
import module.decode.mdc1200.MDCDecoderPanel;
import module.decode.mdc1200.MDCDecoderState;
import module.decode.mdc1200.MDCMessageFilter;
import module.decode.mpt1327.DecodeConfigMPT1327;
import module.decode.mpt1327.MPT1327ConfigEditor;
import module.decode.mpt1327.MPT1327Decoder;
import module.decode.mpt1327.MPT1327Decoder.Sync;
import module.decode.mpt1327.MPT1327DecoderEditor;
import module.decode.mpt1327.MPT1327DecoderPanel;
import module.decode.mpt1327.MPT1327DecoderState;
import module.decode.mpt1327.MPT1327MessageFilter;
import module.decode.nbfm.DecodeConfigNBFM;
import module.decode.nbfm.NBFMDecoder;
import module.decode.nbfm.NBFMDecoderEditor;
import module.decode.nbfm.NBFMDecoderPanel;
import module.decode.nbfm.NBFMEditor;
import module.decode.p25.DecodeConfigP25Phase1;
import module.decode.p25.P25Decoder.Modulation;
import module.decode.p25.P25DecoderEditor;
import module.decode.p25.P25DecoderPanel;
import module.decode.p25.P25DecoderState;
import module.decode.p25.P25DecodeEditor;
import module.decode.p25.P25_C4FMDecoder;
import module.decode.p25.P25_LSMDecoder;
import module.decode.p25.audio.P25AudioModule;
import module.decode.p25.message.filter.P25MessageFilterSet;
import module.decode.passport.DecodeConfigPassport;
import module.decode.passport.PassportDecoder;
import module.decode.passport.PassportDecoderEditor;
import module.decode.passport.PassportDecoderPanel;
import module.decode.passport.PassportDecoderState;
import module.decode.passport.PassportEditor;
import module.decode.passport.PassportMessageFilter;
import module.decode.state.AlwaysUnsquelchedDecoderState;
import module.decode.state.DecoderPanel;
@@ -84,33 +88,30 @@ import module.decode.tait.Tait1200Decoder;
import module.decode.tait.Tait1200DecoderPanel;
import module.decode.tait.Tait1200DecoderState;
import module.demodulate.am.AMDemodulatorModule;
import module.demodulate.audio.DemodulatedAudioFilterModule;
import module.demodulate.fm.FMDemodulatorModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import playlist.PlaylistManager;
import properties.SystemProperties;
import record.RecorderType;
import record.config.RecordConfiguration;
import settings.SettingsManager;
import util.TimeStamp;
import alias.AliasList;
import alias.AliasModel;
import audio.AudioModule;
import controller.ResourceManager;
import controller.channel.Channel;
import controller.channel.Channel.ChannelType;
import controller.channel.ChannelNode;
import controller.channel.ChannelModel;
import controller.channel.ChannelProcessingManager;
import controller.channel.map.ChannelMap;
import controller.site.Site;
import controller.system.System;
import controller.channel.map.ChannelMapModel;
import filter.AllPassFilter;
import filter.FilterSet;
import filter.IFilter;
import gui.editor.EmptyValidatingEditor;
import gui.editor.ValidatingEditor;
public class DecoderFactory
{
private final static Logger mLog = LoggerFactory.getLogger( DecoderFactory.class );
public static final boolean NO_REMOVE_DC = false;
public static final boolean REMOVE_DC = true;
@@ -120,72 +121,46 @@ public class DecoderFactory
* Returns a list of one primary decoder and any auxiliary decoders, as
* specified in the configurations.
*
* @param channelType - standard or traffic channel type
* @param resourceManager
* @param decodeConfig - primary decoder configuration
* @param recordConfig - recording configuration used by traffic channel manager
* @param auxConfig - auxiliary decoder(s) configuration
* @param optional alias list - (null is ok)
*
* @return list of configured decoders
*/
public static List<Module> getModules( ChannelType channelType,
ResourceManager resourceManager,
DecodeConfiguration decodeConfig,
RecordConfiguration recordConfig,
AuxDecodeConfiguration auxConfig,
AliasList aliasList,
System system,
Site site,
String channelName )
public static List<Module> getModules( ChannelModel channelModel,
ChannelMapModel channelMapModel,
ChannelProcessingManager channelProcessingManager,
AliasModel aliasModel,
Channel channel )
{
List<Module> modules = getPrimaryModules( channelType, decodeConfig,
recordConfig, aliasList, system, site, channelName, resourceManager );
modules.addAll( getAuxiliaryDecoders( auxConfig, aliasList ) );
/* Get the optional alias list for the decode modules to use */
AliasList aliasList = aliasModel.getAliasList( channel.getAliasListName() );
List<Module> modules = getPrimaryModules( channelModel, channelMapModel,
channelProcessingManager, aliasList, channel );
modules.addAll( getAuxiliaryDecoders( channel.getAuxDecodeConfiguration(), aliasList ) );
return modules;
}
public static FMDemodulatorModule getFMDemodulator(
DecodeConfiguration config, int pass, int stop, boolean removeDC )
{
if( config.isAFCEnabled() )
{
return new FMDemodulatorModule( pass, stop,
config.getAFCMaximumCorrection(), removeDC );
}
else
{
return new FMDemodulatorModule( pass, stop,
NO_FREQUENCY_CORRECTION, removeDC );
}
}
/**
* Constructs a primary decoder as specified in the decode configuration
*
* @param channelType - traffic or standard decode channel
* @param decodeConfig - primary decoder configuration
* @param recordConfig - recording options
* @param aliasList - optional alias list
* @param resourceManager - shared resource manager
* @return configured decoder or null
*/
public static List<Module> getPrimaryModules( ChannelType channelType,
DecodeConfiguration decodeConfig,
RecordConfiguration recordConfig,
public static List<Module> getPrimaryModules( ChannelModel channelModel,
ChannelMapModel channelMapModel,
ChannelProcessingManager channelProcessingManager,
AliasList aliasList,
System system,
Site site,
String channelName,
ResourceManager resourceManager )
Channel channel )
{
List<Module> modules = new ArrayList<Module>();
ChannelType channelType = channel.getChannelType();
/* Baseband low-pass filter pass and stop frequencies */
int pass = decodeConfig.getDecoderType().getChannelBandwidth() / 2;
int stop = pass + 1250;
DecodeConfiguration decodeConfig = channel.getDecodeConfiguration();
int iqPass = decodeConfig.getDecoderType().getChannelBandwidth() / 2;
int iqStop = iqPass + 1250;
RecordConfiguration recordConfig = channel.getRecordConfiguration();
boolean recordAudio = recordConfig == null ? false :
recordConfig.getRecorders().contains( RecorderType.AUDIO );
@@ -193,41 +168,45 @@ public class DecoderFactory
switch( decodeConfig.getDecoderType() )
{
case AM:
modules.add( new AMDemodulatorModule() );
modules.add( new AMDecoder( decodeConfig ) );
modules.add( new AlwaysUnsquelchedDecoderState( DecoderType.AM, channelName ) );
modules.add( new AudioModule( recordAudio, REMOVE_DC ) );
modules.add( new AlwaysUnsquelchedDecoderState( DecoderType.AM, channel.getName() ) );
modules.add( new AMDemodulatorModule() );
modules.add( new DemodulatedAudioFilterModule( 4000, 6000 ));
modules.add( new AudioModule( recordAudio ) );
break;
case NBFM:
modules.add( new AudioModule( recordAudio, NO_REMOVE_DC ) );
modules.add( new NBFMDecoder( decodeConfig ) );
modules.add( new AlwaysUnsquelchedDecoderState( DecoderType.NBFM, channelName ) );
modules.add( getFMDemodulator( decodeConfig, pass, stop, REMOVE_DC ) );
modules.add( new AlwaysUnsquelchedDecoderState( DecoderType.NBFM, channel.getName() ) );
modules.add( new FMDemodulatorModule( iqPass, iqStop ) );
modules.add( new DemodulatedAudioFilterModule( 4000, 6000 ));
modules.add( new AudioModule( recordAudio ) );
break;
case LTR_STANDARD:
modules.add( new AudioModule( recordAudio, REMOVE_DC ) );
MessageDirection direction = ((DecodeConfigLTRStandard)decodeConfig).getMessageDirection();
modules.add( new LTRStandardDecoder( aliasList, direction ) );
modules.add( new LTRStandardDecoderState( aliasList ) );
modules.add( getFMDemodulator( decodeConfig, pass, stop, NO_REMOVE_DC ) );
modules.add( new FMDemodulatorModule( iqPass, iqStop ) );
modules.add( new DemodulatedAudioFilterModule( 4000, 6000 ));
modules.add( new AudioModule( recordAudio ) );
break;
case LTR_NET:
modules.add( new AudioModule( recordAudio, REMOVE_DC ) );
modules.add( new LTRNetDecoder( (DecodeConfigLTRNet)decodeConfig, aliasList ) );
modules.add( new LTRNetDecoderState( aliasList ) );
modules.add( getFMDemodulator( decodeConfig, pass, stop, NO_REMOVE_DC ) );
modules.add( new FMDemodulatorModule( iqPass, iqStop ) );
modules.add( new DemodulatedAudioFilterModule( 4000, 6000 ));
modules.add( new AudioModule( recordAudio ) );
break;
case MPT1327:
DecodeConfigMPT1327 mptConfig = (DecodeConfigMPT1327)decodeConfig;
modules.add( new AudioModule( recordAudio, NO_REMOVE_DC ) );
ChannelMap channelMap = resourceManager.getPlaylistManager().getPlayist()
.getChannelMapList().getChannelMap( mptConfig.getChannelMapName() );
ChannelMap channelMap = channelMapModel
.getChannelMap( mptConfig.getChannelMapName() );
Sync sync = mptConfig.getSync();
modules.add( new MPT1327Decoder( aliasList, sync ) );
modules.add( new MPT1327DecoderState( aliasList, channelMap,
channelType, mptConfig.getCallTimeout() * 1000 ) );
@@ -235,30 +214,34 @@ public class DecoderFactory
{
long timeout = mptConfig.getCallTimeout() * 1000; //convert to milliseconds
modules.add( new TrafficChannelManager( resourceManager,
decodeConfig, recordConfig, system, site,
( aliasList != null ? aliasList.getName() : null ), timeout,
mptConfig.getTrafficChannelPoolSize() ) );
modules.add( new TrafficChannelManager( channelModel, channelProcessingManager,
decodeConfig, recordConfig, channel.getSystem(),
channel.getSite(), ( aliasList != null ? aliasList.getName() : null ), timeout,
mptConfig.getTrafficChannelPoolSize() ) );
}
modules.add( getFMDemodulator( decodeConfig, pass, stop, REMOVE_DC ) );
modules.add( new FMDemodulatorModule( iqPass, iqStop ) );
modules.add( new DemodulatedAudioFilterModule( 4000, 6000 ));
modules.add( new AudioModule( recordAudio ) );
break;
case PASSPORT:
modules.add( new AudioModule( recordAudio, REMOVE_DC ) );
modules.add( new PassportDecoder( decodeConfig, aliasList ) );
modules.add( new PassportDecoderState( aliasList ) );
modules.add( getFMDemodulator( decodeConfig, pass, stop, NO_REMOVE_DC ) );
modules.add( new FMDemodulatorModule( iqPass, iqStop ) );
modules.add( new DemodulatedAudioFilterModule( 4000, 6000 ));
modules.add( new AudioModule( recordAudio ) );
break;
case P25_PHASE1:
DecodeConfigP25Phase1 p25Config = (DecodeConfigP25Phase1)decodeConfig;
Modulation modulation = p25Config.getModulation();
switch( modulation )
{
case C4FM:
modules.add( getFMDemodulator( decodeConfig, 6750, 7500, NO_REMOVE_DC ) );
modules.add( new P25_C4FMDecoder( aliasList ) );
modules.add( new FMDemodulatorModule( 6750, 7500 ) );
modules.add( new P25_C4FMDecoder( aliasList, decodeConfig.getAFCMaximumCorrection() ) );
modules.add( new P25DecoderState( aliasList, channelType,
Modulation.C4FM, p25Config.getIgnoreDataCalls() ) );
break;
@@ -277,8 +260,9 @@ public class DecoderFactory
//Set call timeout to 3 seconds for P25 traffic channels
long timeout = 3000;
modules.add( new TrafficChannelManager( resourceManager,
decodeConfig, recordConfig, system, site,
modules.add( new TrafficChannelManager( channelModel,
channelProcessingManager, decodeConfig,
recordConfig, channel.getSystem(), channel.getSite(),
( aliasList != null ? aliasList.getName() : null ), timeout,
p25Config.getTrafficChannelPoolSize() ) );
}
@@ -447,41 +431,132 @@ public class DecoderFactory
return filters;
}
public static DecodeEditor getEditorPanel( DecodeConfiguration config,
ChannelNode channelNode, PlaylistManager playlistManager )
public static DecodeConfiguration getDefaultDecodeConfiguration()
{
DecodeEditor configuredPanel;
switch( config.getDecoderType() )
return getDecodeConfiguration( DecoderType.NBFM );
}
public static DecodeConfiguration getDecodeConfiguration( DecoderType decoder )
{
DecodeConfiguration retVal;
switch( decoder )
{
case NBFM:
configuredPanel = new NBFMEditor( config );
break;
case LTR_STANDARD:
configuredPanel = new LTRStandardEditor( config );
break;
case AM:
return new DecodeConfigAM();
case LTR_NET:
configuredPanel = new LTRNetEditor( config );
break;
return new DecodeConfigLTRNet();
case LTR_STANDARD:
return new DecodeConfigLTRStandard();
case MPT1327:
configuredPanel = new MPT1327ConfigEditor( config,
channelNode, playlistManager );
break;
return new DecodeConfigMPT1327();
case NBFM:
return new DecodeConfigNBFM();
case PASSPORT:
configuredPanel = new PassportEditor( config );
break;
return new DecodeConfigPassport();
case P25_PHASE1:
configuredPanel = new P25DecodeEditor( config );
break;
return new DecodeConfigP25Phase1();
default:
throw new IllegalArgumentException( "DecodeConfigFactory - unknown decoder type ["
+ decoder.toString() + "]" );
}
}
public static ValidatingEditor<Channel> getEditor( DecoderType type, ChannelMapModel model )
{
switch( type )
{
case AM:
return new AMDecoderEditor();
case LTR_NET:
return new LTRNetDecoderEditor();
case LTR_STANDARD:
return new LTRStandardDecoderEditor();
case MPT1327:
return new MPT1327DecoderEditor( model );
case NBFM:
return new NBFMDecoderEditor();
case P25_PHASE1:
return new P25DecoderEditor();
case PASSPORT:
return new PassportDecoderEditor();
default:
configuredPanel = new DecodeEditor( config );
break;
}
return configuredPanel;
return new EmptyValidatingEditor<Channel>( "a decoder" );
}
/**
* Creates a copy of the configuration
*/
public static DecodeConfiguration copy( DecodeConfiguration config )
{
if( config != null )
{
switch( config.getDecoderType() )
{
case AM:
DecodeConfigAM originalAM = (DecodeConfigAM)config;
DecodeConfigAM copyAM = new DecodeConfigAM();
copyAM.setAFC( originalAM.getAFC() );
copyAM.setAFCMaximumCorrection( originalAM.getAFCMaximumCorrection() );
return copyAM;
case LTR_NET:
DecodeConfigLTRNet originalLTRNet = (DecodeConfigLTRNet)config;
DecodeConfigLTRNet copyLTRNet = new DecodeConfigLTRNet();
copyLTRNet.setAFC( originalLTRNet.getAFC() );
copyLTRNet.setAFCMaximumCorrection( originalLTRNet.getAFCMaximumCorrection() );
copyLTRNet.setMessageDirection( originalLTRNet.getMessageDirection() );
return copyLTRNet;
case LTR_STANDARD:
DecodeConfigLTRStandard originalLTRStandard = (DecodeConfigLTRStandard)config;
DecodeConfigLTRStandard copyLTRStandard = new DecodeConfigLTRStandard();
copyLTRStandard.setAFC( originalLTRStandard.getAFC() );
copyLTRStandard.setAFCMaximumCorrection( originalLTRStandard.getAFCMaximumCorrection() );
copyLTRStandard.setMessageDirection( originalLTRStandard.getMessageDirection() );
return copyLTRStandard;
case MPT1327:
DecodeConfigMPT1327 originalMPT = (DecodeConfigMPT1327)config;
DecodeConfigMPT1327 copyMPT = new DecodeConfigMPT1327();
copyMPT.setAFC( originalMPT.getAFC() );
copyMPT.setAFCMaximumCorrection( originalMPT.getAFCMaximumCorrection() );
copyMPT.setCallTimeout( originalMPT.getCallTimeout() );
copyMPT.setChannelMapName( originalMPT.getChannelMapName() );
copyMPT.setSync( originalMPT.getSync() );
copyMPT.setTrafficChannelPoolSize( originalMPT.getTrafficChannelPoolSize() );
return copyMPT;
case NBFM:
DecodeConfigNBFM originalNBFM = (DecodeConfigNBFM)config;
DecodeConfigNBFM copyNBFM = new DecodeConfigNBFM();
copyNBFM.setAFC( originalNBFM.getAFC() );
copyNBFM.setAFCMaximumCorrection( originalNBFM.getAFCMaximumCorrection() );
return copyNBFM;
case P25_PHASE1:
DecodeConfigP25Phase1 originalP25 = (DecodeConfigP25Phase1)config;
DecodeConfigP25Phase1 copyP25 = new DecodeConfigP25Phase1();
copyP25.setAFC( originalP25.getAFC() );
copyP25.setAFCMaximumCorrection( originalP25.getAFCMaximumCorrection() );
copyP25.setIgnoreDataCalls( originalP25.getIgnoreDataCalls() );
copyP25.setModulation( originalP25.getModulation() );
copyP25.setTrafficChannelPoolSize( originalP25.getTrafficChannelPoolSize() );
return copyP25;
case PASSPORT:
DecodeConfigPassport originalPass = (DecodeConfigPassport)config;
DecodeConfigPassport copyPass = new DecodeConfigPassport();
copyPass.setAFC( originalPass.getAFC() );
copyPass.setAFCMaximumCorrection( originalPass.getAFCMaximumCorrection() );
return copyPass;
default:
throw new IllegalArgumentException( "Unrecognized decoder "
+ "configuration type:" + config.getDecoderType() );
}
}
return null;
}
public static String getRecordingFilename( String token )
{
//Get the base recording filename

View File

@@ -18,6 +18,8 @@
package module.decode.am;
import java.util.concurrent.ScheduledExecutorService;
import module.decode.DecoderType;
import module.decode.PrimaryDecoder;
import module.decode.config.DecodeConfiguration;
@@ -41,7 +43,7 @@ public class AMDecoder extends PrimaryDecoder
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}

View File

@@ -0,0 +1,76 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.am;
import gui.editor.Editor;
import gui.editor.EditorValidationException;
import gui.editor.ValidatingEditor;
import javax.swing.JLabel;
import net.miginfocom.swing.MigLayout;
import controller.channel.Channel;
public class AMDecoderEditor extends ValidatingEditor<Channel>
{
private static final long serialVersionUID = 1L;
public AMDecoderEditor()
{
setLayout( new MigLayout( "insets 0 0 0 0", "", "" ) );
add( new JLabel( "AM Decoder" ) );
}
@Override
public void validate( Editor<Channel> editor ) throws EditorValidationException
{
}
@Override
public void setItem( Channel item )
{
super.setItem( item );
if( hasItem() )
{
if( getItem().getDecodeConfiguration() instanceof DecodeConfigAM )
{
setModified( false );
}
else
{
setModified( true );
}
}
else
{
setModified( false );
}
}
@Override
public void save()
{
if( hasItem() && isModified() )
{
getItem().setDecodeConfiguration( new DecodeConfigAM() );
}
setModified( false );
}
}

View File

@@ -1,31 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.am;
import module.decode.DecodeEditor;
import module.decode.config.DecodeConfiguration;
public class AMEditor extends DecodeEditor
{
private static final long serialVersionUID = 1L;
public AMEditor( DecodeConfiguration config )
{
super( config );
}
}

View File

@@ -1,71 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.config;
import module.decode.DecoderType;
import module.decode.am.DecodeConfigAM;
import module.decode.ltrnet.DecodeConfigLTRNet;
import module.decode.ltrstandard.DecodeConfigLTRStandard;
import module.decode.mpt1327.DecodeConfigMPT1327;
import module.decode.nbfm.DecodeConfigNBFM;
import module.decode.p25.DecodeConfigP25Phase1;
import module.decode.passport.DecodeConfigPassport;
public class DecodeConfigFactory
{
public static DecodeConfiguration getDefaultDecodeConfiguration()
{
return getDecodeConfiguration( DecoderType.NBFM );
}
public static DecodeConfiguration
getDecodeConfiguration( DecoderType decoder )
{
DecodeConfiguration retVal;
switch( decoder )
{
case AM:
retVal = new DecodeConfigAM();
break;
case NBFM:
retVal = new DecodeConfigNBFM();
break;
case LTR_STANDARD:
retVal = new DecodeConfigLTRStandard();
break;
case LTR_NET:
retVal = new DecodeConfigLTRNet();
break;
case MPT1327:
retVal = new DecodeConfigMPT1327();
break;
case PASSPORT:
retVal = new DecodeConfigPassport();
break;
case P25_PHASE1:
retVal = new DecodeConfigP25Phase1();
break;
default:
throw new IllegalArgumentException( "DecodeConfigFactory - "
+ "unknown decoder type [" + decoder.toString() + "]" );
}
return retVal;
}
}

View File

@@ -17,7 +17,7 @@
******************************************************************************/
package module.decode.config;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
@@ -48,10 +48,12 @@ public abstract class DecodeConfiguration extends Configuration
public static final int TRAFFIC_CHANNEL_LIMIT_DEFAULT = 3;
public static final int TRAFFIC_CHANNEL_LIMIT_MINIMUM = 0;
public static final int TRAFFIC_CHANNEL_LIMIT_MAXIMUM = 30;
public static final int DEFAULT_AFC_MAX_CORRECTION = 1000;
private DecoderType mDecoderType = DecoderType.NBFM;
private boolean mAFCEnabled = true;
private int mAFCMaxCorrection = 3000;
private int mAFCMaxCorrection = DEFAULT_AFC_MAX_CORRECTION;
public DecodeConfiguration()
{
@@ -68,7 +70,7 @@ public abstract class DecodeConfiguration extends Configuration
return mDecoderType;
}
@XmlElement( name = "afc" )
@XmlAttribute( name = "afc" )
public boolean getAFC()
{
return mAFCEnabled;
@@ -84,6 +86,7 @@ public abstract class DecodeConfiguration extends Configuration
mAFCEnabled = enabled;
}
@XmlAttribute( name = "AFCMaximumCorrection" )
public int getAFCMaximumCorrection()
{
return mAFCMaxCorrection;

View File

@@ -20,9 +20,6 @@ package module.decode.event;
import javax.swing.ImageIcon;
import javax.swing.table.DefaultTableCellRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import settings.SettingsManager;
import alias.Alias;
@@ -35,9 +32,6 @@ public class CallEventAliasCellRenderer extends DefaultTableCellRenderer
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory
.getLogger( CallEventAliasCellRenderer.class );
private SettingsManager mSettingsManager;
public CallEventAliasCellRenderer( SettingsManager settingsManager )

View File

@@ -25,20 +25,13 @@ import java.util.List;
import javax.swing.table.AbstractTableModel;
import module.decode.event.CallEvent.CallEventType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
public class CallEventModel extends AbstractTableModel implements Listener<CallEvent>
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( CallEventModel.class );
private static DecimalFormat mFrequencyFormatter =
new DecimalFormat( "0.000000" );
private static DecimalFormat mFrequencyFormatter = new DecimalFormat( "0.000000" );
public static final int TIME = 0;
public static final int EVENT = 1;

View File

@@ -23,12 +23,14 @@ import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import module.ProcessingChain;
import net.miginfocom.swing.MigLayout;
import settings.SettingsManager;
import controller.channel.Channel;
import controller.channel.ChannelEvent;
import controller.channel.ChannelEvent.Event;
import controller.channel.ChannelEventListener;
import controller.channel.ChannelProcessingManager;
public class CallEventPanel extends JPanel implements ChannelEventListener
{
@@ -37,9 +39,13 @@ public class CallEventPanel extends JPanel implements ChannelEventListener
private JScrollPane mEmptyScroller;
private Channel mDisplayedChannel;
private CallEventAliasCellRenderer mRenderer;
private ChannelProcessingManager mChannelProcessingManager;
public CallEventPanel( SettingsManager settingsManager )
public CallEventPanel( SettingsManager settingsManager,
ChannelProcessingManager channelProcessingManager )
{
mChannelProcessingManager = channelProcessingManager;
setLayout( new MigLayout("insets 0 0 0 0 ", "[grow,fill]", "[grow,fill]") );
JTable table = new JTable( new CallEventModel() );
@@ -62,45 +68,54 @@ public class CallEventPanel extends JPanel implements ChannelEventListener
@Override
public void channelChanged( final ChannelEvent event )
{
if( event.getEvent() == Event.CHANGE_SELECTED &&
if( event.getEvent() == Event.NOTIFICATION_SELECTION_CHANGE &&
event.getChannel().isSelected() )
{
if( mDisplayedChannel == null ||
( mDisplayedChannel != null &&
mDisplayedChannel != event.getChannel() ) )
{
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
removeAll();
JTable table = new JTable(
event.getChannel().getCallEventModel() );
table.setAutoCreateRowSorter( true );
table.setAutoResizeMode( JTable.AUTO_RESIZE_LAST_COLUMN );
table.getColumnModel().getColumn( CallEventModel.FROM_ALIAS )
.setCellRenderer( mRenderer );
table.getColumnModel().getColumn( CallEventModel.TO_ALIAS )
.setCellRenderer( mRenderer );
add( new JScrollPane( table ) );
mDisplayedChannel = event.getChannel();
revalidate();
repaint();
}
} );
ProcessingChain chain = mChannelProcessingManager
.getProcessingChain( event.getChannel() );
if( chain != null )
{
final CallEventModel model = chain.getCallEventModel();
if( model != null )
{
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
removeAll();
JTable table = new JTable( model );
table.setAutoCreateRowSorter( true );
table.setAutoResizeMode( JTable.AUTO_RESIZE_LAST_COLUMN );
table.getColumnModel().getColumn( CallEventModel.FROM_ALIAS )
.setCellRenderer( mRenderer );
table.getColumnModel().getColumn( CallEventModel.TO_ALIAS )
.setCellRenderer( mRenderer );
add( new JScrollPane( table ) );
mDisplayedChannel = event.getChannel();
revalidate();
repaint();
}
} );
}
}
}
}
else if( event.getEvent() == Event.CHANNEL_PROCESSING_STOPPED ||
event.getEvent() == Event.CHANNEL_DISABLED )
else if( event.getEvent() == Event.NOTIFICATION_PROCESSING_STOP ||
event.getEvent() == Event.REQUEST_DISABLE )
{
if( mDisplayedChannel != null &&
mDisplayedChannel == event.getChannel() )

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 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
@@ -32,11 +32,11 @@ public class MessageActivityModel extends AbstractTableModel
implements Listener<Message>
{
private static final long serialVersionUID = 1L;
private static final int sTIME = 0;
private static final int sPROTOCOL = 1;
private static final int sERROR_STATUS = 2;
private static final int sMESSAGE = 3;
private static final int sMESSAGE_BITS = 4;
private static final int TIME = 0;
private static final int PROTOCOL = 1;
private static final int ERROR_STATUS = 2;
private static final int MESSAGE = 3;
private static final int MESSAGE_BITS = 4;
protected int mMaxMessages = 500;
protected LinkedList<Message> mMessages = new LinkedList<Message>();
@@ -174,18 +174,18 @@ public class MessageActivityModel extends AbstractTableModel
switch( columnIndex )
{
case sTIME:
case TIME:
return mSDFTime.format( new Date( message.getTimeReceived() ) );
case sPROTOCOL:
case PROTOCOL:
return message.getProtocol();
case sERROR_STATUS:
case ERROR_STATUS:
return message.getErrorStatus();
case sMESSAGE:
case MESSAGE:
return message.getMessage();
case sMESSAGE_BITS:
case MESSAGE_BITS:
return message.getBinaryMessage();
}
return null;
}
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 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
@@ -36,6 +36,7 @@ import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import message.Message;
import module.ProcessingChain;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
@@ -48,6 +49,7 @@ import controller.channel.Channel;
import controller.channel.ChannelEvent;
import controller.channel.ChannelEvent.Event;
import controller.channel.ChannelEventListener;
import controller.channel.ChannelProcessingManager;
import filter.FilterEditorPanel;
import filter.FilterSet;
@@ -63,16 +65,21 @@ public class MessageActivityPanel extends JPanel implements ChannelEventListener
private JTable mMessageTable;
private Channel mDisplayedChannel;
private MessageActivityModel mDisplayedModel = EMPTY_MODEL;
private MessageManagementPanel mManagementPanel = new MessageManagementPanel();
private ChannelProcessingManager mChannelProcessingManager;
public MessageActivityPanel()
public MessageActivityPanel( ChannelProcessingManager channelProcessingManager )
{
mChannelProcessingManager = channelProcessingManager;
setLayout( new MigLayout("insets 0 0 0 0", "[][grow,fill]", "[]0[grow,fill]") );
add( mManagementPanel, "span,growx" );
mMessageTable = new JTable( EMPTY_MODEL );
mMessageTable = new JTable( mDisplayedModel );
add( new JScrollPane( mMessageTable ), "span,grow" );
}
@@ -82,7 +89,7 @@ public class MessageActivityPanel extends JPanel implements ChannelEventListener
{
boolean changed = false;
if( event.getEvent() == Event.CHANGE_SELECTED &&
if( event.getEvent() == Event.NOTIFICATION_SELECTION_CHANGE &&
event.getChannel().isSelected() )
{
if( mDisplayedChannel == null ||
@@ -91,7 +98,19 @@ public class MessageActivityPanel extends JPanel implements ChannelEventListener
{
mDisplayedChannel = event.getChannel();
mMessageTable.setModel( event.getChannel().getMessageActivityModel() );
ProcessingChain chain = mChannelProcessingManager
.getProcessingChain( mDisplayedChannel );
if( chain != null )
{
mDisplayedModel = chain.getMessageActivityModel();
}
else
{
mDisplayedModel = EMPTY_MODEL;
}
mMessageTable.setModel( mDisplayedModel );
if( mDisplayedChannel != null )
{
@@ -105,8 +124,8 @@ public class MessageActivityPanel extends JPanel implements ChannelEventListener
changed = true;
}
}
else if( event.getEvent() == Event.CHANNEL_PROCESSING_STOPPED ||
event.getEvent() == Event.CHANNEL_DISABLED )
else if( event.getEvent() == Event.NOTIFICATION_PROCESSING_STOP ||
event.getEvent() == Event.REQUEST_DISABLE )
{
if( mDisplayedChannel != null &&
mDisplayedChannel == event.getChannel() )
@@ -195,10 +214,9 @@ public class MessageActivityPanel extends JPanel implements ChannelEventListener
public void mouseReleased( MouseEvent arg0 ) {}
} );
if( mDisplayedChannel != null )
if( mDisplayedModel != null )
{
slider.setValue( mDisplayedChannel.getMessageActivityModel()
.getMaxMessageCount() );
slider.setValue( mDisplayedModel.getMaxMessageCount() );
}
else
{
@@ -210,10 +228,9 @@ public class MessageActivityPanel extends JPanel implements ChannelEventListener
@Override
public void stateChanged( ChangeEvent arg0 )
{
if( mDisplayedChannel != null )
if( mDisplayedModel != null )
{
mDisplayedChannel.getMessageActivityModel()
.setMaxMessageCount( slider.getValue() );
mDisplayedModel.setMaxMessageCount( slider.getValue() );
}
}
});
@@ -228,9 +245,9 @@ public class MessageActivityPanel extends JPanel implements ChannelEventListener
@Override
public void actionPerformed( ActionEvent e )
{
if( mDisplayedChannel != null )
if( mDisplayedModel != null )
{
mDisplayedChannel.getMessageActivityModel().clear();
mDisplayedModel.clear();
}
}
} );
@@ -258,50 +275,52 @@ public class MessageActivityPanel extends JPanel implements ChannelEventListener
}
else
{
final JFrame editor = new JFrame();
editor.setTitle( "Message Filter Editor" );
editor.setSize( 600, 400 );
editor.setLocationRelativeTo( MessageFilterButton.this );
editor.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
editor.setLayout( new MigLayout( "", "[grow,fill]",
"[grow,fill][][]" ) );
@SuppressWarnings( "unchecked" )
FilterSet<Message> filter = (FilterSet<Message>)
mDisplayedChannel.getMessageActivityModel()
.getMessageFilter();
FilterEditorPanel<Message> panel =
new FilterEditorPanel<Message>( filter );
JScrollPane scroller = new JScrollPane( panel );
scroller.setViewportView( panel );
editor.add( scroller, "wrap" );
editor.add( new JLabel( "Right-click to select/deselect "
+ "all nodes" ), "wrap" );
JButton close = new JButton( "Close" );
close.addActionListener( new ActionListener()
if( mDisplayedModel != null )
{
@Override
public void actionPerformed( ActionEvent e )
{
editor.dispose();
}
} );
editor.add( close );
final JFrame editor = new JFrame();
editor.setTitle( "Message Filter Editor" );
editor.setSize( 600, 400 );
editor.setLocationRelativeTo( MessageFilterButton.this );
editor.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
editor.setLayout( new MigLayout( "", "[grow,fill]",
"[grow,fill][][]" ) );
EventQueue.invokeLater( new Runnable()
{
public void run()
{
editor.setVisible( true );
}
} );
@SuppressWarnings( "unchecked" )
FilterSet<Message> filter = (FilterSet<Message>)
mDisplayedModel.getMessageFilter();
FilterEditorPanel<Message> panel =
new FilterEditorPanel<Message>( filter );
JScrollPane scroller = new JScrollPane( panel );
scroller.setViewportView( panel );
editor.add( scroller, "wrap" );
editor.add( new JLabel( "Right-click to select/deselect "
+ "all nodes" ), "wrap" );
JButton close = new JButton( "Close" );
close.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
editor.dispose();
}
} );
editor.add( close );
EventQueue.invokeLater( new Runnable()
{
public void run()
{
editor.setVisible( true );
}
} );
}
}
}
} );

View File

@@ -25,11 +25,12 @@ import instrument.tap.stream.FloatBufferTap;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import module.decode.Decoder;
import module.decode.DecoderType;
import sample.Listener;
import sample.real.IRealBufferListener;
import sample.real.IFilteredRealBufferListener;
import sample.real.RealBuffer;
import alias.AliasList;
import bits.MessageFramer;
@@ -44,7 +45,7 @@ import dsp.fsk.FSK2Decoder.Output;
* Fleetsync II Decoder - 1200 baud 2FSK decoder that can process 48k sample rate
* floating point samples and output fully framed Fleetsync II messages
*/
public class Fleetsync2Decoder extends Decoder implements IRealBufferListener,
public class Fleetsync2Decoder extends Decoder implements IFilteredRealBufferListener,
Instrumentable
{
/* Decimated sample rate ( 48,000 / 2 = 24,000 ) feeding the decoder */
@@ -90,7 +91,7 @@ public class Fleetsync2Decoder extends Decoder implements IRealBufferListener,
mMessageProcessor = new Fleetsync2MessageProcessor( aliasList );
mMessageFramer.addMessageListener( mMessageProcessor );
mMessageProcessor.setMessageListener( mMessageBroadcaster );
mMessageProcessor.setMessageListener( this );
}
public void dispose()
@@ -169,7 +170,7 @@ public class Fleetsync2Decoder extends Decoder implements IRealBufferListener,
}
@Override
public Listener<RealBuffer> getRealBufferListener()
public Listener<RealBuffer> getFilteredRealBufferListener()
{
return mDecimationFilter;
}
@@ -180,7 +181,7 @@ public class Fleetsync2Decoder extends Decoder implements IRealBufferListener,
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}

View File

@@ -19,6 +19,7 @@ package module.decode.fleetsync2;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.concurrent.ScheduledExecutorService;
import message.Message;
import module.decode.DecoderType;
@@ -58,7 +59,7 @@ public class Fleetsync2DecoderState extends DecoderState
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}

View File

@@ -26,12 +26,13 @@ import instrument.tap.stream.FloatTap;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import module.decode.Decoder;
import module.decode.DecoderType;
import sample.Broadcaster;
import sample.Listener;
import sample.real.IRealBufferListener;
import sample.real.IFilteredRealBufferListener;
import sample.real.RealBuffer;
import sample.real.RealSampleListener;
import alias.AliasList;
@@ -46,7 +47,7 @@ import dsp.fsk.FSK2Decoder.Output;
/**
* LJ1200 - 1200 baud 2FSK decoder
*/
public class LJ1200Decoder extends Decoder implements IRealBufferListener,
public class LJ1200Decoder extends Decoder implements IFilteredRealBufferListener,
Instrumentable
{
/* Decimated sample rate ( 48,000 / 2 = 24,000 ) feeding the decoder */
@@ -100,7 +101,7 @@ public class LJ1200Decoder extends Decoder implements IRealBufferListener,
mMessageProcessor = new LJ1200MessageProcessor( aliasList );
mTowerMessageFramer.addMessageListener( mMessageProcessor );
mTransponderMessageFramer.addMessageListener( mMessageProcessor );
mMessageProcessor.setMessageListener( mMessageBroadcaster );
mMessageProcessor.setMessageListener( this );
}
@Override
@@ -187,7 +188,7 @@ public class LJ1200Decoder extends Decoder implements IRealBufferListener,
}
@Override
public Listener<RealBuffer> getRealBufferListener()
public Listener<RealBuffer> getFilteredRealBufferListener()
{
return mDecimationFilter;
}
@@ -198,7 +199,7 @@ public class LJ1200Decoder extends Decoder implements IRealBufferListener,
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}

View File

@@ -22,18 +22,19 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.ScheduledExecutorService;
import message.Message;
import module.decode.DecoderType;
import module.decode.p25.P25DecoderState;
import module.decode.state.ChangedAttribute;
import module.decode.state.DecoderState;
import module.decode.state.DecoderStateEvent;
import module.decode.state.DecoderStateEvent.Event;
import module.decode.state.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import alias.Alias;
import alias.AliasList;
@@ -58,7 +59,7 @@ public class LJ1200DecoderState extends DecoderState
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}

View File

@@ -51,16 +51,22 @@ public class LTRCallEvent extends CallEvent
*/
public boolean isMatchingTalkgroup( LTRNetMessage message )
{
String talkgroup = message.getTalkgroupID();
if( talkgroup != null && getToID() != null &&
talkgroup.contentEquals( getToID() ) )
{
return true;
}
return isMatchingTalkgroup( message.getTalkgroupID() );
}
public boolean isMatchingTalkgroup( String talkgroup )
{
return talkgroup != null &&
getToID() != null &&
talkgroup.contentEquals( getToID() );
return talkgroup != null && getToID() != null && talkgroup.contentEquals( getToID() );
}
private Alias getAlias( String talkgroup )
{
if( hasAliasList() )

View File

@@ -23,19 +23,21 @@ import instrument.tap.TapGroup;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import message.MessageDirection;
import module.decode.Decoder;
import module.decode.DecoderType;
import sample.Listener;
import sample.real.IRealBufferListener;
import sample.real.IUnFilteredRealBufferListener;
import sample.real.RealBuffer;
import alias.AliasList;
import bits.MessageFramer;
import bits.SyncPattern;
import dsp.fsk.LTRFSKDecoder;
public class LTRNetDecoder extends Decoder implements IRealBufferListener, Instrumentable
public class LTRNetDecoder extends Decoder
implements IUnFilteredRealBufferListener, Instrumentable
{
public static final int LTR_STANDARD_MESSAGE_LENGTH = 40;
private LTRFSKDecoder mLTRFSKDecoder;
@@ -44,6 +46,10 @@ public class LTRNetDecoder extends Decoder implements IRealBufferListener, Instr
private List<TapGroup> mAvailableTaps;
/**
* LTR-Net Decoder. Decodes unfiltered (e.g. demodulated but with no DC or
* audio filtering) samples and produces LTR-Net messages.
*/
public LTRNetDecoder( DecodeConfigLTRNet config, AliasList aliasList )
{
mLTRFSKDecoder = new LTRFSKDecoder();
@@ -69,7 +75,7 @@ public class LTRNetDecoder extends Decoder implements IRealBufferListener, Instr
mLTRMessageFramer.addMessageListener( mLTRMessageProcessor );
mLTRMessageProcessor.setMessageListener( mMessageBroadcaster );
mLTRMessageProcessor.setMessageListener( this );
}
@Override
@@ -79,7 +85,7 @@ public class LTRNetDecoder extends Decoder implements IRealBufferListener, Instr
}
@Override
public Listener<RealBuffer> getRealBufferListener()
public Listener<RealBuffer> getUnFilteredRealBufferListener()
{
return mLTRFSKDecoder;
}
@@ -116,7 +122,7 @@ public class LTRNetDecoder extends Decoder implements IRealBufferListener, Instr
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}

View File

@@ -0,0 +1,179 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.ltrnet;
import gui.editor.Editor;
import gui.editor.EditorValidationException;
import gui.editor.ValidatingEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import message.MessageDirection;
import module.decode.config.DecodeConfiguration;
import net.miginfocom.swing.MigLayout;
import controller.channel.Channel;
public class LTRNetDecoderEditor extends ValidatingEditor<Channel>
{
private static final long serialVersionUID = 1L;
private JCheckBox mAFC;
private JSlider mAFCMaximumCorrection;
private JComboBox<MessageDirection> mComboDirection;
public LTRNetDecoderEditor()
{
init();
}
private void init()
{
setLayout( new MigLayout( "insets 0 0 0 0,wrap 4", "[right][grow,fill][right][grow,fill]", "" ) );
mAFC = new JCheckBox( "AFC: 3000 Hz" );
mAFC.setEnabled( false );
mAFC.setToolTipText( "AFC automatically adjusts the center frequency of the channel to "
+ "correct/compensate for inaccuracies and frequency drift in the tuner" );
mAFC.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
setModified( true );
if( mAFC.isSelected() && !mAFCMaximumCorrection.isEnabled() )
{
mAFCMaximumCorrection.setEnabled( true );
}
else if( !mAFC.isSelected() && mAFCMaximumCorrection.isEnabled() )
{
mAFCMaximumCorrection.setEnabled( false );
}
}
} );
add( mAFC );
mAFCMaximumCorrection = new JSlider( 0, 7000, 3000 );
mAFCMaximumCorrection.setEnabled( false );
mAFCMaximumCorrection.setToolTipText( "Maximum AFC frequency correction (0 - 15kHz)" );
mAFCMaximumCorrection.setMajorTickSpacing( 2000 );
mAFCMaximumCorrection.setMinorTickSpacing( 1000 );
mAFCMaximumCorrection.setPaintTicks( true );
mAFCMaximumCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mAFC.setText( "AFC: " + mAFCMaximumCorrection.getValue() + " Hz" );
setModified( true );
}
} );
add( mAFCMaximumCorrection );
mComboDirection = new JComboBox<MessageDirection>();
mComboDirection.setModel( new DefaultComboBoxModel<MessageDirection>( MessageDirection.values() ) );
mComboDirection.setSelectedItem( MessageDirection.OSW );
mComboDirection.setEnabled( false );
mComboDirection.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( new JLabel( "Format:" ) );
add( mComboDirection );
}
@Override
public void validate( Editor<Channel> editor ) throws EditorValidationException
{
//No validation
}
@Override
public void setItem( Channel item )
{
super.setItem( item );
if( hasItem() )
{
mAFC.setEnabled( true );
mComboDirection.setEnabled( true );
DecodeConfiguration config = getItem().getDecodeConfiguration();
if( config instanceof DecodeConfigLTRNet )
{
DecodeConfigLTRNet ltr = (DecodeConfigLTRNet)config;
mComboDirection.setSelectedItem( ltr.getMessageDirection() );
mAFC.setSelected( ltr.isAFCEnabled() );
mAFCMaximumCorrection.setValue( ltr.getAFCMaximumCorrection() );
mAFCMaximumCorrection.setEnabled( ltr.isAFCEnabled() );
setModified( false );
}
else
{
mComboDirection.setSelectedItem( MessageDirection.OSW );
mAFC.setSelected( false );
mAFCMaximumCorrection.setValue( DecodeConfiguration.DEFAULT_AFC_MAX_CORRECTION );
mAFCMaximumCorrection.setEnabled( false );
setModified( true );
}
}
else
{
mAFC.setEnabled( false );
mComboDirection.setEnabled( false );
setModified( false );
}
}
@Override
public void save()
{
if( hasItem() && isModified() )
{
DecodeConfigLTRNet ltr = new DecodeConfigLTRNet();
ltr.setAFC( mAFC.isSelected() );
ltr.setAFCMaximumCorrection( mAFCMaximumCorrection.getValue() );
ltr.setMessageDirection( (MessageDirection)mComboDirection.getSelectedItem() );
getItem().setDecodeConfiguration( ltr );
}
setModified( false );
}
}

View File

@@ -21,6 +21,7 @@ import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.concurrent.ScheduledExecutorService;
import message.Message;
import module.decode.DecoderType;
@@ -777,7 +778,7 @@ public class LTRNetDecoderState extends DecoderState
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}

View File

@@ -1,71 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.ltrnet;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import message.MessageDirection;
import module.decode.DecodeEditor;
import module.decode.config.DecodeConfiguration;
public class LTRNetEditor extends DecodeEditor
{
private static final long serialVersionUID = 1L;
private JComboBox<MessageDirection> mComboDirection;
public LTRNetEditor( DecodeConfiguration config )
{
super( config );
initGUI();
}
private void initGUI()
{
mComboDirection = new JComboBox<MessageDirection>();
mComboDirection.setModel(
new DefaultComboBoxModel<MessageDirection>( MessageDirection.values() ) );
mComboDirection.setSelectedItem( ((DecodeConfigLTRNet)mConfig).getMessageDirection() );
mComboDirection.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
MessageDirection selected = mComboDirection
.getItemAt( mComboDirection.getSelectedIndex() );
if( selected != null )
{
((DecodeConfigLTRNet)mConfig).setMessageDirection( selected );
}
}
} );
add( new JLabel( "Format:" ) );
add( mComboDirection, "wrap" );
}
}

View File

@@ -17,18 +17,20 @@
******************************************************************************/
package module.decode.ltrstandard;
import java.util.concurrent.ScheduledExecutorService;
import message.MessageDirection;
import module.decode.Decoder;
import module.decode.DecoderType;
import sample.Listener;
import sample.real.IRealBufferListener;
import sample.real.IUnFilteredRealBufferListener;
import sample.real.RealBuffer;
import alias.AliasList;
import bits.MessageFramer;
import bits.SyncPattern;
import dsp.fsk.LTRFSKDecoder;
public class LTRStandardDecoder extends Decoder implements IRealBufferListener
public class LTRStandardDecoder extends Decoder implements IUnFilteredRealBufferListener
{
public static final int LTR_STANDARD_MESSAGE_LENGTH = 40;
@@ -36,6 +38,10 @@ public class LTRStandardDecoder extends Decoder implements IRealBufferListener
private MessageFramer mLTRMessageFramer;
private LTRStandardMessageProcessor mLTRMessageProcessor;
/**
* LTR Decoder. Decodes unfiltered (e.g. demodulated but with no DC or
* audio filtering) samples and produces LTR Standard messages.
*/
public LTRStandardDecoder( AliasList aliasList,
MessageDirection direction )
{
@@ -58,7 +64,7 @@ public class LTRStandardDecoder extends Decoder implements IRealBufferListener
mLTRMessageProcessor = new LTRStandardMessageProcessor( direction, aliasList );
mLTRMessageFramer.addMessageListener( mLTRMessageProcessor );
mLTRMessageProcessor.setMessageListener( mMessageBroadcaster );
mLTRMessageProcessor.setMessageListener( this );
}
@Override
@@ -68,7 +74,7 @@ public class LTRStandardDecoder extends Decoder implements IRealBufferListener
}
@Override
public Listener<RealBuffer> getRealBufferListener()
public Listener<RealBuffer> getUnFilteredRealBufferListener()
{
return mLTRFSKDecoder;
}
@@ -80,7 +86,7 @@ public class LTRStandardDecoder extends Decoder implements IRealBufferListener
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}

View File

@@ -0,0 +1,176 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.ltrstandard;
import gui.editor.Editor;
import gui.editor.EditorValidationException;
import gui.editor.ValidatingEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import message.MessageDirection;
import module.decode.config.DecodeConfiguration;
import net.miginfocom.swing.MigLayout;
import controller.channel.Channel;
public class LTRStandardDecoderEditor extends ValidatingEditor<Channel>
{
private static final long serialVersionUID = 1L;
private JCheckBox mAFC;
private JSlider mAFCMaximumCorrection;
private JComboBox<MessageDirection> mComboDirection;
public LTRStandardDecoderEditor()
{
init();
}
private void init()
{
setLayout( new MigLayout( "insets 0 0 0 0,wrap 4", "[right][grow,fill][right][grow,fill]", "" ) );
mAFC = new JCheckBox( "AFC: 3000 Hz" );
mAFC.setEnabled( false );
mAFC.setToolTipText( "AFC automatically adjusts the center frequency of the channel to "
+ "correct/compensate for inaccuracies and frequency drift in the tuner" );
mAFC.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
setModified( true );
if( mAFC.isSelected() && !mAFCMaximumCorrection.isEnabled() )
{
mAFCMaximumCorrection.setEnabled( true );
}
else if( !mAFC.isSelected() && mAFCMaximumCorrection.isEnabled() )
{
mAFCMaximumCorrection.setEnabled( false );
}
}
} );
add( mAFC );
mAFCMaximumCorrection = new JSlider( 0, 7000, 3000 );
mAFCMaximumCorrection.setEnabled( false );
mAFCMaximumCorrection.setToolTipText( "Maximum AFC frequency correction (0 - 15kHz)" );
mAFCMaximumCorrection.setMajorTickSpacing( 2000 );
mAFCMaximumCorrection.setMinorTickSpacing( 1000 );
mAFCMaximumCorrection.setPaintTicks( true );
mAFCMaximumCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mAFC.setText( "AFC: " + mAFCMaximumCorrection.getValue() + " Hz" );
setModified( true );
}
} );
add( mAFCMaximumCorrection );
mComboDirection = new JComboBox<MessageDirection>();
mComboDirection.setModel( new DefaultComboBoxModel<MessageDirection>( MessageDirection.values() ) );
mComboDirection.setSelectedItem( MessageDirection.OSW );
mComboDirection.setEnabled( false );
mComboDirection.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( new JLabel( "Format:" ) );
add( mComboDirection );
}
@Override
public void validate( Editor<Channel> editor ) throws EditorValidationException
{
}
@Override
public void setItem( Channel item )
{
super.setItem( item );
if( hasItem() )
{
mAFC.setEnabled( true );
mComboDirection.setEnabled( true );
DecodeConfiguration config = getItem().getDecodeConfiguration();
if( config instanceof DecodeConfigLTRStandard )
{
DecodeConfigLTRStandard ltr = (DecodeConfigLTRStandard)config;
mComboDirection.setSelectedItem( ltr.getMessageDirection() );
mAFC.setSelected( ltr.isAFCEnabled() );
mAFCMaximumCorrection.setValue( ltr.getAFCMaximumCorrection() );
mAFCMaximumCorrection.setEnabled( ltr.isAFCEnabled() );
setModified( false );
}
else
{
mComboDirection.setSelectedItem( MessageDirection.OSW );
mAFC.setSelected( false );
mAFCMaximumCorrection.setValue( DecodeConfiguration.DEFAULT_AFC_MAX_CORRECTION );
mAFCMaximumCorrection.setEnabled( false );
setModified( true );
}
}
else
{
mAFC.setEnabled( false );
mComboDirection.setEnabled( false );
setModified( false );
}
}
@Override
public void save()
{
if( hasItem() && isModified() )
{
DecodeConfigLTRStandard ltr = new DecodeConfigLTRStandard();
ltr.setAFC( mAFC.isSelected() );
ltr.setAFCMaximumCorrection( mAFCMaximumCorrection.getValue() );
ltr.setMessageDirection( (MessageDirection)mComboDirection.getSelectedItem() );
getItem().setDecodeConfiguration( ltr );
}
setModified( false );
}
}

View File

@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ScheduledExecutorService;
import message.Message;
import module.decode.DecoderType;
@@ -73,8 +74,10 @@ public class LTRStandardDecoderState extends DecoderState
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
// TODO Auto-generated method stub
}
@Override
@@ -490,4 +493,4 @@ public class LTRStandardDecoderState extends DecoderState
return active;
}
}
}
}

View File

@@ -1,71 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.ltrstandard;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import message.MessageDirection;
import module.decode.DecodeEditor;
import module.decode.config.DecodeConfiguration;
public class LTRStandardEditor extends DecodeEditor
{
private static final long serialVersionUID = 1L;
private JComboBox<MessageDirection> mComboDirection;
public LTRStandardEditor( DecodeConfiguration config )
{
super( config );
initGUI();
}
private void initGUI()
{
mComboDirection = new JComboBox<MessageDirection>();
mComboDirection.setModel(
new DefaultComboBoxModel<MessageDirection>( MessageDirection.values() ) );
mComboDirection.setSelectedItem( ((DecodeConfigLTRStandard)mConfig).getMessageDirection() );
mComboDirection.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
MessageDirection selected = mComboDirection
.getItemAt( mComboDirection.getSelectedIndex() );
if( selected != null )
{
((DecodeConfigLTRStandard)mConfig).setMessageDirection( selected );
}
}
} );
add( new JLabel( "Format:" ) );
add( mComboDirection, "wrap" );
}
}

View File

@@ -118,4 +118,4 @@ public class LTRStandardMessageProcessor implements Listener<BinaryMessage>
{
mMessageListener = null;
}
}
}

View File

@@ -1,67 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.ltrstandard.message;
import message.MessageDirection;
import message.MessageType;
import alias.Alias;
import alias.AliasList;
import bits.BinaryMessage;
import edac.CRC;
public class CallEndMessage extends LTRStandardMessage
{
public CallEndMessage( BinaryMessage message, MessageDirection direction,
AliasList list, CRC crc )
{
super( message, direction, list, crc );
}
@Override
public MessageType getMessageType()
{
return MessageType.CA_ENDD;
}
@Override
public String getMessage()
{
StringBuilder sb = new StringBuilder();
sb.append( "END* AREA:" );
sb.append( getArea() );
sb.append( " LCN:" );
sb.append( getChannelFormatted() );
sb.append( " TG [" );
sb.append( getToID() );
sb.append( "/" );
Alias endAlias = getToIDAlias();
if( endAlias != null )
{
sb.append( getToIDAlias().getName() );
}
else
{
sb.append( "UNKNOWN" );
}
sb.append( "] FREE:" );
sb.append( getFreeFormatted() );
return sb.toString();
}
}

View File

@@ -1,68 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.ltrstandard.message;
import message.MessageDirection;
import message.MessageType;
import alias.Alias;
import alias.AliasList;
import bits.BinaryMessage;
import edac.CRC;
public class CallMessage extends LTRStandardMessage
{
public CallMessage( BinaryMessage message, MessageDirection direction,
AliasList list, CRC crc )
{
super( message, direction, list, crc );
}
@Override
public MessageType getMessageType()
{
return MessageType.CA_STRT;
}
@Override
public String getMessage()
{
StringBuilder sb = new StringBuilder();
sb.append( "CALL LCN:" );
sb.append( getChannelFormatted() );
sb.append( " TG [ " );
sb.append( getToID() );
sb.append( "/" );
Alias alias = getToIDAlias();
if( alias != null )
{
sb.append( getToIDAlias().getName() );
}
else
{
sb.append( "UNKNOWN" );
}
sb.append( " ] FREE:" );
sb.append( getFreeFormatted() );
return sb.toString();
}
}

View File

@@ -1,58 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.ltrstandard.message;
import message.MessageDirection;
import message.MessageType;
import alias.AliasList;
import bits.BinaryMessage;
import edac.CRC;
public class IdleMessage extends LTRStandardMessage
{
public IdleMessage( BinaryMessage message, MessageDirection direction,
AliasList list, CRC crc )
{
super( message, direction, list, crc );
}
@Override
public MessageType getMessageType()
{
return MessageType.SY_IDLE;
}
@Override
public String getMessage()
{
StringBuilder sb = new StringBuilder();
sb.append( "IDLE AREA:" );
sb.append( getArea() );
sb.append( " LCN:" );
sb.append( getChannelFormatted() );
sb.append( " HOME:" );
sb.append( getHomeRepeaterFormatted() );
sb.append( " GRP:" );
sb.append( getGroupFormatted() );
sb.append( " FREE:" );
sb.append( getFreeFormatted() );
return sb.toString();
}
}

View File

@@ -1,213 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.ltrstandard.message;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import message.Message;
import message.MessageDirection;
import message.MessageType;
import module.decode.DecoderType;
import org.apache.commons.lang3.StringUtils;
import alias.Alias;
import alias.AliasList;
import bits.BinaryMessage;
import edac.CRC;
public abstract class LTRStandardMessage extends Message
{
protected SimpleDateFormat mDatestampFormatter =
new SimpleDateFormat( "yyyyMMdd HHmmss" );
public static final int[] SYNC = { 0,1,2,3,4,5,6,7,8 };
public static final int[] AREA = { 9 };
public static final int[] CHANNEL = { 10,11,12,13,14 };
public static final int[] HOME_REPEATER = { 15,16,17,18,19 };
public static final int[] GROUP = { 20,21,22,23,24,25,26,27 };
public static final int[] FREE = { 28,29,30,31,32 };
public static final int[] CHECKSUM = { 33,34,35,36,37,38,39 };
protected BinaryMessage mMessage;
protected MessageDirection mMessageDirection;
protected AliasList mAliasList;
protected CRC mCRC;
public LTRStandardMessage( BinaryMessage message,
MessageDirection direction,
AliasList list,
CRC crc )
{
mMessage = message;
mMessageDirection = direction;
mAliasList = list;
mCRC = crc;
}
public abstract MessageType getMessageType();
public boolean isValid()
{
return mCRC != CRC.FAILED_CRC && mCRC != CRC.FAILED_PARITY;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append( mDatestampFormatter.format(
new Date( System.currentTimeMillis() ) ) );
sb.append( " LTR " );
sb.append( mMessageDirection.name() );
sb.append( " [" );
sb.append( mCRC.getAbbreviation() );
sb.append( "] " );
sb.append( getMessage() );
return sb.toString();
}
@Override
public String getBinaryMessage()
{
return mMessage.toString();
}
public CRC getCRC()
{
return mCRC;
}
public int getArea()
{
return mMessage.getInt( AREA );
}
public int getChannel()
{
return mMessage.getInt( CHANNEL );
}
public String getChannelFormatted()
{
return StringUtils.leftPad( String.valueOf( getChannel() ), 2, "0" );
}
public int getHomeRepeater()
{
return mMessage.getInt( HOME_REPEATER );
}
public String getHomeRepeaterFormatted()
{
return StringUtils.leftPad( String.valueOf( getHomeRepeater() ), 2, "0" );
}
public int getGroup()
{
return mMessage.getInt( GROUP );
}
public String getGroupFormatted()
{
return StringUtils.leftPad( String.valueOf( getGroup() ), 3, "0" );
}
public int getFree()
{
return mMessage.getInt( FREE );
}
public String getFreeFormatted()
{
return StringUtils.leftPad( String.valueOf( getFree() ), 2, "0" );
}
@Override
public String getFromID()
{
return null;
}
@Override
public Alias getFromIDAlias()
{
return null;
}
@Override
public String getToID()
{
StringBuilder sb = new StringBuilder();
sb.append( getArea() );
sb.append( "-" );
sb.append( getHomeRepeaterFormatted() );
sb.append( "-" );
sb.append( getGroupFormatted() );
return sb.toString();
}
@Override
public Alias getToIDAlias()
{
return mAliasList.getTalkgroupAlias( getToID() );
}
public List<Alias> getAliases()
{
List<Alias> aliases = new ArrayList<>();
Alias talkgroupAlias = getToIDAlias();
if( talkgroupAlias != null )
{
aliases.add( talkgroupAlias );
}
return aliases;
}
public int getCRCChecksum()
{
return mMessage.getInt( CHECKSUM );
}
@Override
public String getProtocol()
{
return DecoderType.LTR_STANDARD.getDisplayString();
}
@Override
public String getEventType()
{
return getMessageType().getDisplayText();
}
@Override
public String getErrorStatus()
{
return mCRC.getDisplayText();
}
}

View File

@@ -1,58 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.ltrstandard.message;
import message.MessageDirection;
import message.MessageType;
import alias.AliasList;
import bits.BinaryMessage;
import edac.CRC;
public class UnknownMessage extends LTRStandardMessage
{
public UnknownMessage( BinaryMessage message, MessageDirection direction,
AliasList list, CRC crc )
{
super( message, direction, list, crc );
}
@Override
public MessageType getMessageType()
{
return MessageType.UN_KNWN;
}
@Override
public String getMessage()
{
StringBuilder sb = new StringBuilder();
sb.append( "UNKNOWN AREA:" );
sb.append( getArea() );
sb.append( " LCN:" );
sb.append( getChannelFormatted() );
sb.append( " HOME:" );
sb.append( getHomeRepeaterFormatted() );
sb.append( " GRP:" );
sb.append( getGroupFormatted() );
sb.append( " FREE:" );
sb.append( getFreeFormatted() );
return sb.toString();
}
}

View File

@@ -26,11 +26,12 @@ import instrument.tap.stream.FloatTap;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import module.decode.Decoder;
import module.decode.DecoderType;
import sample.Listener;
import sample.real.IRealBufferListener;
import sample.real.IFilteredRealBufferListener;
import sample.real.RealBuffer;
import alias.AliasList;
import bits.MessageFramer;
@@ -46,7 +47,7 @@ import dsp.fsk.FSK2Decoder.Output;
* MDC1200 Decoder - 1200 baud 2FSK decoder that can process 48k sample rate
* complex or floating point samples and output fully framed MDC1200 messages
*/
public class MDCDecoder extends Decoder implements IRealBufferListener,
public class MDCDecoder extends Decoder implements IFilteredRealBufferListener,
Instrumentable
{
/* Decimated sample rate ( 48,000 / 2 = 24,000 ) feeding the decoder */
@@ -102,7 +103,7 @@ public class MDCDecoder extends Decoder implements IRealBufferListener,
/* Message Processor */
mMessageProcessor = new MDCMessageProcessor( aliasList );
mMessageFramer.addMessageListener( mMessageProcessor );
mMessageProcessor.addMessageListener( mMessageBroadcaster );
mMessageProcessor.addMessageListener( this );
}
public void dispose()
@@ -197,7 +198,7 @@ public class MDCDecoder extends Decoder implements IRealBufferListener,
}
@Override
public Listener<RealBuffer> getRealBufferListener()
public Listener<RealBuffer> getFilteredRealBufferListener()
{
return mDecimationFilter;
}
@@ -210,7 +211,7 @@ public class MDCDecoder extends Decoder implements IRealBufferListener,
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
// TODO Auto-generated method stub

View File

@@ -19,6 +19,7 @@ package module.decode.mdc1200;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.concurrent.ScheduledExecutorService;
import message.Message;
import module.decode.DecoderType;
@@ -54,7 +55,7 @@ public class MDCDecoderState extends DecoderState
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}

View File

@@ -1,202 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.mpt1327;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import module.decode.DecodeEditor;
import module.decode.config.DecodeConfiguration;
import module.decode.mpt1327.MPT1327Decoder.Sync;
import playlist.PlaylistManager;
import controller.channel.ChannelNode;
import controller.channel.map.ChannelMap;
public class MPT1327ConfigEditor extends DecodeEditor
{
private static final long serialVersionUID = 1L;
private JComboBox<ChannelMap> mComboChannelMaps;
private JComboBox<Sync> mComboSync;
private JLabel mCallTimeoutLabel;
private JSlider mCallTimeout;
private JLabel mTrafficChannelPoolSizeLabel;
private JSlider mTrafficChannelPoolSize;
private ChannelNode mChannelNode;
private PlaylistManager mPlaylistManager;
public MPT1327ConfigEditor( DecodeConfiguration config,
ChannelNode channelNode,
PlaylistManager playlistManager )
{
super( config );
mChannelNode = channelNode;
mPlaylistManager = playlistManager;
initGUI();
}
private DecodeConfigMPT1327 getMPTConfig()
{
return (DecodeConfigMPT1327)mConfig;
}
private void initGUI()
{
/**
* ComboBox: Alias Lists
*/
List<ChannelMap> maps = ( mPlaylistManager == null ?
new ArrayList<ChannelMap>() : mPlaylistManager.getPlayist()
.getChannelMapList().getChannelMap() );
ChannelMap[] mapArray = maps.toArray( new ChannelMap[ maps.size() ] );
mComboChannelMaps = new JComboBox<ChannelMap>();
mComboChannelMaps.setModel(
new DefaultComboBoxModel<ChannelMap>( mapArray ) );
add( new JLabel( "Channel Map:" ) );
add( mComboChannelMaps, "wrap" );
mComboSync = new JComboBox<Sync>();
mComboSync.setModel( new DefaultComboBoxModel<Sync>( Sync.values() ) );
add( new JLabel( "Sync:" ) );
add( mComboSync, "wrap" );
mCallTimeout = new JSlider( JSlider.HORIZONTAL,
DecodeConfiguration.CALL_TIMEOUT_MINIMUM,
DecodeConfiguration.CALL_TIMEOUT_MAXIMUM,
DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS );
mCallTimeout.setMajorTickSpacing( 90 );
mCallTimeout.setMinorTickSpacing( 10 );
mCallTimeout.setPaintTicks( true );
mCallTimeout.setLabelTable( mCallTimeout.createStandardLabels( 100, 100 ) );
mCallTimeout.setPaintLabels( true );
mCallTimeoutLabel = new JLabel( "Call Timeout: " + mCallTimeout.getValue() + " " );
mCallTimeout.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mCallTimeoutLabel.setText( "Call Timeout: " + mCallTimeout.getValue() );
}
} );
add( mCallTimeoutLabel );
add( mCallTimeout, "wrap,grow" );
mTrafficChannelPoolSize = new JSlider( JSlider.HORIZONTAL,
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MINIMUM,
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MAXIMUM,
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT );
mTrafficChannelPoolSize.setMajorTickSpacing( 10 );
mTrafficChannelPoolSize.setMinorTickSpacing( 1 );
mTrafficChannelPoolSize.setPaintTicks( true );
mTrafficChannelPoolSize.setLabelTable( mTrafficChannelPoolSize.createStandardLabels( 10, 10 ) );
mTrafficChannelPoolSize.setPaintLabels( true );
mTrafficChannelPoolSizeLabel = new JLabel( "Traffic Channel Pool: " + mTrafficChannelPoolSize.getValue() + " " );
mTrafficChannelPoolSize.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mTrafficChannelPoolSizeLabel.setText( "Traffic Channel Pool: " + mTrafficChannelPoolSize.getValue() );
}
} );
add( mTrafficChannelPoolSizeLabel );
add( mTrafficChannelPoolSize, "wrap,grow" );
reset();
}
@Override
public void save()
{
DecodeConfigMPT1327 config = getMPTConfig();
ChannelMap selected = (ChannelMap)mComboChannelMaps.getSelectedItem();
if( selected != null )
{
config.setChannelMapName( selected.getName() );
}
Sync selectedSync = (Sync)mComboSync.getSelectedItem();
if( selectedSync != null )
{
config.setSync( selectedSync );
}
config.setCallTimeout( mCallTimeout.getValue() );
config.setTrafficChannelPoolSize( mTrafficChannelPoolSize.getValue() );
}
@Override
public void reset()
{
DecodeConfigMPT1327 config = (DecodeConfigMPT1327)mConfig;
String name = config.getChannelMapName();
ChannelMap selected = null;
if( name != null )
{
for( ChannelMap map: mChannelNode.getModel().getResourceManager()
.getPlaylistManager().getPlayist().getChannelMapList()
.getChannelMap() )
{
if( map.getName().equalsIgnoreCase( name ) )
{
selected = map;
}
}
}
mComboChannelMaps.setSelectedItem( selected );
mComboChannelMaps.requestFocus();
mComboChannelMaps.requestFocusInWindow();
mComboSync.setSelectedItem( config.getSync() );
mCallTimeout.setValue( config.getCallTimeout() );
mTrafficChannelPoolSize.setValue( config.getTrafficChannelPoolSize() );
}
}

View File

@@ -26,6 +26,7 @@ import instrument.tap.stream.FloatTap;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import module.decode.Decoder;
import module.decode.DecoderType;
@@ -35,7 +36,7 @@ import org.slf4j.LoggerFactory;
import sample.Broadcaster;
import sample.Listener;
import sample.real.IRealBufferListener;
import sample.real.IFilteredRealBufferListener;
import sample.real.RealBuffer;
import alias.AliasList;
import bits.MessageFramer;
@@ -55,7 +56,7 @@ import dsp.fsk.FSK2Decoder.Output;
* traffic messages.
*/
public class MPT1327Decoder extends Decoder
implements IRealBufferListener, Instrumentable
implements IFilteredRealBufferListener, Instrumentable
{
private final static Logger mLog = LoggerFactory.getLogger( MPT1327Decoder.class );
@@ -140,13 +141,13 @@ public class MPT1327Decoder extends Decoder
/* Fully decoded and framed messages processor */
mMessageProcessor = new MPT1327MessageProcessor( aliasList );
mMessageProcessor.setMessageListener( mMessageBroadcaster );
mMessageProcessor.setMessageListener( this );
mControlMessageFramer.addMessageListener( mMessageProcessor );
mTrafficMessageFramer.addMessageListener( mMessageProcessor );
}
@Override
public Listener<RealBuffer> getRealBufferListener()
public Listener<RealBuffer> getFilteredRealBufferListener()
{
return mDecimationFilter;
}
@@ -306,7 +307,7 @@ public class MPT1327Decoder extends Decoder
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
// TODO Auto-generated method stub

View File

@@ -0,0 +1,285 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.mpt1327;
import gui.editor.Editor;
import gui.editor.EditorValidationException;
import gui.editor.ValidatingEditor;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import module.decode.config.DecodeConfiguration;
import net.miginfocom.swing.MigLayout;
import controller.channel.Channel;
import controller.channel.map.ChannelMap;
import controller.channel.map.ChannelMapManagerFrame;
import controller.channel.map.ChannelMapModel;
public class MPT1327DecoderEditor extends ValidatingEditor<Channel>
{
private static final long serialVersionUID = 1L;
private JCheckBox mAFC;
private JSlider mAFCMaximumCorrection;
private JComboBox<ChannelMap> mComboChannelMaps;
private JLabel mCallTimeoutLabel;
private JSlider mCallTimeout;
private JLabel mTrafficChannelPoolSizeLabel;
private JSlider mTrafficChannelPoolSize;
private ChannelMapModel mChannelMapModel;
public MPT1327DecoderEditor( ChannelMapModel channelMapModel )
{
mChannelMapModel = channelMapModel;
init();
}
private void init()
{
setLayout( new MigLayout( "insets 0 0 0 0,wrap 4", "[right][grow,fill][right][grow,fill]", "" ) );
mAFC = new JCheckBox( "AFC: 3000 Hz" );
mAFC.setEnabled( false );
mAFC.setToolTipText( "AFC automatically adjusts the center frequency of the channel to "
+ "correct/compensate for inaccuracies and frequency drift in the tuner" );
mAFC.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
setModified( true );
if( mAFC.isSelected() && !mAFCMaximumCorrection.isEnabled() )
{
mAFCMaximumCorrection.setEnabled( true );
}
else if( !mAFC.isSelected() && mAFCMaximumCorrection.isEnabled() )
{
mAFCMaximumCorrection.setEnabled( false );
}
}
} );
add( mAFC );
mAFCMaximumCorrection = new JSlider( 0, 7000, 3000 );
mAFCMaximumCorrection.setEnabled( false );
mAFCMaximumCorrection.setToolTipText( "Maximum AFC frequency correction (0 - 15kHz)" );
mAFCMaximumCorrection.setMajorTickSpacing( 2000 );
mAFCMaximumCorrection.setMinorTickSpacing( 1000 );
mAFCMaximumCorrection.setPaintTicks( true );
mAFCMaximumCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mAFC.setText( "AFC: " + mAFCMaximumCorrection.getValue() + " Hz" );
setModified( true );
}
} );
add( mAFCMaximumCorrection );
JButton channelMaps = new JButton( "Channel Maps" );
channelMaps.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
final ChannelMapManagerFrame manager =
new ChannelMapManagerFrame( mChannelMapModel );
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
manager.setVisible( true );
}
} );
}
} );
add( channelMaps, "span 2" );
List<ChannelMap> maps = mChannelMapModel.getChannelMaps();
ChannelMap[] mapArray = maps.toArray( new ChannelMap[ maps.size() ] );
mComboChannelMaps = new JComboBox<ChannelMap>();
mComboChannelMaps.setModel( new DefaultComboBoxModel<ChannelMap>( mapArray ) );
mComboChannelMaps.setEnabled( false );
add( new JLabel( "Channel Map:" ) );
add( mComboChannelMaps, "span 3,grow" );
mTrafficChannelPoolSize = new JSlider( JSlider.HORIZONTAL, DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MINIMUM,
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MAXIMUM, DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT );
mTrafficChannelPoolSize.setEnabled( false );
mTrafficChannelPoolSize.setMajorTickSpacing( 10 );
mTrafficChannelPoolSize.setMinorTickSpacing( 5 );
mTrafficChannelPoolSize.setPaintTicks( true );
mTrafficChannelPoolSizeLabel = new JLabel( "Traffic Pool: " +
mTrafficChannelPoolSize.getValue() + " " );
mTrafficChannelPoolSize.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mTrafficChannelPoolSizeLabel.setText( "Traffic Pool: " +
mTrafficChannelPoolSize.getValue() );
}
} );
add( mTrafficChannelPoolSizeLabel );
add( mTrafficChannelPoolSize );
mCallTimeout = new JSlider( JSlider.HORIZONTAL, DecodeConfiguration.CALL_TIMEOUT_MINIMUM,
DecodeConfiguration.CALL_TIMEOUT_MAXIMUM, DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS );
mCallTimeout.setEnabled( false );
mCallTimeout.setMajorTickSpacing( 100 );
mCallTimeout.setMinorTickSpacing( 50 );
mCallTimeout.setPaintTicks( true );
mCallTimeoutLabel = new JLabel( "Timeout: " + mCallTimeout.getValue() + " " );
mCallTimeout.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mCallTimeoutLabel.setText( "Timeout: " + mCallTimeout.getValue() );
}
} );
add( mCallTimeoutLabel );
add( mCallTimeout );
}
@Override
public void save()
{
if( hasItem() && isModified() )
{
DecodeConfigMPT1327 mpt = new DecodeConfigMPT1327();
mpt.setAFC( mAFC.isSelected() );
mpt.setAFCMaximumCorrection( mAFCMaximumCorrection.getValue() );
mpt.setTrafficChannelPoolSize( mTrafficChannelPoolSize.getValue() );
mpt.setCallTimeout( mCallTimeout.getValue() );
if( mComboChannelMaps.getSelectedItem() != null )
{
ChannelMap map = (ChannelMap)mComboChannelMaps.getSelectedItem();
mpt.setChannelMapName( map.getName() );
}
getItem().setDecodeConfiguration( mpt );
}
setModified( false );
}
@Override
public void validate( Editor<Channel> editor ) throws EditorValidationException
{
//No validation required
}
private void setControlsEnabled( boolean enabled )
{
if( mAFC.isEnabled() != enabled )
{
mAFC.setEnabled( enabled );
}
if( mComboChannelMaps.isEnabled() != enabled )
{
mComboChannelMaps.setEnabled( enabled );
}
if( mTrafficChannelPoolSize.isEnabled() != enabled )
{
mTrafficChannelPoolSize.setEnabled( enabled );
}
if( mCallTimeout.isEnabled() != enabled )
{
mCallTimeout.setEnabled( enabled );
}
}
@Override
public void setItem( Channel item )
{
super.setItem( item );
if( hasItem() )
{
setControlsEnabled( true );
DecodeConfiguration config = getItem().getDecodeConfiguration();
if( config instanceof DecodeConfigMPT1327 )
{
DecodeConfigMPT1327 mpt = (DecodeConfigMPT1327)config;
mAFC.setSelected( mpt.isAFCEnabled() );
mAFCMaximumCorrection.setValue( mpt.getAFCMaximumCorrection() );
mAFCMaximumCorrection.setEnabled( mpt.isAFCEnabled() );
ChannelMap map = mChannelMapModel.getChannelMap( mpt.getChannelMapName() );
if( map != null )
{
mComboChannelMaps.setSelectedItem( map );
}
mTrafficChannelPoolSize.setValue( mpt.getTrafficChannelPoolSize() );
mCallTimeout.setValue( mpt.getCallTimeout() );
setModified( false );
}
else
{
mAFC.setSelected( false );
mAFCMaximumCorrection.setValue( DecodeConfiguration.DEFAULT_AFC_MAX_CORRECTION );
mAFCMaximumCorrection.setEnabled( false );
mTrafficChannelPoolSize.setValue( DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT );
mCallTimeout.setValue( DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS );
setModified( true );
}
}
else
{
setControlsEnabled( false );
setModified( false );
}
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 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
@@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
import java.util.concurrent.ScheduledExecutorService;
import message.Message;
import module.decode.DecoderType;
@@ -85,7 +86,7 @@ public class MPT1327DecoderState extends DecoderState
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}
@@ -612,4 +613,4 @@ public class MPT1327DecoderState extends DecoderState
break;
}
}
}
}

View File

@@ -17,6 +17,8 @@
******************************************************************************/
package module.decode.nbfm;
import java.util.concurrent.ScheduledExecutorService;
import module.decode.DecoderType;
import module.decode.PrimaryDecoder;
import module.decode.config.DecodeConfiguration;
@@ -40,7 +42,7 @@ public class NBFMDecoder extends PrimaryDecoder
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}

View File

@@ -0,0 +1,161 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.nbfm;
import gui.editor.Editor;
import gui.editor.EditorValidationException;
import gui.editor.ValidatingEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JCheckBox;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import module.decode.config.DecodeConfiguration;
import net.miginfocom.swing.MigLayout;
import controller.channel.Channel;
public class NBFMDecoderEditor extends ValidatingEditor<Channel>
{
private static final long serialVersionUID = 1L;
private JCheckBox mAFC;
private JSlider mAFCMaximumCorrection;
public NBFMDecoderEditor()
{
init();
}
private void init()
{
setLayout( new MigLayout( "insets 0 0 0 0,wrap 2", "[right][grow,fill]", "" ) );
mAFC = new JCheckBox( "AFC: 3000 Hz" );
mAFC.setEnabled( false );
mAFC.setToolTipText( "AFC automatically adjusts the center frequency of the channel to "
+ "correct/compensate for inaccuracies and frequency drift in the tuner" );
mAFC.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
setModified( true );
if( mAFC.isSelected() && !mAFCMaximumCorrection.isEnabled() )
{
mAFCMaximumCorrection.setEnabled( true );
}
else if( !mAFC.isSelected() && mAFCMaximumCorrection.isEnabled() )
{
mAFCMaximumCorrection.setEnabled( false );
}
}
} );
add( mAFC );
mAFCMaximumCorrection = new JSlider( 0, 7000, 3000 );
mAFCMaximumCorrection.setEnabled( false );
mAFCMaximumCorrection.setToolTipText( "Maximum AFC frequency correction (0 - 15kHz)" );
mAFCMaximumCorrection.setMajorTickSpacing( 2000 );
mAFCMaximumCorrection.setMinorTickSpacing( 1000 );
mAFCMaximumCorrection.setPaintTicks( true );
mAFCMaximumCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mAFC.setText( "AFC: " + mAFCMaximumCorrection.getValue() + " Hz" );
setModified( true );
}
} );
add( mAFCMaximumCorrection );
}
@Override
public void validate( Editor<Channel> editor ) throws EditorValidationException
{
//No validation
}
@Override
public void save()
{
if( hasItem() && isModified() )
{
DecodeConfigNBFM nbfm = new DecodeConfigNBFM();
nbfm.setAFC( mAFC.isSelected() );
nbfm.setAFCMaximumCorrection( mAFCMaximumCorrection.getValue() );
getItem().setDecodeConfiguration( nbfm );
}
setModified( false );
}
private void setControlsEnabled( boolean enabled )
{
if( mAFC.isEnabled() != enabled )
{
mAFC.setEnabled( enabled );
}
}
@Override
public void setItem( Channel item )
{
super.setItem( item );
if( hasItem() )
{
setControlsEnabled( true );
DecodeConfiguration config = getItem().getDecodeConfiguration();
if( config instanceof DecodeConfigNBFM )
{
DecodeConfigNBFM nbfm = (DecodeConfigNBFM)config;
mAFC.setSelected( nbfm.isAFCEnabled() );
mAFCMaximumCorrection.setValue( nbfm.getAFCMaximumCorrection() );
mAFCMaximumCorrection.setEnabled( nbfm.isAFCEnabled() );
setModified( false );
}
else
{
mAFC.setSelected( false );
mAFCMaximumCorrection.setValue( DecodeConfiguration.DEFAULT_AFC_MAX_CORRECTION );
mAFCMaximumCorrection.setEnabled( false );
setModified( true );
}
}
else
{
setControlsEnabled( false );
setModified( false );
}
}
}

View File

@@ -1,35 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.nbfm;
import javax.swing.JCheckBox;
import module.decode.DecodeEditor;
import module.decode.config.DecodeConfiguration;
public class NBFMEditor extends DecodeEditor
{
private static final long serialVersionUID = 1L;
private JCheckBox mAFC;
public NBFMEditor( DecodeConfiguration config )
{
super( config );
}
}

View File

@@ -9,25 +9,20 @@ import instrument.tap.stream.FloatTap;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import sample.real.RealBuffer;
import sample.real.RealSampleListener;
import sample.real.RealSampleProvider;
import source.tuner.frequency.FrequencyCorrectionControl;
import source.tuner.frequency.FrequencyCorrectionControl.FrequencyCorrectionResetListener;
import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.FrequencyChangeEvent.Event;
import source.tuner.frequency.IFrequencyChangeListener;
import dsp.gain.DirectGainControl;
public class C4FMSymbolFilter implements FrequencyCorrectionResetListener,
Listener<RealBuffer>,
public class C4FMSymbolFilter implements Listener<RealBuffer>,
IFrequencyChangeListener,
RealSampleProvider,
Instrumentable
{
private final static Logger mLog =
LoggerFactory.getLogger( C4FMSymbolFilter.class );
private static final float TAPS[][] =
{
{ 0.00000e+00f, 0.00000e+00f, 0.00000e+00f, 0.00000e+00f, 1.00000e+00f, 0.00000e+00f, 0.00000e+00f, 0.00000e+00f }, // 0/128
@@ -201,15 +196,17 @@ public class C4FMSymbolFilter implements FrequencyCorrectionResetListener,
private float mHistory[] = new float[ NUMBER_FILTER_TAPS ];
private int mHistoryLast = 0;
private boolean mResetFrequencyTracker = false;
private RealSampleListener mListener;
private DirectGainControl mGainController =
new DirectGainControl( 15.0f, 0.1f, 35.0f, 0.3f );
private FrequencyCorrectionControl mFrequencyCorrectionControl;
private int mFrequencyAdjustmentRequested = 0;
private int mFrequencyCorrection = 0;
private int mFrequencyCorrectionMaximum = 3000;
private boolean mResetFrequencyTracker = false;
private FrequencyCorrectionProcessor mFrequencyCorrectionProcessor;
private Listener<FrequencyChangeEvent> mFrequencyChangeListener;
/**
* C4FM Symbol Filter
@@ -224,18 +221,15 @@ public class C4FMSymbolFilter implements FrequencyCorrectionResetListener,
* setting for this filter is 15.4 and that yields a symbol spread that
* is centered on 2.0, ranging 1.92 to 2.08.
*/
public C4FMSymbolFilter( FrequencyCorrectionControl frequencyControl )
public C4FMSymbolFilter( int frequencyCorrectionMaximum )
{
mFrequencyCorrectionControl = frequencyControl;
/* Register for reset events, so we can reset internal frequency tracking */
mFrequencyCorrectionControl.setListener( this );
mFrequencyCorrectionMaximum = frequencyCorrectionMaximum;
}
public void dispose()
{
mGainController = null;
mFrequencyCorrectionControl = null;
// mFrequencyCorrectionControl = null;
mListener = null;
}
@@ -253,13 +247,21 @@ public class C4FMSymbolFilter implements FrequencyCorrectionResetListener,
* the internal frequency correction tracker */
if( mFrequencyAdjustmentRequested != 0 )
{
mFrequencyCorrectionControl.adjust( mFrequencyAdjustmentRequested );
int correction = mFrequencyCorrection + mFrequencyAdjustmentRequested;
if( correction > mFrequencyCorrectionMaximum )
{
correction = mFrequencyCorrectionMaximum;
}
else if( correction < -mFrequencyCorrectionMaximum )
{
correction = -mFrequencyCorrectionMaximum;
}
broadcast( new FrequencyChangeEvent(
Event.REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE, correction ) );
mFrequencyAdjustmentRequested = 0;
//Reset internal frequency tracking
mCoarseFrequencyCorrection = 0.0f;
mFineFrequencyCorrection = 0.0f;
}
}
@@ -272,7 +274,8 @@ public class C4FMSymbolFilter implements FrequencyCorrectionResetListener,
mCoarseFrequencyCorrection = 0.0f;
mFineFrequencyCorrection = 0.0f;
mFrequencyCorrectionControl.setFrequencyCorrection( 0 );
broadcast( new FrequencyChangeEvent(
Event.REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE, 0 ));
mResetFrequencyTracker = false;
}
@@ -397,17 +400,6 @@ public class C4FMSymbolFilter implements FrequencyCorrectionResetListener,
}
}
/**
* Listener interface for frequency correction reset events. We reset the
* coarse and fine frequency control values when the tuner channel source
* has changed frequency (PPM) or sample rate
*/
@Override
public void resetFrequencyCorrection()
{
mResetFrequencyTracker = true;
}
@Override
public void setListener( RealSampleListener listener )
{
@@ -459,4 +451,56 @@ public class C4FMSymbolFilter implements FrequencyCorrectionResetListener,
mSymbolSpreadTap = null;
}
}
public void broadcast( FrequencyChangeEvent event )
{
if( mFrequencyChangeListener != null )
{
mFrequencyChangeListener.receive( event );
}
}
public void setFrequencyChangeListener( Listener<FrequencyChangeEvent> listener )
{
mFrequencyChangeListener = listener;
}
@Override
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
{
if( mFrequencyCorrectionProcessor == null )
{
mFrequencyCorrectionProcessor = new FrequencyCorrectionProcessor();
}
return mFrequencyCorrectionProcessor;
}
/**
* Receives notifications that the channel frequency correction has been
* applied and updates internal tracking value.
*/
public class FrequencyCorrectionProcessor implements Listener<FrequencyChangeEvent>
{
@Override
public void receive( FrequencyChangeEvent event )
{
switch( event.getEvent() )
{
case NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
mFrequencyCorrection = event.getValue().intValue();
//Reset internal frequency tracking
mCoarseFrequencyCorrection = 0.0f;
mFineFrequencyCorrection = 0.0f;
break;
case NOTIFICATION_FREQUENCY_CORRECTION_CHANGE:
case NOTIFICATION_SAMPLE_RATE_CHANGE:
mResetFrequencyTracker = true;
break;
default:
break;
}
}
}
}

View File

@@ -1,147 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.p25;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import module.decode.DecodeEditor;
import module.decode.config.DecodeConfiguration;
import module.decode.p25.P25Decoder.Modulation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceEditor;
import source.tuner.TunerEditor;
import controller.Editor;
import controller.channel.ChannelValidationException;
public class P25DecodeEditor extends DecodeEditor
{
private final static Logger mLog = LoggerFactory.getLogger( P25DecodeEditor.class );
private static final long serialVersionUID = 1L;
private JComboBox<P25_LSMDecoder.Modulation> mComboModulation;
private JCheckBox mIgnoreDataCalls;
private JLabel mTrafficChannelPoolSizeLabel;
private JSlider mTrafficChannelPoolSize;
public P25DecodeEditor( DecodeConfiguration config )
{
super( config );
initGUI();
}
private void initGUI()
{
final DecodeConfigP25Phase1 config = (DecodeConfigP25Phase1)mConfig;
mComboModulation = new JComboBox<P25_LSMDecoder.Modulation>();
mComboModulation.setModel( new DefaultComboBoxModel<P25_LSMDecoder.Modulation>(
P25_LSMDecoder.Modulation.values() ) );
mComboModulation.setSelectedItem( config.getModulation() );
add( new JLabel( "Modulation:" ) );
add( mComboModulation, "wrap" );
mTrafficChannelPoolSize = new JSlider( JSlider.HORIZONTAL,
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MINIMUM,
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MAXIMUM,
config.getTrafficChannelPoolSize() );
mTrafficChannelPoolSize.setMajorTickSpacing( 10 );
mTrafficChannelPoolSize.setMinorTickSpacing( 1 );
mTrafficChannelPoolSize.setPaintTicks( true );
mTrafficChannelPoolSize.setLabelTable( mTrafficChannelPoolSize.createStandardLabels( 10, 10 ) );
mTrafficChannelPoolSize.setPaintLabels( true );
mTrafficChannelPoolSizeLabel = new JLabel( "Traffic Channel Pool: " + mTrafficChannelPoolSize.getValue() + " " );
mTrafficChannelPoolSize.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mTrafficChannelPoolSizeLabel.setText( "Traffic Channel Pool: " + mTrafficChannelPoolSize.getValue() );
}
} );
add( mTrafficChannelPoolSizeLabel );
add( mTrafficChannelPoolSize, "wrap,grow" );
mIgnoreDataCalls = new JCheckBox();
mIgnoreDataCalls.setSelected( config.getIgnoreDataCalls() );
add( new JLabel( "Ignore Data Calls" ) );
add( mIgnoreDataCalls, "wrap,grow" );
reset();
}
/**
* Enforce source=tuner for CQPSK modulation
*/
@Override
public void validate( Editor editor ) throws ChannelValidationException
{
if( editor instanceof SourceEditor &&
((DecodeConfigP25Phase1)mConfig).getModulation() == Modulation.CQPSK )
{
if( !( editor instanceof TunerEditor ) )
{
throw new ChannelValidationException(
"<html><body width='175'><h1>LSM Simulcast</h1>"
+ "<p>P25 LSM Simulcast decoder can only be used with "
+ "a tuner source. Please change the Source to use a tuner"
+ " or change the P25 Decoder to C4FM modulation" );
}
}
}
@Override
public void save()
{
DecodeConfigP25Phase1 config = (DecodeConfigP25Phase1)mConfig;
config.setModulation( (Modulation)mComboModulation.getSelectedItem() );
config.setIgnoreDataCalls( mIgnoreDataCalls.isSelected() );
config.setTrafficChannelPoolSize( mTrafficChannelPoolSize.getValue() );
}
@Override
public void reset()
{
DecodeConfigP25Phase1 config = (DecodeConfigP25Phase1)mConfig;
mComboModulation.setSelectedItem( config.getModulation() );
mIgnoreDataCalls.setSelected( config.getIgnoreDataCalls() );
mTrafficChannelPoolSize.setValue( config.getTrafficChannelPoolSize() );
}
}

View File

@@ -1,20 +1,18 @@
package module.decode.p25;
import alias.AliasList;
import instrument.Instrumentable;
import module.decode.Decoder;
import module.decode.DecoderType;
import source.tuner.frequency.IFrequencyCorrectionController;
import alias.AliasList;
public abstract class P25Decoder extends Decoder
implements IFrequencyCorrectionController, Instrumentable
public abstract class P25Decoder extends Decoder implements Instrumentable
{
private P25MessageProcessor mMessageProcessor;
public P25Decoder( AliasList aliasList )
{
mMessageProcessor = new P25MessageProcessor( aliasList );
mMessageProcessor.setMessageListener( mMessageBroadcaster );
mMessageProcessor.setMessageListener( this );
}
public void dispose()

View File

@@ -0,0 +1,226 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.p25;
import gui.editor.Editor;
import gui.editor.EditorValidationException;
import gui.editor.ValidatingEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import module.decode.AuxDecodeConfigurationEditor;
import module.decode.config.AuxDecodeConfiguration;
import module.decode.config.DecodeConfiguration;
import module.decode.p25.P25Decoder.Modulation;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.SourceConfigurationEditor;
import source.config.SourceConfigTuner;
import source.config.SourceConfiguration;
import controller.channel.Channel;
public class P25DecoderEditor extends ValidatingEditor<Channel>
{
private final static Logger mLog = LoggerFactory.getLogger( P25DecoderEditor.class );
private static final long serialVersionUID = 1L;
private JComboBox<P25_LSMDecoder.Modulation> mComboModulation;
private JCheckBox mIgnoreDataCalls;
private JLabel mTrafficChannelPoolSizeLabel;
private JSlider mTrafficChannelPoolSize;
public P25DecoderEditor()
{
init();
}
private void init()
{
setLayout( new MigLayout( "insets 0 0 0 0,wrap 3", "[right][grow,fill][]", "" ) );
mComboModulation = new JComboBox<P25_LSMDecoder.Modulation>();
mComboModulation.setModel( new DefaultComboBoxModel<P25_LSMDecoder.Modulation>(
P25_LSMDecoder.Modulation.values() ) );
mComboModulation.setEnabled( false );
mComboModulation.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( new JLabel( "Modulation:" ) );
add( mComboModulation );
mIgnoreDataCalls = new JCheckBox( "Ignore Data Calls" );
mIgnoreDataCalls.setEnabled( false );
mIgnoreDataCalls.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( mIgnoreDataCalls );
mTrafficChannelPoolSize = new JSlider( JSlider.HORIZONTAL, DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MINIMUM,
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MAXIMUM, DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT );
mTrafficChannelPoolSize.setEnabled( false );
mTrafficChannelPoolSize.setMajorTickSpacing( 10 );
mTrafficChannelPoolSize.setMinorTickSpacing( 5 );
mTrafficChannelPoolSize.setPaintTicks( true );
mTrafficChannelPoolSize.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mTrafficChannelPoolSizeLabel.setText( "Traffic Pool: " + mTrafficChannelPoolSize.getValue() );
setModified( true );
}
} );
mTrafficChannelPoolSizeLabel = new JLabel( "Traffic Pool: " + mTrafficChannelPoolSize.getValue() + " " );
add( mTrafficChannelPoolSizeLabel );
add( mTrafficChannelPoolSize );
}
@Override
public void save()
{
if( hasItem() && isModified() )
{
DecodeConfigP25Phase1 p25 = new DecodeConfigP25Phase1();
p25.setModulation( (Modulation)mComboModulation.getSelectedItem() );
p25.setIgnoreDataCalls( mIgnoreDataCalls.isSelected() );
p25.setTrafficChannelPoolSize( mTrafficChannelPoolSize.getValue() );
getItem().setDecodeConfiguration( p25 );
}
setModified( false );
}
@Override
public void validate( Editor<Channel> editor ) throws EditorValidationException
{
mLog.debug( "Validating editor:" + editor.getClass() );
/**
* Enforce CQPSK modulation uses a Tuner Source for I/Q sample data
*/
if( editor instanceof SourceConfigurationEditor &&
((Modulation)mComboModulation.getSelectedItem()) == Modulation.CQPSK )
{
SourceConfiguration config = ((SourceConfigurationEditor)editor).getSourceConfiguration();
if( config != null && !( config instanceof SourceConfigTuner ) )
{
throw new EditorValidationException( editor,
"<html><body width='175'><h3>LSM Simulcast</h3>"
+ "<p>P25 LSM Simulcast decoder can only be used with "
+ "a tuner source. Please change the Source to use a tuner"
+ " or change the P25 Decoder to C4FM modulation</p>" );
}
}
if( editor instanceof AuxDecodeConfigurationEditor )
{
AuxDecodeConfiguration config = ((AuxDecodeConfigurationEditor)editor).getConfiguration();
if( config != null && !config.getAuxDecoders().isEmpty() )
{
throw new EditorValidationException( editor,
"<html><body width='175'><h3>Auxilary Decoders</h3>"
+ "<p>The auxiliary decoders work with analog audio and are not "
+ "compatible with the P25 Decoder. Please uncheck any auxiliary "
+ "decoders that you have selected for this channel</p>" );
}
}
}
private void setControlsEnabled( boolean enabled )
{
if( mComboModulation.isEnabled() != enabled )
{
mComboModulation.setEnabled( enabled );
}
if( mTrafficChannelPoolSize.isEnabled() != enabled )
{
mTrafficChannelPoolSize.setEnabled( enabled );
}
if( mIgnoreDataCalls.isEnabled() != enabled )
{
mIgnoreDataCalls.setEnabled( enabled );
}
}
@Override
public void setItem( Channel item )
{
super.setItem( item );
if( hasItem() )
{
setControlsEnabled( true );
DecodeConfiguration config = getItem().getDecodeConfiguration();
if( config instanceof DecodeConfigP25Phase1 )
{
DecodeConfigP25Phase1 p25 = (DecodeConfigP25Phase1)config;
mComboModulation.setSelectedItem( p25.getModulation() );
mIgnoreDataCalls.setSelected( p25.getIgnoreDataCalls() );
mTrafficChannelPoolSize.setValue( p25.getTrafficChannelPoolSize() );
setModified( false );
}
else
{
mComboModulation.setSelectedItem( Modulation.C4FM );
mIgnoreDataCalls.setSelected( false );
mTrafficChannelPoolSize.setValue( DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT );
setModified( true );
}
}
else
{
setControlsEnabled( false );
setModified( false );
}
}
}

View File

@@ -25,10 +25,10 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ScheduledExecutorService;
import message.Message;
import module.decode.DecoderType;
import module.decode.event.CallEvent;
import module.decode.event.CallEvent.CallEventType;
import module.decode.p25.P25Decoder.Modulation;
import module.decode.p25.message.IAdjacentSite;
@@ -121,6 +121,7 @@ import module.decode.p25.reference.IPProtocol;
import module.decode.p25.reference.LinkControlOpcode;
import module.decode.p25.reference.Response;
import module.decode.p25.reference.Vendor;
import module.decode.state.ChangeChannelTimeoutEvent;
import module.decode.state.ChangedAttribute;
import module.decode.state.DecoderState;
import module.decode.state.DecoderStateEvent;
@@ -204,11 +205,6 @@ public class P25DecoderState extends DecoderState
return DecoderType.P25_PHASE1;
}
@Override
public void start()
{
}
@Override
public void stop()
{
@@ -1668,7 +1664,7 @@ public class P25DecoderState extends DecoderState
.to( satcr.getLogicalLinkID() )
.build() );
break;
case SN_ACTIVATE_TDS_CONTEXT_REQUEST:
case SNDCP_ACTIVATE_TDS_CONTEXT_REQUEST:
SNDCPActivateTDSContextRequest satcreq =
(SNDCPActivateTDSContextRequest)pduc;
@@ -2292,6 +2288,8 @@ public class P25DecoderState extends DecoderState
logAlternateVendorMessage( pdu );
}
break;
default:
break;
}
}
@@ -2437,8 +2435,6 @@ public class P25DecoderState extends DecoderState
private void processTSBKResponse( TSBKMessage message )
{
CallEvent event = null;
switch( message.getOpcode() )
{
case ACKNOWLEDGE_RESPONSE:
@@ -3560,4 +3556,14 @@ public class P25DecoderState extends DecoderState
break;
}
}
@Override
public void start( ScheduledExecutorService executor )
{
//Change the default (45-second) traffic channel timeout to 1 second
if( mChannelType == ChannelType.TRAFFIC )
{
broadcast( new ChangeChannelTimeoutEvent( this, ChannelType.TRAFFIC, 1000 ) );
}
}
}

View File

@@ -17,6 +17,8 @@ import module.decode.p25.message.tdu.lc.TDULCMessageFactory;
import module.decode.p25.message.tdu.lc.TDULinkControlMessage;
import module.decode.p25.message.tsbk.TSBKMessage;
import module.decode.p25.message.tsbk.TSBKMessageFactory;
import module.decode.p25.message.vselp.VSELP1Message;
import module.decode.p25.message.vselp.VSELP2Message;
import module.decode.p25.reference.DataUnitID;
import org.slf4j.Logger;
@@ -129,7 +131,7 @@ public class P25MessageFramer implements Listener<Dibit>
if( demodulator != null )
{
/* For CQPSK, we include 3 additional sync detectors to watch for and
* correction +/-90 and 180 degree costas loop phase lock errors */
* correct +/-90 and 180 degree costas loop phase lock errors */
mMatcher.add( new CostasPhaseErrorDetector( FrameSync.P25_PHASE1_ERROR_90_CCW,
demodulator, PHASE_CORRECTION_90_DEGREES ) );
@@ -289,7 +291,7 @@ public class P25MessageFramer implements Listener<Dibit>
else
{
mComplete = true;
dispatch( new P25Message( mMessage.copy(), duid, mAliasList ) );
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );
}
}
else
@@ -631,6 +633,14 @@ public class P25MessageFramer implements Listener<Dibit>
mComplete = true;
break;
case VSELP1:
mComplete = true;
dispatch( new VSELP1Message( mMessage.copy(), mDUID, mAliasList ) );
break;
case VSELP2:
mComplete = true;
dispatch( new VSELP2Message( mMessage.copy(), mDUID, mAliasList ) );
break;
case UNKN:
mComplete = true;
dispatch( new P25Message( mMessage.copy(), mDUID, mAliasList ) );

View File

@@ -10,8 +10,8 @@ import module.decode.p25.message.ldu.LDUMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import alias.AliasList;
import sample.Listener;
public class P25MessageProcessor implements Listener<Message>
{

View File

@@ -24,22 +24,25 @@ import instrument.tap.stream.FloatBufferTap;
import instrument.tap.stream.FloatTap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import sample.real.IRealBufferListener;
import sample.real.RealBuffer;
import source.tuner.frequency.FrequencyCorrectionControl;
import alias.AliasList;
import sample.Listener;
import sample.real.IFilteredRealBufferListener;
import sample.real.RealBuffer;
import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.IFrequencyChangeListener;
import source.tuner.frequency.IFrequencyChangeProvider;
import dsp.filter.FilterFactory;
import dsp.filter.Window.WindowType;
import dsp.filter.fir.real.RealFIRFilter_RB_RB;
public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
public class P25_C4FMDecoder extends P25Decoder
implements IFrequencyChangeListener, IFrequencyChangeProvider,IFilteredRealBufferListener
{
private final static Logger mLog = LoggerFactory.getLogger( P25_C4FMDecoder.class );
@@ -48,11 +51,8 @@ public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
private static final String INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT = "Tap Point: Symbol Filter Output";
private static final String INSTRUMENT_C4FM_SLICER_OUTPUT = "Tap Point: C4FM Slicer Output";
private final static int MAXIMUM_FREQUENCY_CORRECTION = 3000; //Hertz, +/-
private List<TapGroup> mAvailableTaps;
private RealFIRFilter_RB_RB mC4FMPreFilter;
private FrequencyCorrectionControl mFrequencyCorrectionControl;
private C4FMSymbolFilter mSymbolFilter;
private C4FMSlicer mC4FMSlicer;
private P25MessageFramer mMessageFramer;
@@ -70,7 +70,7 @@ public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
* infrastructure and subscriber identities that will be included in each
* decoded message
*/
public P25_C4FMDecoder( AliasList aliasList )
public P25_C4FMDecoder( AliasList aliasList, int frequencyCorrectionMaximum )
{
super( aliasList );
@@ -79,13 +79,8 @@ public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
mC4FMPreFilter = new RealFIRFilter_RB_RB( filter, 1.0f );
/* Issue tuned frequency correction commands, remotely controlled by the
* downstream symbol filter */
mFrequencyCorrectionControl = new FrequencyCorrectionControl(
MAXIMUM_FREQUENCY_CORRECTION );
/* Shape gain and frequency offsets to optimize sample stream */
mSymbolFilter = new C4FMSymbolFilter( mFrequencyCorrectionControl );
mSymbolFilter = new C4FMSymbolFilter( frequencyCorrectionMaximum );
mC4FMPreFilter.setListener( mSymbolFilter );
/* Convert samples to symbols */
@@ -108,9 +103,6 @@ public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
mC4FMPreFilter.dispose();
mC4FMPreFilter = null;
mFrequencyCorrectionControl.dispose();
mFrequencyCorrectionControl = null;
mSymbolFilter.dispose();
mSymbolFilter = null;
@@ -127,19 +119,7 @@ public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
}
@Override
public boolean hasFrequencyCorrectionControl()
{
return mFrequencyCorrectionControl != null;
}
@Override
public FrequencyCorrectionControl getFrequencyCorrectionControl()
{
return mFrequencyCorrectionControl;
}
@Override
public Listener<RealBuffer> getRealBufferListener()
public Listener<RealBuffer> getFilteredRealBufferListener()
{
return mC4FMPreFilter;
}
@@ -249,7 +229,7 @@ public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
// TODO Auto-generated method stub
@@ -261,4 +241,33 @@ public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
// TODO Auto-generated method stub
}
@Override
public void setFrequencyChangeListener( Listener<FrequencyChangeEvent> listener )
{
if( mSymbolFilter != null )
{
mSymbolFilter.setFrequencyChangeListener( listener );
}
}
@Override
public void removeFrequencyChangeListener()
{
if( mSymbolFilter != null )
{
mSymbolFilter.setFrequencyChangeListener( null );
}
}
@Override
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
{
if( mSymbolFilter != null )
{
return mSymbolFilter.getFrequencyChangeListener();
}
return null;
}
}

View File

@@ -26,16 +26,16 @@ import instrument.tap.stream.QPSKTap;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import alias.AliasList;
import sample.Listener;
import sample.complex.ComplexBuffer;
import sample.complex.ComplexBufferToStreamConverter;
import sample.complex.IComplexBufferListener;
import source.tuner.frequency.FrequencyCorrectionControl;
import alias.AliasList;
import dsp.filter.FilterFactory;
import dsp.filter.Window.WindowType;
import dsp.filter.fir.complex.ComplexFIRFilter_CB_CB;
@@ -50,8 +50,8 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
/* Instrumentation Taps */
private static final String INSTRUMENT_BASEBAND_FILTER_OUTPUT = "Tap Point: Baseband Filter Output";
private static final String INSTRUMENT_AGC_OUTPUT = "Tap Point: AGC Output";
private static final String INSTRUMENT_QPSK_DEMODULATOR_OUTPUT = "Tap Point: CQPSK Demodulator Output";
private static final String INSTRUMENT_CQPSK_SLICER_OUTPUT = "Tap Point: CQPSK Slicer Output";
private static final String INSTRUMENT_LSM_DEMODULATOR_OUTPUT = "Tap Point: LSM Demodulator Output";
private static final String INSTRUMENT_QPSK_SLICER_OUTPUT = "Tap Point: QPSK Slicer Output";
private List<TapGroup> mAvailableTaps;
@@ -60,8 +60,8 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
new ComplexBufferToStreamConverter();
private ComplexFeedForwardGainControl mAGC =
new ComplexFeedForwardGainControl( 32 );
private LSMDemodulator mCQPSKDemodulator = new LSMDemodulator();
private QPSKPolarSlicer mCQPSKSlicer = new QPSKPolarSlicer();
private LSMDemodulator mLSMDemodulator = new LSMDemodulator();
private QPSKPolarSlicer mQPSKSlicer = new QPSKPolarSlicer();
private P25MessageFramer mMessageFramer;
public P25_LSMDecoder( AliasList aliasList )
@@ -75,12 +75,12 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
mStreamConverter.setListener( mAGC );
mAGC.setListener( mCQPSKDemodulator );
mAGC.setListener( mLSMDemodulator );
mCQPSKDemodulator.setSymbolListener( mCQPSKSlicer );
mLSMDemodulator.setSymbolListener( mQPSKSlicer );
mMessageFramer = new P25MessageFramer( aliasList, mCQPSKDemodulator );
mCQPSKSlicer.addListener( mMessageFramer );
mMessageFramer = new P25MessageFramer( aliasList, mLSMDemodulator );
mQPSKSlicer.addListener( mMessageFramer );
mMessageFramer.setListener( getMessageProcessor() );
}
@@ -98,11 +98,11 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
mAGC.dispose();
mAGC = null;
mCQPSKDemodulator.dispose();
mCQPSKDemodulator = null;
mLSMDemodulator.dispose();
mLSMDemodulator = null;
mCQPSKSlicer.dispose();
mCQPSKSlicer = null;
mQPSKSlicer.dispose();
mQPSKSlicer = null;
mMessageFramer.dispose();
mMessageFramer = null;
@@ -119,18 +119,6 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
return Modulation.CQPSK;
}
@Override
public boolean hasFrequencyCorrectionControl()
{
return false;
}
@Override
public FrequencyCorrectionControl getFrequencyCorrectionControl()
{
return null;
}
/**
* Provides a list of instrumentation taps for monitoring internal processing
*/
@@ -145,14 +133,14 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
group.add( new ComplexTap( INSTRUMENT_BASEBAND_FILTER_OUTPUT, 0, 1.0f ) );
group.add( new ComplexTap( INSTRUMENT_AGC_OUTPUT, 0, 1.0f ) );
group.add( new QPSKTap( INSTRUMENT_QPSK_DEMODULATOR_OUTPUT, 0, 1.0f ) );
group.add( new DibitTap( INSTRUMENT_CQPSK_SLICER_OUTPUT, 0, 0.1f ) );
group.add( new QPSKTap( INSTRUMENT_LSM_DEMODULATOR_OUTPUT, 0, 1.0f ) );
group.add( new DibitTap( INSTRUMENT_QPSK_SLICER_OUTPUT, 0, 0.1f ) );
mAvailableTaps.add( group );
if( mCQPSKDemodulator != null )
if( mLSMDemodulator != null )
{
mAvailableTaps.addAll( mCQPSKDemodulator.getTapGroups() );
mAvailableTaps.addAll( mLSMDemodulator.getTapGroups() );
}
}
@@ -165,9 +153,9 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
@Override
public void registerTap( Tap tap )
{
if( mCQPSKDemodulator != null )
if( mLSMDemodulator != null )
{
mCQPSKDemodulator.registerTap( tap );
mLSMDemodulator.registerTap( tap );
}
switch( tap.getName() )
@@ -180,15 +168,15 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
case INSTRUMENT_AGC_OUTPUT:
ComplexSampleTap agcSymbol = (ComplexSampleTap)tap;
mAGC.setListener( agcSymbol );
agcSymbol.setListener( mCQPSKDemodulator );
agcSymbol.setListener( mLSMDemodulator );
break;
case INSTRUMENT_QPSK_DEMODULATOR_OUTPUT:
case INSTRUMENT_LSM_DEMODULATOR_OUTPUT:
QPSKTap qpsk = (QPSKTap)tap;
mCQPSKDemodulator.setSymbolListener( qpsk );
qpsk.setListener( mCQPSKSlicer );
mLSMDemodulator.setSymbolListener( qpsk );
qpsk.setListener( mQPSKSlicer );
break;
case INSTRUMENT_CQPSK_SLICER_OUTPUT:
mCQPSKSlicer.addListener( (DibitTap)tap );
case INSTRUMENT_QPSK_SLICER_OUTPUT:
mQPSKSlicer.addListener( (DibitTap)tap );
break;
default:
throw new IllegalArgumentException( "Unrecognized tap: " +
@@ -202,9 +190,9 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
@Override
public void unregisterTap( Tap tap )
{
if( mCQPSKDemodulator != null )
if( mLSMDemodulator != null )
{
mCQPSKDemodulator.unregisterTap( tap );
mLSMDemodulator.unregisterTap( tap );
}
switch( tap.getName() )
@@ -213,13 +201,13 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
mStreamConverter.setListener( mAGC );
break;
case INSTRUMENT_AGC_OUTPUT:
mAGC.setListener( mCQPSKDemodulator );
mAGC.setListener( mLSMDemodulator );
break;
case INSTRUMENT_QPSK_DEMODULATOR_OUTPUT:
mCQPSKDemodulator.setSymbolListener( mCQPSKSlicer );
case INSTRUMENT_LSM_DEMODULATOR_OUTPUT:
mLSMDemodulator.setSymbolListener( mQPSKSlicer );
break;
case INSTRUMENT_CQPSK_SLICER_OUTPUT:
mCQPSKSlicer.removeListener( (DibitTap)tap );
case INSTRUMENT_QPSK_SLICER_OUTPUT:
mQPSKSlicer.removeListener( (DibitTap)tap );
break;
default:
throw new IllegalArgumentException( "Unrecognized tap: " +
@@ -235,7 +223,7 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
// TODO Auto-generated method stub

View File

@@ -1,5 +1,7 @@
package module.decode.p25.audio;
import java.util.concurrent.ScheduledExecutorService;
import jmbe.iface.AudioConversionLibrary;
import jmbe.iface.AudioConverter;
import message.IMessageListener;
@@ -21,7 +23,6 @@ import audio.squelch.ISquelchStateListener;
import audio.squelch.SquelchState;
import controller.channel.ChannelEvent;
import controller.channel.IChannelEventListener;
import dsp.filter.iir.DeemphasisFilter;
import dsp.gain.NonClippingGain;
public class P25AudioModule extends Module implements Listener<Message>,
@@ -78,7 +79,7 @@ public class P25AudioModule extends Module implements Listener<Message>,
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}
@@ -232,10 +233,10 @@ public class P25AudioModule extends Module implements Listener<Message>,
{
switch( event.getEvent() )
{
case CHANNEL_STATE_RESET:
case NOTIFICATION_STATE_RESET:
mAudioMetadata.reset();
break;
case CHANGE_SELECTED:
case NOTIFICATION_SELECTION_CHANGE:
mAudioMetadata.setSelected( event.getChannel().isSelected() );
break;
default:

View File

@@ -86,7 +86,6 @@ public class P25Message extends Message
sb.append( getNAC() );
sb.append( " " );
sb.append( getDUID().getLabel() );
sb.append( " DATA UNIT ID:" + mMessage.getInt( DUID ) );
return sb.toString();

View File

@@ -7,15 +7,9 @@ import module.decode.p25.message.ldu.LDU1Message;
import module.decode.p25.message.tsbk.osp.control.SystemService;
import module.decode.p25.reference.LinkControlOpcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AdjacentSiteStatusBroadcast extends LDU1Message
implements IdentifierReceiver, IAdjacentSite
{
private final static Logger mLog =
LoggerFactory.getLogger( AdjacentSiteStatusBroadcast.class );
public static final int[] LRA = { 364,365,366,367,372,373,374,375 };
public static final int[] SYSTEM_ID = { 384,385,386,387,536,537,538,539,540,
541,546,547 };

View File

@@ -6,15 +6,9 @@ import module.decode.p25.message.IdentifierReceiver;
import module.decode.p25.message.ldu.LDU1Message;
import module.decode.p25.reference.LinkControlOpcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AdjacentSiteStatusBroadcastExplicit extends LDU1Message
implements IdentifierReceiver, IAdjacentSite
{
private final static Logger mLog =
LoggerFactory.getLogger( AdjacentSiteStatusBroadcastExplicit.class );
public static final int[] LRA = { 364,365,366,367,372,373,374,375 };
public static final int[] TRANSMIT_IDENTIFIER = { 376,377,382,383 };
public static final int[] TRANSMIT_CHANNEL = { 384,385,386,387,536,537,538,

View File

@@ -3,13 +3,8 @@ package module.decode.p25.message.ldu.lc;
import module.decode.p25.message.ldu.LDU1Message;
import module.decode.p25.reference.LinkControlOpcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CallAlert extends LDU1Message
{
private final static Logger mLog =
LoggerFactory.getLogger( CallAlert.class );
public static final int[] TARGET_ADDRESS = { 536,537,538,539,540,541,546,
547,548,549,550,551,556,557,558,559,560,561,566,567,568,569,570,571 };
public static final int[] SOURCE_ADDRESS = { 720,721,722,723,724,725,730,

View File

@@ -3,13 +3,8 @@ package module.decode.p25.message.ldu.lc;
import module.decode.p25.message.ldu.LDU1Message;
import module.decode.p25.reference.LinkControlOpcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CallTermination extends LDU1Message
{
private final static Logger mLog = LoggerFactory.getLogger( CallTermination.class );
public static final int[] SOURCE_ADDRESS = { 720,721,722,723,724,725,730,
731,732,733,734,735,740,741,742,743,744,745,750,751,752,753,754,755 };

View File

@@ -4,15 +4,9 @@ import module.decode.p25.message.IBandIdentifier;
import module.decode.p25.message.ldu.LDU1Message;
import module.decode.p25.reference.LinkControlOpcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ChannelIdentifierUpdate extends LDU1Message
implements IBandIdentifier
{
private final static Logger mLog =
LoggerFactory.getLogger( ChannelIdentifierUpdate.class );
public static final int[] IDENTIFIER = { 364,365,366,367 };
public static final int[] BANDWIDTH = { 372,373,374,375,376,377,382,383,384 };
public static final int[] TRANSMIT_OFFSET = { 385,386,387,536,537,538,539,

View File

@@ -4,15 +4,9 @@ import module.decode.p25.message.IBandIdentifier;
import module.decode.p25.message.ldu.LDU1Message;
import module.decode.p25.reference.LinkControlOpcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ChannelIdentifierUpdateExplicit extends LDU1Message
implements IBandIdentifier
{
private final static Logger mLog =
LoggerFactory.getLogger( ChannelIdentifierUpdateExplicit.class );
public static final int[] IDENTIFIER = { 364,365,366,367 };
public static final int[] BANDWIDTH = { 372,373,374,375 };
public static final int[] TRANSMIT_OFFSET = { 376,377,382,383,384,385,386,

View File

@@ -1,6 +1,5 @@
package module.decode.p25.message.pdu;
import module.decode.p25.message.pdu.confirmed.PacketData;
import module.decode.p25.message.pdu.osp.control.AdjacentStatusBroadcastExtended;
import module.decode.p25.message.pdu.osp.control.CallAlertExtended;
import module.decode.p25.message.pdu.osp.control.GroupAffiliationQueryExtended;
@@ -122,8 +121,7 @@ public class PDUMessageFactory
}
return new PDUMessage( message, duid, aliasList );
case PACKET_DATA:
return new PacketData( message, aliasList );
case UNCONFIRMED_MULTI_BLOCK_TRUNKING_CONTROL:
return new PDUMessage( message, duid, aliasList );
default:

View File

@@ -3,7 +3,6 @@ package module.decode.p25.message.pdu.confirmed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PDUConfirmedMessageFactory
{
public final static Logger mLog =
@@ -52,7 +51,7 @@ public class PDUConfirmedMessageFactory
return new SNDCPActivateTDSContextAccept( message );
case SNDCP_ACTIVATE_TDS_CONTEXT_REJECT:
return new SNDCPActivateTDSContextReject( message );
case SN_ACTIVATE_TDS_CONTEXT_REQUEST:
case SNDCP_ACTIVATE_TDS_CONTEXT_REQUEST:
return new SNDCPActivateTDSContextRequest( message );
case SNDCP_DEACTIVATE_TDS_CONTEXT_ACCEPT:
case SNDCP_DEACTIVATE_TDS_CONTEXT_REQUEST:
@@ -61,14 +60,6 @@ public class PDUConfirmedMessageFactory
return new SNDCPUserData( message );
case SNDCP_RF_UNCONFIRMED_DATA:
break;
case PDU_TYPE_6:
case PDU_TYPE_7:
case PDU_TYPE_8:
case PDU_TYPE_9:
case PDU_TYPE_10:
case PDU_TYPE_11:
return new PDUTypeUnknown( message );
case UNKNOWN:
default:
break;
}

View File

@@ -1,3 +1,21 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.p25.message.tdu;
import module.decode.p25.message.P25Message;
@@ -18,7 +36,7 @@ public class TDUMessage extends P25Message
mCRC = new CRC[ 1 ];
mCRC[ 0 ] = CRC.PASSED;
}
@Override
public String getMessage()
{

View File

@@ -5,17 +5,10 @@ import module.decode.p25.message.IBandIdentifier;
import module.decode.p25.message.IdentifierReceiver;
import module.decode.p25.message.tsbk.osp.control.SystemService;
import module.decode.p25.reference.LinkControlOpcode;
import module.decode.p25.reference.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AdjacentSiteStatusBroadcast extends TDULinkControlMessage
implements IdentifierReceiver, IAdjacentSite
{
private final static Logger mLog =
LoggerFactory.getLogger( AdjacentSiteStatusBroadcast.class );
public static final int[] LRA = { 72,73,74,75,88,89,90,91 };
public static final int[] SYSTEM_ID = { 96,97,98,99,112,113,114,115,
116,117,118,119 };

View File

@@ -5,15 +5,9 @@ import module.decode.p25.message.IBandIdentifier;
import module.decode.p25.message.IdentifierReceiver;
import module.decode.p25.reference.LinkControlOpcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AdjacentSiteStatusBroadcastExplicit extends TDULinkControlMessage
implements IdentifierReceiver, IAdjacentSite
{
private final static Logger mLog =
LoggerFactory.getLogger( AdjacentSiteStatusBroadcastExplicit.class );
public static final int[] LRA = { 72,73,74,75,88,89,90,91 };
public static final int[] TRANSMIT_IDENTIFIER = { 92,93,94,95 };
public static final int[] TRANSMIT_CHANNEL = { 96,97,98,99,112,113,114,115,

View File

@@ -2,13 +2,8 @@ package module.decode.p25.message.tdu.lc;
import module.decode.p25.reference.LinkControlOpcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CallAlert extends TDULinkControlMessage
{
private final static Logger mLog =
LoggerFactory.getLogger( CallAlert.class );
public static final int[] TARGET_ADDRESS = { 112,113,114,115,116,117,118,
119,120,121,122,123,136,137,138,139,140,141,142,143,144,145,146,147 };
public static final int[] SOURCE_ADDRESS = { 160,161,162,163,164,165,166,

View File

@@ -2,13 +2,8 @@ package module.decode.p25.message.tdu.lc;
import module.decode.p25.reference.LinkControlOpcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CallTermination extends TDULinkControlMessage
{
private final static Logger mLog = LoggerFactory.getLogger( CallTermination.class );
public static final int[] SOURCE_ADDRESS = { 160,161,162,163,164,165,166,
167,168,169,170,171,184,185,186,187,188,189,190,191,192,193,194,195 };

View File

@@ -3,15 +3,9 @@ package module.decode.p25.message.tdu.lc;
import module.decode.p25.message.IBandIdentifier;
import module.decode.p25.reference.LinkControlOpcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ChannelIdentifierUpdate extends TDULinkControlMessage
implements IBandIdentifier
{
private final static Logger mLog =
LoggerFactory.getLogger( ChannelIdentifierUpdate.class );
public static final int[] IDENTIFIER = { 72,73,74,75 };
public static final int[] BANDWIDTH = { 88,89,90,91,92,93,94,95,96 };
public static final int[] TRANSMIT_OFFSET = { 97,98,99,112,113,114,115,116,

View File

@@ -3,15 +3,9 @@ package module.decode.p25.message.tdu.lc;
import module.decode.p25.message.IBandIdentifier;
import module.decode.p25.reference.LinkControlOpcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ChannelIdentifierUpdateExplicit extends TDULinkControlMessage
implements IBandIdentifier
{
private final static Logger mLog =
LoggerFactory.getLogger( ChannelIdentifierUpdateExplicit.class );
public static final int[] IDENTIFIER = { 72,73,74,75 };
public static final int[] BANDWIDTH = { 88,89,90,91 };
public static final int[] TRANSMIT_OFFSET = { 92,93,94,95,96,97,98,99,112,

View File

@@ -78,93 +78,67 @@ public class TSBKMessageFactory
switch( opcode )
{
case ACKNOWLEDGE_RESPONSE:
return new AcknowledgeResponse( message, duid,
aliasList );
return new AcknowledgeResponse( message, duid, aliasList );
case ADJACENT_STATUS_BROADCAST:
return new AdjacentStatusBroadcast( message, duid,
aliasList );
return new AdjacentStatusBroadcast( message, duid, aliasList );
case AUTHENTICATION_COMMAND:
return new AuthenticationCommand( message, duid,
aliasList );
return new AuthenticationCommand( message, duid, aliasList );
case CALL_ALERT:
return new CallAlert( message, duid, aliasList );
case DENY_RESPONSE:
return new DenyResponse( message, duid, aliasList );
case EXTENDED_FUNCTION_COMMAND:
return new ExtendedFunctionCommand( message, duid,
aliasList );
return new ExtendedFunctionCommand( message, duid, aliasList );
case GROUP_AFFILIATION_QUERY:
return new GroupAffiliationQuery( message, duid,
aliasList );
return new GroupAffiliationQuery( message, duid, aliasList );
case GROUP_AFFILIATION_RESPONSE:
return new GroupAffiliationResponse( message, duid,
aliasList );
return new GroupAffiliationResponse( message, duid, aliasList );
case GROUP_DATA_CHANNEL_ANNOUNCEMENT:
return new GroupDataChannelAnnouncement( message, duid,
aliasList );
return new GroupDataChannelAnnouncement( message, duid, aliasList );
case GROUP_DATA_CHANNEL_ANNOUNCEMENT_EXPLICIT:
return new GroupDataChannelAnnouncementExplicit(
message, duid, aliasList );
return new GroupDataChannelAnnouncementExplicit( message, duid, aliasList );
case GROUP_DATA_CHANNEL_GRANT:
return new GroupDataChannelGrant( message, duid,
aliasList );
return new GroupDataChannelGrant( message, duid, aliasList );
case GROUP_VOICE_CHANNEL_GRANT:
return new GroupVoiceChannelGrant( message, duid,
aliasList );
return new GroupVoiceChannelGrant( message, duid, aliasList );
case GROUP_VOICE_CHANNEL_GRANT_UPDATE:
return new GroupVoiceChannelGrantUpdate( message, duid,
aliasList );
return new GroupVoiceChannelGrantUpdate( message, duid, aliasList );
case GROUP_VOICE_CHANNEL_GRANT_UPDATE_EXPLICIT:
return new GroupVoiceChannelGrantUpdateExplicit( message,
duid, aliasList );
return new GroupVoiceChannelGrantUpdateExplicit( message, duid, aliasList );
case IDENTIFIER_UPDATE_NON_VUHF:
return new IdentifierUpdateNonVUHF( message, duid,
aliasList );
return new IdentifierUpdateNonVUHF( message, duid, aliasList );
case IDENTIFIER_UPDATE_TDMA:
return new IdentifierUpdateTDMA( message, duid, aliasList );
case IDENTIFIER_UPDATE_VHF_UHF_BANDS:
return new IdentifierUpdateVUHF( message, duid,
aliasList );
return new IdentifierUpdateVUHF( message, duid, aliasList );
case INDIVIDUAL_DATA_CHANNEL_GRANT:
return new IndividualDataChannelGrant( message, duid,
aliasList );
return new IndividualDataChannelGrant( message, duid, aliasList );
case LOCATION_REGISTRATION_RESPONSE:
return new LocationRegistrationResponse( message, duid,
aliasList );
return new LocationRegistrationResponse( message, duid, aliasList );
case MESSAGE_UPDATE:
return new MessageUpdate( message, duid, aliasList );
case NETWORK_STATUS_BROADCAST:
return new NetworkStatusBroadcast( message, duid,
aliasList );
return new NetworkStatusBroadcast( message, duid, aliasList );
case QUEUED_RESPONSE:
return new QueuedResponse( message, duid, aliasList );
case PROTECTION_PARAMETER_UPDATE:
return new ProtectionParameterUpdate( message, duid,
aliasList );
return new ProtectionParameterUpdate( message, duid, aliasList );
case RADIO_UNIT_MONITOR_COMMAND:
return new RadioUnitMonitorCommand( message, duid,
aliasList );
return new RadioUnitMonitorCommand( message, duid, aliasList );
case RFSS_STATUS_BROADCAST:
return new RFSSStatusBroadcast( message, duid,
aliasList );
return new RFSSStatusBroadcast( message, duid, aliasList );
case ROAMING_ADDRESS_COMMAND:
return new RoamingAddressCommand( message, duid,
aliasList );
return new RoamingAddressCommand( message, duid, aliasList );
case SECONDARY_CONTROL_CHANNEL_BROADCAST:
return new SecondaryControlChannelBroadcast( message,
duid, aliasList );
return new SecondaryControlChannelBroadcast( message, duid, aliasList );
case SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT:
return new SecondaryControlChannelBroadcastExplicit(
message, duid, aliasList );
return new SecondaryControlChannelBroadcastExplicit( message, duid, aliasList );
case SNDCP_DATA_CHANNEL_GRANT:
return new SNDCPDataChannelGrant( message, duid,
aliasList );
return new SNDCPDataChannelGrant( message, duid, aliasList );
case SNDCP_DATA_CHANNEL_ANNOUNCEMENT_EXPLICIT:
return new SNDCPDataChannelAnnouncementExplicit(
message, duid, aliasList );
return new SNDCPDataChannelAnnouncementExplicit( message, duid, aliasList );
case SNDCP_DATA_PAGE_REQUEST:
return new SNDCPDataPageRequest( message, duid,
aliasList );
return new SNDCPDataPageRequest( message, duid, aliasList );
case STATUS_QUERY:
return new StatusQuery( message, duid, aliasList );
case STATUS_UPDATE:
@@ -172,35 +146,25 @@ public class TSBKMessageFactory
case TDMA_SYNC_BROADCAST:
return new SyncBroadcast( message, duid, aliasList );
case SYSTEM_SERVICE_BROADCAST:
return new SystemServiceBroadcast( message, duid,
aliasList );
return new SystemServiceBroadcast( message, duid, aliasList );
case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
return new TelephoneInterconnectAnswerRequest(
message, duid, aliasList );
return new TelephoneInterconnectAnswerRequest( message, duid, aliasList );
case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_GRANT:
return new TelephoneInterconnectVoiceChannelGrant(
message, duid, aliasList );
return new TelephoneInterconnectVoiceChannelGrant( message, duid, aliasList );
case TIME_DATE_ANNOUNCEMENT:
return new TimeAndDateAnnouncement( message, duid,
aliasList );
return new TimeAndDateAnnouncement( message, duid, aliasList );
case UNIT_DEREGISTRATION_ACKNOWLEDGE:
return new UnitDeregistrationAcknowledge( message,
duid, aliasList );
return new UnitDeregistrationAcknowledge( message, duid, aliasList );
case UNIT_REGISTRATION_COMMAND:
return new UnitRegistrationCommand( message, duid,
aliasList );
return new UnitRegistrationCommand( message, duid, aliasList );
case UNIT_REGISTRATION_RESPONSE:
return new UnitRegistrationResponse( message, duid,
aliasList );
return new UnitRegistrationResponse( message, duid, aliasList );
case UNIT_TO_UNIT_ANSWER_REQUEST:
return new UnitToUnitAnswerRequest( message, duid,
aliasList );
return new UnitToUnitAnswerRequest( message, duid, aliasList );
case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT:
return new UnitToUnitVoiceChannelGrant( message,
duid, aliasList );
return new UnitToUnitVoiceChannelGrant( message, duid, aliasList );
case UNIT_TO_UNIT_VOICE_CHANNEL_GRANT_UPDATE:
return new UnitToUnitVoiceChannelGrantUpdate( message,
duid, aliasList );
return new UnitToUnitVoiceChannelGrantUpdate( message, duid, aliasList );
default:
return new TSBKMessage( message, duid, aliasList );
}
@@ -235,4 +199,4 @@ public class TSBKMessageFactory
return new TSBKMessage( message, duid, aliasList );
}
}
}
}

View File

@@ -156,4 +156,4 @@ public class IdentifierUpdateTDMA extends IdentifierUpdate
{
HALF_RATE, FULL_RATE;
}
}
}

View File

@@ -271,4 +271,4 @@ public class SyncBroadcast extends TSBKMessage
{
return mMessage.getInt( MICRO_SLOTS );
}
}
}

View File

@@ -0,0 +1,42 @@
package module.decode.p25.message.vselp;
import module.decode.p25.message.P25Message;
import module.decode.p25.reference.DataUnitID;
import alias.AliasList;
import bits.BinaryMessage;
public class VSELP1Message extends P25Message
{
/**
* Motorola VSELP audio message 1.
*
* @param message
* @param duid
* @param aliasList
*/
public VSELP1Message( BinaryMessage message, DataUnitID duid, AliasList aliasList )
{
super( message, duid, aliasList );
}
@Override
public String getMessage()
{
StringBuilder sb = new StringBuilder();
sb.append( getMessageStub() );
sb.append( " " );
sb.append( mMessage.toString() );
return sb.toString();
}
public String getMessageStub()
{
StringBuilder sb = new StringBuilder();
sb.append( "VSELP 1 VOICE FRAME" );
return sb.toString();
}
}

View File

@@ -0,0 +1,42 @@
package module.decode.p25.message.vselp;
import alias.AliasList;
import bits.BinaryMessage;
import module.decode.p25.message.P25Message;
import module.decode.p25.reference.DataUnitID;
public class VSELP2Message extends P25Message
{
/**
* Motorola VSELP audio message 1.
*
* @param message
* @param duid
* @param aliasList
*/
public VSELP2Message( BinaryMessage message, DataUnitID duid, AliasList aliasList )
{
super( message, duid, aliasList );
}
@Override
public String getMessage()
{
StringBuilder sb = new StringBuilder();
sb.append( getMessageStub() );
sb.append( " " );
sb.append( mMessage.toString() );
return sb.toString();
}
public String getMessageStub()
{
StringBuilder sb = new StringBuilder();
sb.append( "VSELP 2 VOICE FRAME" );
return sb.toString();
}
}

View File

@@ -14,7 +14,7 @@ public enum DataUnitID
TSBK1( 7, 260, false, "TSBK1", "Trunking Signaling Block" ),
TSBK2( 7, 260, false, "TSBK2", "Trunking Signaling Block" ),
TSBK3( 7, 260, false, "TSBK3", "Trunking Signaling Block" ),
VSELP2( 9, 1680, false, "VSEL1", "Motorola VSELP Unit 1" ),
VSELP2( 9, 1680, false, "VSEL2", "Motorola VSELP Unit 2" ),
LDU2 ( 10, 1632, true, "LDU2 ", "Logical Link Data Unit 2" ),
PDU0 ( 12, 260, false, "PDU0 ", "Packet Header Data Unit" ),
PDU1 ( 12, 356, false, "PDU1 ", "Packet Data Unit-Unconfirmed" ),
@@ -75,8 +75,12 @@ public enum DataUnitID
return TDU;
case 5:
return LDU1;
case 6:
return VSELP1;
case 7:
return TSBK1;
case 9:
return VSELP2;
case 10:
return LDU2;
case 12:

View File

@@ -17,7 +17,7 @@ public enum PDUType
PDU_TYPE_11( "PDU TYPE 11 UNKNOWN", 11 ),
/* Inbound */
SN_ACTIVATE_TDS_CONTEXT_REQUEST( "SN-ACTIVATE TDS CONTEXT REQUEST", 0 ),
SNDCP_ACTIVATE_TDS_CONTEXT_REQUEST( "SNDCP-ACTIVATE TDS CONTEXT REQUEST", 0 ),
UNKNOWN( "UNKNOWN", -1 );
@@ -48,9 +48,9 @@ public enum PDUType
}
else if( value == 0 && !outbound )
{
return SN_ACTIVATE_TDS_CONTEXT_REQUEST;
return SNDCP_ACTIVATE_TDS_CONTEXT_REQUEST;
}
return UNKNOWN;
}
}
}

View File

@@ -2,7 +2,7 @@ package module.decode.p25.reference;
public enum ServiceAccessPoint
{
UNENCRYPTED_USER_DATA( "UNENCRYPTED USER DATA", 0 ),
UNENCRYPTED_USER_DATA( "USER DATA", 0 ),
ENCRYPTED_USER_DATA( "ENCRYPTED USER DATA", 1 ),
CIRCUIT_DATA( "CIRCUIT DATA", 2 ),
CIRCUIT_DATA_CONTROL( "CIRCUIT DATA CONTROL", 3 ),

View File

@@ -23,12 +23,13 @@ import instrument.tap.TapGroup;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import module.decode.Decoder;
import module.decode.DecoderType;
import module.decode.config.DecodeConfiguration;
import sample.Listener;
import sample.real.IRealBufferListener;
import sample.real.IUnFilteredRealBufferListener;
import sample.real.RealBuffer;
import alias.AliasList;
import bits.MessageFramer;
@@ -36,7 +37,7 @@ import bits.SyncPattern;
import dsp.fsk.LTRFSKDecoder;
public class PassportDecoder extends Decoder
implements IRealBufferListener, Instrumentable
implements IUnFilteredRealBufferListener, Instrumentable
{
public static final int PASSPORT_MESSAGE_LENGTH = 68;
public static final int PASSPORT_SYNC_LENGTH = 9;
@@ -47,8 +48,11 @@ public class PassportDecoder extends Decoder
private List<TapGroup> mAvailableTaps;
public PassportDecoder( DecodeConfiguration config,
AliasList aliasList )
/**
* Passport Decoder. Decodes unfiltered (e.g. demodulated but with no DC or
* audio filtering) samples and produces Passport messages.
*/
public PassportDecoder( DecodeConfiguration config, AliasList aliasList )
{
mPassportFSKDecoder = new LTRFSKDecoder();
@@ -60,11 +64,11 @@ public class PassportDecoder extends Decoder
mPassportMessageProcessor = new PassportMessageProcessor( aliasList );
mPassportMessageFramer.addMessageListener( mPassportMessageProcessor );
mPassportMessageProcessor.setMessageListener( mMessageBroadcaster );
mPassportMessageProcessor.setMessageListener( this );
}
@Override
public Listener<RealBuffer> getRealBufferListener()
public Listener<RealBuffer> getUnFilteredRealBufferListener()
{
return mPassportFSKDecoder;
}
@@ -107,7 +111,7 @@ public class PassportDecoder extends Decoder
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}

View File

@@ -0,0 +1,159 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.passport;
import gui.editor.Editor;
import gui.editor.EditorValidationException;
import gui.editor.ValidatingEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JCheckBox;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import module.decode.config.DecodeConfiguration;
import net.miginfocom.swing.MigLayout;
import controller.channel.Channel;
public class PassportDecoderEditor extends ValidatingEditor<Channel>
{
private static final long serialVersionUID = 1L;
private JCheckBox mAFC;
private JSlider mAFCMaximumCorrection;
public PassportDecoderEditor()
{
init();
}
private void init()
{
setLayout( new MigLayout( "insets 0 0 0 0,wrap 2", "[right][grow,fill]", "" ) );
mAFC = new JCheckBox( "AFC: 3000 Hz" );
mAFC.setEnabled( false );
mAFC.setToolTipText( "AFC automatically adjusts the center frequency of the channel to "
+ "correct/compensate for inaccuracies and frequency drift in the tuner" );
mAFC.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
setModified( true );
if( mAFC.isSelected() && !mAFCMaximumCorrection.isEnabled() )
{
mAFCMaximumCorrection.setEnabled( true );
}
else if( !mAFC.isSelected() && mAFCMaximumCorrection.isEnabled() )
{
mAFCMaximumCorrection.setEnabled( false );
}
}
} );
add( mAFC );
mAFCMaximumCorrection = new JSlider( 0, 7000, 3000 );
mAFCMaximumCorrection.setEnabled( false );
mAFCMaximumCorrection.setToolTipText( "Maximum AFC frequency correction (0 - 15kHz)" );
mAFCMaximumCorrection.setMajorTickSpacing( 2000 );
mAFCMaximumCorrection.setMinorTickSpacing( 1000 );
mAFCMaximumCorrection.setPaintTicks( true );
mAFCMaximumCorrection.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent e )
{
mAFC.setText( "AFC: " + mAFCMaximumCorrection.getValue() + " Hz" );
setModified( true );
}
} );
add( mAFCMaximumCorrection );
}
@Override
public void validate( Editor<Channel> editor ) throws EditorValidationException
{
//No validation
}
@Override
public void save()
{
if( hasItem() && isModified() )
{
DecodeConfigPassport passport = new DecodeConfigPassport();
passport.setAFC( mAFC.isSelected() );
passport.setAFCMaximumCorrection( mAFCMaximumCorrection.getValue() );
getItem().setDecodeConfiguration( passport );
}
setModified( false );
}
private void setControlsEnabled( boolean enabled )
{
if( mAFC.isEnabled() != enabled )
{
mAFC.setEnabled( enabled );
}
}
@Override
public void setItem( Channel item )
{
super.setItem( item );
if( hasItem() )
{
setControlsEnabled( true );
DecodeConfiguration config = getItem().getDecodeConfiguration();
if( config instanceof DecodeConfigPassport )
{
DecodeConfigPassport passport = (DecodeConfigPassport)config;
mAFC.setSelected( passport.isAFCEnabled() );
mAFCMaximumCorrection.setValue( passport.getAFCMaximumCorrection() );
mAFCMaximumCorrection.setEnabled( passport.isAFCEnabled() );
setModified( false );
}
else
{
mAFC.setSelected( false );
mAFCMaximumCorrection.setValue( DecodeConfiguration.DEFAULT_AFC_MAX_CORRECTION );
mAFCMaximumCorrection.setEnabled( false );
setModified( true );
}
}
else
{
setControlsEnabled( false );
setModified( false );
}
}
}

View File

@@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.concurrent.ScheduledExecutorService;
import message.Message;
import module.decode.DecoderType;
@@ -75,7 +76,7 @@ public class PassportDecoderState extends DecoderState
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}

View File

@@ -1,31 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.passport;
import module.decode.DecodeEditor;
import module.decode.config.DecodeConfiguration;
public class PassportEditor extends DecodeEditor
{
private static final long serialVersionUID = 1L;
public PassportEditor( DecodeConfiguration config )
{
super( config );
}
}

View File

@@ -17,13 +17,11 @@
******************************************************************************/
package module.decode.state;
import java.util.concurrent.ScheduledExecutorService;
import message.Message;
import module.decode.DecoderType;
import module.decode.state.DecoderStateEvent.Event;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import audio.metadata.Metadata;
import audio.metadata.MetadataType;
@@ -33,9 +31,6 @@ import audio.metadata.MetadataType;
*/
public class AlwaysUnsquelchedDecoderState extends DecoderState
{
private final static Logger mLog =
LoggerFactory.getLogger( AlwaysUnsquelchedDecoderState.class );
private DecoderType mDecoderType;
private String mChannelName;
@@ -90,7 +85,7 @@ public class AlwaysUnsquelchedDecoderState extends DecoderState
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
broadcast( new Metadata( MetadataType.TO, mChannelName, false ) );
broadcast( new DecoderStateEvent( this, Event.ALWAYS_UNSQUELCH, State.IDLE ) );

View File

@@ -26,4 +26,4 @@ public class ChangeChannelTimeoutEvent extends DecoderStateEvent
{
return mCallTimeout;
}
}
}

View File

@@ -1,146 +0,0 @@
package module.decode.state;
import java.awt.Component;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JMenu;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import playlist.PlaylistManager;
import settings.SettingsManager;
import controller.channel.Channel;
/**
* Channel Collection assembles a primary channel panel and any related decoder
* state panels, provides contextual access to the channel and supports channel
* selection.
*/
public class ChannelCollectionPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( ChannelCollectionPanel.class );
private PlaylistManager mPlaylistManager;
private SettingsManager mSettingsManager;
private List<ChannelStatePanel> mChannelPanels = new ArrayList<ChannelStatePanel>();
public ChannelCollectionPanel( PlaylistManager playlistManager,
SettingsManager settingsManager,
Channel channel )
{
mPlaylistManager = playlistManager;
mSettingsManager = settingsManager;
init( channel );
}
protected void init( Channel channel )
{
setLayout( new MigLayout( "insets 0 0 0 0", "[grow,fill]", "[]0[]0[]") );
setOpaque( false );
ChannelStatePanel csp = new ChannelStatePanel( mPlaylistManager,
mSettingsManager, channel );
mChannelPanels.add( csp );
add( csp, "span,grow" );
}
public Channel getChannel()
{
if( mChannelPanels.size() >= 1 )
{
return mChannelPanels.get( 0 ).getChannel();
}
return null;
}
public void dispose()
{
for( ChannelStatePanel panel: mChannelPanels )
{
panel.dispose();
}
mChannelPanels.clear();
mPlaylistManager = null;
mSettingsManager = null;
}
/**
* Toggles the selection state of the channel if it matches the channel
* argument. Otherwise, sets the selection state to false.
*/
public void setSelectedChannel( Channel channel )
{
for( ChannelStatePanel panel: mChannelPanels )
{
if( panel.getChannel() == channel )
{
/* Toggle the selection state */
panel.getChannel().setSelected( !panel.getChannel().isSelected() );
panel.repaint();
}
else
{
if( panel.getChannel().isSelected() )
{
panel.getChannel().setSelected( false );
panel.repaint();
}
}
}
}
/**
* Returns the channel represented by the channel panel at the gui point
* location, to selecting the channel
*
* @param point - current location of the mouse
*
* @return - channel or null
*/
public Channel getChannelAt( Point point )
{
Component c = this.getComponentAt( point );
if( c instanceof ChannelCollectionPanel )
{
return ((ChannelCollectionPanel)c).getChannel();
}
else
{
return getChannel();
}
}
protected SettingsManager getSettingsManager()
{
return mSettingsManager;
}
public JMenu getContextMenu()
{
if( !mChannelPanels.isEmpty() )
{
return mChannelPanels.get( 0 ).getContextMenu();
}
return null;
}
}

View File

@@ -19,7 +19,6 @@ package module.decode.state;
import java.awt.Color;
import java.awt.Component;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Map;
@@ -29,21 +28,19 @@ import javax.swing.JMenu;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.SwingUtilities;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import playlist.PlaylistManager;
import settings.ColorSetting.ColorSettingName;
import settings.ColorSettingMenuItem;
import settings.ColorSettingResetMenuItem;
import settings.SettingsManager;
import audio.AudioPanel;
import controller.channel.Channel;
import controller.channel.ChannelEvent;
import controller.channel.ChannelEvent.Event;
import controller.channel.ChannelEventListener;
import controller.channel.ChannelModel;
import controller.channel.ChannelProcessingManager;
/**
* Gui wrapper for the list of currently processing primary channels
@@ -52,29 +49,37 @@ public class ChannelList extends JPanel implements ChannelEventListener
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( ChannelList.class );
private Map<Channel,ChannelPanel> mDisplayedPanels = new ConcurrentHashMap<>();
private Map<Channel,ChannelCollectionPanel> mDisplayedPanels =
new ConcurrentHashMap<Channel,ChannelCollectionPanel>();
private PlaylistManager mPlaylistManager;
private ChannelModel mChannelModel;
private ChannelProcessingManager mChannelProcessingManager;
private SettingsManager mSettingsManager;
private AudioPanel mAudioPanel;
public ChannelList( PlaylistManager playlistManager,
SettingsManager settingsManager )
public ChannelList( ChannelModel channelModel,
ChannelProcessingManager channelProcessingManager,
SettingsManager settingsManager,
AudioPanel audioPanel )
{
mPlaylistManager = playlistManager;
mChannelModel = channelModel;
mChannelProcessingManager = channelProcessingManager;
mSettingsManager = settingsManager;
mAudioPanel = audioPanel;
init();
}
private void init()
{
setLayout( new MigLayout( "insets 0 0 0 0", "[grow,fill]", "[]0[]") );
setLayout( new MigLayout( "insets 0 0 0 0,wrap 1", "[grow,fill]", "[]0[]") );
setBackground( Color.BLACK );
addMouseListener( new ListSelectionListener() );
add( mAudioPanel );
JSeparator separator = new JSeparator( JSeparator.HORIZONTAL );
add( separator );
}
@Override
@@ -82,10 +87,10 @@ public class ChannelList extends JPanel implements ChannelEventListener
{
switch( event.getEvent() )
{
case CHANNEL_PROCESSING_STARTED:
case NOTIFICATION_PROCESSING_START:
addChannelPanel( event.getChannel() );
break;
case CHANNEL_PROCESSING_STOPPED:
case NOTIFICATION_PROCESSING_STOP:
removeChannelPanel( event.getChannel() );
break;
default:
@@ -97,12 +102,12 @@ public class ChannelList extends JPanel implements ChannelEventListener
{
if( !mDisplayedPanels.containsKey( channel ) )
{
ChannelCollectionPanel panel = new ChannelCollectionPanel(
mPlaylistManager, mSettingsManager, channel );
ChannelPanel channelPanel = new ChannelPanel( mChannelModel,
mChannelProcessingManager, mSettingsManager, channel );
add( panel, "wrap" );
add( channelPanel );
mDisplayedPanels.put( channel, panel );
mDisplayedPanels.put( channel, channelPanel );
revalidate();
repaint();
@@ -113,7 +118,7 @@ public class ChannelList extends JPanel implements ChannelEventListener
{
if( mDisplayedPanels.containsKey( channel ) )
{
ChannelCollectionPanel panel = mDisplayedPanels.remove( channel );
ChannelPanel panel = mDisplayedPanels.remove( channel );
if( panel != null )
{
@@ -127,18 +132,6 @@ public class ChannelList extends JPanel implements ChannelEventListener
}
}
public void setSelectedChannel( Channel channel )
{
synchronized( mDisplayedPanels )
{
/* Send channel selection to each channel panel */
for( ChannelCollectionPanel panel: mDisplayedPanels.values() )
{
panel.setSelectedChannel( channel );
}
}
}
public class ListSelectionListener implements MouseListener
{
@Override
@@ -146,18 +139,22 @@ public class ChannelList extends JPanel implements ChannelEventListener
{
Component component = getComponentAt( e.getPoint() );
if( component instanceof ChannelCollectionPanel )
if( component instanceof ChannelPanel )
{
ChannelCollectionPanel panel = (ChannelCollectionPanel)component;
ChannelPanel panel = (ChannelPanel)component;
Point translatedPoint = SwingUtilities
.convertPoint( e.getComponent(), e.getPoint(), panel );
Channel channel = panel.getChannelAt( translatedPoint );
Channel channel = panel.getChannel();
if( e.getButton() == MouseEvent.BUTTON1 )
{
setSelectedChannel( channel );
if( channel.isSelected() )
{
mChannelModel.broadcast( new ChannelEvent( channel, Event.REQUEST_DESELECT ) );
}
else
{
mChannelModel.broadcast( new ChannelEvent( channel, Event.REQUEST_SELECT ) );
}
}
else if( e.getButton() == MouseEvent.BUTTON3 )
{
@@ -254,6 +251,20 @@ public class ChannelList extends JPanel implements ChannelEventListener
idleMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_IDLE ) );
JMenu noTunerMenu = new JMenu( "No Tuner" );
channelsMenu.add( noTunerMenu );
noTunerMenu.add( new ColorSettingMenuItem( mSettingsManager,
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_NO_TUNER ) );
noTunerMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_NO_TUNER ) );
noTunerMenu.add( new JSeparator() );
noTunerMenu.add( new ColorSettingMenuItem( mSettingsManager,
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_NO_TUNER ) );
noTunerMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_NO_TUNER ) );
JMenu labelMenu = new JMenu( "Labels" );
colorMenu.add( labelMenu );

View File

@@ -14,14 +14,13 @@ import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JPanel;
import module.ProcessingChain;
import module.decode.DecoderFactory;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import controller.channel.Channel;
import controller.channel.ChannelUtils;
import module.decode.DecoderFactory;
import net.miginfocom.swing.MigLayout;
import playlist.PlaylistManager;
import record.RecorderType;
import record.config.RecordConfiguration;
import sample.Listener;
@@ -30,17 +29,22 @@ import settings.ColorSetting.ColorSettingName;
import settings.Setting;
import settings.SettingChangeListener;
import settings.SettingsManager;
import controller.channel.Channel;
import controller.channel.ChannelEvent;
import controller.channel.ChannelEvent.Event;
import controller.channel.ChannelEventListener;
import controller.channel.ChannelModel;
import controller.channel.ChannelProcessingManager;
import controller.channel.ChannelUtils;
public class ChannelStatePanel extends JPanel
implements Listener<ChangedAttribute>, SettingChangeListener
public class ChannelPanel extends JPanel
implements Listener<ChangedAttribute>,
SettingChangeListener,
ChannelEventListener
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( ChannelStatePanel.class );
private static final boolean ENABLED = true;
private static final boolean DISABLED = false;
private static final boolean BROADCAST_CHANGE = true;
private final static Logger mLog = LoggerFactory.getLogger( ChannelPanel.class );
private Font mFontDetails = new Font( Font.MONOSPACED, Font.PLAIN, 12 );
private Font mFontDecoder = new Font( Font.MONOSPACED, Font.PLAIN, 12 );
@@ -71,11 +75,13 @@ public class ChannelStatePanel extends JPanel
private JLabel mSiteLabel;
private JLabel mChannelLabel;
private PlaylistManager mPlaylistManager;
protected SettingsManager mSettingsManager;
private Channel mChannel;
private ChannelState mChannelState;
private List<DecoderPanel> mDecoderPanels = new ArrayList<>();
private ChannelModel mChannelModel;
private ChannelProcessingManager mChannelProcessingManager;
/**
* Gui component to a channel state. Provides System, Site and channel
@@ -83,26 +89,40 @@ public class ChannelStatePanel extends JPanel
*
* Updates color background according to current channel state.
*/
public ChannelStatePanel( PlaylistManager playlistManager,
SettingsManager settingsManager,
Channel channel )
public ChannelPanel( ChannelModel channelModel,
ChannelProcessingManager channelProcessingManager,
SettingsManager settingsManager,
Channel channel )
{
mPlaylistManager = playlistManager;
mChannelModel = channelModel;
mChannelProcessingManager = channelProcessingManager;
mSettingsManager = settingsManager;
mSettingsManager.addListener( this );
mChannel = channel;
mChannel.getChannelState().setChangedAttributeListener( this );
init();
ProcessingChain processingChain =
channelProcessingManager.getProcessingChain( mChannel );
for( DecoderState decoderState: getChannel().getProcessingChain().getDecoderStates() )
{
DecoderPanel panel = DecoderFactory.getDecoderPanel( mSettingsManager, decoderState );
mDecoderPanels.add( panel );
add( panel, "grow,span" );
}
if( processingChain != null )
{
mChannelState = processingChain.getChannelState();
init();
for( DecoderState decoderState: processingChain.getDecoderStates() )
{
DecoderPanel panel = DecoderFactory.getDecoderPanel( mSettingsManager, decoderState );
mDecoderPanels.add( panel );
add( panel, "grow,span" );
}
mChannelState.setChangedAttributeListener( this );
mChannelModel.addListener( this );
mSettingsManager.addListener( this );
}
else
{
mLog.error( "Processing Chain was null!" );
}
}
private void init()
@@ -111,12 +131,12 @@ public class ChannelStatePanel extends JPanel
setLayout( new MigLayout( "insets 1 1 1 1", "[grow,fill]", "[]0[]0[]") );
mSystemLabel = new JLabel( mChannel.getSystem().getName() );
mSystemLabel = new JLabel( mChannel.getSystem() );
mSystemLabel.setFont( mFontDetails );
mSystemLabel.setForeground( mColorLabelDetails );
add( mSystemLabel );
mSiteLabel = new JLabel( mChannel.getSite().getName() );
mSiteLabel = new JLabel( mChannel.getSite() );
mSiteLabel.setFont( mFontDetails );
mSiteLabel.setForeground( mColorLabelDetails );
add( mSiteLabel );
@@ -126,8 +146,7 @@ public class ChannelStatePanel extends JPanel
mChannelLabel.setForeground( mColorLabelDetails );
add( mChannelLabel, "wrap" );
mStateLabel = new JLabel( mChannel.getChannelState().getState()
.getDisplayValue() );
mStateLabel = new JLabel( mChannelState.getState().getDisplayValue() );
mStateLabel.setFont( mFontDecoder );
mStateLabel.setForeground( mColorLabelDecoder );
add( mStateLabel );
@@ -161,8 +180,6 @@ public class ChannelStatePanel extends JPanel
mOptionsLabel.setFont( mFontDetails );
mOptionsLabel.setForeground( mColorLabelAuxDecoder );
add( mOptionsLabel, "wrap" );
// add( new JSeparator( JSeparator.HORIZONTAL ), "span,growx" );
}
public Channel getChannel()
@@ -172,12 +189,16 @@ public class ChannelStatePanel extends JPanel
public void dispose()
{
mPlaylistManager = null;
mChannelModel.removeListener( this );
mChannelModel = null;
mChannelProcessingManager = null;
mSettingsManager.removeListener( this );
mSettingsManager = null;
mChannel.getChannelState().removeChangedAttributeListener();
mChannelState.removeChangedAttributeListener();
mChannelState = null;
mChannel = null;
for( DecoderPanel panel: mDecoderPanels )
@@ -192,8 +213,6 @@ public class ChannelStatePanel extends JPanel
@Override
public void receive( final ChangedAttribute changedAttribute )
{
final ChannelState state = mChannel.getChannelState();
EventQueue.invokeLater( new Runnable()
{
@Override
@@ -202,9 +221,9 @@ public class ChannelStatePanel extends JPanel
switch( changedAttribute )
{
case CHANNEL_STATE:
if( state != null && state.getState() != null )
if( mChannelState != null && mChannelState.getState() != null )
{
mStateLabel.setText( state.getState().getDisplayValue() );
mStateLabel.setText( mChannelState.getState().getDisplayValue() );
}
break;
case SOURCE:
@@ -214,7 +233,7 @@ public class ChannelStatePanel extends JPanel
case CHANNEL_NAME:
case SITE_NAME:
case SYSTEM_NAME:
mChannelLabel.setText( mChannel.getChannelDisplayName() );
mChannelLabel.setText( mChannel.toString() );
break;
default:
break;
@@ -238,11 +257,9 @@ public class ChannelStatePanel extends JPanel
final Channel channel = mChannel;
final ChannelState channelState = ( channel == null ? null : channel.getChannelState() );
if( channelState != null )
if( mChannelState != null )
{
switch( channelState.getState() )
switch( mChannelState.getState() )
{
case CALL:
p = getGradient( mColorTopCall, mColorMiddleCall );
@@ -260,7 +277,7 @@ public class ChannelStatePanel extends JPanel
default:
p = getGradient( mColorTopIdle, mColorMiddleIdle );
break;
}
}
}
if( p == null )
@@ -419,7 +436,17 @@ public class ChannelStatePanel extends JPanel
public JMenu getContextMenu()
{
return ChannelUtils.getContextMenu( mPlaylistManager, mChannel,
ChannelStatePanel.this );
return ChannelUtils.getContextMenu( mChannelModel, mChannelProcessingManager,
mChannel, ChannelPanel.this );
}
@Override
public void channelChanged( ChannelEvent event )
{
if( event.getEvent() == Event.NOTIFICATION_SELECTION_CHANGE &&
event.getChannel() == mChannel )
{
repaint();
}
}
}

View File

@@ -18,32 +18,30 @@
package module.decode.state;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import module.Module;
import module.decode.config.DecodeConfiguration;
import module.decode.event.CallEvent;
import module.decode.event.ICallEventProvider;
import module.decode.state.DecoderStateEvent.Event;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import audio.metadata.IMetadataProvider;
import audio.metadata.Metadata;
import audio.metadata.MetadataReset;
import audio.metadata.MetadataType;
import audio.squelch.ISquelchStateProvider;
import audio.squelch.SquelchState;
import controller.ThreadPoolManager;
import controller.ThreadPoolManager.ThreadType;
import controller.channel.Channel.ChannelType;
import module.Module;
import module.decode.config.DecodeConfiguration;
import module.decode.event.CallEvent;
import module.decode.event.ICallEventProvider;
import module.decode.state.DecoderStateEvent.Event;
import sample.Listener;
public class ChannelState extends Module implements ICallEventProvider,
IChangedAttributeProvider, IDecoderStateEventListener,
IDecoderStateEventProvider, IMetadataProvider, ISquelchStateProvider
public class ChannelState extends Module implements ICallEventProvider, IChangedAttributeProvider,
IDecoderStateEventListener, IDecoderStateEventProvider, IMetadataProvider, ISquelchStateProvider
{
private final static Logger mLog =
LoggerFactory.getLogger( ChannelState.class );
@@ -65,19 +63,16 @@ public class ChannelState extends Module implements ICallEventProvider,
private boolean mSelected = false;
private long mStandardChannelFadeTimeout = FADE_TIMEOUT_DELAY;
private long mTrafficChannelFadeTimeout =
DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS * 1000;
private long mTrafficChannelFadeTimeout = DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS * 1000;
private long mFadeTimeout;
private long mEndTimeout;
private StateMonitor mStateMonitor = new StateMonitor();
private AtomicBoolean mMonitoring = new AtomicBoolean();
private ScheduledFuture<?> mStateMonitorFuture;
private ThreadPoolManager mThreadPoolManager;
private ChannelType mChannelType;
private TrafficChannelStatusListener mTrafficChannelStatusListener;
private TrafficChannelManager mTrafficChannelEndListener;
private CallEvent mTrafficChannelCallEvent;
/**
@@ -106,9 +101,8 @@ public class ChannelState extends Module implements ICallEventProvider,
* ended, while continuing to display the call details for the user
* TEARDOWN Indicates a traffic channel that will be torn down for reuse.
*/
public ChannelState( ThreadPoolManager manager, ChannelType channelType )
public ChannelState( ChannelType channelType )
{
mThreadPoolManager = manager;
mChannelType = channelType;
}
@@ -126,23 +120,22 @@ public class ChannelState extends Module implements ICallEventProvider,
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
//Start a monitoring task to check for FADE and END event timeouts
if( mMonitoring.compareAndSet( false, true ) )
if( mStateMonitorFuture == null && mStateMonitor != null )
{
if( mStateMonitorFuture == null && mStateMonitor != null )
if( mTrafficChannelEndListener != null )
{
try
{
mStateMonitorFuture = mThreadPoolManager.scheduleFixedRate(
ThreadType.DECODER, mStateMonitor, 20, TimeUnit.MILLISECONDS );
}
catch( RejectedExecutionException ree )
{
mLog.error( "state monitor scheduled task rejected", ree );
mMonitoring.set( false );
}
setState( State.CALL );
}
try
{
mStateMonitorFuture = executor.scheduleAtFixedRate( mStateMonitor, 0, 20, TimeUnit.MILLISECONDS );
}
catch( RejectedExecutionException ree )
{
mLog.error( "state monitor scheduled task rejected", ree );
}
}
}
@@ -150,23 +143,29 @@ public class ChannelState extends Module implements ICallEventProvider,
@Override
public void stop()
{
mSquelchLocked = false;
//Shutdown the state montoring task
if( mMonitoring.compareAndSet( true, false ) )
if( mStateMonitorFuture != null )
{
if( mStateMonitorFuture != null )
{
boolean success = mThreadPoolManager.cancel( mStateMonitorFuture );
if( !success )
{
mLog.error("Couldn't stop monitoring scheduled future" );
}
}
boolean success = mStateMonitorFuture.cancel( true );
mStateMonitorFuture = null;
if( !success )
{
mLog.error("Couldn't stop monitoring scheduled future" );
}
}
mTrafficChannelEndListener = null;
if( mTrafficChannelCallEvent != null )
{
mTrafficChannelCallEvent.end();
broadcast( mTrafficChannelCallEvent );
}
mTrafficChannelCallEvent = null;
mStateMonitorFuture = null;
mSquelchLocked = false;
}
public void dispose()
@@ -175,7 +174,6 @@ public class ChannelState extends Module implements ICallEventProvider,
mChangedAttributeListener = null;
mDecoderStateListener = null;
mSquelchStateListener = null;
mThreadPoolManager = null;
mStateMonitor = null;
}
@@ -205,7 +203,7 @@ public class ChannelState extends Module implements ICallEventProvider,
if( mChannelType == ChannelType.TRAFFIC )
{
mFadeTimeout = mTrafficChannelFadeTimeout;
mFadeTimeout = System.currentTimeMillis() + mTrafficChannelFadeTimeout;
}
}
@@ -237,6 +235,7 @@ public class ChannelState extends Module implements ICallEventProvider,
{
mFadeTimeout = System.currentTimeMillis() + mStandardChannelFadeTimeout;
}
}
/**
@@ -389,23 +388,9 @@ public class ChannelState extends Module implements ICallEventProvider,
broadcast( ChangedAttribute.CHANNEL_STATE );
if( mTrafficChannelCallEvent != null )
if( mTrafficChannelEndListener != null )
{
mTrafficChannelCallEvent.end();
broadcast( mTrafficChannelCallEvent );
mTrafficChannelCallEvent = null;
}
if( mTrafficChannelStatusListener != null )
{
mTrafficChannelStatusListener.callEnd();
mTrafficChannelStatusListener = null;
}
else
{
mLog.error( "Traffic channel status listener was null - couldn't "
+ "teardown the channel");
mTrafficChannelEndListener.callEnd( mTrafficChannelCallEvent.getChannel() );
}
}
@@ -530,11 +515,11 @@ public class ChannelState extends Module implements ICallEventProvider,
* Registers a listener to be notified when a traffic channel call event is
* completed, so that the listener can perform call tear-down
*/
public void configureAsTrafficChannel( TrafficChannelStatusListener listener,
TrafficChannelAllocationEvent allocationEvent )
public void configureAsTrafficChannel( TrafficChannelManager manager, CallEvent callEvent )
{
mTrafficChannelStatusListener = listener;
mTrafficChannelCallEvent = allocationEvent.getCallEvent();
mTrafficChannelEndListener = manager;
mTrafficChannelCallEvent = callEvent;
/* Broadcast the call event details as metadata for the audio manager */
String channel = mTrafficChannelCallEvent.getChannel();
@@ -543,9 +528,9 @@ public class ChannelState extends Module implements ICallEventProvider,
{
broadcast( new Metadata( MetadataType.CHANNEL_NUMBER, channel, true ) );
}
broadcast( new Metadata( MetadataType.PROTOCOL,
mTrafficChannelCallEvent.getDecoderType().getDisplayString(), true ) );
mTrafficChannelCallEvent.getDecoderType().getDisplayString(), true ) );
String details = mTrafficChannelCallEvent.getDetails();
@@ -574,13 +559,12 @@ public class ChannelState extends Module implements ICallEventProvider,
if( frequency > 0 )
{
broadcast( new Metadata( MetadataType.FREQUENCY,
String.valueOf( frequency ), true ) );
broadcast( new Metadata( MetadataType.FREQUENCY, String.valueOf( frequency ), true ) );
}
/* Rebroadcast the allocation event so that the internal decoder states
* can self-configure with the call event details */
broadcast( allocationEvent );
broadcast( mTrafficChannelCallEvent );
}
/**
@@ -662,7 +646,6 @@ public class ChannelState extends Module implements ICallEventProvider,
if( State.CALL_STATES.contains( mState ) &&
mFadeTimeout <= System.currentTimeMillis() )
{
mState = State.FADE;
processFadeState();
}
else if( mState == State.FADE &&

View File

@@ -7,10 +7,6 @@ import module.decode.DecoderType;
import module.decode.event.ActivitySummaryProvider;
import module.decode.event.CallEvent;
import module.decode.event.ICallEventProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Broadcaster;
import sample.Listener;
import alias.AliasList;
@@ -33,8 +29,6 @@ public abstract class DecoderState extends Module
IMessageListener,
IMetadataProvider
{
private final static Logger mLog = LoggerFactory.getLogger( DecoderState.class );
/* This has to be a broadcaster in order for references to persist */
private Broadcaster<CallEvent> mCallEventBroadcaster = new Broadcaster<>();
private Listener<ChangedAttribute> mChangedAttributeListener;

View File

@@ -65,4 +65,4 @@ public class DecoderStateEvent
START,
TRAFFIC_CHANNEL_ALLOCATION;
}
}
}

View File

@@ -1,3 +1,20 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package module.decode.state;
import java.util.EnumSet;
@@ -86,11 +103,8 @@ public enum State
private String mDisplayValue;
public static final EnumSet<State> CALL_STATES =
EnumSet.of( CALL, CONTROL, DATA, ENCRYPTED );
public static final EnumSet<State> IDLE_STATES =
EnumSet.of( IDLE, FADE );
public static final EnumSet<State> CALL_STATES = EnumSet.of( CALL, CONTROL, DATA, ENCRYPTED );
public static final EnumSet<State> IDLE_STATES = EnumSet.of( IDLE, FADE );
private State( String displayValue )
{
@@ -103,4 +117,4 @@ public enum State
{
return mDisplayValue;
}
}
}

View File

@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import module.Module;
import module.decode.config.DecodeConfiguration;
@@ -15,18 +16,19 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import record.config.RecordConfiguration;
import sample.Broadcaster;
import sample.Listener;
import source.config.SourceConfigTuner;
import source.tuner.TunerChannel;
import source.tuner.TunerChannel.Type;
import alias.Alias;
import alias.priority.Priority;
import controller.ResourceManager;
import alias.id.priority.Priority;
import controller.channel.Channel;
import controller.channel.Channel.ChannelType;
import controller.site.Site;
import controller.system.System;
import controller.channel.ChannelEvent;
import controller.channel.ChannelEvent.Event;
import controller.channel.ChannelModel;
import controller.channel.ChannelProcessingManager;
import controller.channel.TrafficChannelEvent;
public class TrafficChannelManager extends Module
implements ICallEventProvider, IDecoderStateEventListener
@@ -41,15 +43,14 @@ public class TrafficChannelManager extends Module
private DecoderStateEventListener mEventListener = new DecoderStateEventListener();
private Listener<CallEvent> mCallEventListener;
private ChannelModel mChannelModel;
private ChannelProcessingManager mChannelProcessingManager;
private DecodeConfiguration mDecodeConfiguration;
private RecordConfiguration mRecordConfiguration;
private ResourceManager mResourceManager;
private System mSystem;
private Site mSite;
private String mSystem;
private String mSite;
private String mAliasListName;
private long mTrafficChannelTimeout;
private CallEvent mPreviousDoNotMonitorCallEvent;
private boolean mShuttingDown = false;
/**
* Monitors call events and allocates traffic decoder channels in response
@@ -69,22 +70,23 @@ public class TrafficChannelManager extends Module
* @param trafficChannelPoolSize - maximum number of allocated traffic channels
* in the pool
*/
public TrafficChannelManager( ResourceManager resourceManager,
public TrafficChannelManager( ChannelModel channelModel,
ChannelProcessingManager channelProcessingManager,
DecodeConfiguration decodeConfiguration,
RecordConfiguration recordConfiguration,
System system,
Site site,
String system,
String site,
String aliasListName,
long trafficChannelTimeout,
int trafficChannelPoolSize )
{
mResourceManager = resourceManager;
mChannelModel = channelModel;
mChannelProcessingManager = channelProcessingManager;
mDecodeConfiguration = decodeConfiguration;
mRecordConfiguration = recordConfiguration;
mSystem = system;
mSite = site;
mAliasListName = aliasListName;
mTrafficChannelTimeout = trafficChannelTimeout;
mTrafficChannelPoolMaximumSize = trafficChannelPoolSize;
}
@@ -93,14 +95,14 @@ public class TrafficChannelManager extends Module
{
for( Channel trafficChannel: mTrafficChannelPool )
{
trafficChannel.setEnabled( false );
trafficChannel.dispose();
mChannelModel.broadcast( new ChannelEvent( trafficChannel, Event.REQUEST_DISABLE ) );
}
mTrafficChannelPool.clear();
mTrafficChannelsInUse.clear();
mCallEventListener = null;
mResourceManager = null;
mDecodeConfiguration = null;
mPreviousDoNotMonitorCallEvent = null;
}
@@ -124,7 +126,7 @@ public class TrafficChannelManager extends Module
{
for( Channel configuredChannel: mTrafficChannelPool )
{
if( !configuredChannel.isProcessing() )
if( !configuredChannel.getEnabled() )
{
channel = configuredChannel;
break;
@@ -139,39 +141,22 @@ public class TrafficChannelManager extends Module
channel.setRecordConfiguration( mRecordConfiguration );
channel.setResourceManager( mResourceManager );
channel.setTrafficChannelTimeout( mTrafficChannelTimeout );
channel.setAliasListName( mAliasListName );
mChannelModel.addChannel( channel );
mTrafficChannelPool.add( channel );
}
/* If we have a configured channel, start it and track it */
/* If we have a configured channel, update metadata */
if( channel != null )
{
channel.setSourceConfiguration( new SourceConfigTuner( tunerChannel ) );
channel.setSystem( mSystem, false );
channel.setSite( mSite, false );
channel.setSystem( mSystem );
channel.setSite( mSite );
channel.setName( channelNumber );
channel.setEnabled( true );
/* Check the channel obtained a source and is currently processing */
if( channel.isProcessing() )
{
mTrafficChannelsInUse.put( channelNumber, channel );
}
else
{
channel.setEnabled( false );
channel.setSystem( mSystem, false );
channel.setSite( mSite, false );
channel.setName( "Traffic" );
}
mChannelModel.broadcast( new ChannelEvent( channel, Event.NOTIFICATION_CONFIGURATION_CHANGE ) );
}
}
@@ -212,33 +197,26 @@ public class TrafficChannelManager extends Module
}
else if( frequency > 0 )
{
Channel channel = getChannel( callEvent.getChannel(),
new TunerChannel( Type.TRAFFIC, frequency,
mDecodeConfiguration.getDecoderType()
.getChannelBandwidth() ) );
Channel channel = getChannel( callEvent.getChannel(), new TunerChannel( Type.TRAFFIC,
frequency, mDecodeConfiguration.getDecoderType().getChannelBandwidth() ) );
if( channel != null )
{
if( channel.isProcessing() )
TrafficChannelEvent trafficChannelEvent =
new TrafficChannelEvent( this, channel, Event.REQUEST_ENABLE, callEvent );
//Request to enable the channel
mChannelModel.broadcast( trafficChannelEvent );
if( channel.getEnabled() )
{
callEvent.setDetails( "TRAFFIC CHANNEL ALLOCATED" );
ChannelState state = channel.getChannelState();
/* Register as a listener to be notified when the call
* is completed */
state.configureAsTrafficChannel(
new TrafficChannelStatusListener( this,
callEvent.getChannel() ), event );
/* Set state to call so that audio squelch state is correct */
state.setState( State.CALL );
mTrafficChannelsInUse.put( callEvent.getChannel(), channel );
}
else
{
callEvent.setCallEventType( CallEventType.CALL_DETECT );
callEvent.setDetails( "CHANNEL PROCESSING ERROR" );
}
callEvent.setDetails( "CHANNEL START REJECTED" );
}
}
else
{
@@ -325,7 +303,7 @@ public class TrafficChannelManager extends Module
Alias to = event.getToIDAlias();
if( to != null &&
to.hasPriority() &&
to.hasCallPriority() &&
to.getCallPriority() == Priority.DO_NOT_MONITOR )
{
return true;
@@ -334,7 +312,7 @@ public class TrafficChannelManager extends Module
Alias from = event.getFromIDAlias();
if( from != null &&
from.hasPriority() &&
from.hasCallPriority() &&
from.getCallPriority() == Priority.DO_NOT_MONITOR )
{
return true;
@@ -367,7 +345,7 @@ public class TrafficChannelManager extends Module
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}
@@ -399,15 +377,13 @@ public class TrafficChannelManager extends Module
{
synchronized( mTrafficChannelsInUse )
{
if( channelNumber != null &&
mTrafficChannelsInUse.containsKey( channelNumber ) )
if( channelNumber != null && mTrafficChannelsInUse.containsKey( channelNumber ) )
{
Channel channel = mTrafficChannelsInUse.get( channelNumber );
mTrafficChannelsInUse.remove( channelNumber );
/* Disable the channel and broadcast a notification */
channel.setEnabled( false, true );
mChannelModel.broadcast( new ChannelEvent( channel, Event.REQUEST_DISABLE ) );
mTrafficChannelsInUse.remove( channelNumber );
}
}
}

View File

@@ -1,21 +0,0 @@
package module.decode.state;
public class TrafficChannelStatusListener
{
private TrafficChannelManager mTrafficChannelManager;
private String mChannelNumber;
public TrafficChannelStatusListener( TrafficChannelManager manager, String channelNumber )
{
mTrafficChannelManager = manager;
mChannelNumber = channelNumber;
}
public void callEnd()
{
if( mTrafficChannelManager != null )
{
mTrafficChannelManager.callEnd( mChannelNumber );
}
}
}

View File

@@ -26,12 +26,13 @@ import instrument.tap.stream.FloatTap;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import module.decode.Decoder;
import module.decode.DecoderType;
import sample.Broadcaster;
import sample.Listener;
import sample.real.IRealBufferListener;
import sample.real.IFilteredRealBufferListener;
import sample.real.RealBuffer;
import alias.AliasList;
import bits.MessageFramer;
@@ -45,7 +46,7 @@ import dsp.fsk.FSK2Decoder.Output;
/**
* TAIT 1200 - 1200 baud 2FSK decoder
*/
public class Tait1200Decoder extends Decoder implements IRealBufferListener,
public class Tait1200Decoder extends Decoder implements IFilteredRealBufferListener,
Instrumentable
{
/* Decimated sample rate ( 48,000 / 2 = 24,000 ) feeding the decoder */
@@ -104,8 +105,8 @@ public class Tait1200Decoder extends Decoder implements IRealBufferListener,
mMessageFramerGPS.addMessageListener( mMessageAProcessor );
mMessageFramerANI.addMessageListener( mMessageBProcessor );
mMessageAProcessor.setMessageListener( mMessageBroadcaster );
mMessageBProcessor.setMessageListener( mMessageBroadcaster );
mMessageAProcessor.setMessageListener( this );
mMessageBProcessor.setMessageListener( this );
}
public void dispose()
@@ -179,7 +180,7 @@ public class Tait1200Decoder extends Decoder implements IRealBufferListener,
}
@Override
public Listener<RealBuffer> getRealBufferListener()
public Listener<RealBuffer> getFilteredRealBufferListener()
{
return mDecimationFilter;
}
@@ -198,7 +199,7 @@ public class Tait1200Decoder extends Decoder implements IRealBufferListener,
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
// TODO Auto-generated method stub

View File

@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TreeSet;
import java.util.concurrent.ScheduledExecutorService;
import org.jdesktop.swingx.mapviewer.GeoPosition;
@@ -60,7 +61,7 @@ public class Tait1200DecoderState extends DecoderState
}
@Override
public void start()
public void start( ScheduledExecutorService executor )
{
}