Compare commits

...

23 Commits

Author SHA1 Message Date
Denny
fbc6e508bd Increments build to 0.3.0-beta10 2017-04-14 07:46:18 -04:00
Denny Sheirer
f9b6e67b00 Merge pull request #240 from DSheirer/234-long-alias-names-cause-audio-label-to-wrap
Long alias names cause audio label to wrap
2017-03-31 01:13:17 +00:00
Denny
a628800a71 Resolves #234 - updates the miglayout layout manager to allow jlabel text strings to be automatically truncated (with ellipses) when the alias name is too long. 2017-03-30 21:12:06 -04:00
Denny
25f71a76c4 Resolves #234 - hard codes alias name truncation when name exceeds 33 characters in length. 2017-03-30 20:03:48 -04:00
Denny
5fe8ccd478 Resolves #234 - change the order of assigning an icon and alias text to the audio panel in an attempt to prevent the audio channel panel from wrapping to the next line when the text is too long to display. 2017-03-30 19:52:35 -04:00
Denny Sheirer
069f951a86 Merge pull request #239 from DSheirer/228-traffic-channel-allocation-for-do-not-monitor
Traffic channel manager now allocates traffic channels for do not monitor aliases
2017-03-30 23:27:38 +00:00
Denny
dab6df7836 Resolves #228 - traffic channel manager now allocates traffic channels even when the alias is marked as do not monitor 2017-03-30 19:26:35 -04:00
Denny Sheirer
89da46b63c Merge pull request #238 from DSheirer/235-lojack-decoder-error-on-construction
Resolves error on constructing a LoJack decoder state.
2017-03-30 23:19:29 +00:00
Denny
5f2ce2a9f2 Resolves #235 - fixes error on constructing a LoJack decoder state. 2017-03-30 19:18:39 -04:00
Denny Sheirer
7a0b377971 Merge pull request #232 from DSheirer/229-p25-phase2-event-duplicates
Resolves #229 - duplicate P25 TDMA call events.
2017-03-23 21:52:47 +00:00
Denny
5dbe0ecce3 Resolves #229 - duplicate P25 TDMA call events. 2017-03-23 21:48:52 +00:00
Denny Sheirer
6647c581a6 Merge pull request #231 from DSheirer/230-p25-tdma-frequency-bands
P25 Phase II TDMA frequency bands are now displayed in details summary
2017-03-23 21:01:58 +00:00
Denny
a2ab5bfa95 Resolves #230 - P25 Phase II TDMA frequency bands are now displayed in the channel details summary. 2017-03-23 20:55:42 +00:00
Denny
ed486440b8 Merge remote-tracking branch 'origin/master' 2017-03-12 11:33:17 -04:00
Denny
13464e01fc Updates build to 0.3.0 Beta 9 2017-03-12 11:33:04 -04:00
Denny Sheirer
ea46a8b0e8 Merge pull request #225 from DSheirer/222-spectral-display-of-frequency-correction-offset
Frequency change event handling in the processing chain
2017-03-11 17:03:34 +00:00
Denny
d510c34356 Adds frequency change event listener handler to LSM decoder. 2017-03-11 12:01:45 -05:00
Denny
ae8a44caed Removes cic cleanup filter from processing chain. 2017-03-11 11:53:12 -05:00
Denny
1aa85a86ca Resolves issue with channel frequency correction events not being broadcast within the processing chain and rendering in the spectral display. 2017-03-11 10:16:08 -05:00
Denny Sheirer
17539d4d55 Merge pull request #224 from DSheirer/223-now-playing-frequency-format
Now Playing frequency display formatting
2017-03-11 11:14:58 +00:00
Denny
1db1d28390 Resolves issue with frequency display formating in the Now Playing window. 2017-03-11 06:13:59 -05:00
Denny Sheirer
37a941e904 Merge pull request #219 from DSheirer/218-audio-priority-
Resolves issue with audio playback allowing higher priority audio to preempt lower priority audio
2017-03-05 12:34:09 +00:00
Denny
57f6655824 Resolves issue where higher priority audio was not preempting lower priority audio. 2017-03-05 07:32:42 -05:00
30 changed files with 1851 additions and 1489 deletions

View File

@@ -7,7 +7,7 @@
<property name="major" value="0"/> <property name="major" value="0"/>
<property name="minor" value="3"/> <property name="minor" value="3"/>
<property name="patch" value="0"/> <property name="patch" value="0"/>
<property name="release" value="-beta8"/> <property name="release" value="-beta10"/>
<property name="filename" value="sdrtrunk_${major}.${minor}.${patch}${release}"/> <property name="filename" value="sdrtrunk_${major}.${minor}.${patch}${release}"/>
<!-- Build properties --> <!-- Build properties -->

View File

@@ -90,7 +90,8 @@ public class AudioChannelPanel extends JPanel
private void init() private void init()
{ {
setLayout(new MigLayout("align center center, insets 0 0 0 0", "[][][align right]0[grow,fill]", "")); setLayout(new MigLayout("align center center, insets 0 0 0 0",
"[][][align right]0[grow,fill]", ""));
setBackground(mBackgroundColor); setBackground(mBackgroundColor);
mMutedLabel.setFont(mFont); mMutedLabel.setFont(mFont);
@@ -109,7 +110,7 @@ public class AudioChannelPanel extends JPanel
mTo.setFont(mFont); mTo.setFont(mFont);
mTo.setForeground(mValueColor); mTo.setForeground(mValueColor);
add(mTo); add(mTo,"wmin 10lp");
} }
@Override @Override
@@ -159,29 +160,39 @@ public class AudioChannelPanel extends JPanel
* does not occur on the Swing event thread -- wrap any calls to this * does not occur on the Swing event thread -- wrap any calls to this
* method with an event thread call. * method with an event thread call.
*/ */
private void updateLabel(JLabel valueLabel, String value, JLabel aliasLabel, Alias alias) private void updateLabel(JLabel textLabel, String value, JLabel iconLabel, Alias alias)
{ {
if(value != null) if(value != null)
{ {
if(alias != null) if(alias != null)
{ {
valueLabel.setText(alias.getName()); iconLabel.setIcon(mIconManager.getIcon(alias.getIconName(), 18));
aliasLabel.setIcon(mIconManager.getIcon(alias.getIconName(), 18));
}
else
{
valueLabel.setText(value);
aliasLabel.setIcon(null);
}
}
else
{
valueLabel.setText("-----");
aliasLabel.setIcon(null);
}
}
String aliasName = alias.getName();
//Truncate label if length exceeds 33 characters - hack!
if(aliasName.length() > 33)
{
textLabel.setText(aliasName.substring(0,30) + "...");
}
else
{
textLabel.setText(aliasName);
}
}
else
{
iconLabel.setIcon(null);
textLabel.setText(value);
}
}
else
{
iconLabel.setIcon(null);
textLabel.setText("-----");
}
}
/** /**
* Processes audio metadata to update this panel's display values * Processes audio metadata to update this panel's display values

View File

@@ -33,8 +33,7 @@ public class AudioChannelsPanel extends JPanel
public AudioChannelsPanel(IconManager iconManager, SettingsManager settingsManager, IAudioController controller) public AudioChannelsPanel(IconManager iconManager, SettingsManager settingsManager, IAudioController controller)
{ {
// setLayout(new MigLayout("insets 0 0 0 0", "[][grow,fill][][grow,fill]", "[grow,fill]")); setLayout(new MigLayout("insets 0 0 0 0", "[][sg abc,grow,fill][][sg abc,grow,fill]", "[grow,fill]"));
setLayout(new MigLayout("insets 0 0 0 0", "[][sg,grow,fill][][sg,grow,fill]", "[grow,fill]"));
setBackground(Color.BLACK); setBackground(Color.BLACK);
@@ -44,7 +43,7 @@ public class AudioChannelsPanel extends JPanel
for(int x = 0; x < outputs.size(); x++) for(int x = 0; x < outputs.size(); x++)
{ {
add(new AudioChannelPanel(iconManager, settingsManager, outputs.get(x)), "growx"); add(new AudioChannelPanel(iconManager, settingsManager, outputs.get(x)));
if(x < outputs.size() - 1) if(x < outputs.size() - 1)
{ {

View File

@@ -86,6 +86,9 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
loadSettings(); loadSettings();
} }
/**
* Loads the saved mixer configuration or a default configuration for audio playback.
*/
private void loadSettings() private void loadSettings()
{ {
MixerChannelConfiguration configuration = null; MixerChannelConfiguration configuration = null;
@@ -132,6 +135,9 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
} }
} }
/**
* Creates a default audio playback configuration with a mono audio playback channel.
*/
private MixerChannelConfiguration getDefaultConfiguration() private MixerChannelConfiguration getDefaultConfiguration()
{ {
/* Use the system default mixer and mono channel as default startup */ /* Use the system default mixer and mono channel as default startup */
@@ -161,6 +167,9 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
mAudioOutputConnections.clear(); mAudioOutputConnections.clear();
} }
/**
* Primary ingest point for audio produced by all decoding channels, for distribution to audio playback devices.
*/
@Override @Override
public synchronized void receive(AudioPacket packet) public synchronized void receive(AudioPacket packet)
{ {
@@ -176,11 +185,11 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
for(AudioOutputConnection connection : mAudioOutputConnections) for(AudioOutputConnection connection : mAudioOutputConnections)
{ {
if(connection.isInactive() && if(connection.isInactive() && mChannelConnectionMap.containsKey(connection.getChannelMetadataID()))
mChannelConnectionMap.containsKey(connection.getChannelMetadataID()))
{ {
mChannelConnectionMap.remove(connection.getChannelMetadataID()); mChannelConnectionMap.remove(connection.getChannelMetadataID());
connection.disconnect(); connection.disconnect();
mAvailableConnectionCount++;
changed = true; changed = true;
} }
} }
@@ -192,7 +201,7 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
} }
/** /**
* Identifies the lowest priority channel connection * Identifies the lowest priority channel connection where the a higher value indicates a lower priority.
*/ */
private void updateLowestPriorityAssignment() private void updateLowestPriorityAssignment()
{ {
@@ -201,19 +210,32 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
for(AudioOutputConnection connection : mAudioOutputConnections) for(AudioOutputConnection connection : mAudioOutputConnections)
{ {
if(connection.isConnected() && if(connection.isConnected() &&
(mLowestPriorityConnection == null || mLowestPriorityConnection.getPriority() > connection.getPriority())) (mLowestPriorityConnection == null || mLowestPriorityConnection.getPriority() < connection.getPriority()))
{ {
mLowestPriorityConnection = connection; mLowestPriorityConnection = connection;
} }
} }
} }
/**
* Configures audio playback to use the configuration specified in the entry argument.
*
* @param entry to use in configuring the audio playback setup.
* @throws AudioException if there is an error
*/
@Override @Override
public void setMixerChannelConfiguration(MixerChannelConfiguration entry) throws AudioException public void setMixerChannelConfiguration(MixerChannelConfiguration entry) throws AudioException
{ {
setMixerChannelConfiguration(entry, true); setMixerChannelConfiguration(entry, true);
} }
/**
* Configures audio playback to use the configuration specified in the entry argument.
*
* @param entry to use in configuring the audio playback setup.
* @param saveSettings to save the audio playback configuration settings in the properties file.
* @throws AudioException if there is an error
*/
public void setMixerChannelConfiguration(MixerChannelConfiguration entry, boolean saveSettings) throws AudioException public void setMixerChannelConfiguration(MixerChannelConfiguration entry, boolean saveSettings) throws AudioException
{ {
if(entry != null && (entry.getMixerChannel() == MixerChannel.MONO || entry.getMixerChannel() == MixerChannel.STEREO)) if(entry != null && (entry.getMixerChannel() == MixerChannel.MONO || entry.getMixerChannel() == MixerChannel.STEREO))
@@ -266,9 +288,8 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
} }
/** /**
* Clears all channel assignments and terminates all audio outputs in * Clears all channel assignments and terminates all audio outputs in preparation for complete shutdown or change
* preparation for complete shutdown or change to another mixer/channel * to another mixer/channel configuration
* configuration
*/ */
private void disposeCurrentConfiguration() private void disposeCurrentConfiguration()
{ {
@@ -288,12 +309,18 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
mLowestPriorityConnection = null; mLowestPriorityConnection = null;
} }
/**
* Current audio playback mixer channel configuration setting.
*/
@Override @Override
public MixerChannelConfiguration getMixerChannelConfiguration() throws AudioException public MixerChannelConfiguration getMixerChannelConfiguration() throws AudioException
{ {
return mMixerChannelConfiguration; return mMixerChannelConfiguration;
} }
/**
* List of audio outputs available for the current mixer channel configuration
*/
@Override @Override
public List<AudioOutput> getAudioOutputs() public List<AudioOutput> getAudioOutputs()
{ {
@@ -311,12 +338,18 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
return outputs; return outputs;
} }
/**
* Adds an audio event listener to receive audio event notifications.
*/
@Override @Override
public void addControllerListener(Listener<AudioEvent> listener) public void addControllerListener(Listener<AudioEvent> listener)
{ {
mControllerBroadcaster.addListener(listener); mControllerBroadcaster.addListener(listener);
} }
/**
* Removes an audio event listener from receiving audio event notifications.
*/
@Override @Override
public void removeControllerListener(Listener<AudioEvent> listener) public void removeControllerListener(Listener<AudioEvent> listener)
{ {
@@ -324,16 +357,15 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
} }
/** /**
* Returns an audio output connection for the packet if one is * Returns an audio output connection for the packet if one is available, or overrides an existing lower priority
* available, or overrides an existing lower priority connection. * connection. Returns null if no connection is available for the audio packet.
* Returns null if no connection is available for the audio packet.
* *
* @param packet from a source * @param audioPacket from a decoding channel source
* @return an audio output connection or null * @return an audio output connection or null
*/ */
private AudioOutputConnection getConnection(AudioPacket packet) private AudioOutputConnection getConnection(AudioPacket audioPacket)
{ {
int channelMetadataID = packet.getMetadata().getMetadataID(); int channelMetadataID = audioPacket.getMetadata().getMetadataID();
//Use an existing connection //Use an existing connection
if(mChannelConnectionMap.containsKey(channelMetadataID)) if(mChannelConnectionMap.containsKey(channelMetadataID))
@@ -341,37 +373,35 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
return mChannelConnectionMap.get(channelMetadataID); return mChannelConnectionMap.get(channelMetadataID);
} }
//Connect to and use an available connection //Connect to an unused, available connection
if(mAvailableConnectionCount > 0) if(mAvailableConnectionCount > 0)
{ {
for(AudioOutputConnection connection : mAudioOutputConnections) for(AudioOutputConnection connection : mAudioOutputConnections)
{ {
if(connection.isDisconnected()) if(connection.isDisconnected())
{ {
connection.connect(channelMetadataID); connection.connect(channelMetadataID, audioPacket.getMetadata().getAudioPriority());
mChannelConnectionMap.put(channelMetadataID, connection); mChannelConnectionMap.put(channelMetadataID, connection);
mAvailableConnectionCount--;
return connection; return connection;
} }
} }
} }
//Preempt an existing connection and connect it to this higher priority source //Preempt an existing lower priority connection and connect when this is a higher priority packet
else //Check for a channel priority override else
{ {
int priority = packet.getMetadata().getAudioPriority(); int priority = audioPacket.getMetadata().getAudioPriority();
if(mLowestPriorityConnection != null &&
priority < mLowestPriorityConnection.getPriority())
{
AudioOutputConnection connection = mLowestPriorityConnection; AudioOutputConnection connection = mLowestPriorityConnection;
if(connection != null && priority < connection.getPriority())
{
mChannelConnectionMap.remove(connection.getChannelMetadataID()); mChannelConnectionMap.remove(connection.getChannelMetadataID());
connection.connect(channelMetadataID); connection.connect(channelMetadataID, priority);
mChannelConnectionMap.put(channelMetadataID, connection); mChannelConnectionMap.put(channelMetadataID, connection);
updateLowestPriorityAssignment();
return connection; return connection;
} }
} }
@@ -494,9 +524,11 @@ public class AudioManager implements Listener<AudioPacket>, IAudioController
* Connects this assignment to the indicated source so that audio * Connects this assignment to the indicated source so that audio
* packets from this source can be sent to the audio output * packets from this source can be sent to the audio output
*/ */
public void connect(int source) public void connect(int source, int priority)
{ {
mChannelMetadataID = source; mChannelMetadataID = source;
mPriority = priority;
updateLowestPriorityAssignment();
mAudioOutput.updateTimestamp(); mAudioOutput.updateTimestamp();
} }

