mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
Initial code check in continued
This commit is contained in:
42
src/controller/channel/AbstractChannelEditor.java
Normal file
42
src/controller/channel/AbstractChannelEditor.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
import controller.Editor;
|
||||
|
||||
public abstract class AbstractChannelEditor extends Editor
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected ChannelNode mChannelNode;
|
||||
|
||||
public AbstractChannelEditor( ChannelNode channel )
|
||||
{
|
||||
super();
|
||||
mChannelNode = channel;
|
||||
}
|
||||
|
||||
public ChannelNode getChannelNode()
|
||||
{
|
||||
return mChannelNode;
|
||||
}
|
||||
|
||||
public abstract void save();
|
||||
|
||||
public abstract void reset();
|
||||
}
|
||||
902
src/controller/channel/Channel.java
Normal file
902
src/controller/channel/Channel.java
Normal file
@@ -0,0 +1,902 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
|
||||
import log.Log;
|
||||
import message.Message;
|
||||
import record.config.RecordConfiguration;
|
||||
import sample.Listener;
|
||||
import source.SourceType;
|
||||
import source.config.SourceConfigFactory;
|
||||
import source.config.SourceConfigTuner;
|
||||
import source.config.SourceConfiguration;
|
||||
import source.tuner.TunerChannel;
|
||||
import source.tuner.TunerChannel.Type;
|
||||
import controller.ResourceManager;
|
||||
import controller.activity.ActivitySummaryFrame;
|
||||
import controller.config.Configuration;
|
||||
import controller.site.Site;
|
||||
import controller.state.ChannelState;
|
||||
import controller.state.ChannelState.State;
|
||||
import controller.system.System;
|
||||
import decode.config.AuxDecodeConfiguration;
|
||||
import decode.config.DecodeConfigFactory;
|
||||
import decode.config.DecodeConfiguration;
|
||||
import eventlog.config.EventLogConfiguration;
|
||||
|
||||
@XmlSeeAlso( { Configuration.class } )
|
||||
@XmlRootElement( name = "channel" )
|
||||
public class Channel extends Configuration
|
||||
{
|
||||
public enum ChannelType
|
||||
{
|
||||
STANDARD,
|
||||
TRAFFIC
|
||||
};
|
||||
|
||||
private static final boolean ENABLED = true;
|
||||
private static final boolean DISABLED = false;
|
||||
private static final boolean BROADCAST_CHANGE = true;
|
||||
|
||||
private CopyOnWriteArrayList<ChannelListener> mChannelListeners =
|
||||
new CopyOnWriteArrayList<ChannelListener>();
|
||||
|
||||
private CopyOnWriteArrayList<Listener<Message>> mMessageListeners =
|
||||
new CopyOnWriteArrayList<Listener<Message>>();
|
||||
|
||||
private HashMap<Integer,Channel> mTrafficChannels =
|
||||
new HashMap<Integer,Channel>();
|
||||
|
||||
private DecodeConfiguration mDecodeConfiguration =
|
||||
DecodeConfigFactory.getDefaultDecodeConfiguration();
|
||||
private AuxDecodeConfiguration mAuxDecodeConfiguration =
|
||||
new AuxDecodeConfiguration();
|
||||
private SourceConfiguration mSourceConfiguration =
|
||||
SourceConfigFactory.getDefaultSourceConfiguration();
|
||||
private EventLogConfiguration mEventLogConfiguration =
|
||||
new EventLogConfiguration();
|
||||
private RecordConfiguration mRecordConfiguration = new RecordConfiguration();
|
||||
|
||||
private ResourceManager mResourceManager;
|
||||
private String mAliasListName;
|
||||
private System mSystem;
|
||||
private Site mSite;
|
||||
private String mName;
|
||||
private boolean mEnabled;
|
||||
private boolean mSelected;
|
||||
private ChannelType mChannelType;
|
||||
private ProcessingChain mProcessingChain;
|
||||
|
||||
/**
|
||||
* Constructs a new standard channel with a default name of "New Channel"
|
||||
*/
|
||||
public Channel()
|
||||
{
|
||||
this( "New Channel", ChannelType.STANDARD );
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new standard channel with the specified channel name
|
||||
*/
|
||||
public Channel( String channelName )
|
||||
{
|
||||
this( channelName, ChannelType.STANDARD );
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new channel with the specified channel name and type.
|
||||
*
|
||||
* @param channelName
|
||||
* @param channelType
|
||||
*/
|
||||
public Channel( String channelName, ChannelType channelType )
|
||||
{
|
||||
mName = channelName;
|
||||
mChannelType = channelType;
|
||||
}
|
||||
|
||||
public ChannelType getChannelType()
|
||||
{
|
||||
return mChannelType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the resource manager responsible for this channel and registers
|
||||
* the channel manager as a listener to this channel. Fires channel add
|
||||
* channel event to the newly added channel manager channel listener.
|
||||
*/
|
||||
public void setResourceManager( ResourceManager resourceManager )
|
||||
{
|
||||
mResourceManager = resourceManager;
|
||||
|
||||
/* Add system-wide channel listeners onto this channel */
|
||||
addListeners( mResourceManager.getChannelManager().getChannelListeners() );
|
||||
|
||||
/* If we're enabled, fire enable changed event to get processing started */
|
||||
if( mEnabled )
|
||||
{
|
||||
enableChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@XmlTransient
|
||||
public ResourceManager getResourceManager()
|
||||
{
|
||||
return mResourceManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the processing chain for this channel. If the processing chain
|
||||
* is not currently constructed and running, this method will return null.
|
||||
*/
|
||||
@XmlTransient
|
||||
public ProcessingChain getProcessingChain()
|
||||
{
|
||||
return mProcessingChain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this channel has a processing chain constructed and it
|
||||
* is processing.
|
||||
*/
|
||||
public boolean isProcessing()
|
||||
{
|
||||
return mProcessingChain != null && mProcessingChain.isProcessing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this channel has been selected for audio output
|
||||
*/
|
||||
@XmlTransient
|
||||
public boolean getSelected()
|
||||
{
|
||||
return mSelected;
|
||||
}
|
||||
|
||||
public void setSelected( boolean selected )
|
||||
{
|
||||
mSelected = selected;
|
||||
|
||||
if( mProcessingChain != null && mProcessingChain.isProcessing() )
|
||||
{
|
||||
mProcessingChain.getAudioOutput().setAudioPlaybackEnabled( selected );
|
||||
}
|
||||
|
||||
fireChannelEvent( ChannelEvent.CHANGE_SELECTED );
|
||||
}
|
||||
|
||||
public JMenu getContextMenu()
|
||||
{
|
||||
JMenu menu = new JMenu( mSite + "-" + mName );
|
||||
|
||||
if( mEnabled )
|
||||
{
|
||||
JMenuItem disable = new JMenuItem( "Disable" );
|
||||
disable.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
setEnabled( DISABLED, BROADCAST_CHANGE );
|
||||
getResourceManager().getPlaylistManager().save();
|
||||
}
|
||||
} );
|
||||
|
||||
menu.add( disable );
|
||||
|
||||
menu.add( new JSeparator() );
|
||||
|
||||
JMenuItem actySummaryItem =
|
||||
new JMenuItem( "Activity Summary" );
|
||||
|
||||
actySummaryItem.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
if( mResourceManager != null )
|
||||
{
|
||||
ProcessingChain chain = getProcessingChain();
|
||||
|
||||
if( chain != null )
|
||||
{
|
||||
ChannelState state = chain.getChannelState();
|
||||
|
||||
if( state != null )
|
||||
{
|
||||
String summary = state.getActivitySummary();
|
||||
|
||||
new ActivitySummaryFrame( summary,
|
||||
mResourceManager.getController().getTree() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
menu.add( actySummaryItem );
|
||||
}
|
||||
else
|
||||
{
|
||||
JMenuItem enable = new JMenuItem( "Enable" );
|
||||
enable.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
setEnabled( ENABLED, BROADCAST_CHANGE );
|
||||
getResourceManager().getPlaylistManager().save(); }
|
||||
} );
|
||||
|
||||
menu.add( enable );
|
||||
}
|
||||
|
||||
menu.add( new JSeparator() );
|
||||
|
||||
JMenuItem deleteItem = new JMenuItem( "Delete" );
|
||||
deleteItem.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
dispose();
|
||||
getResourceManager().getPlaylistManager().save(); }
|
||||
} );
|
||||
|
||||
menu.add( deleteItem );
|
||||
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Orderly shutdown method when this channel is going to be deleted.
|
||||
*/
|
||||
public void dispose()
|
||||
{
|
||||
setEnabled( DISABLED, BROADCAST_CHANGE );
|
||||
|
||||
/* Broadcast channel deleted event */
|
||||
fireChannelEvent( ChannelEvent.CHANNEL_DELETED );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a full channel name containing the system, site and channel name.
|
||||
*/
|
||||
public String getChannelDisplayName()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if( mSystem != null )
|
||||
{
|
||||
sb.append( mSystem.getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "-" );
|
||||
}
|
||||
|
||||
sb.append( "/" );
|
||||
|
||||
if( mSite != null )
|
||||
{
|
||||
sb.append( mSite.getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "-" );
|
||||
}
|
||||
|
||||
sb.append( "/" );
|
||||
|
||||
sb.append( mName );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tuner channel requirement for this channel when the source
|
||||
* configuration specifies a tuner and frequency as the source for this
|
||||
* channel.
|
||||
*
|
||||
* If the source configuration is anything else, this method returns null.
|
||||
*/
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
TunerChannel retVal = null;
|
||||
|
||||
if( mSourceConfiguration.getSourceType() == SourceType.TUNER )
|
||||
{
|
||||
SourceConfigTuner config = (SourceConfigTuner)mSourceConfiguration;
|
||||
|
||||
retVal = new TunerChannel( Type.LOCKED, config.getFrequency(),
|
||||
mDecodeConfiguration.getDecoderType().getChannelBandwidth() );
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the owning system for this channel.
|
||||
*/
|
||||
public System getSystem()
|
||||
{
|
||||
return mSystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the owning system for this channel and optionally broadcasts a
|
||||
* system change channel event.
|
||||
*/
|
||||
public void setSystem( System system, boolean fireChangeEvent )
|
||||
{
|
||||
mSystem = system;
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_SYSTEM );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the owning site for this channel.
|
||||
*/
|
||||
public Site getSite()
|
||||
{
|
||||
return mSite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the owning site for this channel and optionally broadcasts a site
|
||||
* change channel event.
|
||||
*/
|
||||
public void setSite( Site site, boolean fireChangeEvent )
|
||||
{
|
||||
mSite = site;
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_SITE );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default display string for this channel -- the channel name.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this channel is enabled for processing.
|
||||
*/
|
||||
@XmlAttribute
|
||||
public boolean getEnabled()
|
||||
{
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables/disables this channel for processing. Automatically starts or
|
||||
* stops channel processing in response to this change.
|
||||
*/
|
||||
public void setEnabled( boolean enabled )
|
||||
{
|
||||
mEnabled = enabled;
|
||||
|
||||
enableChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables/disables this channel for processing. Automatically starts or
|
||||
* stops channel processing in response to this change. Optionally
|
||||
* broadcasts a enabled change channel event.
|
||||
*/
|
||||
public void setEnabled( boolean enabled, boolean fireChannelEvent )
|
||||
{
|
||||
setEnabled( enabled );
|
||||
|
||||
if( fireChannelEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_ENABLED );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alias list that is used by this channel for looking up alias
|
||||
* values for the various identifiers produced by the decoder.
|
||||
*/
|
||||
@XmlElement( name = "alias_list_name" )
|
||||
public String getAliasListName()
|
||||
{
|
||||
return mAliasListName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alias list to be used for looking up the alias values for the
|
||||
* various identifiers produced by the decoder
|
||||
*/
|
||||
public void setAliasListName( String name )
|
||||
{
|
||||
mAliasListName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alias list to be used for looking up the alias values for the
|
||||
* various identifiers produced by the decoder. This method is the same
|
||||
* as setAliasName(name) and optionally broadcasts an alias list change
|
||||
* channel event.
|
||||
*/
|
||||
public void setAliasListName( String name, boolean fireChangeEvent )
|
||||
{
|
||||
mAliasListName = name;
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_ALIAS_LIST );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the decoder configuration used by this channel
|
||||
*/
|
||||
@XmlElement( name = "decode_configuration" )
|
||||
public DecodeConfiguration getDecodeConfiguration()
|
||||
{
|
||||
return mDecodeConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the decoder configuration used by this channel
|
||||
*/
|
||||
public void setDecodeConfiguration( DecodeConfiguration config )
|
||||
{
|
||||
mDecodeConfiguration = config;
|
||||
|
||||
if( mProcessingChain != null && mProcessingChain.isRunning() )
|
||||
{
|
||||
mProcessingChain.updateDecoder();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the aux decoder configuration used by this channel
|
||||
*/
|
||||
@XmlElement( name = "aux_decode_configuration" )
|
||||
public AuxDecodeConfiguration getAuxDecodeConfiguration()
|
||||
{
|
||||
return mAuxDecodeConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the decoder configuration used by this channel
|
||||
*/
|
||||
public void setAuxDecodeConfiguration( AuxDecodeConfiguration config )
|
||||
{
|
||||
mAuxDecodeConfiguration = config;
|
||||
|
||||
if( mProcessingChain != null && mProcessingChain.isRunning() )
|
||||
{
|
||||
mProcessingChain.updateDecoder();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the decoder configuration used by this channel and optionally
|
||||
* broadcasts a decoder change channel event.
|
||||
*/
|
||||
public void setDecodeConfiguration( DecodeConfiguration config,
|
||||
boolean fireChangeEvent )
|
||||
{
|
||||
setDecodeConfiguration( config );
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_DECODER );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source configuration for this channel.
|
||||
*/
|
||||
@XmlElement( name = "source_configuration" )
|
||||
public SourceConfiguration getSourceConfiguration()
|
||||
{
|
||||
return mSourceConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source configuration for this channel.
|
||||
*/
|
||||
public void setSourceConfiguration( SourceConfiguration config )
|
||||
{
|
||||
mSourceConfiguration = config;
|
||||
|
||||
if( mProcessingChain != null && mProcessingChain.isRunning() )
|
||||
{
|
||||
mProcessingChain.updateSource();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source configuration for this channel and optionally broadcasts
|
||||
* a source change channel event.
|
||||
*/
|
||||
public void setSourceConfiguration( SourceConfiguration config,
|
||||
boolean fireChangeEvent )
|
||||
{
|
||||
setSourceConfiguration( config );
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_SOURCE );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event logger configuration for this channel.
|
||||
*/
|
||||
@XmlElement( name = "event_log_configuration" )
|
||||
public EventLogConfiguration getEventLogConfiguration()
|
||||
{
|
||||
return mEventLogConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event logger configuration for this channel.
|
||||
*/
|
||||
public void setEventLogConfiguration( EventLogConfiguration config )
|
||||
{
|
||||
mEventLogConfiguration = config;
|
||||
|
||||
if( mProcessingChain != null && mProcessingChain.isRunning() )
|
||||
{
|
||||
mProcessingChain.updateEventLogging();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event logger configuration for this channel and optionally
|
||||
* broadcasts an event logger change channel event.
|
||||
*/
|
||||
public void setEventLogConfiguration( EventLogConfiguration config,
|
||||
boolean fireChangeEvent )
|
||||
{
|
||||
setEventLogConfiguration( config );
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_EVENT_LOGGER );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recorder configuration for this channel.
|
||||
*/
|
||||
@XmlElement( name = "record_configuration" )
|
||||
public RecordConfiguration getRecordConfiguration()
|
||||
{
|
||||
return mRecordConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the recorder configuration for this channel.
|
||||
*/
|
||||
public void setRecordConfiguration( RecordConfiguration config )
|
||||
{
|
||||
mRecordConfiguration = config;
|
||||
|
||||
if( mProcessingChain != null && mProcessingChain.isRunning() )
|
||||
{
|
||||
mProcessingChain.updateRecording();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the recorder configuration for this channel and optionally broadcasts
|
||||
* a recorder configuration change channel event.
|
||||
*/
|
||||
public void setRecordConfiguration( RecordConfiguration config,
|
||||
boolean fireChangeEvent )
|
||||
{
|
||||
setRecordConfiguration( config );
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_RECORDER );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this channel.
|
||||
*/
|
||||
@XmlAttribute
|
||||
public String getName()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this channel.
|
||||
*/
|
||||
public void setName( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this channel and optionally broadcasts a name change
|
||||
* channel event.
|
||||
*/
|
||||
public void setName( String name, boolean fireChangeEvent )
|
||||
{
|
||||
mName = name;
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_NAME );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds to changes in the enabled setting by starting the processing
|
||||
* change if the channel is now enabled, or stopping the procesing chain
|
||||
* if it was already started.
|
||||
*/
|
||||
private void enableChanged()
|
||||
{
|
||||
if( mEnabled )
|
||||
{
|
||||
start();
|
||||
}
|
||||
else
|
||||
{
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the channel processing chain.
|
||||
*/
|
||||
private void start()
|
||||
{
|
||||
if( mEnabled && mProcessingChain == null && mResourceManager != null )
|
||||
{
|
||||
mProcessingChain = new ProcessingChain( this, mResourceManager );
|
||||
|
||||
/* Add system-wide message listeners */
|
||||
mProcessingChain.addListeners(
|
||||
mResourceManager.getChannelManager().getMessageListeners() );
|
||||
|
||||
/* Add individual message listeners */
|
||||
mProcessingChain.addListeners( mMessageListeners );
|
||||
|
||||
mProcessingChain.start();
|
||||
|
||||
fireChannelEvent( ChannelEvent.PROCESSING_STARTED );
|
||||
}
|
||||
|
||||
/* If this is a traffic channel, override the call fade timeout before
|
||||
* we set the state to call, so that it will auto-expire after the
|
||||
* fade timeout and be auto deleted */
|
||||
if( mChannelType == ChannelType.TRAFFIC )
|
||||
{
|
||||
if( mProcessingChain.isProcessing() )
|
||||
{
|
||||
mProcessingChain.getChannelState().setCallFadeTimeout( 40000 );
|
||||
mProcessingChain.getChannelState().setState( State.CALL );
|
||||
}
|
||||
else
|
||||
{
|
||||
mProcessingChain.getChannelState().setCallFadeTimeout( 5000 );
|
||||
/* Channel state should already be no_tuner */
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the channel processing chain
|
||||
*/
|
||||
private void stop()
|
||||
{
|
||||
/* Stop and remove any traffic channels */
|
||||
for( Channel traffic: mTrafficChannels.values() )
|
||||
{
|
||||
traffic.stop();
|
||||
traffic.dispose();
|
||||
}
|
||||
|
||||
mTrafficChannels.clear();
|
||||
|
||||
if( !mEnabled && mProcessingChain != null )
|
||||
{
|
||||
mProcessingChain.stop();
|
||||
|
||||
mProcessingChain.dispose();
|
||||
|
||||
mProcessingChain = null;
|
||||
|
||||
mSelected = false;
|
||||
}
|
||||
|
||||
fireChannelEvent( ChannelEvent.PROCESSING_STOPPED );
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a channel change event to all registered listeners
|
||||
*/
|
||||
public void fireChannelEvent( ChannelEvent event )
|
||||
{
|
||||
for( ChannelListener listener: mChannelListeners )
|
||||
{
|
||||
listener.occurred( this, event );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a channel listener to receive all channel events from this channel
|
||||
* and automatically sends the listener a channel add event.
|
||||
*/
|
||||
public void addListener( ChannelListener listener )
|
||||
{
|
||||
if( !mChannelListeners.contains( listener ) )
|
||||
{
|
||||
mChannelListeners.add( listener );
|
||||
|
||||
listener.occurred( this, ChannelEvent.CHANNEL_ADDED );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error( "Channel - attempt to add already existing channel listener [" + listener.getClass() + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a list of channel listeners to receive all channel events from this
|
||||
* channel and automatically sends each one a channel add event.
|
||||
*/
|
||||
public void addListeners( List<ChannelListener> listeners )
|
||||
{
|
||||
for( ChannelListener listener: listeners )
|
||||
{
|
||||
addListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a channel listener from receiving channel events from this channel
|
||||
*/
|
||||
public void removeListener( ChannelListener listener )
|
||||
{
|
||||
mChannelListeners.remove( listener );
|
||||
}
|
||||
|
||||
public void addListener( Listener<Message> listener )
|
||||
{
|
||||
mMessageListeners.add( listener );
|
||||
|
||||
if( isProcessing() )
|
||||
{
|
||||
mProcessingChain.addListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener( Listener<Message> listener )
|
||||
{
|
||||
mMessageListeners.remove( listener );
|
||||
|
||||
if( isProcessing() )
|
||||
{
|
||||
mProcessingChain.removeListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if any part of this channel is contained within the
|
||||
* minimum and maximum frequency values.
|
||||
*/
|
||||
public boolean isWithin( int minimum, int maximum )
|
||||
{
|
||||
return getTunerChannel() != null &&
|
||||
getTunerChannel().isWithin( minimum, maximum );
|
||||
}
|
||||
|
||||
public void addTrafficChannel( int channelNumber, Channel channel )
|
||||
{
|
||||
mTrafficChannels.put( channelNumber, channel );
|
||||
}
|
||||
|
||||
public boolean hasTrafficChannel( Channel channel )
|
||||
{
|
||||
return mTrafficChannels.containsValue( channel );
|
||||
}
|
||||
|
||||
public void removeTrafficChannel( Channel channel )
|
||||
{
|
||||
int keyToRemove = -1;
|
||||
|
||||
if( mTrafficChannels.values().contains( channel ) )
|
||||
{
|
||||
for( Integer channelNumber: mTrafficChannels.keySet() )
|
||||
{
|
||||
if( mTrafficChannels.get( channelNumber ).equals( channel ) )
|
||||
{
|
||||
keyToRemove = channelNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( keyToRemove != -1 )
|
||||
{
|
||||
mTrafficChannels.remove( keyToRemove );
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Channel> getTrafficChannels()
|
||||
{
|
||||
return Collections.unmodifiableCollection( mTrafficChannels.values() );
|
||||
}
|
||||
|
||||
public boolean hasTrafficChannel( int channelNumber )
|
||||
{
|
||||
return mTrafficChannels.containsKey( channelNumber );
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel Events - used to specify channel events and changes to channel
|
||||
* configurations and settings.
|
||||
*/
|
||||
public enum ChannelEvent
|
||||
{
|
||||
CHANGE_ALIAS_LIST,
|
||||
CHANGE_DECODER,
|
||||
CHANGE_ENABLED,
|
||||
CHANGE_EVENT_LOGGER,
|
||||
CHANGE_NAME,
|
||||
CHANGE_SITE,
|
||||
CHANGE_RECORDER,
|
||||
CHANGE_SELECTED,
|
||||
CHANGE_SOURCE,
|
||||
CHANGE_SYSTEM,
|
||||
|
||||
CHANNEL_ADDED,
|
||||
CHANNEL_DELETED,
|
||||
|
||||
PROCESSING_STARTED,
|
||||
PROCESSING_STOPPED,
|
||||
}
|
||||
}
|
||||
235
src/controller/channel/ChannelEditor.java
Normal file
235
src/controller/channel/ChannelEditor.java
Normal file
@@ -0,0 +1,235 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.ComponentOrientation;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.Collections;
|
||||
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.JTextField;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import record.RecordComponentEditor;
|
||||
import source.SourceComponentEditor;
|
||||
import alias.AliasList;
|
||||
|
||||
import com.jidesoft.swing.JideTabbedPane;
|
||||
|
||||
import controller.Editor;
|
||||
import decode.AuxDecodeComponentEditor;
|
||||
import decode.DecodeComponentEditor;
|
||||
import eventlog.EventLogComponentEditor;
|
||||
|
||||
public class ChannelEditor extends Editor implements ActionListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private DefaultTreeModel mTreeModel;
|
||||
private ChannelNode mChannelNode;
|
||||
|
||||
private DecodeComponentEditor mDecodeEditor;
|
||||
private AuxDecodeComponentEditor mAuxDecodeEditor;
|
||||
private EventLogComponentEditor mEventLogEditor;
|
||||
private RecordComponentEditor mRecordEditor;
|
||||
private SourceComponentEditor mSourceEditor;
|
||||
|
||||
private JTextField mChannelName;
|
||||
private JCheckBox mChannelEnabled = new JCheckBox();
|
||||
private JComboBox<AliasList> mComboAliasLists;
|
||||
|
||||
public ChannelEditor( ChannelNode channel )
|
||||
{
|
||||
super();
|
||||
|
||||
mChannelNode = channel;
|
||||
|
||||
initGUI();
|
||||
}
|
||||
|
||||
private void initGUI()
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 2", "[right,grow][grow]", "[][][][][grow][]" ) );
|
||||
|
||||
add( new JLabel( "Channel Configuration" ), "span, align center" );
|
||||
|
||||
add( new JLabel( "Enabled:" ) );
|
||||
|
||||
mChannelEnabled.setSelected(
|
||||
mChannelNode.getChannel().getEnabled() );
|
||||
mChannelEnabled.setComponentOrientation( ComponentOrientation.RIGHT_TO_LEFT );
|
||||
add( mChannelEnabled );
|
||||
|
||||
add( new JLabel( "Name:" ) );
|
||||
|
||||
mChannelName = new JTextField( mChannelNode.getChannel().getName() );
|
||||
add( mChannelName, "growx,push" );
|
||||
|
||||
/**
|
||||
* ComboBox: Alias Lists
|
||||
*/
|
||||
add( new JLabel( "Aliases:" ) );
|
||||
|
||||
mComboAliasLists = new JComboBox<AliasList>();
|
||||
|
||||
List<AliasList> lists = mChannelNode.getModel().getResourceManager()
|
||||
.getPlaylistManager().getPlayist().getAliasDirectory().getAliasList();
|
||||
|
||||
Collections.sort( lists );
|
||||
|
||||
mComboAliasLists.setModel( new DefaultComboBoxModel<AliasList>(
|
||||
lists.toArray( new AliasList[ lists.size() ] ) ) );
|
||||
|
||||
String aliasListName =
|
||||
mChannelNode.getChannel().getAliasListName();
|
||||
|
||||
if( aliasListName != null )
|
||||
{
|
||||
AliasList selected = mChannelNode.getModel().getResourceManager()
|
||||
.getPlaylistManager().getPlayist().getAliasDirectory()
|
||||
.getAliasList( aliasListName );
|
||||
|
||||
mComboAliasLists.setSelectedItem( selected );
|
||||
}
|
||||
|
||||
add( mComboAliasLists, "growx,push" );
|
||||
|
||||
JideTabbedPane tabs = new JideTabbedPane();
|
||||
tabs.setFont( this.getFont() );
|
||||
tabs.setForeground( Color.BLACK );
|
||||
|
||||
mSourceEditor = new SourceComponentEditor( mChannelNode );
|
||||
tabs.addTab( "Source", mSourceEditor );
|
||||
|
||||
mDecodeEditor = new DecodeComponentEditor( mChannelNode );
|
||||
tabs.addTab( "Decoder", mDecodeEditor );
|
||||
|
||||
mAuxDecodeEditor = new AuxDecodeComponentEditor( mChannelNode );
|
||||
tabs.addTab( "Aux", mAuxDecodeEditor );
|
||||
|
||||
mEventLogEditor = new EventLogComponentEditor( mChannelNode );
|
||||
tabs.addTab( "Event Log", mEventLogEditor );
|
||||
|
||||
mRecordEditor = new RecordComponentEditor( mChannelNode );
|
||||
tabs.addTab( "Record", mRecordEditor );
|
||||
|
||||
add( tabs, "span,grow,push" );
|
||||
|
||||
JButton btnSave = new JButton( "Save" );
|
||||
btnSave.addActionListener( ChannelEditor.this );
|
||||
add( btnSave, "growx,push" );
|
||||
|
||||
JButton btnReset = new JButton( "Reset" );
|
||||
btnReset.addActionListener( ChannelEditor.this );
|
||||
add( btnReset, "growx,push" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
String command = e.getActionCommand();
|
||||
|
||||
if( command.contentEquals( "Save" ) )
|
||||
{
|
||||
save();
|
||||
}
|
||||
else if( command.contentEquals( "Reset" ) )
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
if( mTreeModel != null )
|
||||
{
|
||||
mTreeModel.nodeChanged( mChannelNode );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
boolean expanded = mChannelNode.getModel().getTree()
|
||||
.isExpanded( new TreePath( mChannelNode ) );
|
||||
|
||||
mSourceEditor.save();
|
||||
mDecodeEditor.save();
|
||||
mAuxDecodeEditor.save();
|
||||
mEventLogEditor.save();
|
||||
mRecordEditor.save();
|
||||
|
||||
mChannelNode.getChannel().setName( mChannelName.getText(), false );
|
||||
mChannelNode.getChannel().setEnabled( mChannelEnabled.isSelected(), false );
|
||||
|
||||
AliasList selected = mComboAliasLists.getItemAt(
|
||||
mComboAliasLists.getSelectedIndex() );
|
||||
if( selected != null )
|
||||
{
|
||||
mChannelNode.getChannel().setAliasListName( selected.getName(), false );
|
||||
}
|
||||
|
||||
|
||||
mChannelNode.save();
|
||||
mChannelNode.show();
|
||||
|
||||
if( expanded )
|
||||
{
|
||||
mChannelNode.getModel().getTree().expandPath( new TreePath( mChannelNode ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
mChannelName.setText(
|
||||
mChannelNode.getChannel().getName() );
|
||||
mChannelName.requestFocus();
|
||||
mChannelName.requestFocusInWindow();
|
||||
|
||||
mChannelEnabled.setSelected(
|
||||
mChannelNode.getChannel().getEnabled() );
|
||||
mChannelEnabled.requestFocus();
|
||||
mChannelEnabled.requestFocusInWindow();
|
||||
|
||||
String aliasListName =
|
||||
mChannelNode.getChannel().getAliasListName();
|
||||
|
||||
if( aliasListName != null )
|
||||
{
|
||||
AliasList selected = mChannelNode.getModel().getResourceManager()
|
||||
.getPlaylistManager().getPlayist().getAliasDirectory()
|
||||
.getAliasList( aliasListName );
|
||||
|
||||
mComboAliasLists.setSelectedItem( selected );
|
||||
}
|
||||
|
||||
|
||||
mSourceEditor.reset();
|
||||
mDecodeEditor.reset();
|
||||
mAuxDecodeEditor.reset();
|
||||
mEventLogEditor.reset();
|
||||
mRecordEditor.reset();
|
||||
}
|
||||
}
|
||||
32
src/controller/channel/ChannelListener.java
Normal file
32
src/controller/channel/ChannelListener.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
import controller.channel.Channel.ChannelEvent;
|
||||
|
||||
/**
|
||||
* Interface for receiving channel events. Each listener will receive
|
||||
* notification of all channel events.
|
||||
*/
|
||||
public interface ChannelListener
|
||||
{
|
||||
/**
|
||||
* Notifies the listener that a channel has changed and what has changed
|
||||
*/
|
||||
public void occurred( Channel channel, ChannelEvent event );
|
||||
}
|
||||
127
src/controller/channel/ChannelManager.java
Normal file
127
src/controller/channel/ChannelManager.java
Normal file
@@ -0,0 +1,127 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import message.Message;
|
||||
import sample.Listener;
|
||||
import controller.ResourceManager;
|
||||
import controller.channel.Channel.ChannelEvent;
|
||||
|
||||
public class ChannelManager implements ChannelListener
|
||||
{
|
||||
private ArrayList<Channel> mChannels = new ArrayList<Channel>();
|
||||
|
||||
private ArrayList<ChannelListener> mChannelListeners =
|
||||
new ArrayList<ChannelListener>();
|
||||
private ArrayList<Listener<Message>> mMessageListeners =
|
||||
new ArrayList<Listener<Message>>();
|
||||
|
||||
public ChannelManager( ResourceManager resourceManager )
|
||||
{
|
||||
mChannelListeners.add( this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that a channel has been added or deleted, so that we can
|
||||
* keep track of all channels and manage system-wide listeners for each
|
||||
* of those channels
|
||||
*/
|
||||
@SuppressWarnings( "incomplete-switch" )
|
||||
@Override
|
||||
public void occurred( Channel channel, ChannelEvent component )
|
||||
{
|
||||
switch( component )
|
||||
{
|
||||
case CHANNEL_ADDED:
|
||||
if( !mChannels.contains( channel ) )
|
||||
{
|
||||
mChannels.add( channel );
|
||||
}
|
||||
break;
|
||||
case CHANNEL_DELETED:
|
||||
mChannels.remove( channel );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a channel listener that will be added to all channels to receive
|
||||
* any channel change events. This listener will automatically receive
|
||||
* a channel add event as it is added to each of the existing channels.
|
||||
*/
|
||||
public void addListener( ChannelListener listener )
|
||||
{
|
||||
mChannelListeners.add( listener );
|
||||
|
||||
for( Channel channel: mChannels )
|
||||
{
|
||||
channel.addListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a channel listener from being automatically added to all channels
|
||||
* to receive channel change events.
|
||||
*/
|
||||
public void removeListener( ChannelListener listener )
|
||||
{
|
||||
mChannelListeners.remove( listener );
|
||||
|
||||
for( Channel channel: mChannels )
|
||||
{
|
||||
channel.removeListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of channel change listeners that will be automatically
|
||||
* added to all channels to receive channel change events
|
||||
*/
|
||||
public ArrayList<ChannelListener> getChannelListeners()
|
||||
{
|
||||
return mChannelListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of channel change listeners that will be automatically
|
||||
* added to all channels to receive channel change events
|
||||
*/
|
||||
public ArrayList<Listener<Message>> getMessageListeners()
|
||||
{
|
||||
return mMessageListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a message listener that will be added to all channels to receive
|
||||
* any messages.
|
||||
*/
|
||||
public void addListener( Listener<Message> listener )
|
||||
{
|
||||
mMessageListeners.add( listener );
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a message listener.
|
||||
*/
|
||||
public void removeListener( Listener<Message> listener )
|
||||
{
|
||||
mMessageListeners.remove( listener );
|
||||
}
|
||||
}
|
||||
120
src/controller/channel/ChannelMap.java
Normal file
120
src/controller/channel/ChannelMap.java
Normal file
@@ -0,0 +1,120 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
|
||||
@XmlSeeAlso( { ChannelRange.class } )
|
||||
public class ChannelMap
|
||||
{
|
||||
private String mName;
|
||||
|
||||
private ArrayList<ChannelRange> mRanges = new ArrayList<ChannelRange>();
|
||||
|
||||
public ChannelMap()
|
||||
{
|
||||
this( "New Channel Map" );
|
||||
}
|
||||
|
||||
public ChannelMap( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
/**
|
||||
* Creates a copy of this channel map
|
||||
*/
|
||||
public ChannelMap copyOf()
|
||||
{
|
||||
ChannelMap map = new ChannelMap( mName );
|
||||
|
||||
for( ChannelRange range: mRanges )
|
||||
{
|
||||
map.addRange( range.copyOf() );
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public int getInvalidRange()
|
||||
{
|
||||
for( int x = 0; x < mRanges.size(); x++ )
|
||||
{
|
||||
if( !mRanges.get( x ).isValid() )
|
||||
{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public ArrayList<ChannelRange> getRanges()
|
||||
{
|
||||
return mRanges;
|
||||
}
|
||||
|
||||
@XmlElement( name = "range" )
|
||||
public void setRanges( ArrayList<ChannelRange> ranges )
|
||||
{
|
||||
mRanges = ranges;
|
||||
}
|
||||
|
||||
@XmlAttribute
|
||||
public String getName()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
public void setName( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
public int getFrequency( int channelNumber )
|
||||
{
|
||||
for( ChannelRange range: mRanges )
|
||||
{
|
||||
if( range.hasChannel( channelNumber ) )
|
||||
{
|
||||
return range.getFrequency( channelNumber );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void addRange( ChannelRange range )
|
||||
{
|
||||
mRanges.add( range );
|
||||
}
|
||||
|
||||
public void deleteRange( ChannelRange range )
|
||||
{
|
||||
mRanges.remove( range );
|
||||
}
|
||||
|
||||
}
|
||||
223
src/controller/channel/ChannelMapEditor.java
Normal file
223
src/controller/channel/ChannelMapEditor.java
Normal file
@@ -0,0 +1,223 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
|
||||
import javax.swing.AbstractCellEditor;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFormattedTextField;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.table.TableCellEditor;
|
||||
import javax.swing.text.InternationalFormatter;
|
||||
|
||||
import log.Log;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
public class ChannelMapEditor extends JPanel implements ActionListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private ChannelMapNode mChannelMapNode;
|
||||
|
||||
private JLabel mNameLabel;
|
||||
private JTextField mNameText;
|
||||
private ChannelMapModel mRangeModel;
|
||||
private JTable mRangeTable;
|
||||
private JButton mDelete;
|
||||
private ChannelMap mChannelMapCopy;
|
||||
|
||||
public ChannelMapEditor( ChannelMapNode ChannelMap )
|
||||
{
|
||||
mChannelMapNode = ChannelMap;
|
||||
mChannelMapCopy = mChannelMapNode.getChannelMap().copyOf();
|
||||
initGUI();
|
||||
}
|
||||
|
||||
private void initGUI()
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 2", "[right][grow]", "[][][grow][][]" ) );
|
||||
|
||||
add( new JLabel( "Channel Map" ), "span, align center" );
|
||||
|
||||
mNameLabel = new JLabel( "Name:" );
|
||||
add( mNameLabel );
|
||||
|
||||
mNameText = new JTextField( mChannelMapCopy.getName() );
|
||||
mNameText.addFocusListener( new FocusListener()
|
||||
{
|
||||
@Override public void focusGained( FocusEvent arg0 ) {}
|
||||
|
||||
@Override
|
||||
public void focusLost( FocusEvent arg0 )
|
||||
{
|
||||
Log.info( "text field action event fired, new value:" + mNameText.getText() );
|
||||
mChannelMapCopy.setName( mNameText.getText() );
|
||||
}
|
||||
} );
|
||||
add( mNameText, "growx, push" );
|
||||
|
||||
mRangeModel = new ChannelMapModel( mChannelMapCopy );
|
||||
|
||||
mRangeTable = new JTable( mRangeModel );
|
||||
mRangeTable.setPreferredScrollableViewportSize( new Dimension( 300, 150 ) );
|
||||
mRangeTable.setFillsViewportHeight( true );
|
||||
mRangeTable.setAutoCreateRowSorter( true );
|
||||
for( int x = 0; x < mRangeTable.getColumnCount(); x++ )
|
||||
{
|
||||
mRangeTable.getColumnModel().getColumn( x )
|
||||
.setCellEditor( new RangeTableEditor() );
|
||||
}
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane( mRangeTable );
|
||||
add( scrollPane, "span,grow,push");
|
||||
|
||||
JButton btnNew = new JButton( "New Range" );
|
||||
btnNew.addActionListener( ChannelMapEditor.this );
|
||||
add( btnNew );
|
||||
|
||||
mDelete = new JButton( "Delete" );
|
||||
mDelete.addActionListener( ChannelMapEditor.this );
|
||||
add( mDelete, "wrap" );
|
||||
|
||||
JButton btnSave = new JButton( "Save" );
|
||||
btnSave.addActionListener( ChannelMapEditor.this );
|
||||
add( btnSave, "growx" );
|
||||
|
||||
JButton btnReset = new JButton( "Reset " );
|
||||
btnReset.addActionListener( ChannelMapEditor.this );
|
||||
add( btnReset, "wrap" );
|
||||
}
|
||||
|
||||
private boolean checkForValidRanges()
|
||||
{
|
||||
int invalidRow = mChannelMapCopy.getInvalidRange();
|
||||
|
||||
if( invalidRow != -1 && invalidRow <= mRangeTable.getRowCount() )
|
||||
{
|
||||
mRangeTable.setRowSelectionInterval( invalidRow, invalidRow );
|
||||
|
||||
JOptionPane.showMessageDialog( this,
|
||||
"Starting channel number must be less than ending channel number",
|
||||
"Channel number range error",
|
||||
JOptionPane.WARNING_MESSAGE );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
String command = e.getActionCommand();
|
||||
|
||||
switch( command )
|
||||
{
|
||||
case "New Range":
|
||||
mRangeModel.addRange( new ChannelRange() );
|
||||
break;
|
||||
case "Save":
|
||||
if( checkForValidRanges() )
|
||||
{
|
||||
mChannelMapNode.getChannelMap()
|
||||
.setName( mChannelMapCopy.getName() );
|
||||
mChannelMapNode.getChannelMap()
|
||||
.setRanges( mChannelMapCopy.getRanges() );
|
||||
|
||||
mChannelMapNode.save();
|
||||
|
||||
mChannelMapNode.refresh();
|
||||
|
||||
mChannelMapNode.show();
|
||||
}
|
||||
case "Reset":
|
||||
mChannelMapCopy = mChannelMapNode.getChannelMap();
|
||||
mRangeModel.setChannelMap( mChannelMapCopy );
|
||||
mNameText.setText( mChannelMapCopy.getName() );
|
||||
break;
|
||||
case "Delete":
|
||||
int row = mRangeTable.getSelectedRow();
|
||||
|
||||
if( row < 0 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( this,
|
||||
"Please select a channel range to delete",
|
||||
"Select a range",
|
||||
JOptionPane.WARNING_MESSAGE );
|
||||
}
|
||||
else
|
||||
{
|
||||
mRangeModel.removeRange(
|
||||
mRangeTable.convertRowIndexToModel( row ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public class RangeTableEditor extends AbstractCellEditor
|
||||
implements TableCellEditor, ActionListener
|
||||
{
|
||||
JFormattedTextField mEditor;
|
||||
|
||||
public RangeTableEditor()
|
||||
{
|
||||
InternationalFormatter nf = new InternationalFormatter();
|
||||
nf.setMinimum( 1 );
|
||||
nf.setAllowsInvalid( false );
|
||||
|
||||
mEditor = new JFormattedTextField( nf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCellEditorValue()
|
||||
{
|
||||
Log.info( "getCellEditorValue - I've been invoked!" );
|
||||
return mEditor.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
Log.info( "Action Performed:" + e.getActionCommand() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellEditorComponent( JTable table,
|
||||
Object value,
|
||||
boolean isSelected,
|
||||
int row,
|
||||
int column )
|
||||
{
|
||||
mEditor.setValue( value );
|
||||
|
||||
return mEditor;
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/controller/channel/ChannelMapList.java
Normal file
76
src/controller/channel/ChannelMapList.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
|
||||
@XmlSeeAlso( ChannelMap.class )
|
||||
public class ChannelMapList
|
||||
{
|
||||
private ArrayList<ChannelMap> mChannelMap = new ArrayList<ChannelMap>();
|
||||
|
||||
public ChannelMapList()
|
||||
{
|
||||
/* Empty constructor for JAXB */
|
||||
}
|
||||
|
||||
@XmlElement( name = "channel_map" )
|
||||
public ArrayList<ChannelMap> getChannelMap()
|
||||
{
|
||||
return mChannelMap;
|
||||
}
|
||||
|
||||
public void setChannelMap( ArrayList<ChannelMap> ChannelMaps )
|
||||
{
|
||||
mChannelMap = ChannelMaps;
|
||||
}
|
||||
|
||||
public void addChannelMap( ChannelMap ChannelMap )
|
||||
{
|
||||
mChannelMap.add( ChannelMap );
|
||||
}
|
||||
|
||||
public void removeChannelMap( ChannelMap ChannelMap )
|
||||
{
|
||||
mChannelMap.remove( ChannelMap );
|
||||
}
|
||||
|
||||
public void clearChannelMaps()
|
||||
{
|
||||
mChannelMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the named channel map, or returns an empty map
|
||||
*/
|
||||
public ChannelMap getChannelMap( String name )
|
||||
{
|
||||
for( ChannelMap map: mChannelMap )
|
||||
{
|
||||
if( map.getName().equalsIgnoreCase( name ) )
|
||||
{
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
return new ChannelMap();
|
||||
}
|
||||
}
|
||||
87
src/controller/channel/ChannelMapListNode.java
Normal file
87
src/controller/channel/ChannelMapListNode.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
import controller.ConfigurableNode;
|
||||
|
||||
public class ChannelMapListNode extends ConfigurableNode
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ChannelMapListNode( ChannelMapList list )
|
||||
{
|
||||
super( list );
|
||||
}
|
||||
|
||||
public ChannelMapList getChannelMapList()
|
||||
{
|
||||
return (ChannelMapList)getUserObject();
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
for( ChannelMap channelMap: getChannelMapList().getChannelMap() )
|
||||
{
|
||||
ChannelMapNode node = new ChannelMapNode( channelMap );
|
||||
|
||||
getModel().addNode( node, ChannelMapListNode.this, getChildCount() );
|
||||
|
||||
node.init();
|
||||
}
|
||||
|
||||
sort();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "Channel Maps [" + this.getChildCount() + "]";
|
||||
}
|
||||
|
||||
public JPopupMenu getContextMenu()
|
||||
{
|
||||
JPopupMenu retVal = new JPopupMenu();
|
||||
|
||||
JMenuItem addSystemItem = new JMenuItem( "Add Channel Map" );
|
||||
addSystemItem.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
ChannelMap channelMap = new ChannelMap();
|
||||
|
||||
getChannelMapList().addChannelMap( channelMap );
|
||||
|
||||
getModel().addNode( new ChannelMapNode( channelMap ),
|
||||
ChannelMapListNode.this,
|
||||
ChannelMapListNode.this.getChildCount() );
|
||||
|
||||
save();
|
||||
}
|
||||
} );
|
||||
|
||||
retVal.add( addSystemItem );
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
167
src/controller/channel/ChannelMapModel.java
Normal file
167
src/controller/channel/ChannelMapModel.java
Normal file
@@ -0,0 +1,167 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
|
||||
import log.Log;
|
||||
|
||||
public class ChannelMapModel extends AbstractTableModel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final int sSTART = 0;
|
||||
private static final int sSTOP = 1;
|
||||
private static final int sBASE = 2;
|
||||
private static final int sSIZE = 3;
|
||||
|
||||
protected int[] mColumnWidths = { 110, 110, 110, -1 };
|
||||
|
||||
protected String[] mHeaders = new String[] { "Begin",
|
||||
"End",
|
||||
"Base",
|
||||
"Size" };
|
||||
|
||||
private ChannelMap mChannelMap;
|
||||
|
||||
public ChannelMapModel( ChannelMap map )
|
||||
{
|
||||
mChannelMap = map;
|
||||
}
|
||||
|
||||
public ChannelMap getChannelMap()
|
||||
{
|
||||
return mChannelMap;
|
||||
}
|
||||
|
||||
public void setChannelMap( ChannelMap map )
|
||||
{
|
||||
mChannelMap = map;
|
||||
|
||||
fireTableDataChanged();
|
||||
}
|
||||
|
||||
public void addRange( ChannelRange range )
|
||||
{
|
||||
mChannelMap.addRange( range );
|
||||
|
||||
int index = mChannelMap.getRanges().size() - 1;
|
||||
|
||||
fireTableRowsInserted( index, index );
|
||||
}
|
||||
|
||||
public void removeRange( int rangeIndex )
|
||||
{
|
||||
if( rangeIndex < mChannelMap.getRanges().size() )
|
||||
{
|
||||
mChannelMap.getRanges().remove( rangeIndex );
|
||||
}
|
||||
|
||||
fireTableRowsDeleted( rangeIndex, rangeIndex );
|
||||
}
|
||||
|
||||
public int[] getColumnWidths()
|
||||
{
|
||||
return mColumnWidths;
|
||||
}
|
||||
|
||||
public void setColumnWidths( int[] widths )
|
||||
{
|
||||
if( widths.length != 4 )
|
||||
{
|
||||
throw new IllegalArgumentException( "ChannelMapRangeModel - "
|
||||
+ "column widths array should have 5 elements" );
|
||||
}
|
||||
else
|
||||
{
|
||||
mColumnWidths = widths;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount()
|
||||
{
|
||||
return mChannelMap.getRanges().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount()
|
||||
{
|
||||
return mHeaders.length;
|
||||
}
|
||||
|
||||
public String getColumnName( int column )
|
||||
{
|
||||
return mHeaders[ column ];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt( int rowIndex, int columnIndex )
|
||||
{
|
||||
ChannelRange range = mChannelMap.getRanges().get( rowIndex );
|
||||
|
||||
switch( columnIndex )
|
||||
{
|
||||
case sSTART:
|
||||
return range.getFirstChannelNumber();
|
||||
case sSTOP:
|
||||
return range.getLastChannelNumber();
|
||||
case sBASE:
|
||||
return range.getBase();
|
||||
case sSIZE:
|
||||
return range.getSize();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isCellEditable( int row, int column )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setValueAt( Object value, int row, int column )
|
||||
{
|
||||
try
|
||||
{
|
||||
int parsedValue = Integer.parseInt( (String)value );
|
||||
|
||||
ChannelRange range = mChannelMap.getRanges().get( row );
|
||||
|
||||
switch( column )
|
||||
{
|
||||
case sSTART:
|
||||
range.setFirstChannelNumber( parsedValue );
|
||||
break;
|
||||
case sSTOP:
|
||||
range.setLastChannelNumber( parsedValue );
|
||||
break;
|
||||
case sBASE:
|
||||
range.setBase( parsedValue );
|
||||
break;
|
||||
case sSIZE:
|
||||
range.setSize( parsedValue );
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
Log.info( "ChannelMapModel - couldn't parse integer value "
|
||||
+ "for [" + value + "] - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
102
src/controller/channel/ChannelMapNode.java
Normal file
102
src/controller/channel/ChannelMapNode.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
import controller.ConfigurableNode;
|
||||
|
||||
public class ChannelMapNode extends ConfigurableNode
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ChannelMapNode( ChannelMap ChannelMap )
|
||||
{
|
||||
super( ChannelMap );
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
//For consistency, but not used
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIconPath()
|
||||
{
|
||||
return "images/ChannelMap.png";
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getEditor()
|
||||
{
|
||||
return new ChannelMapEditor( this );
|
||||
}
|
||||
|
||||
public ChannelMap getChannelMap()
|
||||
{
|
||||
return (ChannelMap)getUserObject();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return getChannelMap().getName();
|
||||
}
|
||||
|
||||
public void delete()
|
||||
{
|
||||
ChannelMapListNode parent = (ChannelMapListNode)getParent();
|
||||
|
||||
parent.getChannelMapList().removeChannelMap( getChannelMap() );
|
||||
|
||||
save();
|
||||
|
||||
getModel().removeNodeFromParent( ChannelMapNode.this );
|
||||
|
||||
/* Show the first child, if one exists so that we don't have a
|
||||
* collapsed list */
|
||||
if( parent.getChildCount() > 0 )
|
||||
{
|
||||
((ConfigurableNode)parent.getFirstChild()).show();
|
||||
}
|
||||
}
|
||||
|
||||
public JPopupMenu getContextMenu()
|
||||
{
|
||||
JPopupMenu retVal = new JPopupMenu();
|
||||
|
||||
JMenuItem deleteItem = new JMenuItem( "Delete" );
|
||||
deleteItem.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
delete();
|
||||
}
|
||||
} );
|
||||
|
||||
retVal.add( deleteItem );
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
168
src/controller/channel/ChannelNode.java
Normal file
168
src/controller/channel/ChannelNode.java
Normal file
@@ -0,0 +1,168 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
import log.Log;
|
||||
import source.tuner.TunerChannel;
|
||||
import controller.ConfigurableNode;
|
||||
import controller.channel.Channel.ChannelEvent;
|
||||
import controller.site.SiteNode;
|
||||
import controller.system.SystemNode;
|
||||
|
||||
/**
|
||||
* A channel has all of the pieces needed to wire together a source, decoder,
|
||||
* event logger and recorder and be started and stopped.
|
||||
*/
|
||||
public class ChannelNode extends ConfigurableNode implements ChannelListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static DecimalFormat sFORMAT = new DecimalFormat( "0.0000" );
|
||||
|
||||
public ChannelNode( Channel channel )
|
||||
{
|
||||
super( channel );
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
/* Set the owning system and site names for the channel */
|
||||
SiteNode siteNode = (SiteNode)getParent();
|
||||
|
||||
if( siteNode != null )
|
||||
{
|
||||
getChannel().setSite( siteNode.getSite(), false );
|
||||
|
||||
SystemNode systemNode = (SystemNode)siteNode.getParent();
|
||||
|
||||
if( systemNode != null )
|
||||
{
|
||||
getChannel().setSystem( systemNode.getSystem(), false );
|
||||
}
|
||||
}
|
||||
|
||||
/* Add this node as listener to receive changes from underlying channel */
|
||||
getChannel().addListener( this );
|
||||
|
||||
/* Add the resource manager to the channel so that the channel
|
||||
* can provide channel change events to all system resources */
|
||||
getChannel().setResourceManager( getModel().getResourceManager() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener method to receive channel changes from the underlying chnannel
|
||||
*/
|
||||
@Override
|
||||
public void occurred( Channel channel, ChannelEvent event )
|
||||
{
|
||||
switch( event )
|
||||
{
|
||||
/* Refresh the node for each of these events */
|
||||
case CHANGE_DECODER:
|
||||
case CHANGE_ENABLED:
|
||||
case CHANGE_NAME:
|
||||
case CHANGE_SELECTED:
|
||||
case CHANGE_SITE:
|
||||
case CHANGE_SYSTEM:
|
||||
case PROCESSING_STARTED:
|
||||
case PROCESSING_STOPPED:
|
||||
this.refresh();
|
||||
break;
|
||||
/* We're being deleted, so cleanup */
|
||||
case CHANNEL_DELETED:
|
||||
delete();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIconPath()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
Channel channel = getChannel();
|
||||
|
||||
sb.append( channel.getDecodeConfiguration().getDecoderType().getIconPrefix() );
|
||||
|
||||
if( channel.getEnabled() )
|
||||
{
|
||||
sb.append( channel.isProcessing() ? "_green" : "_red" );
|
||||
}
|
||||
|
||||
sb.append( ".png" );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getEditor()
|
||||
{
|
||||
return new ChannelEditor( this );
|
||||
}
|
||||
|
||||
public Channel getChannel()
|
||||
{
|
||||
return (Channel)this.getUserObject();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( getChannel().getName() );
|
||||
|
||||
TunerChannel channel = getChannel().getTunerChannel();
|
||||
|
||||
if( channel != null )
|
||||
{
|
||||
sb.append( " (" );
|
||||
sb.append( sFORMAT.format( (double)channel.getFrequency() / 1000000.0d ) + " MHz" );
|
||||
sb.append( ")" );
|
||||
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public JPopupMenu getContextMenu()
|
||||
{
|
||||
JPopupMenu popupMenu = new JPopupMenu( "Channel Menu" );
|
||||
popupMenu.add( getChannel().getContextMenu() );
|
||||
|
||||
return popupMenu;
|
||||
}
|
||||
|
||||
public void delete()
|
||||
{
|
||||
Log.info( "Channel Node - deleting ..." );
|
||||
((SiteNode)getParent()).getSite().removeChannel( getChannel() );
|
||||
|
||||
Log.info( "Channel Node - saving after channel delete" );
|
||||
save();
|
||||
|
||||
Log.info( "Channel Node - removing from site node" );
|
||||
getModel().removeNodeFromParent( ChannelNode.this );
|
||||
}
|
||||
}
|
||||
122
src/controller/channel/ChannelRange.java
Normal file
122
src/controller/channel/ChannelRange.java
Normal file
@@ -0,0 +1,122 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
@XmlRootElement
|
||||
@XmlType( name = "range" )
|
||||
public class ChannelRange
|
||||
{
|
||||
private int mFirst = 1;
|
||||
private int mLast = 1023;
|
||||
private int mBase = 450000000;
|
||||
private int mSize = 12500;
|
||||
|
||||
/* JAXB requirement - do not remove */
|
||||
public ChannelRange() {}
|
||||
|
||||
public ChannelRange( int first, int last, int base, int size )
|
||||
{
|
||||
mFirst = first;
|
||||
mLast = last;
|
||||
mBase = base;
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
public ChannelRange copyOf()
|
||||
{
|
||||
return new ChannelRange( mFirst, mLast, mBase, mSize );
|
||||
}
|
||||
|
||||
public boolean isValid()
|
||||
{
|
||||
return mFirst < mLast;
|
||||
}
|
||||
|
||||
public boolean hasChannel( int channel )
|
||||
{
|
||||
return mFirst <= channel && channel <= mLast;
|
||||
}
|
||||
|
||||
public int getFrequency( int channel )
|
||||
{
|
||||
if( hasChannel( channel ) )
|
||||
{
|
||||
return mBase + ( ( channel - mFirst ) * mSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "first" )
|
||||
public int getFirstChannelNumber()
|
||||
{
|
||||
return mFirst;
|
||||
}
|
||||
|
||||
public void setFirstChannelNumber( int first )
|
||||
{
|
||||
mFirst = first;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "last" )
|
||||
public void setLastChannelNumber( int last )
|
||||
{
|
||||
mLast = last;
|
||||
}
|
||||
|
||||
public int getLastChannelNumber()
|
||||
{
|
||||
return mLast;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the base frequency
|
||||
* @param base frequency in hertz
|
||||
*/
|
||||
@XmlAttribute( name = "base" )
|
||||
public void setBase( int base )
|
||||
{
|
||||
mBase = base;
|
||||
}
|
||||
|
||||
public int getBase()
|
||||
{
|
||||
return mBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the channel size
|
||||
* @param size in hertz
|
||||
*/
|
||||
@XmlAttribute( name = "size" )
|
||||
public void setSize( int size )
|
||||
{
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
}
|
||||
23
src/controller/channel/ChannelSelectionListener.java
Normal file
23
src/controller/channel/ChannelSelectionListener.java
Normal file
@@ -0,0 +1,23 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
public interface ChannelSelectionListener
|
||||
{
|
||||
public void channelSelected( ProcessingChain channel );
|
||||
}
|
||||
721
src/controller/channel/ProcessingChain.java
Normal file
721
src/controller/channel/ProcessingChain.java
Normal file
@@ -0,0 +1,721 @@
|
||||
/*******************************************************************************
|
||||
* 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 controller.channel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedTransferQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import log.Log;
|
||||
import message.Message;
|
||||
import record.Recorder;
|
||||
import record.wave.ComplexWaveRecorder;
|
||||
import record.wave.FloatWaveRecorder;
|
||||
import sample.Broadcaster;
|
||||
import sample.Listener;
|
||||
import sample.Provider;
|
||||
import sample.complex.ComplexSample;
|
||||
import source.ComplexSource;
|
||||
import source.FloatArraySource;
|
||||
import source.FloatSource;
|
||||
import source.Source;
|
||||
import source.Source.SampleType;
|
||||
import source.config.SourceConfigMixer;
|
||||
import source.tuner.Tuner;
|
||||
import source.tuner.TunerChannelSource;
|
||||
import alias.AliasList;
|
||||
import audio.AudioOutput;
|
||||
import audio.AudioTypeListener;
|
||||
import audio.SquelchListener;
|
||||
import controller.ResourceManager;
|
||||
import controller.ThreadPoolManager.ThreadType;
|
||||
import controller.activity.CallEvent;
|
||||
import controller.channel.Channel.ChannelType;
|
||||
import controller.state.ChannelState;
|
||||
import controller.state.ChannelState.State;
|
||||
import decode.Decoder;
|
||||
import decode.DecoderFactory;
|
||||
import eventlog.EventLogType;
|
||||
import eventlog.EventLogger;
|
||||
|
||||
/**
|
||||
* A channel has all of the pieces needed to wire together a source, decoder,
|
||||
* event logger and recorder and be started and stopped.
|
||||
*/
|
||||
public class ProcessingChain implements Listener<Message>
|
||||
{
|
||||
protected AtomicBoolean mRunning = new AtomicBoolean();
|
||||
protected Channel mChannel;
|
||||
protected Source mSource;
|
||||
protected Decoder mDecoder;
|
||||
protected List<Recorder> mRecorders = new ArrayList<Recorder>();
|
||||
protected ArrayList<EventLogger> mEventLoggers = new ArrayList<EventLogger>();
|
||||
protected AudioOutput mAudioOutput;
|
||||
protected ChannelState mChannelState;
|
||||
protected ResourceManager mResourceManager;
|
||||
private ScheduledFuture<?> mProcessorTask;
|
||||
private AliasList mAliasList;
|
||||
|
||||
private ComplexListener mComplexListener = new ComplexListener();
|
||||
private LinkedTransferQueue<List<ComplexSample>> mComplexBuffer =
|
||||
new LinkedTransferQueue<List<ComplexSample>>();
|
||||
|
||||
private FloatListener mFloatListener = new FloatListener();
|
||||
private FloatArrayListener mFloatArrayListener = new FloatArrayListener();
|
||||
private LinkedTransferQueue<Float> mFloatBuffer =
|
||||
new LinkedTransferQueue<Float>();
|
||||
|
||||
protected Broadcaster<Message> mBroadcaster = new Broadcaster<Message>();
|
||||
|
||||
public ProcessingChain( Channel channel, ResourceManager resourceManager )
|
||||
{
|
||||
mChannel = channel;
|
||||
mResourceManager = resourceManager;
|
||||
|
||||
if( mResourceManager != null )
|
||||
{
|
||||
mAliasList = mResourceManager.getPlaylistManager()
|
||||
.getPlayist().getAliasDirectory().getAliasList(
|
||||
mChannel.getAliasListName() );
|
||||
}
|
||||
}
|
||||
|
||||
public Listener<List<ComplexSample>> getComplexListener()
|
||||
{
|
||||
return mComplexListener;
|
||||
}
|
||||
|
||||
public Listener<Float> getFloatListener()
|
||||
{
|
||||
return mFloatListener;
|
||||
}
|
||||
|
||||
public Listener<Float[]> getFloatArrayListener()
|
||||
{
|
||||
return mFloatArrayListener;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return mChannel.getName();
|
||||
}
|
||||
|
||||
public AliasList getAliasList()
|
||||
{
|
||||
return mAliasList;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
if( mProcessorTask != null )
|
||||
{
|
||||
mResourceManager.getThreadPoolManager().cancel( mProcessorTask );
|
||||
}
|
||||
|
||||
if( mChannelState != null )
|
||||
{
|
||||
mChannelState.dispose();
|
||||
}
|
||||
|
||||
mChannelState = null;
|
||||
|
||||
if( mDecoder != null )
|
||||
{
|
||||
mDecoder.dispose();
|
||||
}
|
||||
|
||||
mBroadcaster.dispose();
|
||||
mEventLoggers.clear();
|
||||
mRecorders.clear();
|
||||
|
||||
|
||||
if( mAudioOutput != null )
|
||||
{
|
||||
mAudioOutput.dispose();
|
||||
}
|
||||
|
||||
mResourceManager = null;
|
||||
}
|
||||
|
||||
public ResourceManager getResourceManager()
|
||||
{
|
||||
return mResourceManager;
|
||||
}
|
||||
|
||||
public void start()
|
||||
{
|
||||
if( !mRunning.get() && mChannel.getEnabled() )
|
||||
{
|
||||
updateSource();
|
||||
|
||||
updateDecoder();
|
||||
|
||||
updateEventLogging();
|
||||
|
||||
updateRecording();
|
||||
|
||||
mRunning.set( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.info( getLogPrefix() + "start() invoked, but processing chain is "
|
||||
+ "already started" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs closeout operations to prepare for channel deletion
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
if( mRunning.get() )
|
||||
{
|
||||
updateSource();
|
||||
|
||||
updateDecoder();
|
||||
|
||||
updateRecording();
|
||||
|
||||
/* Flush call events to the logger */
|
||||
if( getChannel().getChannelType() == ChannelType.STANDARD )
|
||||
{
|
||||
getChannelState().getCallEventModel().flush();
|
||||
}
|
||||
|
||||
updateEventLogging();
|
||||
|
||||
if( mAudioOutput != null )
|
||||
{
|
||||
mAudioOutput.setAudioPlaybackEnabled( false );
|
||||
}
|
||||
|
||||
mRunning.set( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.info( getLogPrefix() + "stop() invoked, but processing chain was "
|
||||
+ "already stopped" );
|
||||
}
|
||||
}
|
||||
|
||||
private String getLogPrefix()
|
||||
{
|
||||
return "Channel [" + mChannel.getName() + "] - ";
|
||||
}
|
||||
|
||||
public void updateSource()
|
||||
{
|
||||
/* Cleanup existing source */
|
||||
if( mSource != null )
|
||||
{
|
||||
if( mSource instanceof ComplexSource )
|
||||
{
|
||||
((ComplexSource)mSource).removeListener( this.getComplexListener() );
|
||||
}
|
||||
else if( mSource instanceof FloatSource )
|
||||
{
|
||||
((FloatSource)mSource).removeListener( this.getFloatListener() );
|
||||
}
|
||||
else if( mSource instanceof FloatArraySource )
|
||||
{
|
||||
((FloatArraySource)mSource)
|
||||
.removeListener( this.getFloatArrayListener() );
|
||||
}
|
||||
|
||||
if( mProcessorTask != null )
|
||||
{
|
||||
mResourceManager.getThreadPoolManager().cancel( mProcessorTask );
|
||||
}
|
||||
|
||||
mSource.dispose();
|
||||
|
||||
mSource = null;
|
||||
}
|
||||
|
||||
/* Get a new source if needed and start the sample processor thread */
|
||||
if( mChannel.getEnabled() && mResourceManager != null )
|
||||
{
|
||||
mSource = mResourceManager.getSourceManager()
|
||||
.getSource( ProcessingChain.this );
|
||||
|
||||
if( mSource != null )
|
||||
{
|
||||
if( mSource instanceof ComplexSource )
|
||||
{
|
||||
try
|
||||
{
|
||||
mProcessorTask =
|
||||
mResourceManager.getThreadPoolManager()
|
||||
.schedule( ThreadType.DECODER,
|
||||
new ComplexProcessor(),
|
||||
50, TimeUnit.MILLISECONDS );
|
||||
|
||||
((ComplexSource)mSource)
|
||||
.setListener( this.getComplexListener() );
|
||||
}
|
||||
catch( RejectedExecutionException ree )
|
||||
{
|
||||
Log.error( getLogPrefix() + "ProcessingChain - "
|
||||
+ "error scheduling complex sample processing "
|
||||
+ "thread - " + ree.getLocalizedMessage() );
|
||||
|
||||
mSource.dispose();
|
||||
}
|
||||
}
|
||||
else if( mSource instanceof FloatSource )
|
||||
{
|
||||
try
|
||||
{
|
||||
mProcessorTask =
|
||||
mResourceManager.getThreadPoolManager()
|
||||
.schedule( ThreadType.DECODER,
|
||||
new FloatProcessor(),
|
||||
50, TimeUnit.MILLISECONDS );
|
||||
|
||||
((FloatSource)mSource)
|
||||
.setListener( this.getFloatListener() );
|
||||
}
|
||||
catch( RejectedExecutionException ree )
|
||||
{
|
||||
Log.error( getLogPrefix() + "ProcessingChain - "
|
||||
+ "error scheduling float sample processing "
|
||||
+ "thread - " + ree.getLocalizedMessage() );
|
||||
|
||||
mSource.dispose();
|
||||
}
|
||||
}
|
||||
else if( mSource instanceof FloatArraySource )
|
||||
{
|
||||
try
|
||||
{
|
||||
mProcessorTask =
|
||||
mResourceManager.getThreadPoolManager()
|
||||
.schedule( ThreadType.DECODER,
|
||||
new FloatProcessor(),
|
||||
50, TimeUnit.MILLISECONDS );
|
||||
|
||||
((FloatArraySource)mSource)
|
||||
.setListener( this.getFloatArrayListener() );
|
||||
}
|
||||
catch( RejectedExecutionException ree )
|
||||
{
|
||||
Log.error( getLogPrefix() + "ProcessingChain - "
|
||||
+ "error scheduling float sample processing "
|
||||
+ "thread - " + ree.getLocalizedMessage() );
|
||||
|
||||
mSource.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateDecoder()
|
||||
{
|
||||
if( mChannel.getEnabled() )
|
||||
{
|
||||
AliasList aliasList = null;
|
||||
|
||||
if( mResourceManager != null )
|
||||
{
|
||||
aliasList = mResourceManager.getPlaylistManager()
|
||||
.getPlayist().getAliasDirectory().getAliasList(
|
||||
mChannel.getAliasListName() );
|
||||
}
|
||||
|
||||
/* Setup the channel state */
|
||||
mChannelState = DecoderFactory.getChannelStateNew( this, aliasList );
|
||||
|
||||
if( mSource == null )
|
||||
{
|
||||
mChannelState.setState( State.NO_TUNER );
|
||||
}
|
||||
else
|
||||
{
|
||||
mDecoder = DecoderFactory.
|
||||
getDecoder( this, mSource.getSampleType(), aliasList );
|
||||
|
||||
if( mDecoder != null )
|
||||
{
|
||||
/* Register to receive decoded messages and auxiliary messages */
|
||||
mDecoder.addMessageListener( ProcessingChain.this );
|
||||
|
||||
/* Setup the audio output processing thread */
|
||||
String threadName = "SDRTrunk Audio - " +
|
||||
mChannel.getSite().getName() +
|
||||
"-" + mChannel.getName();
|
||||
|
||||
mAudioOutput = new AudioOutput( threadName );
|
||||
addFloatListener( mAudioOutput );
|
||||
}
|
||||
}
|
||||
|
||||
if( mAudioOutput != null )
|
||||
{
|
||||
/* Register audio output to be controlled by the channel state */
|
||||
mChannelState.addListener( (SquelchListener)mAudioOutput );
|
||||
mChannelState.setListener( (AudioTypeListener)mAudioOutput );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts, stops or changes event logging
|
||||
*/
|
||||
public void updateEventLogging()
|
||||
{
|
||||
/* Shutdown and remove existing event loggers */
|
||||
if( mEventLoggers != null )
|
||||
{
|
||||
for( EventLogger logger: mEventLoggers )
|
||||
{
|
||||
logger.stop();
|
||||
}
|
||||
|
||||
mEventLoggers.clear();
|
||||
}
|
||||
|
||||
/* Construct event loggers and add as message listeners */
|
||||
if( mChannel.getEnabled() &&
|
||||
mResourceManager != null )
|
||||
{
|
||||
//Get the event loggers
|
||||
ArrayList<EventLogType> types = getChannel()
|
||||
.getEventLogConfiguration().getLoggers();
|
||||
|
||||
for( EventLogType type: types )
|
||||
{
|
||||
EventLogger logger;
|
||||
|
||||
if( type == EventLogType.CALL_EVENT )
|
||||
{
|
||||
logger = mResourceManager.getEventLogManager()
|
||||
.getLogger( this, type );
|
||||
|
||||
getChannelState().getCallEventModel()
|
||||
.addListener( (Listener<CallEvent>)logger );
|
||||
}
|
||||
else
|
||||
{
|
||||
logger = mResourceManager.getEventLogManager()
|
||||
.getLogger( this, type );
|
||||
|
||||
addListener( (Listener<Message>)logger );
|
||||
}
|
||||
|
||||
logger.start();
|
||||
|
||||
mEventLoggers.add( logger );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts, stops or changes data recording
|
||||
*/
|
||||
public void updateRecording()
|
||||
{
|
||||
/* Remove any existing recorders */
|
||||
if( mRecorders != null )
|
||||
{
|
||||
for( Recorder recorder: mRecorders )
|
||||
{
|
||||
if( recorder != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
recorder.stop();
|
||||
}
|
||||
catch ( IOException ioe )
|
||||
{
|
||||
Log.error( getLogPrefix() + "Couldn't stop recorder [" +
|
||||
recorder.getFileName() + "] " +
|
||||
ioe.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Start any new recorders */
|
||||
if( mChannel.getEnabled() &&
|
||||
mResourceManager != null &&
|
||||
mDecoder != null )
|
||||
{
|
||||
mRecorders = mResourceManager.getRecorderManager()
|
||||
.getRecorder( this );
|
||||
|
||||
/* Iterate any returned recorders and start/add them */
|
||||
for( Recorder recorder: mRecorders )
|
||||
{
|
||||
try
|
||||
{
|
||||
recorder.start();
|
||||
|
||||
if( recorder instanceof FloatWaveRecorder )
|
||||
{
|
||||
Log.info( getLogPrefix() + "- started audio recording [" +
|
||||
recorder.getFileName() + "]" );
|
||||
|
||||
mDecoder.addFloatListener( (FloatWaveRecorder)recorder );
|
||||
}
|
||||
else if( recorder instanceof ComplexWaveRecorder )
|
||||
{
|
||||
Log.info( getLogPrefix() + "- started baseband recording [" +
|
||||
recorder.getFileName() + "]" );
|
||||
|
||||
mDecoder.addComplexListener( (ComplexWaveRecorder )recorder );
|
||||
}
|
||||
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
Log.error( getLogPrefix() + "Unable to start recorder [" +
|
||||
recorder.getFileName() + "]" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Channel getChannel()
|
||||
{
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
public AudioOutput getAudioOutput()
|
||||
{
|
||||
return mAudioOutput;
|
||||
}
|
||||
|
||||
public Source getSource()
|
||||
{
|
||||
return mSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tuner that is sourcing this channel, or null if it's being
|
||||
* sourced from some other source
|
||||
*/
|
||||
public Tuner getTuner()
|
||||
{
|
||||
Tuner retVal = null;
|
||||
|
||||
if( mSource instanceof TunerChannelSource )
|
||||
{
|
||||
retVal = ((TunerChannelSource)mSource).getTuner();
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public Decoder getDecoder()
|
||||
{
|
||||
return mDecoder;
|
||||
}
|
||||
|
||||
public ChannelState getChannelState()
|
||||
{
|
||||
return mChannelState;
|
||||
}
|
||||
|
||||
public boolean isRunning()
|
||||
{
|
||||
return mRunning.get();
|
||||
}
|
||||
|
||||
public boolean isProcessing()
|
||||
{
|
||||
return isRunning() && mSource != null;
|
||||
}
|
||||
|
||||
private source.mixer.MixerChannel getMixerChannel()
|
||||
{
|
||||
source.mixer.MixerChannel retVal = null;
|
||||
|
||||
if( mChannel.getSourceConfiguration() instanceof SourceConfigMixer )
|
||||
{
|
||||
SourceConfigMixer mixer = (SourceConfigMixer)mChannel.getSourceConfiguration();
|
||||
|
||||
retVal = mixer.getChannel();
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( Message message )
|
||||
{
|
||||
if( message.isValid() )
|
||||
{
|
||||
mBroadcaster.receive( message );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void addFloatListener( Listener<Float> listener )
|
||||
{
|
||||
if( mDecoder != null )
|
||||
{
|
||||
mDecoder.addFloatListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFloatListener( Listener<Float> listener )
|
||||
{
|
||||
if( mDecoder != null )
|
||||
{
|
||||
mDecoder.removeFloatListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
public void addComplexListener( Listener<ComplexSample> listener )
|
||||
{
|
||||
if( mDecoder != null )
|
||||
{
|
||||
mDecoder.addComplexListener( listener );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error( getLogPrefix() + "attempt to add a complex sample "
|
||||
+ "listener, but the decoder is null" );
|
||||
}
|
||||
}
|
||||
|
||||
public void removeComplexListener( Listener<ComplexSample> listener )
|
||||
{
|
||||
if( mDecoder != null )
|
||||
{
|
||||
mDecoder.removeComplexListener( listener );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error( getLogPrefix() + "attempt to remove a complex sample "
|
||||
+ "listener, but the decoder is null" );
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener( Listener<Message> listener )
|
||||
{
|
||||
mBroadcaster.addListener( listener );
|
||||
}
|
||||
|
||||
public void addListeners( List<Listener<Message>> listeners )
|
||||
{
|
||||
for( Listener<Message> listener: listeners )
|
||||
{
|
||||
addListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener( Listener<Message> listener )
|
||||
{
|
||||
mBroadcaster.removeListener( listener );
|
||||
}
|
||||
|
||||
/**
|
||||
* Runnable float sample processing task. Schedule this task to run 20
|
||||
* times a second when we're receiving complex samples from our source.
|
||||
* Schedule execution via the thread pool manager, obtainable from the
|
||||
* resource manager,
|
||||
*/
|
||||
private class FloatProcessor implements Runnable
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
List<Float> samples = new ArrayList<Float>();
|
||||
|
||||
mFloatBuffer.drainTo( samples, 48000 );
|
||||
|
||||
for( Float sample: samples )
|
||||
{
|
||||
if( mDecoder != null )
|
||||
{
|
||||
mDecoder.getFloatReceiver().receive( sample );
|
||||
}
|
||||
}
|
||||
|
||||
samples.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runnable complex sample processing task. Schedule this task to run 20
|
||||
* times a second when we're receiving complex samples from our source.
|
||||
* Schedule execution via the thread pool manager, obtainable from the
|
||||
* resource manager,
|
||||
*/
|
||||
private class ComplexProcessor implements Runnable
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
List<List<ComplexSample>> sampleSets =
|
||||
new ArrayList<List<ComplexSample>>();
|
||||
|
||||
mComplexBuffer.drainTo( sampleSets, 16 );
|
||||
|
||||
for( List<ComplexSample> samples: sampleSets )
|
||||
{
|
||||
for( ComplexSample sample: samples )
|
||||
{
|
||||
if( sample != null && mDecoder != null )
|
||||
{
|
||||
mDecoder.getComplexReceiver().receive( sample );
|
||||
}
|
||||
}
|
||||
|
||||
samples.clear();
|
||||
}
|
||||
|
||||
sampleSets.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public class ComplexListener implements Listener<List<ComplexSample>>
|
||||
{
|
||||
@Override
|
||||
public void receive( List<ComplexSample> samples )
|
||||
{
|
||||
mComplexBuffer.add( samples );
|
||||
}
|
||||
}
|
||||
|
||||
public class FloatListener implements Listener<Float>
|
||||
{
|
||||
@Override
|
||||
public void receive( Float sample )
|
||||
{
|
||||
mFloatBuffer.add( sample );
|
||||
}
|
||||
}
|
||||
|
||||
public class FloatArrayListener implements Listener<Float[]>
|
||||
{
|
||||
@Override
|
||||
public void receive( Float[] samples )
|
||||
{
|
||||
mFloatBuffer.addAll( Arrays.asList( samples ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user