mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
61 Rotating Control Channel Support - P25 Decoder (#475)
* Initial work on add support for rotating control channels. * Creates multiple frequency editor control. * Updates channel source editor to allow user to select multi-frequency configuration and add multiple frequencies. * Adds full support for rotating control channels to the P25 channelizer. Users define multiple frequencies in the channel source configuration. The decoder monitors the state of the channel for a CONTROL state. If the state does not stay in the CONTROL state for a user-specified delay value, then the decoder rotates to the next frequency in the list. This behavior continues until the decoder state once again changes to CONTROL. This is NOT a 'scanner' feature.
This commit is contained in:
@@ -1,25 +1,29 @@
|
||||
/*******************************************************************************
|
||||
* 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/>
|
||||
******************************************************************************/
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 io.github.dsheirer.source;
|
||||
|
||||
import io.github.dsheirer.module.Module;
|
||||
import io.github.dsheirer.sample.IOverflowListener;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.SampleType;
|
||||
import io.github.dsheirer.source.heartbeat.Heartbeat;
|
||||
import io.github.dsheirer.source.heartbeat.HeartbeatManager;
|
||||
import io.github.dsheirer.source.heartbeat.IHeartbeatProvider;
|
||||
|
||||
@@ -39,8 +43,29 @@ public abstract class Source extends Module implements ISourceEventListener, ISo
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Buffer overflow listener
|
||||
*/
|
||||
protected IOverflowListener mOverflowListener;
|
||||
|
||||
/**
|
||||
* Adds the listener to receive heartbeats from this source
|
||||
*/
|
||||
@Override
|
||||
public void addHeartbeatListener(Listener<Heartbeat> listener)
|
||||
{
|
||||
getHeartbeatManager().addHeartbeatListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the listener from receiving heartbeats from this source
|
||||
*/
|
||||
@Override
|
||||
public void removeHeartbeatListener(Listener<Heartbeat> listener)
|
||||
{
|
||||
getHeartbeatManager().removeHeartbeatListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the type of samples provided by this source: real or complex
|
||||
*/
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2016 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 io.github.dsheirer.source;
|
||||
|
||||
import io.github.dsheirer.controller.channel.Channel;
|
||||
@@ -23,6 +25,7 @@ import io.github.dsheirer.gui.editor.EmptyEditor;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
import io.github.dsheirer.source.mixer.MixerSourceEditor;
|
||||
import io.github.dsheirer.source.tuner.TunerSourceEditor;
|
||||
import io.github.dsheirer.source.tuner.TunerSourceMultipleFrequencyEditor;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
@@ -37,99 +40,106 @@ public class SourceConfigurationEditor extends Editor<Channel>
|
||||
private JComboBox<SourceType> mComboSources;
|
||||
private MixerSourceEditor mMixerSourceEditor;
|
||||
private TunerSourceEditor mTunerSourceEditor;
|
||||
private TunerSourceMultipleFrequencyEditor mTunerSourceMultipleFrequencyEditor;
|
||||
private Editor<Channel> mCurrentEditor;
|
||||
|
||||
public SourceConfigurationEditor( SourceManager sourceManager )
|
||||
{
|
||||
mMixerSourceEditor = new MixerSourceEditor( sourceManager );
|
||||
mMixerSourceEditor.setSaveRequestListener( this );
|
||||
|
||||
mTunerSourceEditor = new TunerSourceEditor(sourceManager.getTunerModel());
|
||||
mTunerSourceEditor.setSaveRequestListener( this );
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
public SourceConfigurationEditor(SourceManager sourceManager)
|
||||
{
|
||||
mMixerSourceEditor = new MixerSourceEditor(sourceManager);
|
||||
mMixerSourceEditor.setSaveRequestListener(this);
|
||||
|
||||
mTunerSourceEditor = new TunerSourceEditor(sourceManager.getTunerModel());
|
||||
mTunerSourceEditor.setSaveRequestListener(this);
|
||||
|
||||
mTunerSourceMultipleFrequencyEditor = new TunerSourceMultipleFrequencyEditor(sourceManager.getTunerModel());
|
||||
mTunerSourceMultipleFrequencyEditor.setSaveRequestListener(this);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
public SourceConfiguration getSourceConfiguration()
|
||||
{
|
||||
return hasItem() ? getItem().getSourceConfiguration() : null;
|
||||
return hasItem() ? getItem().getSourceConfiguration() : null;
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "wrap 2", "[][grow,fill]", "[align top][grow]" ) );
|
||||
setLayout(new MigLayout("wrap 2", "[][grow,fill]", "[align top][grow,fill]"));
|
||||
|
||||
mComboSources = new JComboBox<SourceType>();
|
||||
mComboSources.setModel( new DefaultComboBoxModel<SourceType>( SourceType.getTypes() ) );
|
||||
mComboSources.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
SourceType selected = (SourceType)mComboSources.getSelectedItem();
|
||||
|
||||
switch( selected )
|
||||
{
|
||||
case MIXER:
|
||||
setEditor( mMixerSourceEditor );
|
||||
break;
|
||||
case TUNER:
|
||||
setEditor( mTunerSourceEditor );
|
||||
break;
|
||||
default:
|
||||
setEditor( new EmptyEditor<Channel>() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add( mComboSources );
|
||||
|
||||
mCurrentEditor = mTunerSourceEditor;
|
||||
add( mCurrentEditor );
|
||||
mComboSources = new JComboBox<SourceType>();
|
||||
mComboSources.setModel(new DefaultComboBoxModel<SourceType>(SourceType.getTypes()));
|
||||
mComboSources.addActionListener(new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e)
|
||||
{
|
||||
SourceType selected = (SourceType) mComboSources.getSelectedItem();
|
||||
|
||||
switch(selected)
|
||||
{
|
||||
case MIXER:
|
||||
setEditor(mMixerSourceEditor);
|
||||
break;
|
||||
case TUNER:
|
||||
setEditor(mTunerSourceEditor);
|
||||
break;
|
||||
case TUNER_MULTIPLE_FREQUENCIES:
|
||||
setEditor(mTunerSourceMultipleFrequencyEditor);
|
||||
break;
|
||||
default:
|
||||
setEditor(new EmptyEditor<Channel>());
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add(mComboSources);
|
||||
|
||||
mCurrentEditor = mTunerSourceEditor;
|
||||
add(mCurrentEditor, "span 1 2");
|
||||
}
|
||||
|
||||
private void setEditor( Editor<Channel> editor )
|
||||
|
||||
private void setEditor(Editor<Channel> editor)
|
||||
{
|
||||
if( mCurrentEditor != editor )
|
||||
{
|
||||
//Set channel to null to force a save prompt as required
|
||||
mCurrentEditor.setItem( null );
|
||||
|
||||
remove( mCurrentEditor );
|
||||
mCurrentEditor = editor;
|
||||
mCurrentEditor.setSaveRequestListener( this );
|
||||
add( mCurrentEditor );
|
||||
|
||||
mCurrentEditor.setItem( getItem() );
|
||||
|
||||
revalidate();
|
||||
}
|
||||
if(mCurrentEditor != editor)
|
||||
{
|
||||
//Set channel to null to force a save prompt as required
|
||||
mCurrentEditor.setItem(null);
|
||||
|
||||
remove(mCurrentEditor);
|
||||
mCurrentEditor = editor;
|
||||
mCurrentEditor.setSaveRequestListener(this);
|
||||
add(mCurrentEditor, "span 1 2");
|
||||
|
||||
mCurrentEditor.setItem(getItem());
|
||||
|
||||
revalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
if( hasItem() )
|
||||
{
|
||||
mCurrentEditor.save();
|
||||
}
|
||||
if(hasItem())
|
||||
{
|
||||
mCurrentEditor.save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the channel configuration. Note: this method must be invoked from
|
||||
* the swing event dispatch thread.
|
||||
*/
|
||||
@Override
|
||||
public void setItem( Channel channel )
|
||||
{
|
||||
super.setItem( channel );
|
||||
|
||||
if( hasItem() )
|
||||
{
|
||||
mComboSources.setSelectedItem( getItem().getSourceConfiguration().getSourceType() );
|
||||
repaint();
|
||||
mCurrentEditor.setItem( channel );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sets the channel configuration. Note: this method must be invoked from
|
||||
* the swing event dispatch thread.
|
||||
*/
|
||||
@Override
|
||||
public void setItem(Channel channel)
|
||||
{
|
||||
super.setItem(channel);
|
||||
|
||||
if(hasItem())
|
||||
{
|
||||
mComboSources.setSelectedItem(getItem().getSourceConfiguration().getSourceType());
|
||||
repaint();
|
||||
mCurrentEditor.setItem(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*******************************************************************************
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,8 +15,8 @@
|
||||
*
|
||||
* 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 io.github.dsheirer.source;
|
||||
|
||||
import java.util.EnumSet;
|
||||
@@ -31,6 +32,8 @@ public class SourceEvent
|
||||
NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_UNLOCKED,
|
||||
NOTIFICATION_FREQUENCY_CHANGE,
|
||||
NOTIFICATION_FREQUENCY_CORRECTION_CHANGE,
|
||||
NOTIFICATION_FREQUENCY_ROTATION_SUCCESS,
|
||||
NOTIFICATION_FREQUENCY_ROTATION_FAILURE,
|
||||
NOTIFICATION_MEASURED_FREQUENCY_ERROR,
|
||||
NOTIFICATION_MEASURED_FREQUENCY_ERROR_SYNC_LOCKED,
|
||||
NOTIFICATION_SAMPLE_RATE_CHANGE,
|
||||
@@ -38,6 +41,7 @@ public class SourceEvent
|
||||
|
||||
REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
|
||||
REQUEST_FREQUENCY_CHANGE,
|
||||
REQUEST_FREQUENCY_ROTATION,
|
||||
REQUEST_SOURCE_DISPOSE,
|
||||
REQUEST_START_SAMPLE_STREAM,
|
||||
REQUEST_STOP_SAMPLE_STREAM;
|
||||
@@ -64,6 +68,14 @@ public class SourceEvent
|
||||
mEventDescription = eventDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor. Use the static constructor methods to create an event.
|
||||
*/
|
||||
private SourceEvent(Event event)
|
||||
{
|
||||
this(event, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor. Use the static constructor methods to create an event.
|
||||
*/
|
||||
@@ -175,9 +187,9 @@ public class SourceEvent
|
||||
*
|
||||
* @param frequency in hertz
|
||||
*/
|
||||
public static SourceEvent frequencyChange(long frequency)
|
||||
public static SourceEvent frequencyChange(Source source, long frequency)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_CHANGE, frequency);
|
||||
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_CHANGE, source, frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,9 +198,9 @@ public class SourceEvent
|
||||
* @param frequency in hertz
|
||||
* @param eventDescription to add a tag to the event
|
||||
*/
|
||||
public static SourceEvent frequencyChange(long frequency, String eventDescription)
|
||||
public static SourceEvent frequencyChange(Source source, long frequency, String eventDescription)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_CHANGE, frequency, eventDescription);
|
||||
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_CHANGE, source, frequency, eventDescription);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,6 +350,33 @@ public class SourceEvent
|
||||
return new SourceEvent(Event.REQUEST_SOURCE_DISPOSE, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a request to cycle to the next source frequency. This is normally used for decoders to request the
|
||||
* next frequency in a list when a multiple-frequency source configuration is defined.
|
||||
*/
|
||||
public static SourceEvent frequencyRotationRequest()
|
||||
{
|
||||
return new SourceEvent(Event.REQUEST_FREQUENCY_ROTATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a notification that the request to rotate the source frequency to the next frequency in the list
|
||||
* was successful.
|
||||
*/
|
||||
public static SourceEvent frequencyRotationSuccessNotification(Source source, long frequency)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_ROTATION_SUCCESS, source, frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a notification that the request to rotate the source frequency to the next frequency in the list
|
||||
* was unsuccessful.
|
||||
*/
|
||||
public static SourceEvent frequencyRotationFailureNotification(Source source, long frequency)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_ROTATION_FAILURE, source, frequency);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -22,12 +22,16 @@ package io.github.dsheirer.source;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.settings.SettingsManager;
|
||||
import io.github.dsheirer.source.config.SourceConfigTuner;
|
||||
import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
import io.github.dsheirer.source.mixer.MixerManager;
|
||||
import io.github.dsheirer.source.recording.RecordingSourceManager;
|
||||
import io.github.dsheirer.source.tuner.TunerManager;
|
||||
import io.github.dsheirer.source.tuner.TunerModel;
|
||||
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
|
||||
import io.github.dsheirer.source.tuner.channel.MultiFrequencyTunerChannelSource;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||
|
||||
public class SourceManager
|
||||
{
|
||||
@@ -86,7 +90,29 @@ public class SourceManager
|
||||
retVal = mMixerManager.getSource(config);
|
||||
break;
|
||||
case TUNER:
|
||||
retVal = mTunerModel.getSource((SourceConfigTuner) config, channelSpecification);
|
||||
if(config instanceof SourceConfigTuner)
|
||||
{
|
||||
SourceConfigTuner sourceConfigTuner = (SourceConfigTuner)config;
|
||||
TunerChannel tunerChannel = sourceConfigTuner.getTunerChannel(channelSpecification.getBandwidth());
|
||||
String preferredTuner = sourceConfigTuner.getPreferredTuner();
|
||||
retVal = mTunerModel.getSource(tunerChannel, channelSpecification, preferredTuner);
|
||||
}
|
||||
break;
|
||||
case TUNER_MULTIPLE_FREQUENCIES:
|
||||
if(config instanceof SourceConfigTunerMultipleFrequency)
|
||||
{
|
||||
SourceConfigTunerMultipleFrequency sourceConfigTuner = (SourceConfigTunerMultipleFrequency)config;
|
||||
TunerChannel tunerChannel = sourceConfigTuner.getFirstTunerChannel(channelSpecification.getBandwidth());
|
||||
String preferredTuner = sourceConfigTuner.getPreferredTuner();
|
||||
|
||||
Source source = mTunerModel.getSource(tunerChannel, channelSpecification, preferredTuner);
|
||||
|
||||
if(source instanceof TunerChannelSource)
|
||||
{
|
||||
retVal = new MultiFrequencyTunerChannelSource(getTunerModel(), (TunerChannelSource)source,
|
||||
sourceConfigTuner.getFrequencies(), channelSpecification, sourceConfigTuner.getPreferredTuner());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RECORDING:
|
||||
retVal = mRecordingSourceManager.getSource(config, channelSpecification);
|
||||
|
||||
@@ -1,54 +1,51 @@
|
||||
/*******************************************************************************
|
||||
* 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/>
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 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 io.github.dsheirer.source;
|
||||
|
||||
|
||||
/**
|
||||
* Source Configuration Types enumeration.
|
||||
*/
|
||||
public enum SourceType
|
||||
{
|
||||
NONE( "No Source" ),
|
||||
MIXER( "Sound Card" ),
|
||||
TUNER( "Tuner" ),
|
||||
RECORDING( "IQ Recording" );
|
||||
|
||||
NONE("No Source"),
|
||||
MIXER("Sound Card"),
|
||||
TUNER("Tuner"),
|
||||
TUNER_MULTIPLE_FREQUENCIES("Tuner - Multiple Frequencies"),
|
||||
RECORDING("IQ Recording");
|
||||
|
||||
private String mDisplayString;
|
||||
|
||||
SourceType( String displayString )
|
||||
|
||||
SourceType(String displayString)
|
||||
{
|
||||
mDisplayString = displayString;
|
||||
}
|
||||
|
||||
|
||||
public static SourceType[] getTypes()
|
||||
{
|
||||
SourceType[] types = new SourceType[ 2 ];
|
||||
types[ 0 ] = SourceType.TUNER;
|
||||
types[ 1 ] = SourceType.MIXER;
|
||||
SourceType[] types = new SourceType[3];
|
||||
types[0] = SourceType.TUNER;
|
||||
types[1] = SourceType.TUNER_MULTIPLE_FREQUENCIES;
|
||||
types[2] = SourceType.MIXER;
|
||||
|
||||
return types;
|
||||
return types;
|
||||
}
|
||||
|
||||
public String getDisplayString()
|
||||
{
|
||||
return mDisplayString;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return mDisplayString;
|
||||
return mDisplayString;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
/*******************************************************************************
|
||||
* 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/>
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 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 io.github.dsheirer.source.config;
|
||||
|
||||
@@ -21,64 +19,74 @@ import io.github.dsheirer.source.SourceType;
|
||||
|
||||
public class SourceConfigFactory
|
||||
{
|
||||
public static SourceConfiguration getDefaultSourceConfiguration()
|
||||
{
|
||||
return getSourceConfiguration( SourceType.TUNER );
|
||||
}
|
||||
|
||||
public static SourceConfiguration getSourceConfiguration( SourceType source )
|
||||
{
|
||||
SourceConfiguration retVal;
|
||||
public static SourceConfiguration getDefaultSourceConfiguration()
|
||||
{
|
||||
return getSourceConfiguration(SourceType.TUNER);
|
||||
}
|
||||
|
||||
switch( source )
|
||||
{
|
||||
case TUNER:
|
||||
retVal = new SourceConfigTuner();
|
||||
break;
|
||||
case MIXER:
|
||||
retVal = new SourceConfigMixer();
|
||||
break;
|
||||
case NONE:
|
||||
default:
|
||||
retVal = new SourceConfigNone();
|
||||
break;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
public static SourceConfiguration getSourceConfiguration(SourceType source)
|
||||
{
|
||||
SourceConfiguration retVal;
|
||||
|
||||
/**
|
||||
* Creates a copy of the configuration
|
||||
*/
|
||||
public static SourceConfiguration copy( SourceConfiguration config )
|
||||
{
|
||||
if( config != null )
|
||||
{
|
||||
switch( config.getSourceType() )
|
||||
{
|
||||
case MIXER:
|
||||
SourceConfigMixer originalMixer = (SourceConfigMixer)config;
|
||||
SourceConfigMixer copyMixer = new SourceConfigMixer();
|
||||
copyMixer.setChannel( originalMixer.getChannel() );
|
||||
copyMixer.setMixer( originalMixer.getMixer() );
|
||||
return copyMixer;
|
||||
case RECORDING:
|
||||
SourceConfigRecording originalRec = (SourceConfigRecording)config;
|
||||
SourceConfigRecording copyRec = new SourceConfigRecording();
|
||||
copyRec.setFrequency( originalRec.getFrequency() );
|
||||
copyRec.setRecordingAlias( originalRec.getRecordingAlias() );
|
||||
return copyRec;
|
||||
case TUNER:
|
||||
SourceConfigTuner originalTuner = (SourceConfigTuner)config;
|
||||
SourceConfigTuner copyTuner = new SourceConfigTuner();
|
||||
copyTuner.setFrequency( originalTuner.getFrequency() );
|
||||
return copyTuner;
|
||||
case NONE:
|
||||
default:
|
||||
return new SourceConfigNone();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
switch(source)
|
||||
{
|
||||
case TUNER:
|
||||
retVal = new SourceConfigTuner();
|
||||
break;
|
||||
case TUNER_MULTIPLE_FREQUENCIES:
|
||||
retVal = new SourceConfigTunerMultipleFrequency();
|
||||
break;
|
||||
case MIXER:
|
||||
retVal = new SourceConfigMixer();
|
||||
break;
|
||||
case NONE:
|
||||
default:
|
||||
retVal = new SourceConfigNone();
|
||||
break;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of the configuration
|
||||
*/
|
||||
public static SourceConfiguration copy(SourceConfiguration config)
|
||||
{
|
||||
if(config != null)
|
||||
{
|
||||
switch(config.getSourceType())
|
||||
{
|
||||
case MIXER:
|
||||
SourceConfigMixer originalMixer = (SourceConfigMixer) config;
|
||||
SourceConfigMixer copyMixer = new SourceConfigMixer();
|
||||
copyMixer.setChannel(originalMixer.getChannel());
|
||||
copyMixer.setMixer(originalMixer.getMixer());
|
||||
return copyMixer;
|
||||
case RECORDING:
|
||||
SourceConfigRecording originalRec = (SourceConfigRecording) config;
|
||||
SourceConfigRecording copyRec = new SourceConfigRecording();
|
||||
copyRec.setFrequency(originalRec.getFrequency());
|
||||
copyRec.setRecordingAlias(originalRec.getRecordingAlias());
|
||||
return copyRec;
|
||||
case TUNER:
|
||||
SourceConfigTuner originalTuner = (SourceConfigTuner) config;
|
||||
SourceConfigTuner copyTuner = new SourceConfigTuner();
|
||||
copyTuner.setPreferredTuner(originalTuner.getPreferredTuner());
|
||||
copyTuner.setFrequency(originalTuner.getFrequency());
|
||||
return copyTuner;
|
||||
case TUNER_MULTIPLE_FREQUENCIES:
|
||||
SourceConfigTunerMultipleFrequency originalMulti = (SourceConfigTunerMultipleFrequency) config;
|
||||
SourceConfigTunerMultipleFrequency copyMulti = new SourceConfigTunerMultipleFrequency();
|
||||
copyMulti.setPreferredTuner(originalMulti.getPreferredTuner());
|
||||
copyMulti.setFrequencies(originalMulti.getFrequencies());
|
||||
return copyMulti;
|
||||
case NONE:
|
||||
default:
|
||||
return new SourceConfigNone();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* 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.
|
||||
* 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/>
|
||||
******************************************************************************/
|
||||
* 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 io.github.dsheirer.source.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
@@ -31,7 +33,6 @@ public class SourceConfigTuner extends SourceConfiguration
|
||||
private static DecimalFormat FREQUENCY_FORMAT = new DecimalFormat("0.00000");
|
||||
|
||||
private long mFrequency = 0;
|
||||
private int mBandwidth = 12500;
|
||||
private String mPreferredTuner;
|
||||
|
||||
public SourceConfigTuner()
|
||||
@@ -42,9 +43,7 @@ public class SourceConfigTuner extends SourceConfiguration
|
||||
public SourceConfigTuner(TunerChannel tunerChannel)
|
||||
{
|
||||
this();
|
||||
|
||||
mFrequency = tunerChannel.getFrequency();
|
||||
mBandwidth = tunerChannel.getBandwidth();
|
||||
}
|
||||
|
||||
@JacksonXmlProperty(isAttribute = true, localName = "frequency")
|
||||
@@ -94,8 +93,8 @@ public class SourceConfigTuner extends SourceConfiguration
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public TunerChannel getTunerChannel()
|
||||
public TunerChannel getTunerChannel(int bandwidth)
|
||||
{
|
||||
return new TunerChannel(mFrequency, mBandwidth);
|
||||
return new TunerChannel(mFrequency, bandwidth);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 io.github.dsheirer.source.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import io.github.dsheirer.source.SourceType;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Multiple frequency tuner source configuration is used for a system with a rolling/rotating control
|
||||
* channel where the control channel rotates across a pre-defined set of channel frequencies.
|
||||
*/
|
||||
@JsonSubTypes.Type(value = SourceConfigTunerMultipleFrequency.class, name = "sourceConfigTunerMultipleFrequency")
|
||||
public class SourceConfigTunerMultipleFrequency extends SourceConfiguration
|
||||
{
|
||||
private List<Long> mFrequencies = new ArrayList<>();
|
||||
private String mPreferredTuner;
|
||||
|
||||
public SourceConfigTunerMultipleFrequency()
|
||||
{
|
||||
super(SourceType.TUNER_MULTIPLE_FREQUENCIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* List of frequencies for this configuration
|
||||
*/
|
||||
@JacksonXmlProperty(isAttribute = false, localName = "frequency")
|
||||
public List<Long> getFrequencies()
|
||||
{
|
||||
return mFrequencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of frequencies for this configuration
|
||||
*/
|
||||
public void setFrequencies(List<Long> frequencies)
|
||||
{
|
||||
mFrequencies = frequencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this configuration has more than one frequency specified
|
||||
*/
|
||||
@JsonIgnore
|
||||
public boolean hasMultipleFrequencies()
|
||||
{
|
||||
return mFrequencies.size() > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a frequency to the list
|
||||
*/
|
||||
public void addFrequency(long frequency)
|
||||
{
|
||||
mFrequencies.add(frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Preferred tuner to use for this configuration.
|
||||
* @return tuner name or null
|
||||
*/
|
||||
@JacksonXmlProperty(isAttribute = true, localName = "preferred_tuner")
|
||||
public String getPreferredTuner()
|
||||
{
|
||||
return mPreferredTuner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this configuration has a specified preferred tuner
|
||||
*/
|
||||
@JsonIgnore
|
||||
public boolean hasPreferredTuner()
|
||||
{
|
||||
return mPreferredTuner != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the preferred tuner to use for this configuration
|
||||
* @param preferredTuner to use, if available
|
||||
*/
|
||||
public void setPreferredTuner(String preferredTuner)
|
||||
{
|
||||
mPreferredTuner = preferredTuner;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public String getDescription()
|
||||
{
|
||||
return "Frequencies [" + mFrequencies.size() + "]";
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public TunerChannel getFirstTunerChannel(int bandwidth)
|
||||
{
|
||||
if(getFrequencies().size() > 0)
|
||||
{
|
||||
return new TunerChannel(getFrequencies().get(0), bandwidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new TunerChannel(0l, bandwidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ import io.github.dsheirer.source.SourceType;
|
||||
@JsonSubTypes.Type(value = SourceConfigNone.class, name = "sourceConfigNone"),
|
||||
@JsonSubTypes.Type(value = SourceConfigRecording.class, name = "sourceConfigRecording"),
|
||||
@JsonSubTypes.Type(value = SourceConfigTuner.class, name = "sourceConfigTuner"),
|
||||
})
|
||||
@JsonSubTypes.Type(value = SourceConfigTunerMultipleFrequency.class, name = "sourceConfigTunerMultipleFrequency")})
|
||||
@JacksonXmlRootElement(localName = "source_configuration")
|
||||
public class SourceConfiguration extends Configuration
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*******************************************************************************
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,11 +15,22 @@
|
||||
*
|
||||
* 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 io.github.dsheirer.source.heartbeat;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
|
||||
public interface IHeartbeatProvider
|
||||
{
|
||||
public HeartbeatManager getHeartbeatManager();
|
||||
/**
|
||||
* Adds the listener to receive heartbeats
|
||||
*/
|
||||
void addHeartbeatListener(Listener<Heartbeat> listener);
|
||||
|
||||
/**
|
||||
* Removes the listener from receiving heartbeats
|
||||
* @param listener
|
||||
*/
|
||||
void removeHeartbeatListener(Listener<Heartbeat> listener);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -20,7 +20,7 @@
|
||||
package io.github.dsheirer.source.tuner;
|
||||
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.preference.tuner.ChannelizerType;
|
||||
import io.github.dsheirer.preference.source.ChannelizerType;
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
* 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.
|
||||
* 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/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* 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 io.github.dsheirer.source.tuner;
|
||||
|
||||
import io.github.dsheirer.properties.SystemProperties;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.source.Source;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.config.SourceConfigTuner;
|
||||
import io.github.dsheirer.source.tuner.TunerEvent.Event;
|
||||
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
|
||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||
@@ -335,62 +338,60 @@ public class TunerModel extends AbstractTableModel implements Listener<TunerEven
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates current tuners to get a tuner channel source for the frequency
|
||||
* specified in the channel config's source config object.
|
||||
* Iterates current tuners to get a tuner channel source for the specified frequency and bandwidth
|
||||
*
|
||||
* Returns null if no tuner can source the channel
|
||||
*/
|
||||
public Source getSource(SourceConfigTuner config, ChannelSpecification channelSpecification)
|
||||
public Source getSource(TunerChannel tunerChannel, ChannelSpecification channelSpecification, String preferredTuner)
|
||||
{
|
||||
TunerChannelSource retVal = null;
|
||||
TunerChannelSource source = null;
|
||||
|
||||
TunerChannel tunerChannel = config.getTunerChannel();
|
||||
|
||||
tunerChannel.setBandwidth(channelSpecification.getBandwidth());
|
||||
|
||||
Iterator<Tuner> it = mTuners.iterator();
|
||||
|
||||
Tuner tuner;
|
||||
|
||||
if(config.hasPreferredTuner())
|
||||
if(tunerChannel != null && channelSpecification != null)
|
||||
{
|
||||
tuner = getTuner(config.getPreferredTuner());
|
||||
Iterator<Tuner> it = mTuners.iterator();
|
||||
|
||||
if(tuner != null)
|
||||
Tuner tuner;
|
||||
|
||||
if(preferredTuner != null)
|
||||
{
|
||||
tuner = getTuner(preferredTuner);
|
||||
|
||||
if(tuner != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
source = tuner.getChannelSourceManager().getSource(tunerChannel, channelSpecification);
|
||||
|
||||
if(source != null)
|
||||
{
|
||||
return source;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
//Fall through to logger below
|
||||
}
|
||||
}
|
||||
|
||||
mLog.info("Unable to source channel [" + tunerChannel.getFrequency() + "] from preferred tuner [" +
|
||||
preferredTuner + "] - searching for another tuner");
|
||||
}
|
||||
|
||||
while(it.hasNext() && source == null)
|
||||
{
|
||||
tuner = it.next();
|
||||
|
||||
try
|
||||
{
|
||||
retVal = tuner.getChannelSourceManager().getSource(tunerChannel, channelSpecification);
|
||||
|
||||
if(retVal != null)
|
||||
{
|
||||
return retVal;
|
||||
}
|
||||
source = tuner.getChannelSourceManager().getSource(tunerChannel, channelSpecification);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
//Fall through to logger below
|
||||
mLog.error("Error obtaining channel from tuner [" + tuner.getName() + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
mLog.info("Unable to source channel [" + config.getFrequency() + "] from preferred tuner [" +
|
||||
config.getPreferredTuner() + "] - searching for another tuner");
|
||||
}
|
||||
|
||||
while(it.hasNext() && retVal == null)
|
||||
{
|
||||
tuner = it.next();
|
||||
|
||||
try
|
||||
{
|
||||
retVal = tuner.getChannelSourceManager().getSource(tunerChannel, channelSpecification);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
mLog.error("error obtaining channel from tuner [" + tuner.getName() + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
return source;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 io.github.dsheirer.source.tuner;
|
||||
|
||||
import io.github.dsheirer.controller.channel.Channel;
|
||||
import io.github.dsheirer.gui.control.MultipleFrequencyEditor;
|
||||
import io.github.dsheirer.gui.editor.Editor;
|
||||
import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.event.TableModelEvent;
|
||||
import javax.swing.event.TableModelListener;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class TunerSourceMultipleFrequencyEditor extends Editor<Channel>
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String NO_PREFERRED_TUNER = "(none)";
|
||||
private static final String UNAVAILABLE_TUNER = " (unavailable)";
|
||||
private MultipleFrequencyEditor mFrequencyEditor = new MultipleFrequencyEditor(0.0, 6000.0);
|
||||
private JComboBox<String> mTunerNameComboBox;
|
||||
private TunerModel mTunerModel;
|
||||
private List<String> mCurrentTunerNames;
|
||||
|
||||
public TunerSourceMultipleFrequencyEditor(TunerModel tunerModel)
|
||||
{
|
||||
mTunerModel = tunerModel;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
loadTunerNames();
|
||||
|
||||
setLayout(new MigLayout("insets 0 0 0 0",
|
||||
"[grow,fill][][right][grow,fill,left]", "[][grow,fill]"));
|
||||
|
||||
mFrequencyEditor.getFrequencyModel().addTableModelListener(new TableModelListener()
|
||||
{
|
||||
@Override
|
||||
public void tableChanged(TableModelEvent e)
|
||||
{
|
||||
setModified(true);
|
||||
}
|
||||
});
|
||||
// mFrequencyEditor.setSize(new Dimension(100, 30));
|
||||
add(mFrequencyEditor, "span 2 2");
|
||||
|
||||
mTunerNameComboBox = new JComboBox<>(mCurrentTunerNames.toArray(new String[mCurrentTunerNames.size()]));
|
||||
mTunerNameComboBox.addActionListener(new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e)
|
||||
{
|
||||
setModified(true);
|
||||
}
|
||||
});
|
||||
add(new JLabel("Preferred Tuner:"));
|
||||
add(mTunerNameComboBox);
|
||||
}
|
||||
|
||||
private void loadTunerNames()
|
||||
{
|
||||
mCurrentTunerNames = new ArrayList<>();
|
||||
|
||||
for(Tuner tuner: mTunerModel.getTuners())
|
||||
{
|
||||
mCurrentTunerNames.add(tuner.getName());
|
||||
}
|
||||
|
||||
Collections.sort(mCurrentTunerNames);
|
||||
|
||||
mCurrentTunerNames.add(0, NO_PREFERRED_TUNER);
|
||||
}
|
||||
|
||||
private void updateTunerNameCombo(String preferredTuner)
|
||||
{
|
||||
if(preferredTuner != null && !mCurrentTunerNames.contains(preferredTuner))
|
||||
{
|
||||
List<String> updatedTunerNameList = new ArrayList<>(mCurrentTunerNames);
|
||||
String unavailableTuner = preferredTuner + UNAVAILABLE_TUNER;
|
||||
updatedTunerNameList.add(unavailableTuner);
|
||||
String[] tunerNameArray = updatedTunerNameList.toArray(new String[updatedTunerNameList.size()]);
|
||||
mTunerNameComboBox.setModel(new DefaultComboBoxModel<>(tunerNameArray));
|
||||
mTunerNameComboBox.setSelectedItem(unavailableTuner);
|
||||
}
|
||||
else
|
||||
{
|
||||
String[] tunerNameArray = mCurrentTunerNames.toArray(new String[mCurrentTunerNames.size()]);
|
||||
mTunerNameComboBox.setModel(new DefaultComboBoxModel<>(tunerNameArray));
|
||||
|
||||
if(preferredTuner == null)
|
||||
{
|
||||
mTunerNameComboBox.setSelectedItem(NO_PREFERRED_TUNER);
|
||||
}
|
||||
else
|
||||
{
|
||||
mTunerNameComboBox.setSelectedItem(preferredTuner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void save()
|
||||
{
|
||||
if(hasItem() && isModified())
|
||||
{
|
||||
SourceConfigTunerMultipleFrequency config = new SourceConfigTunerMultipleFrequency();
|
||||
|
||||
String preferredTuner = (String)mTunerNameComboBox.getSelectedItem();
|
||||
|
||||
if(preferredTuner != null)
|
||||
{
|
||||
if(preferredTuner.equalsIgnoreCase(NO_PREFERRED_TUNER))
|
||||
{
|
||||
config.setPreferredTuner(null);
|
||||
}
|
||||
else if(preferredTuner.contains(UNAVAILABLE_TUNER))
|
||||
{
|
||||
//don't do anything - the config already contains this unavailable tuner name
|
||||
}
|
||||
else
|
||||
{
|
||||
config.setPreferredTuner(preferredTuner);
|
||||
}
|
||||
}
|
||||
|
||||
config.setFrequencies(mFrequencyEditor.getFrequencyModel().getFrequencies());
|
||||
|
||||
getItem().setSourceConfiguration(config);
|
||||
}
|
||||
|
||||
setModified(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(Channel item)
|
||||
{
|
||||
super.setItem(item);
|
||||
|
||||
mFrequencyEditor.getFrequencyModel().clear();
|
||||
|
||||
if(hasItem())
|
||||
{
|
||||
SourceConfiguration config = getItem().getSourceConfiguration();
|
||||
|
||||
if(config instanceof SourceConfigTunerMultipleFrequency)
|
||||
{
|
||||
SourceConfigTunerMultipleFrequency tunerConfig = (SourceConfigTunerMultipleFrequency) config;
|
||||
updateTunerNameCombo(tunerConfig.getPreferredTuner());
|
||||
mFrequencyEditor.getFrequencyModel().setFrequencies(tunerConfig.getFrequencies());
|
||||
setModified(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setModified(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 io.github.dsheirer.source.tuner.channel;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import io.github.dsheirer.channel.state.State;
|
||||
import io.github.dsheirer.eventbus.MyEventBus;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.identifier.IdentifierUpdateListener;
|
||||
import io.github.dsheirer.identifier.IdentifierUpdateNotification;
|
||||
import io.github.dsheirer.identifier.decoder.ChannelStateIdentifier;
|
||||
import io.github.dsheirer.module.Module;
|
||||
import io.github.dsheirer.preference.PreferenceType;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.source.ISourceEventProvider;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Monitors channel state to detect when a channel is not in an identified active state and issues a request to rotate
|
||||
* the next channel frequency in the list.
|
||||
*/
|
||||
public class ChannelRotationMonitor extends Module implements ISourceEventProvider, IdentifierUpdateListener,
|
||||
Listener<IdentifierUpdateNotification>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ChannelRotationMonitor.class);
|
||||
|
||||
private UserPreferences mUserPreferences;
|
||||
private Collection<State> mActiveStates;
|
||||
private ScheduledFuture<?> mScheduledFuture;
|
||||
private Listener<SourceEvent> mSourceEventListener;
|
||||
private long mRotationDelay;
|
||||
private boolean mActive;
|
||||
private long mInactiveTimestamp = System.currentTimeMillis();
|
||||
|
||||
/**
|
||||
* Constructs a channel rotation monitor.
|
||||
*
|
||||
* @param activeStates to monitor
|
||||
* @param userPreferences to receive updates for rotation delay value from user preferences
|
||||
*/
|
||||
public ChannelRotationMonitor(Collection<State> activeStates, UserPreferences userPreferences)
|
||||
{
|
||||
mActiveStates = activeStates;
|
||||
mUserPreferences = userPreferences;
|
||||
mRotationDelay = mUserPreferences.getChannelMultiFrequencyPreference().getRotationDelay();
|
||||
|
||||
//Register to receive user preference updates
|
||||
MyEventBus.getEventBus().register(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the external listener to receive frequency rotation requests from this module
|
||||
*/
|
||||
@Override
|
||||
public void setSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
mSourceEventListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters the external listener from receiving frequency rotation requests.
|
||||
*/
|
||||
@Override
|
||||
public void removeSourceEventListener()
|
||||
{
|
||||
mSourceEventListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<IdentifierUpdateNotification> getIdentifierUpdateListener()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary method for receiving channel state identifier notifications, enabling this module to track the
|
||||
* current channel state being provided by the Channel State module.
|
||||
*/
|
||||
@Override
|
||||
public void receive(IdentifierUpdateNotification identifierUpdateNotification)
|
||||
{
|
||||
Identifier identifier = identifierUpdateNotification.getIdentifier();
|
||||
|
||||
if(identifier instanceof ChannelStateIdentifier)
|
||||
{
|
||||
State currentState = ((ChannelStateIdentifier)identifier).getValue();
|
||||
|
||||
if(mActiveStates.contains(currentState))
|
||||
{
|
||||
mActive = true;
|
||||
}
|
||||
else if(mActive)
|
||||
{
|
||||
mActive = false;
|
||||
mInactiveTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the current active state and when inactive for longer than the specified delay, issues a
|
||||
* channel frequency rotation request
|
||||
*/
|
||||
private void checkState()
|
||||
{
|
||||
if(mSourceEventListener != null && !mActive &&
|
||||
((mInactiveTimestamp + mRotationDelay) < System.currentTimeMillis()))
|
||||
{
|
||||
mSourceEventListener.receive(SourceEvent.frequencyRotationRequest());
|
||||
mInactiveTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Guava event bus method to receive notifications when user preferences are updated. This allows us to
|
||||
* dynamically adjust rotation delay if/when the user changes the rotation delay value.
|
||||
*/
|
||||
@Subscribe
|
||||
public void preferenceUpdated(PreferenceType preferenceType)
|
||||
{
|
||||
if(preferenceType == PreferenceType.MULTI_FREQUENCY)
|
||||
{
|
||||
mRotationDelay = mUserPreferences.getChannelMultiFrequencyPreference().getRotationDelay();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
if(mScheduledFuture == null)
|
||||
{
|
||||
mScheduledFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(() -> checkState(), 1, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
if(mScheduledFuture != null)
|
||||
{
|
||||
mScheduledFuture.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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 io.github.dsheirer.source.tuner.channel;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.source.Source;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.heartbeat.Heartbeat;
|
||||
import io.github.dsheirer.source.tuner.TunerModel;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Multiple-frequency tuner channel source. Provides a wrapper around a tuner channel source and listens for external
|
||||
* source events requests to change frequency. Maintains an ordered list of frequencies and automatically tears down
|
||||
* an existing tuner channel source and obtains a new one with the next frequency from the list, on request.
|
||||
*/
|
||||
public class MultiFrequencyTunerChannelSource extends TunerChannelSource
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(MultiFrequencyTunerChannelSource.class);
|
||||
|
||||
private TunerModel mTunerModel;
|
||||
private TunerChannelSource mTunerChannelSource;
|
||||
private List<Long> mFrequencies;
|
||||
private int mFrequencyListPointer = 0;
|
||||
private ChannelSpecification mChannelSpecification;
|
||||
private Listener<ReusableComplexBuffer> mReusableComplexBufferListener;
|
||||
private Listener<Heartbeat> mHeartbeatListener;
|
||||
private String mPreferredTuner;
|
||||
private AtomicBoolean mChangingChannels = new AtomicBoolean();
|
||||
private boolean mStarted;
|
||||
private ConsumerSourceEventAdapter mConsumerSourceEventAdapter = new ConsumerSourceEventAdapter();
|
||||
|
||||
public MultiFrequencyTunerChannelSource(TunerModel tunerModel, TunerChannelSource tunerChannelSource,
|
||||
List<Long> frequencies, ChannelSpecification channelSpecification,
|
||||
String preferredTuner)
|
||||
{
|
||||
super(null, tunerChannelSource.getTunerChannel());
|
||||
mTunerModel = tunerModel;
|
||||
mTunerChannelSource = tunerChannelSource;
|
||||
mTunerChannelSource.setSourceEventListener(mConsumerSourceEventAdapter);
|
||||
mFrequencies = frequencies;
|
||||
mChannelSpecification = channelSpecification;
|
||||
mPreferredTuner = preferredTuner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycles this source to use the next frequency in the list
|
||||
*/
|
||||
private void nextFrequency()
|
||||
{
|
||||
if(mChangingChannels.compareAndSet(false, true))
|
||||
{
|
||||
//Only change if we have more than one frequency specified
|
||||
if(mFrequencies.size() > 0)
|
||||
{
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
//Shutdown the existing tuner channel source
|
||||
mTunerChannelSource.stop();
|
||||
mTunerChannelSource.removeListener(mReusableComplexBufferListener);
|
||||
mTunerChannelSource.removeSourceEventListener();
|
||||
mTunerChannelSource.removeHeartbeatListener(mHeartbeatListener);
|
||||
mTunerChannelSource.dispose();
|
||||
mTunerChannelSource = null;
|
||||
}
|
||||
|
||||
//Request the next tuner channel source
|
||||
getNextSource();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Persistently attempts to get the next tuner channel source using the next frequency in the list. This method
|
||||
* should only be invoked by the nextFrequency() method that protects access via the mChangingChannels flag.
|
||||
*
|
||||
* Note: if this channel source is shutdown by the external consumer, the mStarted flag will be set to false and
|
||||
* the persistent attempts will stop.
|
||||
*/
|
||||
private void getNextSource()
|
||||
{
|
||||
if(mStarted)
|
||||
{
|
||||
TunerChannel nextChannel = getNextChannel();
|
||||
Source source = mTunerModel.getSource(nextChannel, mChannelSpecification, mPreferredTuner);
|
||||
|
||||
if(source instanceof TunerChannelSource)
|
||||
{
|
||||
mTunerChannelSource = (TunerChannelSource)source;
|
||||
mTunerChannelSource.setSourceEventListener(mConsumerSourceEventAdapter);
|
||||
mTunerChannelSource.setListener(mReusableComplexBufferListener);
|
||||
mTunerChannelSource.addHeartbeatListener(mHeartbeatListener);
|
||||
mTunerChannelSource.start();
|
||||
mChangingChannels.set(false);
|
||||
getSourceEventListener().receive(SourceEvent.frequencyRotationSuccessNotification(this, nextChannel.getFrequency()));
|
||||
}
|
||||
|
||||
//If we don't get a channel source because a tuner is not available or none of the available tuners can
|
||||
//support the frequency, then persistently attempt to get a source by iterating the frequency list
|
||||
if(mTunerChannelSource == null)
|
||||
{
|
||||
getSourceEventListener().receive(SourceEvent.frequencyRotationFailureNotification(this, nextChannel.getFrequency()));
|
||||
ThreadPool.SCHEDULED.schedule(() -> getNextSource(), 1, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
//The initial source should not be null
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
mTunerChannelSource.start();
|
||||
mStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
mStarted = false;
|
||||
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
mTunerChannelSource.stop();
|
||||
mTunerChannelSource.removeSourceEventListener();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the next tuner channel from the frequency list.
|
||||
*/
|
||||
private TunerChannel getNextChannel()
|
||||
{
|
||||
mFrequencyListPointer++;
|
||||
|
||||
if(mFrequencyListPointer >= mFrequencies.size())
|
||||
{
|
||||
mFrequencyListPointer = 0;
|
||||
}
|
||||
|
||||
long frequency = mFrequencies.get(mFrequencyListPointer);
|
||||
|
||||
return new TunerChannel(frequency, mChannelSpecification.getBandwidth());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the heartbeat listener to receive heartbeats from the enclosed tuner channel source.
|
||||
*/
|
||||
@Override
|
||||
public void addHeartbeatListener(Listener<Heartbeat> listener)
|
||||
{
|
||||
mHeartbeatListener = listener;
|
||||
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
mTunerChannelSource.addHeartbeatListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the heartbeat listener from receiving heartbeats from the enclosed tuner channel source
|
||||
*/
|
||||
@Override
|
||||
public void removeHeartbeatListener(Listener<Heartbeat> listener)
|
||||
{
|
||||
mHeartbeatListener = null;
|
||||
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
mTunerChannelSource.removeHeartbeatListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrequency(long frequency)
|
||||
{
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
mTunerChannelSource.setFrequency(frequency);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setSampleRate(double sampleRate)
|
||||
{
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
mTunerChannelSource.setSampleRate(sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setChannelFrequencyCorrection(long correction)
|
||||
{
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
mTunerChannelSource.setChannelFrequencyCorrection(correction);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChannelFrequencyCorrection()
|
||||
{
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
return mTunerChannelSource.getChannelFrequencyCorrection();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processSamples()
|
||||
{
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
mTunerChannelSource.processSamples();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener(Listener<ReusableComplexBuffer> complexBufferListener)
|
||||
{
|
||||
mReusableComplexBufferListener = complexBufferListener;
|
||||
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
mTunerChannelSource.setListener(complexBufferListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(Listener<ReusableComplexBuffer> listener)
|
||||
{
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
mTunerChannelSource.removeListener(listener);
|
||||
}
|
||||
|
||||
mReusableComplexBufferListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSampleRate()
|
||||
{
|
||||
if(mTunerChannelSource != null)
|
||||
{
|
||||
return mTunerChannelSource.getSampleRate();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the parent method so that we can intercept external requests to change to the next frequency in the
|
||||
* frequency list.
|
||||
*
|
||||
* @param sourceEvent to process
|
||||
* @throws SourceException
|
||||
*/
|
||||
@Override
|
||||
public void process(SourceEvent sourceEvent) throws SourceException
|
||||
{
|
||||
if(sourceEvent.getEvent() == SourceEvent.Event.REQUEST_FREQUENCY_ROTATION)
|
||||
{
|
||||
nextFrequency();
|
||||
}
|
||||
else if(mTunerChannelSource != null)
|
||||
{
|
||||
mTunerChannelSource.process(sourceEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for source events produced by the enclosed tuner channel source. This adapter receives events from
|
||||
* the wrapped tuner channel source and rebroadcasts them as consumer source events from this enclosing multi-frequency
|
||||
* tuner channel source and to the registered external consumer source event listener.
|
||||
*/
|
||||
public class ConsumerSourceEventAdapter implements Listener<SourceEvent>
|
||||
{
|
||||
@Override
|
||||
public void receive(SourceEvent sourceEvent)
|
||||
{
|
||||
broadcastConsumerSourceEvent(sourceEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
/*******************************************************************************
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,8 +15,8 @@
|
||||
*
|
||||
* 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 io.github.dsheirer.source.tuner.channel;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
@@ -117,7 +118,7 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
|
||||
public void start()
|
||||
{
|
||||
//Broadcast current frequency and sample rate so consumer can configure correctly
|
||||
broadcastConsumerSourceEvent(SourceEvent.frequencyChange(getFrequency()));
|
||||
broadcastConsumerSourceEvent(SourceEvent.frequencyChange(this, getFrequency(), "Startup"));
|
||||
broadcastProducerSourceEvent(SourceEvent.startSampleStreamRequest(this));
|
||||
mScheduledIntervalProcessor.start();
|
||||
}
|
||||
@@ -186,6 +187,10 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
|
||||
case REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
|
||||
setChannelFrequencyCorrection(sourceEvent.getValue().longValue());
|
||||
break;
|
||||
case NOTIFICATION_FREQUENCY_ROTATION_FAILURE:
|
||||
case NOTIFICATION_FREQUENCY_ROTATION_SUCCESS:
|
||||
//Ignore
|
||||
break;
|
||||
default:
|
||||
mLog.error("Ignoring unrecognized source event: " + sourceEvent.getEvent() + " from [" +
|
||||
(sourceEvent.hasSource() ? sourceEvent.getSource().getClass() : "") + "]");
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
* 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.
|
||||
* 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/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* 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 io.github.dsheirer.source.tuner.frequency;
|
||||
|
||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||
@@ -267,7 +271,7 @@ public class FrequencyController
|
||||
*/
|
||||
protected void broadcastFrequencyChange() throws SourceException
|
||||
{
|
||||
broadcast(SourceEvent.frequencyChange(mFrequency));
|
||||
broadcast(SourceEvent.frequencyChange(null, mFrequency));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user