View File

@@ -32,7 +32,7 @@ import java.util.Map;
public class ChannelMetadataModel extends AbstractTableModel implements Listener<MutableMetadataChangeEvent> public class ChannelMetadataModel extends AbstractTableModel implements Listener<MutableMetadataChangeEvent>
{ {
private final DecimalFormat FREQUENCY_FORMATTER = new DecimalFormat( "#.0000" ); private final DecimalFormat FREQUENCY_FORMATTER = new DecimalFormat( "#.00000" );
public static final int COLUMN_STATE = 0; public static final int COLUMN_STATE = 0;
public static final int COLUMN_DECODER = 1; public static final int COLUMN_DECODER = 1;

View File

@@ -36,14 +36,19 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sample.Listener; import sample.Listener;
import sample.real.IOverflowListener; import sample.real.IOverflowListener;
import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.IFrequencyChangeListener;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static source.tuner.frequency.FrequencyChangeEvent.Event.NOTIFICATION_FREQUENCY_CHANGE;
public class ChannelState extends Module implements ICallEventProvider, IDecoderStateEventListener, public class ChannelState extends Module implements ICallEventProvider, IDecoderStateEventListener,
IDecoderStateEventProvider, ISquelchStateProvider, IAttributeChangeRequestListener, IOverflowListener IDecoderStateEventProvider, IFrequencyChangeListener, ISquelchStateProvider, IAttributeChangeRequestListener,
IOverflowListener
{ {
private final static Logger mLog = LoggerFactory.getLogger(ChannelState.class); private final static Logger mLog = LoggerFactory.getLogger(ChannelState.class);
@@ -61,6 +66,7 @@ public class ChannelState extends Module implements ICallEventProvider, IDecoder
private ChannelType mChannelType; private ChannelType mChannelType;
private TrafficChannelManager mTrafficChannelEndListener; private TrafficChannelManager mTrafficChannelEndListener;
private CallEvent mTrafficChannelCallEvent; private CallEvent mTrafficChannelCallEvent;
private FrequencyChangeListener mFrequencyChangeListener;
private boolean mSquelchLocked = false; private boolean mSquelchLocked = false;
private boolean mSelected = false; private boolean mSelected = false;
@@ -189,6 +195,17 @@ public class ChannelState extends Module implements ICallEventProvider, IDecoder
mStateMonitor = null; mStateMonitor = null;
} }
@Override
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
{
if(mFrequencyChangeListener == null)
{
mFrequencyChangeListener = new FrequencyChangeListener();
}
return mFrequencyChangeListener;
}
private boolean isStandardChannel() private boolean isStandardChannel()
{ {
return mChannelType == ChannelType.STANDARD; return mChannelType == ChannelType.STANDARD;
@@ -532,6 +549,23 @@ public class ChannelState extends Module implements ICallEventProvider, IDecoder
broadcast(mTrafficChannelCallEvent); broadcast(mTrafficChannelCallEvent);
} }
/**
* Listener to receive frequency change events and rebroadcast them to the decoder states
*/
public class FrequencyChangeListener implements Listener<FrequencyChangeEvent>
{
@Override
public void receive(FrequencyChangeEvent frequencyChangeEvent)
{
if(frequencyChangeEvent.getEvent() == NOTIFICATION_FREQUENCY_CHANGE)
{
long frequency = frequencyChangeEvent.getValue().longValue();
broadcast(new DecoderStateEvent(this, Event.SOURCE_FREQUENCY, getState(), frequency));
}
}
}
/** /**
* DecoderStateEvent receiver wrapper * DecoderStateEvent receiver wrapper
*/ */

View File

@@ -63,13 +63,11 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
private Listener<CallEvent> mCallEventListener; private Listener<CallEvent> mCallEventListener;
private ChannelModel mChannelModel; private ChannelModel mChannelModel;
private ChannelProcessingManager mChannelProcessingManager;
private DecodeConfiguration mDecodeConfiguration; private DecodeConfiguration mDecodeConfiguration;
private RecordConfiguration mRecordConfiguration; private RecordConfiguration mRecordConfiguration;
private String mSystem; private String mSystem;
private String mSite; private String mSite;
private String mAliasListName; private String mAliasListName;
private CallEvent mPreviousDoNotMonitorCallEvent;
/** /**
* Monitors call events and allocates traffic decoder channels in response * Monitors call events and allocates traffic decoder channels in response
@@ -77,7 +75,6 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
* traffic channel allocations. * traffic channel allocations.
* *
* @param channelModel containing channels currently in use * @param channelModel containing channels currently in use
* @param channelProcessingManager
* @param decodeConfiguration - decoder configuration to use for each * @param decodeConfiguration - decoder configuration to use for each
* traffic channel allocation. * traffic channel allocation.
* @param recordConfiguration - recording options for each traffic channel * @param recordConfiguration - recording options for each traffic channel
@@ -88,7 +85,6 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
* in the pool * in the pool
*/ */
public TrafficChannelManager(ChannelModel channelModel, public TrafficChannelManager(ChannelModel channelModel,
ChannelProcessingManager channelProcessingManager,
DecodeConfiguration decodeConfiguration, DecodeConfiguration decodeConfiguration,
RecordConfiguration recordConfiguration, RecordConfiguration recordConfiguration,
String system, String system,
@@ -97,7 +93,6 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
int trafficChannelPoolSize) int trafficChannelPoolSize)
{ {
mChannelModel = channelModel; mChannelModel = channelModel;
mChannelProcessingManager = channelProcessingManager;
mDecodeConfiguration = decodeConfiguration; mDecodeConfiguration = decodeConfiguration;
mRecordConfiguration = recordConfiguration; mRecordConfiguration = recordConfiguration;
mSystem = system; mSystem = system;
@@ -120,7 +115,6 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
mCallEventListener = null; mCallEventListener = null;
mDecodeConfiguration = null; mDecodeConfiguration = null;
mPreviousDoNotMonitorCallEvent = null;
} }
/** /**
@@ -197,21 +191,7 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
long frequency = callEvent.getFrequency(); long frequency = callEvent.getFrequency();
/* Check the from/to aliases for do not monitor priority */ if(frequency > 0)
if(isDoNotMonitor(callEvent))
{
callEvent.setCallEventType(CallEventType.CALL_DO_NOT_MONITOR);
if(isSameCallEvent(mPreviousDoNotMonitorCallEvent, callEvent))
{
return;
}
else
{
mPreviousDoNotMonitorCallEvent = callEvent;
}
}
else if(frequency > 0)
{ {
Channel channel = getChannel(callEvent.getChannel(), new TunerChannel(Type.TRAFFIC, Channel channel = getChannel(callEvent.getChannel(), new TunerChannel(Type.TRAFFIC,
frequency, mDecodeConfiguration.getDecoderType().getChannelBandwidth())); frequency, mDecodeConfiguration.getDecoderType().getChannelBandwidth()));
@@ -330,31 +310,6 @@ public class TrafficChannelManager extends Module implements ICallEventProvider,
return false; return false;
} }
/**
* Checks for aliases that contain a do not follow/process priority.
*
* @param event
* @return - true if there is an alias that has a do not process alias id
*/
private boolean isDoNotMonitor(CallEvent event)
{
Alias to = event.getToIDAlias();
if(to != null && to.hasCallPriority() && to.getCallPriority() == Priority.DO_NOT_MONITOR)
{
return true;
}
Alias from = event.getFromIDAlias();
if(from != null && from.hasCallPriority() && from.getCallPriority() == Priority.DO_NOT_MONITOR)
{
return true;
}
return false;
}
@Override @Override
public Listener<DecoderStateEvent> getDecoderStateListener() public Listener<DecoderStateEvent> getDecoderStateListener()
{ {

View File

@@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
* SDR Trunk * sdrtrunk
* Copyright (C) 2014-2016 Dennis Sheirer * Copyright (C) 2014-2017 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -14,15 +14,11 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/ ******************************************************************************/
package controller.channel; package controller.channel;
import javax.xml.bind.annotation.XmlAttribute; import controller.config.Configuration;
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 module.decode.DecoderFactory; import module.decode.DecoderFactory;
import module.decode.DecoderType; import module.decode.DecoderType;
import module.decode.config.AuxDecodeConfiguration; import module.decode.config.AuxDecodeConfiguration;
@@ -31,6 +27,7 @@ import module.log.EventLogType;
import module.log.config.EventLogConfiguration; import module.log.config.EventLogConfiguration;
import record.RecorderType; import record.RecorderType;
import record.config.RecordConfiguration; import record.config.RecordConfiguration;
import sample.Listener;
import source.SourceType; import source.SourceType;
import source.config.SourceConfigFactory; import source.config.SourceConfigFactory;
import source.config.SourceConfigRecording; import source.config.SourceConfigRecording;
@@ -40,15 +37,24 @@ import source.tuner.TunerChannel;
import source.tuner.TunerChannel.Type; import source.tuner.TunerChannel.Type;
import source.tuner.frequency.FrequencyChangeEvent; import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.FrequencyChangeEvent.Event; import source.tuner.frequency.FrequencyChangeEvent.Event;
import source.tuner.frequency.IFrequencyChangeProcessor;
import controller.config.Configuration; 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;
@XmlSeeAlso({Configuration.class}) @XmlSeeAlso({Configuration.class})
@XmlRootElement(name = "channel") @XmlRootElement(name = "channel")
public class Channel extends Configuration implements IFrequencyChangeProcessor public class Channel extends Configuration implements Listener<FrequencyChangeEvent>
{ {
// Standard channels are persisted and traffic channels are temporary // Standard channels are persisted and traffic channels are temporary
public enum ChannelType { STANDARD, TRAFFIC }; public enum ChannelType
{
STANDARD, TRAFFIC
}
;
// Static unique channel identifier tracking // Static unique channel identifier tracking
@@ -278,7 +284,7 @@ public class Channel extends Configuration implements IFrequencyChangeProcessor
* Note: this method is package private and is intended to be managed * Note: this method is package private and is intended to be managed
* by a co-package central processing manager * by a co-package central processing manager
* *
* @see controller.ChannelProcessingManager * @see controller.channel.ChannelProcessingManager
*/ */
void setEnabled(boolean enabled) void setEnabled(boolean enabled)
{ {
@@ -436,8 +442,7 @@ public class Channel extends Configuration implements IFrequencyChangeProcessor
{ {
TunerChannel tunerChannel = getTunerChannel(); TunerChannel tunerChannel = getTunerChannel();
return tunerChannel != null && return tunerChannel != null && tunerChannel.overlaps(minimum, maximum);
tunerChannel.overlaps( minimum, maximum );
} }
/** /**
@@ -447,7 +452,7 @@ public class Channel extends Configuration implements IFrequencyChangeProcessor
* be used to visually show in the spectral display. * be used to visually show in the spectral display.
*/ */
@Override @Override
public void frequencyChanged( FrequencyChangeEvent event ) public void receive(FrequencyChangeEvent event)
{ {
if(event.getEvent() == Event.NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE) if(event.getEvent() == Event.NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE)
{ {
@@ -455,9 +460,21 @@ public class Channel extends Configuration implements IFrequencyChangeProcessor
} }
} }
/**
* Current channel frequency correction value (when this channel is processing)
* @return
*/
@XmlTransient @XmlTransient
public int getChannelFrequencyCorrection() public int getChannelFrequencyCorrection()
{ {
return mChannelFrequencyCorrection; return mChannelFrequencyCorrection;
} }
/**
* Resets frequency correction value to 0
*/
public void resetFrequencyCorrection()
{
mChannelFrequencyCorrection = 0;
}
} }

View File

@@ -231,7 +231,7 @@ public class ChannelProcessingManager implements ChannelEventListener
if(processingChain == null) if(processingChain == null)
{ {
processingChain = new ProcessingChain(channel.getName(), channel.getChannelType()); processingChain = new ProcessingChain(channel.getChannelType());
/* Register global listeners */ /* Register global listeners */
for(Listener<AudioPacket> listener : mAudioPacketListeners) for(Listener<AudioPacket> listener : mAudioPacketListeners)
@@ -244,6 +244,9 @@ public class ChannelProcessingManager implements ChannelEventListener
processingChain.addMessageListener(listener); processingChain.addMessageListener(listener);
} }
//Register channel to receive frequency correction events to show in the spectral display (hack!)
processingChain.addFrequencyChangeListener(channel);
/* Processing Modules */ /* Processing Modules */
List<Module> modules = DecoderFactory.getModules(mChannelModel, mChannelMapModel, this, List<Module> modules = DecoderFactory.getModules(mChannelModel, mChannelMapModel, this,
mAliasModel, channel, processingChain.getChannelState().getMutableMetadata()); mAliasModel, channel, processingChain.getChannelState().getMutableMetadata());
@@ -347,6 +350,9 @@ public class ChannelProcessingManager implements ChannelEventListener
processingChain.removeRecordingModules(); processingChain.removeRecordingModules();
//Deregister channel from receive frequency correction events to show in the spectral display (hack!)
processingChain.removeFrequencyChangeListener(channel);
channel.resetFrequencyCorrection();
mChannelModel.broadcast(new ChannelEvent(channel, Event.NOTIFICATION_PROCESSING_STOP)); mChannelModel.broadcast(new ChannelEvent(channel, Event.NOTIFICATION_PROCESSING_STOP));

View File

@@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
* SDR Trunk * sdrtrunk
* Copyright (C) 2015 Dennis Sheirer * Copyright (C) 2014-2017 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -14,23 +14,24 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/ ******************************************************************************/
package dsp.filter.cic; package dsp.filter.cic;
import java.util.ArrayList; import dsp.filter.FilterFactory;
import java.util.List; import dsp.filter.Filters;
import dsp.filter.Window.WindowType;
import dsp.filter.fir.complex.ComplexFIRFilter_CB_CB;
import dsp.filter.halfband.complex.HalfBandFilter_CB_CB;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import sample.Listener; import sample.Listener;
import sample.complex.ComplexBuffer; import sample.complex.ComplexBuffer;
import sample.complex.ComplexSampleListener; import sample.complex.ComplexSampleListener;
import sample.complex.ComplexToComplexBufferAssembler; import sample.complex.ComplexToComplexBufferAssembler;
import sample.decimator.ComplexDecimator; import sample.decimator.ComplexDecimator;
import dsp.filter.FilterFactory;
import dsp.filter.Filters; import java.util.ArrayList;
import dsp.filter.Window.WindowType; import java.util.List;
import dsp.filter.fir.complex.ComplexFIRFilter_CB_CB;
import dsp.filter.halfband.complex.HalfBandFilter_CB_CB;
public class ComplexPrimeCICDecimate implements Listener<ComplexBuffer> public class ComplexPrimeCICDecimate implements Listener<ComplexBuffer>
{ {
@@ -367,8 +368,11 @@ public class ComplexPrimeCICDecimate implements Listener<ComplexBuffer>
attenuation, attenuation,
windowType), 0.4f); windowType), 0.4f);
mAssembler.setListener( mCleanupFilter ); //Bypassing the CIC cleanup filter for now
mCleanupFilter.setListener( mHalfBandFilter ); mAssembler.setListener(mHalfBandFilter);
// mAssembler.setListener( mCleanupFilter );
// mCleanupFilter.setListener( mHalfBandFilter );
} }
public void dispose() public void dispose()

View File

@@ -1,21 +1,38 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 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 instrument; package instrument;
import controller.channel.Channel.ChannelType;
import instrument.tap.Tap; import instrument.tap.Tap;
import instrument.tap.TapGroup; import instrument.tap.TapGroup;
import java.util.ArrayList;
import java.util.List;
import module.Module; import module.Module;
import module.ProcessingChain; import module.ProcessingChain;
import source.Source; import source.Source;
import controller.channel.Channel.ChannelType;
import java.util.ArrayList;
import java.util.List;
public class InstrumentableProcessingChain extends ProcessingChain implements Instrumentable public class InstrumentableProcessingChain extends ProcessingChain implements Instrumentable
{ {
public InstrumentableProcessingChain() public InstrumentableProcessingChain()
{ {
super( "instrumented", ChannelType.STANDARD ); super(ChannelType.STANDARD);
} }
public void setSource(Source source) throws IllegalStateException public void setSource(Source source) throws IllegalStateException

View File

@@ -108,7 +108,6 @@ public class ProcessingChain implements IChannelEventListener
private Broadcaster<RealBuffer> mUnFilteredRealBufferBroadcaster = new Broadcaster<>(); private Broadcaster<RealBuffer> mUnFilteredRealBufferBroadcaster = new Broadcaster<>();
private Broadcaster<SquelchState> mSquelchStateBroadcaster = new Broadcaster<>(); private Broadcaster<SquelchState> mSquelchStateBroadcaster = new Broadcaster<>();
private String mName;
private AtomicBoolean mRunning = new AtomicBoolean(); private AtomicBoolean mRunning = new AtomicBoolean();
protected Source mSource; protected Source mSource;
@@ -120,13 +119,10 @@ public class ProcessingChain implements IChannelEventListener
/** /**
* Creates a processing chain for managing a set of modules * Creates a processing chain for managing a set of modules
* *
* @param name for thread pool naming each thread
* @param channelType * @param channelType
*/ */
public ProcessingChain(String name, ChannelType channelType) public ProcessingChain(ChannelType channelType)
{ {
mName = name;
mChannelState = new ChannelState(channelType); mChannelState = new ChannelState(channelType);
addModule(mChannelState); addModule(mChannelState);
@@ -211,6 +207,8 @@ public class ProcessingChain implements IChannelEventListener
} }
mSource = source; mSource = source;
addModule(mSource);
} }
/** /**
@@ -557,25 +555,6 @@ public class ProcessingChain implements IChannelEventListener
+ "sample type - cannot start processing chain"); + "sample type - cannot start processing chain");
} }
/* If this is a tuner source, broadcast the frequency to all
* of the decoder state's and start the samples flowing */
if(mSource instanceof TunerChannelSource)
{
TunerChannelSource tcs = (TunerChannelSource) mSource;
try
{
long frequency = tcs.getFrequency();
mDecoderStateEventBroadcaster.broadcast(
new DecoderStateEvent(this, Event.SOURCE_FREQUENCY, State.IDLE, frequency));
}
catch(SourceException e)
{
mLog.error("Error getting frequency from tuner channel source", e);
}
}
/* Start each of the modules */ /* Start each of the modules */
for(Module module : mModules) for(Module module : mModules)
{ {
@@ -588,8 +567,6 @@ public class ProcessingChain implements IChannelEventListener
mLog.error("Error starting module", e); mLog.error("Error starting module", e);
} }
} }
mSource.start(ThreadPool.SCHEDULED);
} }
else else
{ {
@@ -606,9 +583,16 @@ public class ProcessingChain implements IChannelEventListener
{ {
if(mRunning.compareAndSet(true, false)) if(mRunning.compareAndSet(true, false))
{ {
/* Stop each of the modules */
for(Module module : mModules)
{
module.stop();
}
if(mSource != null) if(mSource != null)
{ {
mSource.stop(); removeModule(mSource);
mSource.setOverflowListener(null); mSource.setOverflowListener(null);
switch(mSource.getSampleType()) switch(mSource.getSampleType())
@@ -629,11 +613,6 @@ public class ProcessingChain implements IChannelEventListener
mSource = null; mSource = null;
} }
/* Stop each of the modules */
for(Module module : mModules)
{
module.stop();
}
} }
} }
@@ -760,6 +739,24 @@ public class ProcessingChain implements IChannelEventListener
mMessageBroadcaster.removeListener(listener); mMessageBroadcaster.removeListener(listener);
} }
/**
* Adds the listener to receive frequency change events from the processing chain
* @param listener to receive events
*/
public void addFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
{
mFrequencyChangeEventBroadcaster.addListener(listener);
}
/**
* Removes the listener from receiving frequency change events
* @param listener to remove
*/
public void removeFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
{
mFrequencyChangeEventBroadcaster.removeListener(listener);
}
/** /**
* Adds the listener to receive call events from all modules. * Adds the listener to receive call events from all modules.
*/ */

View File

@@ -222,7 +222,7 @@ public class DecoderFactory
if(channelType == ChannelType.STANDARD) if(channelType == ChannelType.STANDARD)
{ {
modules.add(new TrafficChannelManager(channelModel, channelProcessingManager, decodeConfig, modules.add(new TrafficChannelManager(channelModel, decodeConfig,
channel.getRecordConfiguration(), channel.getSystem(), channel.getSite(), channel.getRecordConfiguration(), channel.getSystem(), channel.getSite(),
(aliasList != null ? aliasList.getName() : null), mptConfig.getTrafficChannelPoolSize())); (aliasList != null ? aliasList.getName() : null), mptConfig.getTrafficChannelPoolSize()));
} }
@@ -263,7 +263,7 @@ public class DecoderFactory
if(channelType == ChannelType.STANDARD) if(channelType == ChannelType.STANDARD)
{ {
modules.add(new TrafficChannelManager(channelModel, channelProcessingManager, decodeConfig, modules.add(new TrafficChannelManager(channelModel, decodeConfig,
channel.getRecordConfiguration(), channel.getSystem(), channel.getSite(), channel.getRecordConfiguration(), channel.getSystem(), channel.getSite(),
(aliasList != null ? aliasList.getName() : null), p25Config.getTrafficChannelPoolSize())); (aliasList != null ? aliasList.getName() : null), p25Config.getTrafficChannelPoolSize()));
} }

View File

@@ -54,7 +54,7 @@ public class LJ1200DecoderState extends DecoderState
super(aliasList); super(aliasList);
mAddressAttribute = new AliasedStringAttributeMonitor(Attribute.SECONDARY_ADDRESS_TO, mAddressAttribute = new AliasedStringAttributeMonitor(Attribute.SECONDARY_ADDRESS_TO,
getAttributeChangeRequestListener(), getAliasList(), AliasIDType.LOJACK); getAttributeChangeRequestListener(), getAliasList(), AliasIDType.SITE);
} }
@Override @Override

View File

@@ -9,19 +9,19 @@ import instrument.tap.stream.FloatTap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener; import sample.Listener;
import sample.real.RealBuffer; import sample.real.RealBuffer;
import sample.real.RealSampleListener; import sample.real.RealSampleListener;
import sample.real.RealSampleProvider; import sample.real.RealSampleProvider;
import source.tuner.TunerChannelSource;
import source.tuner.frequency.FrequencyChangeEvent; import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.FrequencyChangeEvent.Event; import source.tuner.frequency.FrequencyChangeEvent.Event;
import source.tuner.frequency.IFrequencyChangeListener; import source.tuner.frequency.IFrequencyChangeListener;
import dsp.gain.DirectGainControl; import dsp.gain.DirectGainControl;
public class C4FMSymbolFilter implements Listener<RealBuffer>, public class C4FMSymbolFilter implements Listener<RealBuffer>, IFrequencyChangeListener, RealSampleProvider, Instrumentable
IFrequencyChangeListener,
RealSampleProvider,
Instrumentable
{ {
private static final float TAPS[][] = private static final float TAPS[][] =
{ {
@@ -198,8 +198,7 @@ public class C4FMSymbolFilter implements Listener<RealBuffer>,
private RealSampleListener mListener; private RealSampleListener mListener;
private DirectGainControl mGainController = private DirectGainControl mGainController = new DirectGainControl( 15.0f, 0.1f, 35.0f, 0.3f );
new DirectGainControl( 15.0f, 0.1f, 35.0f, 0.3f );
private int mFrequencyAdjustmentRequested = 0; private int mFrequencyAdjustmentRequested = 0;
private int mFrequencyCorrection = 0; private int mFrequencyCorrection = 0;
@@ -258,8 +257,7 @@ public class C4FMSymbolFilter implements Listener<RealBuffer>,
correction = -mFrequencyCorrectionMaximum; correction = -mFrequencyCorrectionMaximum;
} }
broadcast( new FrequencyChangeEvent( broadcast( new FrequencyChangeEvent(Event.REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE, correction ) );
Event.REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE, correction ) );
mFrequencyAdjustmentRequested = 0; mFrequencyAdjustmentRequested = 0;
} }
@@ -452,6 +450,10 @@ public class C4FMSymbolFilter implements Listener<RealBuffer>,
} }
} }
/**
* Broadcasts a frequency change event to the registered listener
* @param event
*/
public void broadcast( FrequencyChangeEvent event ) public void broadcast( FrequencyChangeEvent event )
{ {
if( mFrequencyChangeListener != null ) if( mFrequencyChangeListener != null )
@@ -460,6 +462,10 @@ public class C4FMSymbolFilter implements Listener<RealBuffer>,
} }
} }
/**
* Sets the listener for frequency change events.
* @param listener
*/
public void setFrequencyChangeListener( Listener<FrequencyChangeEvent> listener ) public void setFrequencyChangeListener( Listener<FrequencyChangeEvent> listener )
{ {
mFrequencyChangeListener = listener; mFrequencyChangeListener = listener;

View File

@@ -4,8 +4,10 @@ import alias.AliasList;
import instrument.Instrumentable; import instrument.Instrumentable;
import module.decode.Decoder; import module.decode.Decoder;
import module.decode.DecoderType; import module.decode.DecoderType;
import source.tuner.frequency.IFrequencyChangeListener;
import source.tuner.frequency.IFrequencyChangeProvider;
public abstract class P25Decoder extends Decoder implements Instrumentable public abstract class P25Decoder extends Decoder implements IFrequencyChangeListener, IFrequencyChangeProvider, Instrumentable
{ {
private P25MessageProcessor mMessageProcessor; private P25MessageProcessor mMessageProcessor;

View File

@@ -315,6 +315,8 @@ public class P25DecoderState extends DecoderState
*/ */
public void registerCallEvent(P25CallEvent event) public void registerCallEvent(P25CallEvent event)
{ {
String channel = event.getChannel();
if(mChannelCallMap.containsKey(event.getChannel())) if(mChannelCallMap.containsKey(event.getChannel()))
{ {
P25CallEvent previousEvent = mChannelCallMap.remove(event.getChannel()); P25CallEvent previousEvent = mChannelCallMap.remove(event.getChannel());
@@ -1557,6 +1559,7 @@ public class P25DecoderState extends DecoderState
break; break;
case IDENTIFIER_UPDATE_NON_VUHF: case IDENTIFIER_UPDATE_NON_VUHF:
case IDENTIFIER_UPDATE_VHF_UHF_BANDS: case IDENTIFIER_UPDATE_VHF_UHF_BANDS:
case IDENTIFIER_UPDATE_TDMA:
IdentifierUpdate iu = (IdentifierUpdate)tsbk; IdentifierUpdate iu = (IdentifierUpdate)tsbk;
if(!mBands.containsKey(iu.getIdentifier())) if(!mBands.containsKey(iu.getIdentifier()))
@@ -2735,6 +2738,7 @@ public class P25DecoderState extends DecoderState
else else
{ {
StringBuilder details = new StringBuilder(); StringBuilder details = new StringBuilder();
details.append(pgvcg.isTDMAChannel() ? "TDMA " : "");
details.append(pgvcg.isEmergency() ? "EMERGENCY " : ""); details.append(pgvcg.isEmergency() ? "EMERGENCY " : "");
details.append("PRI:").append(pgvcg.getPriority()); details.append("PRI:").append(pgvcg.getPriority());
details.append(pgvcg.isEncryptedChannel() ? " ENCRYPTED" : ""); details.append(pgvcg.isEncryptedChannel() ? " ENCRYPTED" : "");
@@ -2742,7 +2746,7 @@ public class P25DecoderState extends DecoderState
P25CallEvent event = new P25CallEvent.Builder(CallEventType.PATCH_GROUP_CALL) P25CallEvent event = new P25CallEvent.Builder(CallEventType.PATCH_GROUP_CALL)
.aliasList(getAliasList()) .aliasList(getAliasList())
.channel(channel + (pgvcg.isTDMAChannel() ? " TDMA" : "")) .channel(channel)
.details(details.toString()) .details(details.toString())
.frequency(pgvcg.getDownlinkFrequency()) .frequency(pgvcg.getDownlinkFrequency())
.from(from) .from(from)
@@ -2775,8 +2779,9 @@ public class P25DecoderState extends DecoderState
{ {
P25CallEvent event = new P25CallEvent.Builder(CallEventType.PATCH_GROUP_CALL) P25CallEvent event = new P25CallEvent.Builder(CallEventType.PATCH_GROUP_CALL)
.aliasList(getAliasList()) .aliasList(getAliasList())
.channel(channel + (gvcgu.isTDMAChannel1() ? " TDMA" : "")) .channel(channel)
.details((gvcgu.isEncrypted() ? "ENCRYPTED " : "")) .details((gvcgu.isTDMAChannel1() ? "TDMA " : "") +
(gvcgu.isEncrypted() ? "ENCRYPTED " : ""))
.frequency(gvcgu.getDownlinkFrequency1()) .frequency(gvcgu.getDownlinkFrequency1())
.to(to) .to(to)
.build(); .build();
@@ -2801,8 +2806,9 @@ public class P25DecoderState extends DecoderState
{ {
P25CallEvent event = new P25CallEvent.Builder(CallEventType.PATCH_GROUP_CALL) P25CallEvent event = new P25CallEvent.Builder(CallEventType.PATCH_GROUP_CALL)
.aliasList(getAliasList()) .aliasList(getAliasList())
.channel(channel2 + (gvcgu.isTDMAChannel2() ? " TDMA" : "")) .channel(channel2)
.details((gvcgu.isEncrypted() ? "ENCRYPTED " : "")) .details((gvcgu.isTDMAChannel2() ? "TDMA " : "") +
(gvcgu.isEncrypted() ? "ENCRYPTED " : ""))
.frequency(gvcgu.getDownlinkFrequency2()) .frequency(gvcgu.getDownlinkFrequency2())
.to(to2) .to(to2)
.build(); .build();
@@ -2866,6 +2872,7 @@ public class P25DecoderState extends DecoderState
else else
{ {
StringBuilder details = new StringBuilder(); StringBuilder details = new StringBuilder();
details.append(gdcg.isTDMAChannel() ? "TDMA " : "");
details.append(gdcg.isEmergency() ? "EMERGENCY " : ""); details.append(gdcg.isEmergency() ? "EMERGENCY " : "");
details.append("PRI:").append(gdcg.getPriority()).append(" "); details.append("PRI:").append(gdcg.getPriority()).append(" ");
details.append(gdcg.isEncryptedChannel() ? "ENCRYPTED " : ""); details.append(gdcg.isEncryptedChannel() ? "ENCRYPTED " : "");
@@ -2873,7 +2880,7 @@ public class P25DecoderState extends DecoderState
P25CallEvent event = new P25CallEvent.Builder(CallEventType.DATA_CALL) P25CallEvent event = new P25CallEvent.Builder(CallEventType.DATA_CALL)
.aliasList(getAliasList()) .aliasList(getAliasList())
.channel(channel + (gdcg.isTDMAChannel() ? " TDMA" : "")) .channel(channel)
.details(details.toString()) .details(details.toString())
.frequency(gdcg.getDownlinkFrequency()) .frequency(gdcg.getDownlinkFrequency())
.from(from) .from(from)
@@ -2904,6 +2911,7 @@ public class P25DecoderState extends DecoderState
else else
{ {
StringBuilder details = new StringBuilder(); StringBuilder details = new StringBuilder();
details.append(gvcg.isTDMAChannel() ? "TDMA " : "");
details.append(gvcg.isEmergency() ? "EMERGENCY " : ""); details.append(gvcg.isEmergency() ? "EMERGENCY " : "");
details.append("PRI:").append(gvcg.getPriority()).append(" "); details.append("PRI:").append(gvcg.getPriority()).append(" ");
details.append(gvcg.isEncryptedChannel() ? "ENCRYPTED " : ""); details.append(gvcg.isEncryptedChannel() ? "ENCRYPTED " : "");
@@ -2911,7 +2919,7 @@ public class P25DecoderState extends DecoderState
P25CallEvent event = new P25CallEvent.Builder(CallEventType.GROUP_CALL) P25CallEvent event = new P25CallEvent.Builder(CallEventType.GROUP_CALL)
.aliasList(getAliasList()) .aliasList(getAliasList())
.channel(channel + (gvcg.isTDMAChannel() ? " TDMA" : "")) .channel(channel)
.details(details.toString()) .details(details.toString())
.frequency(gvcg.getDownlinkFrequency()) .frequency(gvcg.getDownlinkFrequency())
.from(from) .from(from)
@@ -2928,8 +2936,7 @@ public class P25DecoderState extends DecoderState
} }
break; break;
case GROUP_VOICE_CHANNEL_GRANT_UPDATE: case GROUP_VOICE_CHANNEL_GRANT_UPDATE:
GroupVoiceChannelGrantUpdate gvcgu = GroupVoiceChannelGrantUpdate gvcgu = (GroupVoiceChannelGrantUpdate)message;
(GroupVoiceChannelGrantUpdate)message;
channel = gvcgu.getChannel1(); channel = gvcgu.getChannel1();
from = null; from = null;
@@ -2942,6 +2949,7 @@ public class P25DecoderState extends DecoderState
else else
{ {
StringBuilder details = new StringBuilder(); StringBuilder details = new StringBuilder();
details.append(gvcgu.isTDMAChannel() ? "TDMA " : "");
details.append(gvcgu.isEmergency() ? "EMERGENCY " : ""); details.append(gvcgu.isEmergency() ? "EMERGENCY " : "");
details.append("PRI:").append(gvcgu.getPriority()).append(" "); details.append("PRI:").append(gvcgu.getPriority()).append(" ");
details.append(gvcgu.isEncryptedChannel() ? "ENCRYPTED " : ""); details.append(gvcgu.isEncryptedChannel() ? "ENCRYPTED " : "");
@@ -2949,7 +2957,7 @@ public class P25DecoderState extends DecoderState
P25CallEvent event = new P25CallEvent.Builder(CallEventType.GROUP_CALL) P25CallEvent event = new P25CallEvent.Builder(CallEventType.GROUP_CALL)
.aliasList(getAliasList()) .aliasList(getAliasList())
.channel(gvcgu.getChannel1() + (gvcgu.isTDMAChannel1() ? " TDMA" : "")) .channel(gvcgu.getChannel1())
.details(details.toString()) .details(details.toString())
.frequency(gvcgu.getDownlinkFrequency1()) .frequency(gvcgu.getDownlinkFrequency1())
.from(from) .from(from)
@@ -2977,6 +2985,7 @@ public class P25DecoderState extends DecoderState
else else
{ {
StringBuilder details = new StringBuilder(); StringBuilder details = new StringBuilder();
details.append(gvcgu.isTDMAChannel() ? "TDMA " : "");
details.append(gvcgu.isEmergency() ? "EMERGENCY " : ""); details.append(gvcgu.isEmergency() ? "EMERGENCY " : "");
details.append("PRI:").append(gvcgu.getPriority()).append(" "); details.append("PRI:").append(gvcgu.getPriority()).append(" ");
details.append(gvcgu.isEncryptedChannel() ? "ENCRYPTED " : ""); details.append(gvcgu.isEncryptedChannel() ? "ENCRYPTED " : "");
@@ -2984,7 +2993,7 @@ public class P25DecoderState extends DecoderState
P25CallEvent event2 = new P25CallEvent.Builder(CallEventType.GROUP_CALL) P25CallEvent event2 = new P25CallEvent.Builder(CallEventType.GROUP_CALL)
.aliasList(getAliasList()) .aliasList(getAliasList())
.channel(gvcgu.getChannel2() + (gvcgu.isTDMAChannel2() ? " TDMA" : "")) .channel(gvcgu.getChannel2())
.details(details.toString()) .details(details.toString())
.frequency(gvcgu.getDownlinkFrequency2()) .frequency(gvcgu.getDownlinkFrequency2())
.to(gvcgu.getGroupAddress2()) .to(gvcgu.getGroupAddress2())
@@ -3016,6 +3025,7 @@ public class P25DecoderState extends DecoderState
else else
{ {
StringBuilder details = new StringBuilder(); StringBuilder details = new StringBuilder();
details.append(gvcgue.isTDMAChannel() ? "TDMA " : "");
details.append(gvcgue.isEmergency() ? "EMERGENCY " : ""); details.append(gvcgue.isEmergency() ? "EMERGENCY " : "");
details.append("PRI:").append(gvcgue.getPriority()).append(" "); details.append("PRI:").append(gvcgue.getPriority()).append(" ");
details.append(gvcgue.isEncryptedChannel() ? "ENCRYPTED " : ""); details.append(gvcgue.isEncryptedChannel() ? "ENCRYPTED " : "");
@@ -3023,7 +3033,7 @@ public class P25DecoderState extends DecoderState
P25CallEvent event = new P25CallEvent.Builder(CallEventType.GROUP_CALL) P25CallEvent event = new P25CallEvent.Builder(CallEventType.GROUP_CALL)
.aliasList(getAliasList()) .aliasList(getAliasList())
.channel(channel + (gvcgue.isTDMAChannel() ? " TDMA" : "")) .channel(channel)
.details(details.toString()) .details(details.toString())
.frequency(gvcgue.getDownlinkFrequency()) .frequency(gvcgue.getDownlinkFrequency())
.from(from) .from(from)
@@ -3053,6 +3063,7 @@ public class P25DecoderState extends DecoderState
else else
{ {
StringBuilder details = new StringBuilder(); StringBuilder details = new StringBuilder();
details.append(idcg.isTDMAChannel() ? "TDMA " : "");
details.append(idcg.isEmergency() ? "EMERGENCY " : ""); details.append(idcg.isEmergency() ? "EMERGENCY " : "");
details.append("PRI:").append(idcg.getPriority()).append(" "); details.append("PRI:").append(idcg.getPriority()).append(" ");
details.append(idcg.isEncryptedChannel() ? "ENCRYPTED " : ""); details.append(idcg.isEncryptedChannel() ? "ENCRYPTED " : "");
@@ -3060,7 +3071,7 @@ public class P25DecoderState extends DecoderState
P25CallEvent event = new P25CallEvent.Builder(CallEventType.DATA_CALL) P25CallEvent event = new P25CallEvent.Builder(CallEventType.DATA_CALL)
.aliasList(getAliasList()) .aliasList(getAliasList())
.channel(channel + (idcg.isTDMAChannel() ? " TDMA" : "")) .channel(channel)
.details(details.toString()) .details(details.toString())
.frequency(idcg.getDownlinkFrequency()) .frequency(idcg.getDownlinkFrequency())
.from(from) .from(from)
@@ -3090,13 +3101,14 @@ public class P25DecoderState extends DecoderState
else else
{ {
StringBuilder details = new StringBuilder(); StringBuilder details = new StringBuilder();
details.append(sdcg.isTDMAChannel() ? "TDMA " : "");
details.append(sdcg.isEmergency() ? "EMERGENCY " : ""); details.append(sdcg.isEmergency() ? "EMERGENCY " : "");
details.append(sdcg.isEncryptedChannel() ? "ENCRYPTED " : ""); details.append(sdcg.isEncryptedChannel() ? "ENCRYPTED " : "");
details.append(sdcg.getSessionMode().name()); details.append(sdcg.getSessionMode().name());
P25CallEvent event = new P25CallEvent.Builder(CallEventType.DATA_CALL) P25CallEvent event = new P25CallEvent.Builder(CallEventType.DATA_CALL)
.aliasList(getAliasList()) .aliasList(getAliasList())
.channel(channel + (sdcg.isTDMAChannel() ? " TDMA" : "")) .channel(channel)
.details(details.toString()) .details(details.toString())
.frequency(sdcg.getDownlinkFrequency()) .frequency(sdcg.getDownlinkFrequency())
.from(from) .from(from)
@@ -3128,6 +3140,7 @@ public class P25DecoderState extends DecoderState
else else
{ {
StringBuilder details = new StringBuilder(); StringBuilder details = new StringBuilder();
details.append(tivcg.isTDMAChannel() ? "TDMA " : "");
details.append(tivcg.isEmergency() ? "EMERGENCY " : ""); details.append(tivcg.isEmergency() ? "EMERGENCY " : "");
details.append("PRI:").append(tivcg.getPriority()).append(" "); details.append("PRI:").append(tivcg.getPriority()).append(" ");
details.append(tivcg.isEncryptedChannel() ? "ENCRYPTED " : ""); details.append(tivcg.isEncryptedChannel() ? "ENCRYPTED " : "");
@@ -3137,7 +3150,7 @@ public class P25DecoderState extends DecoderState
P25CallEvent event = new P25CallEvent.Builder( P25CallEvent event = new P25CallEvent.Builder(
CallEventType.TELEPHONE_INTERCONNECT) CallEventType.TELEPHONE_INTERCONNECT)
.aliasList(getAliasList()) .aliasList(getAliasList())
.channel(channel + (tivcg.isTDMAChannel() ? " TDMA" : "")) .channel(channel)
.details(details.toString()) .details(details.toString())
.frequency(tivcg.getDownlinkFrequency()) .frequency(tivcg.getDownlinkFrequency())
.from(from) .from(from)
@@ -3170,6 +3183,7 @@ public class P25DecoderState extends DecoderState
else else
{ {
StringBuilder details = new StringBuilder(); StringBuilder details = new StringBuilder();
details.append(tivcgu.isTDMAChannel() ? "TDMA " : "");
details.append(tivcgu.isEmergency() ? "EMERGENCY " : ""); details.append(tivcgu.isEmergency() ? "EMERGENCY " : "");
details.append("PRI:").append(tivcgu.getPriority()).append(" "); details.append("PRI:").append(tivcgu.getPriority()).append(" ");
details.append(tivcgu.isEncryptedChannel() ? "ENCRYPTED " : ""); details.append(tivcgu.isEncryptedChannel() ? "ENCRYPTED " : "");
@@ -3179,7 +3193,7 @@ public class P25DecoderState extends DecoderState
P25CallEvent event = new P25CallEvent.Builder( P25CallEvent event = new P25CallEvent.Builder(
CallEventType.TELEPHONE_INTERCONNECT) CallEventType.TELEPHONE_INTERCONNECT)
.aliasList(getAliasList()) .aliasList(getAliasList())
.channel(channel + (tivcgu.isTDMAChannel() ? " TDMA" : "")) .channel(channel)
.details(details.toString()) .details(details.toString())
.frequency(tivcgu.getDownlinkFrequency()) .frequency(tivcgu.getDownlinkFrequency())
.from(from) .from(from)
@@ -3209,6 +3223,7 @@ public class P25DecoderState extends DecoderState
else else
{ {
StringBuilder details = new StringBuilder(); StringBuilder details = new StringBuilder();
details.append(uuvcg.isTDMAChannel() ? "TDMA " : "");
details.append(uuvcg.isEmergency() ? "EMERGENCY " : ""); details.append(uuvcg.isEmergency() ? "EMERGENCY " : "");
details.append("PRI:").append(uuvcg.getPriority()).append(" "); details.append("PRI:").append(uuvcg.getPriority()).append(" ");
details.append(uuvcg.isEncryptedChannel() ? " ENCRYPTED " : ""); details.append(uuvcg.isEncryptedChannel() ? " ENCRYPTED " : "");
@@ -3217,7 +3232,7 @@ public class P25DecoderState extends DecoderState
P25CallEvent event = new P25CallEvent.Builder( P25CallEvent event = new P25CallEvent.Builder(
CallEventType.UNIT_TO_UNIT_CALL) CallEventType.UNIT_TO_UNIT_CALL)
.aliasList(getAliasList()) .aliasList(getAliasList())
.channel(channel + (uuvcg.isTDMAChannel() ? " TDMA" : "")) .channel(channel)
.details(details.toString()) .details(details.toString())
.frequency(uuvcg.getDownlinkFrequency()) .frequency(uuvcg.getDownlinkFrequency())
.from(from) .from(from)
@@ -3247,6 +3262,7 @@ public class P25DecoderState extends DecoderState
else else
{ {
StringBuilder details = new StringBuilder(); StringBuilder details = new StringBuilder();
details.append(uuvcgu.isTDMAChannel() ? "TDMA " : "");
details.append(uuvcgu.isEmergency() ? "EMERGENCY " : ""); details.append(uuvcgu.isEmergency() ? "EMERGENCY " : "");
details.append("PRI:").append(uuvcgu.getPriority()).append(" "); details.append("PRI:").append(uuvcgu.getPriority()).append(" ");
details.append(uuvcgu.isEncryptedChannel() ? "ENCRYPTED " : ""); details.append(uuvcgu.isEncryptedChannel() ? "ENCRYPTED " : "");
@@ -3255,7 +3271,7 @@ public class P25DecoderState extends DecoderState
P25CallEvent event = new P25CallEvent.Builder( P25CallEvent event = new P25CallEvent.Builder(
CallEventType.UNIT_TO_UNIT_CALL) CallEventType.UNIT_TO_UNIT_CALL)
.aliasList(getAliasList()) .aliasList(getAliasList())
.channel(channel + (uuvcgu.isTDMAChannel() ? " TDMA" : "")) .channel(channel)
.details(details.toString()) .details(details.toString())
.frequency(uuvcgu.getDownlinkFrequency()) .frequency(uuvcgu.getDownlinkFrequency())
.from(from) .from(from)

View File

@@ -689,8 +689,7 @@ public class P25MessageFramer implements Listener<Dibit>
private LSMDemodulator mDemodulator; private LSMDemodulator mDemodulator;
private double mCorrection; private double mCorrection;
public CostasPhaseErrorDetector( FrameSync frameSync, public CostasPhaseErrorDetector( FrameSync frameSync, LSMDemodulator demodulator, double correction )
LSMDemodulator demodulator, double correction )
{ {
super( frameSync.getSync() ); super( frameSync.getSync() );

View File

@@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
* SDR Trunk * sdrtrunk
* Copyright (C) 2014,2015 Dennis Sheirer * Copyright (C) 2014-2017 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -14,6 +14,7 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/ ******************************************************************************/
package module.decode.p25; package module.decode.p25;
@@ -41,8 +42,7 @@ import dsp.filter.FilterFactory;
import dsp.filter.Window.WindowType; import dsp.filter.Window.WindowType;
import dsp.filter.fir.real.RealFIRFilter_RB_RB; import dsp.filter.fir.real.RealFIRFilter_RB_RB;
public class P25_C4FMDecoder extends P25Decoder public class P25_C4FMDecoder extends P25Decoder implements IFilteredRealBufferListener
implements IFrequencyChangeListener, IFrequencyChangeProvider,IFilteredRealBufferListener
{ {
private final static Logger mLog = LoggerFactory.getLogger( P25_C4FMDecoder.class ); private final static Logger mLog = LoggerFactory.getLogger( P25_C4FMDecoder.class );

View File

@@ -42,6 +42,7 @@ import dsp.filter.fir.complex.ComplexFIRFilter_CB_CB;
import dsp.gain.ComplexFeedForwardGainControl; import dsp.gain.ComplexFeedForwardGainControl;
import dsp.psk.LSMDemodulator; import dsp.psk.LSMDemodulator;
import dsp.psk.QPSKPolarSlicer; import dsp.psk.QPSKPolarSlicer;
import source.tuner.frequency.FrequencyChangeEvent;
public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
{ {
@@ -56,8 +57,7 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
private List<TapGroup> mAvailableTaps; private List<TapGroup> mAvailableTaps;
private ComplexFIRFilter_CB_CB mBasebandFilter; private ComplexFIRFilter_CB_CB mBasebandFilter;
private ComplexBufferToStreamConverter mStreamConverter = private ComplexBufferToStreamConverter mStreamConverter = new ComplexBufferToStreamConverter();
new ComplexBufferToStreamConverter();
private ComplexFeedForwardGainControl mAGC = private ComplexFeedForwardGainControl mAGC =
new ComplexFeedForwardGainControl( 32 ); new ComplexFeedForwardGainControl( 32 );
private LSMDemodulator mLSMDemodulator = new LSMDemodulator(); private LSMDemodulator mLSMDemodulator = new LSMDemodulator();
@@ -108,6 +108,29 @@ public class P25_LSMDecoder extends P25Decoder implements IComplexBufferListener
mMessageFramer = null; mMessageFramer = null;
} }
@Override
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
{
}
@Override
public void removeFrequencyChangeListener()
{
}
@Override
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
{
return new Listener<FrequencyChangeEvent>()
{
@Override
public void receive(FrequencyChangeEvent frequencyChangeEvent)
{
//Ignored
}
};
}
@Override @Override
public Listener<ComplexBuffer> getComplexBufferListener() public Listener<ComplexBuffer> getComplexBufferListener()
{ {

View File

@@ -41,7 +41,7 @@ public class IdentifierUpdateTDMA extends IdentifierUpdate
sb.append( " ID:" + getIdentifier() ); sb.append( " ID:" + getIdentifier() );
sb.append( " BASE:" + getBaseFrequency() ); sb.append( " BASE:" + getBaseFrequency() );
sb.append( " BW:" + getBandwidth() ); sb.append( " BANDWIDTH:" + getBandwidth() );
sb.append( " SPACING:" + getChannelSpacing() ); sb.append( " SPACING:" + getChannelSpacing() );
sb.append( " OFFSET:" + getTransmitOffset() ); sb.append( " OFFSET:" + getTransmitOffset() );
sb.append( " TYPE:" + getChannelType().toString() ); sb.append( " TYPE:" + getChannelType().toString() );
@@ -137,7 +137,7 @@ public class IdentifierUpdateTDMA extends IdentifierUpdate
sb.append( mAccessType.name() ); sb.append( mAccessType.name() );
sb.append( " BANDWIDTH:" + mBandwidth ); sb.append( " BANDWIDTH:" + mBandwidth );
sb.append( " SLOT/CARRIER:" + mSlotsPerCarrier ); sb.append( " TIMESLOTS PER CARRIER:" + mSlotsPerCarrier );
sb.append( " VOCODER:" + mVocoder.name() ); sb.append( " VOCODER:" + mVocoder.name() );
return sb.toString(); return sb.toString();

View File

@@ -58,6 +58,11 @@ public class Broadcaster<T> implements Listener<T>
public void addListener( Listener<T> listener ) public void addListener( Listener<T> listener )
{ {
if(listener == null)
{
throw new IllegalArgumentException("Listener cannot be null");
}
mListeners.add( listener ); mListeners.add( listener );
} }

View File

@@ -20,11 +20,13 @@ package source;
import module.Module; import module.Module;
import sample.SampleType; import sample.SampleType;
import sample.real.IOverflowListener; import sample.real.IOverflowListener;
import source.tuner.frequency.IFrequencyChangeListener;
import source.tuner.frequency.IFrequencyChangeProvider;
/** /**
* Abstract class to define the minimum functionality of a sample data provider. * Abstract class to define the minimum functionality of a sample data provider.
*/ */
public abstract class Source extends Module public abstract class Source extends Module implements IFrequencyChangeListener, IFrequencyChangeProvider
{ {
protected SampleType mSampleType; protected SampleType mSampleType;
protected IOverflowListener mOverflowListener; protected IOverflowListener mOverflowListener;

View File

@@ -36,11 +36,11 @@ import sample.real.RealBuffer;
import source.RealSource; import source.RealSource;
import source.SourceException; import source.SourceException;
import dsp.gain.AutomaticGainControl; import dsp.gain.AutomaticGainControl;
import source.tuner.frequency.FrequencyChangeEvent;
public class RealMixerSource extends RealSource public class RealMixerSource extends RealSource
{ {
private final static Logger mLog = private final static Logger mLog = LoggerFactory.getLogger( RealMixerSource.class );
LoggerFactory.getLogger( RealMixerSource.class );
private long mFrequency = 0; private long mFrequency = 0;
private int mBufferSize = 16384; private int mBufferSize = 16384;
@@ -48,13 +48,11 @@ public class RealMixerSource extends RealSource
private BufferReader mBufferReader = new BufferReader(); private BufferReader mBufferReader = new BufferReader();
private TargetDataLine mTargetDataLine; private TargetDataLine mTargetDataLine;
private AudioFormat mAudioFormat; private AudioFormat mAudioFormat;
private String mDisplayName;
private int mBytesPerFrame = 0; private int mBytesPerFrame = 0;
private ISampleAdapter mSampleAdapter; private ISampleAdapter mSampleAdapter;
private AutomaticGainControl mAGC = new AutomaticGainControl(); private AutomaticGainControl mAGC = new AutomaticGainControl();
CopyOnWriteArrayList<Listener<RealBuffer>> mSampleListeners = CopyOnWriteArrayList<Listener<RealBuffer>> mSampleListeners = new CopyOnWriteArrayList<Listener<RealBuffer>>();
new CopyOnWriteArrayList<Listener<RealBuffer>>();
/** /**
* Real Mixer Source - constructs a reader on the mixer/sound card target * Real Mixer Source - constructs a reader on the mixer/sound card target
@@ -81,6 +79,25 @@ public class RealMixerSource extends RealSource
mSampleAdapter = sampleAdapter; mSampleAdapter = sampleAdapter;
} }
@Override
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
{
//Not implemented
}
@Override
public void removeFrequencyChangeListener()
{
//Not implemented
}
@Override
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
{
//Not implemented
return null;
}
@Override @Override
public void reset() public void reset()
{ {
@@ -133,23 +150,15 @@ public class RealMixerSource extends RealSource
* buffer, otherwise send him a copy of the buffer */ * buffer, otherwise send him a copy of the buffer */
if( it.hasNext() ) if( it.hasNext() )
{ {
// next.receive( mAGC.process( samples.copyOf() ) );
next.receive( samples.copyOf() ); next.receive( samples.copyOf() );
} }
else else
{ {
// next.receive( mAGC.process( samples ) );
next.receive( samples ); next.receive( samples );
} }
} }
} }
@Override
public String toString()
{
return mDisplayName;
}
public int getSampleRate() public int getSampleRate()
{ {
if( mTargetDataLine != null ) if( mTargetDataLine != null )

View File

@@ -34,7 +34,9 @@ import source.ComplexSource;
import source.SourceException; import source.SourceException;
import source.tuner.frequency.FrequencyChangeEvent; import source.tuner.frequency.FrequencyChangeEvent;
import source.tuner.frequency.FrequencyChangeEvent.Event; import source.tuner.frequency.FrequencyChangeEvent.Event;
import source.tuner.frequency.IFrequencyChangeListener;
import source.tuner.frequency.IFrequencyChangeProcessor; import source.tuner.frequency.IFrequencyChangeProcessor;
import source.tuner.frequency.IFrequencyChangeProvider;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -65,6 +67,7 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
private ComplexPrimeCICDecimate mDecimationFilter; private ComplexPrimeCICDecimate mDecimationFilter;
private Listener<ComplexBuffer> mListener; private Listener<ComplexBuffer> mListener;
private IFrequencyChangeProcessor mFrequencyChangeProcessor; private IFrequencyChangeProcessor mFrequencyChangeProcessor;
private DownstreamProcessor mDownstreamFrequencyEventProcessor = new DownstreamProcessor();
private ScheduledFuture<?> mTaskHandle; private ScheduledFuture<?> mTaskHandle;
private long mTunerFrequency = 0; private long mTunerFrequency = 0;
@@ -75,7 +78,6 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
private AtomicBoolean mRunning = new AtomicBoolean(); private AtomicBoolean mRunning = new AtomicBoolean();
private boolean mExpended = false; private boolean mExpended = false;
private int mCount;
/** /**
* Provides a Digital Drop Channel (DDC) to decimate the IQ output from a * Provides a Digital Drop Channel (DDC) to decimate the IQ output from a
@@ -109,7 +111,8 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
mMixer = new Oscillator(frequencyOffset, mTuner.getTunerController().getSampleRate()); mMixer = new Oscillator(frequencyOffset, mTuner.getTunerController().getSampleRate());
/* Fire a sample rate change event to setup the decimation chain */ /* Fire a sample rate change event to setup the decimation chain */
frequencyChanged(new FrequencyChangeEvent(Event.NOTIFICATION_SAMPLE_RATE_CHANGE, mTuner.getTunerController().getSampleRate())); frequencyChanged(new FrequencyChangeEvent(Event.NOTIFICATION_SAMPLE_RATE_CHANGE,
mTuner.getTunerController().getSampleRate()));
} }
/** /**
@@ -131,6 +134,10 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
if(mRunning.compareAndSet(false, true)) if(mRunning.compareAndSet(false, true))
{ {
//Broadcast current frequency and sample rate settings so all downstream components are aware
mDownstreamFrequencyEventProcessor.broadcastCurrentFrequency();
mDownstreamFrequencyEventProcessor.broadcastCurrentSampleRate();
//Schedule the decimation task to run every 9 ms (111 iterations/second), an odd periodicity relative //Schedule the decimation task to run every 9 ms (111 iterations/second), an odd periodicity relative
//to the inbound periodicity of 20 ms, to attempt to avoid thread queue contention //to the inbound periodicity of 20 ms, to attempt to avoid thread queue contention
mTaskHandle = executor.scheduleAtFixedRate(mDecimationProcessor, 0, 9, TimeUnit.MILLISECONDS); mTaskHandle = executor.scheduleAtFixedRate(mDecimationProcessor, 0, 9, TimeUnit.MILLISECONDS);
@@ -184,6 +191,20 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
} }
} }
/**
* Changes the frequency correction value and broadcasts the change to the registered downstream listener.
* @param correction current frequency correction value.
*/
private void setFrequencyCorrection(int correction)
{
mChannelFrequencyCorrection = correction;
updateMixerFrequencyOffset();
mDownstreamFrequencyEventProcessor.broadcast(
new FrequencyChangeEvent( Event.NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE, mChannelFrequencyCorrection));
}
public Tuner getTuner() public Tuner getTuner()
{ {
return mTuner; return mTuner;
@@ -242,21 +263,25 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
case NOTIFICATION_FREQUENCY_CHANGE: case NOTIFICATION_FREQUENCY_CHANGE:
mTunerFrequency = event.getValue().longValue(); mTunerFrequency = event.getValue().longValue();
updateMixerFrequencyOffset(); updateMixerFrequencyOffset();
break;
case REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
mChannelFrequencyCorrection = event.getValue().intValue();
updateMixerFrequencyOffset(); //Reset frequency correction so that downstream components can recalculate the value
setFrequencyCorrection(0);
if(mFrequencyChangeProcessor != null)
{
mFrequencyChangeProcessor.frequencyChanged(new FrequencyChangeEvent(
Event.NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE, mChannelFrequencyCorrection));
}
break; break;
case NOTIFICATION_SAMPLE_RATE_CHANGE: case NOTIFICATION_SAMPLE_RATE_CHANGE:
int sampleRate = event.getValue().intValue(); int sampleRate = event.getValue().intValue();
setSampleRate(sampleRate);
break;
default:
break;
}
}
/**
* Updates the sample rate to the requested value and notifies any downstream components of the change
* @param sampleRate to set
*/
private void setSampleRate(int sampleRate)
{
if(mTunerSampleRate != sampleRate) if(mTunerSampleRate != sampleRate)
{ {
mMixer.setSampleRate(sampleRate); mMixer.setSampleRate(sampleRate);
@@ -269,10 +294,8 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
mDecimationFilter.setListener(mListener); mDecimationFilter.setListener(mListener);
mTunerSampleRate = sampleRate; mTunerSampleRate = sampleRate;
}
break; mDownstreamFrequencyEventProcessor.broadcastCurrentSampleRate();
default:
break;
} }
} }
@@ -282,10 +305,7 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
*/ */
private void updateMixerFrequencyOffset() private void updateMixerFrequencyOffset()
{ {
long offset = mTunerFrequency - long offset = mTunerFrequency - mTunerChannel.getFrequency() - mChannelFrequencyCorrection;
mTunerChannel.getFrequency() -
mChannelFrequencyCorrection;
mMixer.setFrequency(offset); mMixer.setFrequency(offset);
} }
@@ -299,6 +319,140 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
return mTunerChannel.getFrequency(); return mTunerChannel.getFrequency();
} }
/**
* Implements IFrequencyChangeProvider to enable this source to broadcast frequency change events to downstream
* listeners.
*
* @param listener to receive downstream events
*/
@Override
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
{
mDownstreamFrequencyEventProcessor.setFrequencyChangeListener(listener);
}
/**
* Implements IFrequencyChangeProvider to remove the frequency change listener from receiving down-stream frequency
* change events.
*/
@Override
public void removeFrequencyChangeListener()
{
mDownstreamFrequencyEventProcessor.removeFrequencyChangeListener();
}
/**
* Implements IFrequencyChangeListener to receive frequency change events containing requests from downstream
* listeners to change frequency values.
* @return listener
*/
@Override
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
{
return mDownstreamFrequencyEventProcessor.getFrequencyChangeListener();
}
/**
* Managers frequency change requests and notifications from/to any downstream component. Downstream
* components are those that receive samples from this tuner channel source. These downstream components will be
* notified of any frequency or sample rate change events and will also be able to request frequency correction
* updates.
*/
public class DownstreamProcessor implements IFrequencyChangeListener, IFrequencyChangeProvider,
Listener<FrequencyChangeEvent>
{
//Listener to receive downstream events
private Listener<FrequencyChangeEvent> mListener;
/**
* Broadcasts the frequency change event to the downstream frequency change listener
* @param event to broadcast
*/
public void broadcast(FrequencyChangeEvent event)
{
if(mListener != null)
{
mListener.receive(event);
}
}
/**
* Broadcasts the current frequency of this tuner channel source to the downstream listener
*/
public void broadcastCurrentFrequency()
{
try
{
long frequency = getFrequency();
broadcast(new FrequencyChangeEvent(Event.NOTIFICATION_FREQUENCY_CHANGE, frequency));
}
catch(SourceException se)
{
mLog.error("Error obtaining frequency from tuner to broadcast downstream");
}
}
/**
* Broadcasts the current decimated sample rate of this tuner channel source
*/
public void broadcastCurrentSampleRate()
{
try
{
//Note: downstream sample rate is currently a fixed value -- it will change in the future
broadcast(new FrequencyChangeEvent(Event.NOTIFICATION_SAMPLE_RATE_CHANGE, getSampleRate()));
}
catch(SourceException se)
{
mLog.error("Error obtaining sample rate from tuner to broadcast downstream");
}
}
/**
* Sets the downstream listener to receive frequency change events from this tuner channel source
* @param listener to receive events
*/
@Override
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
{
mListener = listener;
}
/**
* Removes the downstream listener from receiving frequency change events.
*/
@Override
public void removeFrequencyChangeListener()
{
mListener = null;
}
/**
* Listener for receiving frequency change events from downstream components
*/
@Override
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
{
return this;
}
/**
* Processes frequency change events from downstream components.
* @param event to process
*/
@Override
public void receive(FrequencyChangeEvent event)
{
switch(event.getEvent())
{
//Frequency correction requests are the only change requests supported from downstream components
case REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
setFrequencyCorrection(event.getValue().intValue());
break;
}
}
}
/** /**
* Decimates an inbound buffer of I/Q samples from the source down to the * Decimates an inbound buffer of I/Q samples from the source down to the
* standard 48000 channel sample rate * standard 48000 channel sample rate

View File

@@ -1,9 +1,30 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 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 source.tuner.frequency; package source.tuner.frequency;
import sample.Listener; import sample.Listener;
/**
* Provider of Frequency Change Events
*/
public interface IFrequencyChangeProvider public interface IFrequencyChangeProvider
{ {
public void setFrequencyChangeListener( Listener<FrequencyChangeEvent> listener ); void setFrequencyChangeListener( Listener<FrequencyChangeEvent> listener );
public void removeFrequencyChangeListener(); void removeFrequencyChangeListener();
} }

View File

@@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
* SDR Trunk * sdrtrunk
* Copyright (C) 2014,2015 Dennis Sheirer * Copyright (C) 2014-2017 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -14,6 +14,7 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/ ******************************************************************************/
package source.wave; package source.wave;
@@ -36,6 +37,7 @@ import sample.complex.ComplexBuffer;
import source.ComplexSource; import source.ComplexSource;
import source.IControllableFileSource; import source.IControllableFileSource;
import source.IFrameLocationListener; import source.IFrameLocationListener;
import source.tuner.frequency.FrequencyChangeEvent;
public class ComplexWaveSource extends ComplexSource implements IControllableFileSource public class ComplexWaveSource extends ComplexSource implements IControllableFileSource
{ {
@@ -55,6 +57,25 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil
mFile = file; mFile = file;
} }
@Override
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
{
//Not implemented
}
@Override
public void removeFrequencyChangeListener()
{
//Not implemented
}
@Override
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
{
//Not implemented
return null;
}
@Override @Override
public void reset() public void reset()
{ {

View File

@@ -36,6 +36,7 @@ import sample.real.RealBuffer;
import source.IControllableFileSource; import source.IControllableFileSource;
import source.IFrameLocationListener; import source.IFrameLocationListener;
import source.RealSource; import source.RealSource;
import source.tuner.frequency.FrequencyChangeEvent;
public class RealWaveSource extends RealSource public class RealWaveSource extends RealSource
implements IControllableFileSource, AutoCloseable implements IControllableFileSource, AutoCloseable
@@ -56,6 +57,25 @@ public class RealWaveSource extends RealSource
mFile = file; mFile = file;
} }
@Override
public void setFrequencyChangeListener(Listener<FrequencyChangeEvent> listener)
{
//Not implemented
}
@Override
public void removeFrequencyChangeListener()
{
//Not implemented
}
@Override
public Listener<FrequencyChangeEvent> getFrequencyChangeListener()
{
//Not implemented
return null;
}
@Override @Override
public void reset() public void reset()

View File

@@ -50,6 +50,7 @@ public class OverlayPanel extends JPanel implements ChannelEventListener, IFrequ
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger(OverlayPanel.class); private final static Logger mLog = LoggerFactory.getLogger(OverlayPanel.class);
private final DecimalFormat PPM_FORMATTER = new DecimalFormat( "#.0" );
private final static RenderingHints RENDERING_HINTS = new RenderingHints(RenderingHints.KEY_ANTIALIASING, private final static RenderingHints RENDERING_HINTS = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON); RenderingHints.VALUE_ANTIALIAS_ON);
@@ -187,7 +188,6 @@ public class OverlayPanel extends JPanel implements ChannelEventListener, IFrequ
* 6 64x Zoom * 6 64x Zoom
* *
* @param zoom level, 0 - 6. * @param zoom level, 0 - 6.
* @param offset into the FFT bins for start zoom window
*/ */
public void setZoom(int zoom) public void setZoom(int zoom)
{ {
@@ -412,20 +412,41 @@ public class OverlayPanel extends JPanel implements ChannelEventListener, IFrequ
} }
/** /**
* Draws a vertical line at the xaxis * Draws the Automatic Frequency Control (AFC) channel center offset
*/ */
private void drawAFC(Graphics2D graphics, double frequencyAxis, double errorAxis) private void drawAFC(Graphics2D graphics, double frequencyAxis, double errorAxis, double bandwidth,
int correction, long frequency)
{ {
double height = getSize().getHeight() - mSpectrumInset; double height = getSize().getHeight() - mSpectrumInset;
double lineHeight = height * 0.75d; double verticalAxisTop = height * 0.88d;
double verticalAxisBottom = height * 0.98d;
double halfBandwidth = bandwidth / 2.0;
double errorEdgeStart = errorAxis - halfBandwidth;
double errorEdgeStop = errorAxis + halfBandwidth;
graphics.setColor(Color.YELLOW); graphics.setColor(Color.YELLOW);
//Vertical frequency error line //Horizontal line connecting frequency and error line
graphics.draw(new Line2D.Double(errorAxis, lineHeight, errorAxis, height - 1.0d)); graphics.draw(new Line2D.Double(errorEdgeStart, verticalAxisBottom, errorEdgeStop, verticalAxisBottom));
//Horizontal line connecting frequency and error lines //Vertical band edge lines
graphics.draw(new Line2D.Double(frequencyAxis, lineHeight, errorAxis, lineHeight)); graphics.draw(new Line2D.Double(errorEdgeStart, verticalAxisTop, errorEdgeStart, verticalAxisBottom));
graphics.draw(new Line2D.Double(errorEdgeStop, verticalAxisTop, errorEdgeStop, verticalAxisBottom));
double ppm = (double)correction / ((double)frequency / 1E6d);
String label = "PPM " + PPM_FORMATTER.format(ppm) ;
FontMetrics fontMetrics = graphics.getFontMetrics(this.getFont());
Rectangle2D rect = fontMetrics.getStringBounds(label, graphics);
//Only render the correction value label if the spacing is large enough
if(rect.getWidth() <= bandwidth && rect.getHeight() * 5 <= height)
{
graphics.drawString(label, (float)(errorEdgeStart + 1.0), (float)(verticalAxisBottom - 2.0));
}
} }
/** /**
@@ -564,7 +585,8 @@ public class OverlayPanel extends JPanel implements ChannelEventListener, IFrequ
{ {
long error = frequency + correction; long error = frequency + correction;
drawAFC(graphics, frequencyAxis, getAxisFromFrequency(error)); drawAFC(graphics, frequencyAxis, getAxisFromFrequency(error), width, correction,
tunerChannel.getFrequency());
} }
} }
} }

View File

@@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
* SDR Trunk * sdrtrunk
* Copyright (C) 2014,2015 Dennis Sheirer * Copyright (C) 2014-2017 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -14,56 +14,43 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/ ******************************************************************************/
package spectrum; package spectrum;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.util.Arrays;
import javax.swing.JPanel;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import settings.ColorSetting;
import settings.ColorSetting.ColorSettingName;
import settings.Setting;
import settings.SettingChangeListener;
import settings.SettingsManager;
import dsp.filter.smoothing.GaussianSmoothingFilter; import dsp.filter.smoothing.GaussianSmoothingFilter;
import dsp.filter.smoothing.NoSmoothingFilter; import dsp.filter.smoothing.NoSmoothingFilter;
import dsp.filter.smoothing.RectangularSmoothingFilter; import dsp.filter.smoothing.RectangularSmoothingFilter;
import dsp.filter.smoothing.SmoothingFilter; import dsp.filter.smoothing.SmoothingFilter;
import dsp.filter.smoothing.SmoothingFilter.SmoothingType; import dsp.filter.smoothing.SmoothingFilter.SmoothingType;
import dsp.filter.smoothing.TriangularSmoothingFilter; import dsp.filter.smoothing.TriangularSmoothingFilter;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import settings.ColorSetting;
import settings.ColorSetting.ColorSettingName;
import settings.Setting;
import settings.SettingChangeListener;
import settings.SettingsManager;
public class SpectrumPanel extends JPanel import javax.swing.*;
implements DFTResultsListener, import java.awt.*;
SettingChangeListener, import java.awt.geom.GeneralPath;
SpectralDisplayAdjuster import java.awt.geom.Line2D;
import java.util.Arrays;
public class SpectrumPanel extends JPanel implements DFTResultsListener, SettingChangeListener, SpectralDisplayAdjuster
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final static Logger mLog = private final static Logger mLog = LoggerFactory.getLogger(SpectrumPanel.class);
LoggerFactory.getLogger( SpectrumPanel.class );
private static final RenderingHints RENDERING_HINTS = private static final RenderingHints RENDERING_HINTS =
new RenderingHints( RenderingHints.KEY_ANTIALIASING, new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
RenderingHints.VALUE_ANTIALIAS_ON );
static static
{ {
RENDERING_HINTS.put( RenderingHints.KEY_RENDERING, RENDERING_HINTS.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
RenderingHints.VALUE_RENDER_QUALITY );
} }
private Color mColorSpectrumBackground; private Color mColorSpectrumBackground;
@@ -87,7 +74,8 @@ public class SpectrumPanel extends JPanel
private float mDBScale; private float mDBScale;
private int mZoom = 0; private int mZoom = 0;
private int mZoomWindowOffset = 0;; private int mZoomWindowOffset = 0;
;
private SettingsManager mSettingsManager; private SettingsManager mSettingsManager;
@@ -278,12 +266,13 @@ public class SpectrumPanel extends JPanel
* 3 8x Zoom * 3 8x Zoom
* 4 16x Zoom * 4 16x Zoom
* 5 32x Zoom * 5 32x Zoom
* 6 64x Zoom
* *
* @param zoom level, 0 - 5. * @param zoom level, 0 - 6.
*/ */
public void setZoom(int zoom) public void setZoom(int zoom)
{ {
Validate.isTrue( 0 <= zoom && zoom <= 5 ); Validate.isTrue(0 <= zoom && zoom <= 6, "Unrecognized Zoom Level: " + zoom);
mZoom = zoom; mZoom = zoom;
} }
@@ -427,7 +416,8 @@ public class SpectrumPanel extends JPanel
} }
@Override @Override
public void settingDeleted( Setting setting ) { /* not implemented */ } public void settingDeleted(Setting setting)
{ /* not implemented */ }
/** /**
* Returns the current inter-bin smoothing setting * Returns the current inter-bin smoothing setting