mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
-Separates USB timeout event processing to a dedicated thread -Updates USB transfer buffer processor to better detect errors and auto-restart on error (max 3 times) -Updates Tuner to add an error state and SourceManager to not select tuners with an error state -Updates ChannelProcessingManager to auto-shutdown channels sourced from tuners set with error state -Improves logging of USB related errors.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
||||
* * Copyright (C) 2014-2020 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
|
||||
@@ -47,6 +47,7 @@ import io.github.dsheirer.sample.Broadcaster;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
|
||||
import io.github.dsheirer.source.Source;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.SourceManager;
|
||||
import org.slf4j.Logger;
|
||||
@@ -262,6 +263,30 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
|
||||
processingChain.addDecodeEventListener(listener);
|
||||
}
|
||||
|
||||
//Add a listener to detect source error state that indicates the channel should be shutdown
|
||||
processingChain.addSourceEventListener(sourceEvent ->
|
||||
{
|
||||
if(sourceEvent.getEvent() == SourceEvent.Event.NOTIFICATION_ERROR_STATE && sourceEvent.getSource() != null)
|
||||
{
|
||||
Channel toShutdown = null;
|
||||
|
||||
for(Map.Entry<Channel,ProcessingChain> entry: mProcessingChains.entrySet())
|
||||
{
|
||||
if(entry.getValue().hasSource(sourceEvent.getSource()))
|
||||
{
|
||||
toShutdown = entry.getKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(toShutdown != null)
|
||||
{
|
||||
mLog.info("Channel source error detected - stopping channel [" + toShutdown.getName() + "]");
|
||||
stopProcessing(toShutdown, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//Register this manager to receive channel events from traffic channel manager modules within
|
||||
//the processing chain
|
||||
processingChain.addChannelEventListener(this);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
||||
* * Copyright (C) 2014-2020 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
|
||||
@@ -126,6 +126,18 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
|
||||
this(tunerController, tunerController.getFrequency(), tunerController.getSampleRate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals to all provisioned tuner channel sources that the source complex buffer provider has an error and can
|
||||
* no longer provide channels, so that the tuner channel source can notify the consumer of the error state.
|
||||
*/
|
||||
public void setErrorMessage(String errorMessage)
|
||||
{
|
||||
for(TunerChannelSource tunerChannelSource: mChannelSources)
|
||||
{
|
||||
tunerChannelSource.setError(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Current channel sample rate which is (2 * channel bandwidth).
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
||||
* * Copyright (C) 2014-2020 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
|
||||
@@ -474,7 +474,6 @@ public class SDRTrunk implements Listener<TunerEvent>
|
||||
mAudioPacketManager.stop();
|
||||
mLog.info("Stopping spectral display ...");
|
||||
mSpectralPanel.clearTuner();
|
||||
mLog.info("Releasing tuners ...");
|
||||
mSourceManager.shutdown();
|
||||
mLog.info("Shutdown complete.");
|
||||
mApplicationLog.stop();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
||||
* * Copyright (C) 2014-2020 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
|
||||
@@ -115,14 +115,12 @@ public class ProcessingChain implements Listener<ChannelEvent>
|
||||
private Broadcaster<SourceEvent> mSourceEventBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<IMessage> mMessageBroadcaster = new Broadcaster<>();
|
||||
private Broadcaster<SquelchStateEvent> mSquelchStateEventBroadcaster = new Broadcaster<>();
|
||||
|
||||
private AtomicBoolean mRunning = new AtomicBoolean();
|
||||
|
||||
protected Source mSource;
|
||||
private List<Module> mModules = new ArrayList<>();
|
||||
private DecodeEventModel mDecodeEventModel;
|
||||
private AbstractChannelState mChannelState;
|
||||
private MessageActivityModel mMessageActivityModel;
|
||||
protected Source mSource;
|
||||
|
||||
/**
|
||||
* Creates a processing chain for managing a set of modules
|
||||
@@ -208,6 +206,14 @@ public class ProcessingChain implements Listener<ChannelEvent>
|
||||
return mSource != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this chain's source is the same as the source argument
|
||||
*/
|
||||
public boolean hasSource(Source source)
|
||||
{
|
||||
return mSource != null && mSource.equals(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a sample source to this processing chain. Processing won't
|
||||
* start until the start() method is invoked.
|
||||
@@ -800,6 +806,14 @@ public class ProcessingChain implements Listener<ChannelEvent>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to receive source events from this processing chain
|
||||
*/
|
||||
public void addSourceEventListener(Listener<SourceEvent> listener)
|
||||
{
|
||||
mSourceEventBroadcaster.addListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the listener from receiving decoded messages from all decoders.
|
||||
*/
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.source;
|
||||
|
||||
@@ -39,6 +41,7 @@ public class SourceEvent
|
||||
NOTIFICATION_RECORDING_FILE_LOADED,
|
||||
NOTIFICATION_SAMPLE_RATE_CHANGE,
|
||||
NOTIFICATION_STOP_SAMPLE_STREAM,
|
||||
NOTIFICATION_ERROR_STATE,
|
||||
|
||||
REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
|
||||
REQUEST_FREQUENCY_CHANGE,
|
||||
@@ -69,6 +72,14 @@ public class SourceEvent
|
||||
mEventDescription = eventDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor. Use the static constructor methods to create an event.
|
||||
*/
|
||||
private SourceEvent(Event event, Source source, String eventDescription)
|
||||
{
|
||||
this(event, source, null, eventDescription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor. Use the static constructor methods to create an event.
|
||||
*/
|
||||
@@ -167,6 +178,15 @@ public class SourceEvent
|
||||
return mSource != null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new error state for the specified source and error description
|
||||
*/
|
||||
public static SourceEvent errorState(Source source, String errorDescription)
|
||||
{
|
||||
return new SourceEvent(Event.NOTIFICATION_ERROR_STATE, source, errorDescription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new locked state change event
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||
* *
|
||||
* * This program is free software: you can redistribute it and/or modify
|
||||
* * it under the terms of the GNU General Public License as published by
|
||||
* * the Free Software Foundation, either version 3 of the License, or
|
||||
* * (at your option) any later version.
|
||||
* *
|
||||
* * This program is distributed in the hope that it will be useful,
|
||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* * GNU General Public License for more details.
|
||||
* *
|
||||
* * You should have received a copy of the GNU General Public License
|
||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.source.tuner;
|
||||
|
||||
public interface ITunerErrorListener
|
||||
{
|
||||
/**
|
||||
* Sets an error message for the tuner listener
|
||||
* @param errorMessage to set
|
||||
*/
|
||||
void setErrorMessage(String errorMessage);
|
||||
}
|
||||
@@ -1,21 +1,23 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.source.tuner;
|
||||
|
||||
@@ -36,7 +38,7 @@ import org.slf4j.LoggerFactory;
|
||||
* Tuner provides an interface to a software or hardware tuner controller that provides I/Q sample data coupled with a
|
||||
* channel source manager to provide access to Digital Drop Channel (DDC) resources.
|
||||
*/
|
||||
public abstract class Tuner implements ISourceEventProcessor
|
||||
public abstract class Tuner implements ISourceEventProcessor, ITunerErrorListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(Tuner.class);
|
||||
|
||||
@@ -45,6 +47,7 @@ public abstract class Tuner implements ISourceEventProcessor
|
||||
private TunerController mTunerController;
|
||||
private TunerFrequencyErrorMonitor mTunerFrequencyErrorMonitor;
|
||||
private String mName;
|
||||
private String mErrorMessage;
|
||||
|
||||
public Tuner(String name, TunerController tunerController)
|
||||
{
|
||||
@@ -52,7 +55,7 @@ public abstract class Tuner implements ISourceEventProcessor
|
||||
mTunerController = tunerController;
|
||||
//Register to receive frequency and sample rate change notifications
|
||||
mTunerController.addListener(this::process);
|
||||
|
||||
mTunerController.setTunerErrorListener(this);
|
||||
mTunerFrequencyErrorMonitor = new TunerFrequencyErrorMonitor(this);
|
||||
mTunerFrequencyErrorMonitor.start();
|
||||
}
|
||||
@@ -94,6 +97,34 @@ public abstract class Tuner implements ISourceEventProcessor
|
||||
mChannelSourceManager.addSourceEventListener(this::process);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this tuner to an error state with the errorMessage description.
|
||||
* @param errorMessage describing the error state
|
||||
*/
|
||||
public void setErrorMessage(String errorMessage)
|
||||
{
|
||||
mLog.info("[" + getName() + "] tuner is now disabled for error [" + errorMessage + "]");
|
||||
mErrorMessage = errorMessage;
|
||||
broadcast(new TunerEvent(this, Event.ERROR_STATE));
|
||||
getChannelSourceManager().setErrorMessage(errorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional error message that describes an error state.
|
||||
*/
|
||||
public String getErrorMessage()
|
||||
{
|
||||
return mErrorMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this tuner has an error.
|
||||
*/
|
||||
public boolean hasError()
|
||||
{
|
||||
return mErrorMessage != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(SourceEvent event)
|
||||
{
|
||||
@@ -148,7 +179,7 @@ public abstract class Tuner implements ISourceEventProcessor
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return mName;
|
||||
return mName + (hasError() ? mErrorMessage : "");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
||||
* * Copyright (C) 2014-2020 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
|
||||
@@ -42,7 +42,7 @@ import org.slf4j.LoggerFactory;
|
||||
import java.util.SortedSet;
|
||||
|
||||
public abstract class TunerController implements Tunable, ISourceEventProcessor, ISourceEventListener,
|
||||
IReusableComplexBufferProvider, Listener<ReusableComplexBuffer>
|
||||
IReusableComplexBufferProvider, Listener<ReusableComplexBuffer>, ITunerErrorListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(TunerController.class);
|
||||
protected ReusableBufferBroadcaster mReusableBufferBroadcaster = new ReusableBufferBroadcaster();
|
||||
@@ -52,6 +52,7 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
|
||||
private Listener<SourceEvent> mSourceEventListener;
|
||||
private int mMeasuredFrequencyError;
|
||||
private ComplexBufferWaveRecorder mRecorder;
|
||||
private ITunerErrorListener mTunerErrorListener;
|
||||
|
||||
/**
|
||||
* Abstract tuner controller class. The tuner controller manages frequency bandwidth and currently tuned channels
|
||||
@@ -77,6 +78,24 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
|
||||
*/
|
||||
public abstract void dispose();
|
||||
|
||||
@Override
|
||||
public void setErrorMessage(String errorMessage)
|
||||
{
|
||||
if(mTunerErrorListener != null)
|
||||
{
|
||||
mTunerErrorListener.setErrorMessage(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the listener for tuner error messages that originate outside of the tuner. This is normally the enclosing
|
||||
* tuner so that it can receive error signals from the USB processor(s)..
|
||||
*/
|
||||
public void setTunerErrorListener(ITunerErrorListener tunerErrorListener)
|
||||
{
|
||||
mTunerErrorListener = tunerErrorListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of samples contained in each complex buffer provided by this tuner.
|
||||
*
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||
* *
|
||||
* * This program is free software: you can redistribute it and/or modify
|
||||
* * it under the terms of the GNU General Public License as published by
|
||||
* * the Free Software Foundation, either version 3 of the License, or
|
||||
* * (at your option) any later version.
|
||||
* *
|
||||
* * This program is distributed in the hope that it will be useful,
|
||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* * GNU General Public License for more details.
|
||||
* *
|
||||
* * You should have received a copy of the GNU General Public License
|
||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.source.tuner;
|
||||
|
||||
public class TunerEvent
|
||||
@@ -24,6 +46,7 @@ public class TunerEvent
|
||||
public enum Event
|
||||
{
|
||||
CHANNEL_COUNT,
|
||||
ERROR_STATE,
|
||||
FREQUENCY_UPDATED,
|
||||
FREQUENCY_ERROR_UPDATED,
|
||||
LOCK_STATE_CHANGE,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
||||
* * Copyright (C) 2014-2020 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
|
||||
@@ -58,9 +58,7 @@ public class TunerModel extends AbstractTableModel implements Listener<TunerEven
|
||||
public static final int FREQUENCY_ERROR = 5;
|
||||
public static final int MEASURED_FREQUENCY_ERROR = 6;
|
||||
public static final int SPECTRAL_DISPLAY_NEW = 7;
|
||||
|
||||
private static final int MAXIMUM_RECORDING_TUNERS_ALLOWED = 1;
|
||||
|
||||
private static final String MHZ = " MHz";
|
||||
private static final String[] COLUMNS = {"Tuner", "ID", "Sample Rate", "Frequency", "Channels", "Current PPM",
|
||||
"Measured Error", "Display"};
|
||||
@@ -113,7 +111,7 @@ public class TunerModel extends AbstractTableModel implements Listener<TunerEven
|
||||
{
|
||||
for(Tuner tuner : mTuners)
|
||||
{
|
||||
if(tuner.getName().equalsIgnoreCase(name))
|
||||
if(!tuner.hasError() && tuner.getName().equalsIgnoreCase(name))
|
||||
{
|
||||
return tuner;
|
||||
}
|
||||
@@ -279,6 +277,14 @@ public class TunerModel extends AbstractTableModel implements Listener<TunerEven
|
||||
break;
|
||||
case REQUEST_MAIN_SPECTRAL_DISPLAY:
|
||||
fireTableCellUpdated(index, MEASURED_FREQUENCY_ERROR);
|
||||
break;
|
||||
case ERROR_STATE:
|
||||
fireTableCellUpdated(index, CHANNEL_COUNT);
|
||||
fireTableCellUpdated(index, FREQUENCY);
|
||||
fireTableCellUpdated(index, FREQUENCY_ERROR);
|
||||
fireTableCellUpdated(index, MEASURED_FREQUENCY_ERROR);
|
||||
fireTableCellUpdated(index, SAMPLE_RATE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -314,10 +320,17 @@ public class TunerModel extends AbstractTableModel implements Listener<TunerEven
|
||||
case TUNER_ID:
|
||||
return tuner.getUniqueID();
|
||||
case SAMPLE_RATE:
|
||||
if(tuner.hasError())
|
||||
{
|
||||
return tuner.getErrorMessage();
|
||||
}
|
||||
double sampleRate = tuner.getTunerController().getSampleRate();
|
||||
|
||||
return mSampleRateFormat.format(sampleRate / 1E6D) + MHZ;
|
||||
case FREQUENCY:
|
||||
if(tuner.hasError())
|
||||
{
|
||||
return tuner.getErrorMessage();
|
||||
}
|
||||
try
|
||||
{
|
||||
long frequency = tuner.getTunerController().getFrequency();
|
||||
@@ -329,12 +342,24 @@ public class TunerModel extends AbstractTableModel implements Listener<TunerEven
|
||||
return 0;
|
||||
}
|
||||
case CHANNEL_COUNT:
|
||||
if(tuner.hasError())
|
||||
{
|
||||
return tuner.getErrorMessage();
|
||||
}
|
||||
int channelCount = tuner.getChannelSourceManager().getTunerChannelCount();
|
||||
return channelCount + " (" + (tuner.getTunerController().isLocked() ? "LOCKED)" : "UNLOCKED)");
|
||||
case FREQUENCY_ERROR:
|
||||
if(tuner.hasError())
|
||||
{
|
||||
return tuner.getErrorMessage();
|
||||
}
|
||||
double ppm = tuner.getTunerController().getFrequencyCorrection();
|
||||
return mFrequencyErrorPPMFormat.format(ppm);
|
||||
case MEASURED_FREQUENCY_ERROR:
|
||||
if(tuner.hasError())
|
||||
{
|
||||
return tuner.getErrorMessage();
|
||||
}
|
||||
if(tuner.getTunerController().hasMeasuredFrequencyError())
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -347,7 +372,14 @@ public class TunerModel extends AbstractTableModel implements Listener<TunerEven
|
||||
|
||||
return "";
|
||||
case SPECTRAL_DISPLAY_NEW:
|
||||
return "New";
|
||||
if(tuner.hasError())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "New";
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -373,8 +405,6 @@ public class TunerModel extends AbstractTableModel implements Listener<TunerEven
|
||||
|
||||
if(tunerChannel != null && channelSpecification != null)
|
||||
{
|
||||
Iterator<Tuner> it = mTuners.iterator();
|
||||
|
||||
Tuner tuner;
|
||||
|
||||
if(preferredTuner != null)
|
||||
@@ -402,17 +432,22 @@ public class TunerModel extends AbstractTableModel implements Listener<TunerEven
|
||||
preferredTuner + "] - searching for another tuner");
|
||||
}
|
||||
|
||||
Iterator<Tuner> it = mTuners.iterator();
|
||||
|
||||
while(it.hasNext() && source == null)
|
||||
{
|
||||
tuner = it.next();
|
||||
|
||||
try
|
||||
if(!tuner.hasError())
|
||||
{
|
||||
source = tuner.getChannelSourceManager().getSource(tunerChannel, channelSpecification);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
mLog.error("Error obtaining channel from tuner [" + tuner.getName() + "]", e);
|
||||
try
|
||||
{
|
||||
source = tuner.getChannelSourceManager().getSource(tunerChannel, channelSpecification);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
mLog.error("Error obtaining channel from tuner [" + tuner.getName() + "]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
||||
* * Copyright (C) 2014-2020 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
|
||||
@@ -191,8 +191,15 @@ public class TunerViewPanel extends JPanel
|
||||
}
|
||||
});
|
||||
|
||||
TableCellRenderer renderer = new LinkCellRenderer();
|
||||
mTunerTable.getColumnModel().getColumn(TunerModel.SPECTRAL_DISPLAY_NEW).setCellRenderer(renderer);
|
||||
TableCellRenderer linkCellRenderer = new LinkCellRenderer();
|
||||
mTunerTable.getColumnModel().getColumn(TunerModel.SPECTRAL_DISPLAY_NEW).setCellRenderer(linkCellRenderer);
|
||||
|
||||
TableCellRenderer errorCellRenderer = new ErrorCellRenderer();
|
||||
mTunerTable.getColumnModel().getColumn(TunerModel.SAMPLE_RATE).setCellRenderer(errorCellRenderer);
|
||||
mTunerTable.getColumnModel().getColumn(TunerModel.FREQUENCY).setCellRenderer(errorCellRenderer);
|
||||
mTunerTable.getColumnModel().getColumn(TunerModel.CHANNEL_COUNT).setCellRenderer(errorCellRenderer);
|
||||
mTunerTable.getColumnModel().getColumn(TunerModel.FREQUENCY_ERROR).setCellRenderer(errorCellRenderer);
|
||||
mTunerTable.getColumnModel().getColumn(TunerModel.MEASURED_FREQUENCY_ERROR).setCellRenderer(errorCellRenderer);
|
||||
|
||||
mColumnWidthMonitor = new JTableColumnWidthMonitor(mUserPreferences, mTunerTable, TABLE_PREFERENCE_KEY);
|
||||
JScrollPane tunerTableScroller = new JScrollPane(mTunerTable);
|
||||
@@ -238,6 +245,32 @@ public class TunerViewPanel extends JPanel
|
||||
add(mSplitPane);
|
||||
}
|
||||
|
||||
public class ErrorCellRenderer extends DefaultTableCellRenderer
|
||||
{
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
|
||||
{
|
||||
Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
||||
|
||||
Tuner tuner = mTunerModel.getTuner(mTunerTable.convertRowIndexToModel(row));
|
||||
|
||||
if(isSelected)
|
||||
{
|
||||
component.setBackground(table.getSelectionBackground());
|
||||
}
|
||||
else if(tuner.hasError())
|
||||
{
|
||||
component.setBackground(Color.RED);
|
||||
}
|
||||
else
|
||||
{
|
||||
component.setBackground(table.getBackground());
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
}
|
||||
|
||||
public class LinkCellRenderer extends DefaultTableCellRenderer
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||
* *
|
||||
* * This program is free software: you can redistribute it and/or modify
|
||||
* * it under the terms of the GNU General Public License as published by
|
||||
* * the Free Software Foundation, either version 3 of the License, or
|
||||
* * (at your option) any later version.
|
||||
* *
|
||||
* * This program is distributed in the hope that it will be useful,
|
||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* * GNU General Public License for more details.
|
||||
* *
|
||||
* * You should have received a copy of the GNU General Public License
|
||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.source.tuner.airspy;
|
||||
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
@@ -20,47 +42,6 @@ import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2015-2018 Dennis Sheirer
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Ported from libairspy at:
|
||||
* https://github.com/airspy/host/tree/master/libairspy
|
||||
*
|
||||
* Copyright (c) 2013, Michael Ossmann <mike@ossmann.com>
|
||||
* Copyright (c) 2012, Jared Boone <jared@sharebrained.com>
|
||||
* Copyright (c) 2014, Youssef Touil <youssef@airspy.com>
|
||||
* Copyright (c) 2014, Benjamin Vernoux <bvernoux@airspy.com>
|
||||
* Copyright (c) 2015, Ian Gilmour <ian@sdrsharp.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* Neither the name of AirSpy nor the names of its contributors may be used to
|
||||
* endorse or promote products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
public class AirspyTunerController extends USBTunerController
|
||||
{
|
||||
public static final Gain LINEARITY_GAIN_DEFAULT = Gain.LINEARITY_14;
|
||||
@@ -184,7 +165,7 @@ public class AirspyTunerController extends USBTunerController
|
||||
String deviceName = "Airspy " + getDeviceInfo().getSerialNumber();
|
||||
|
||||
mUSBTransferProcessor = new USBTransferProcessor(deviceName, mDeviceHandle, mSampleAdapter,
|
||||
USB_TRANSFER_BUFFER_SIZE);
|
||||
USB_TRANSFER_BUFFER_SIZE, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
*
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
||||
* * Copyright (C) 2014-2020 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
|
||||
@@ -65,6 +65,15 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
|
||||
return mTunerChannel.getFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that this tuner channel source has an error state so that any channel processing can be shutdown.
|
||||
* @param errorMessage describing the error
|
||||
*/
|
||||
public void setError(String errorMessage)
|
||||
{
|
||||
broadcastConsumerSourceEvent(SourceEvent.errorState(this, errorMessage));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the center frequency for the sample streaming being sent from the producer.
|
||||
* @param frequency in hertz
|
||||
|
||||
@@ -1,56 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
/*
|
||||
*
|
||||
* Ported from libhackrf at:
|
||||
* https://github.com/mossmann/hackrf/tree/master/host/libhackrf
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2012, Jared Boone <jared@sharebrained.com>
|
||||
* Copyright (c) 2013, Benjamin Vernoux <titanmkd@gmail.com>
|
||||
* copyright (c) 2013, Michael Ossmann <mike@ossmann.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of Great Scott Gadgets nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
*/
|
||||
package io.github.dsheirer.source.tuner.hackrf;
|
||||
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
@@ -160,7 +128,8 @@ public class HackRFTunerController extends USBTunerController
|
||||
name = "HackRF - Unidentified Serial";
|
||||
}
|
||||
|
||||
mUSBTransferProcessor = new USBTransferProcessor(name, mDeviceHandle, mNativeBufferConverter, USB_TRANSFER_BUFFER_SIZE);
|
||||
mUSBTransferProcessor = new USBTransferProcessor(name, mDeviceHandle, mNativeBufferConverter,
|
||||
USB_TRANSFER_BUFFER_SIZE, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
*/
|
||||
package io.github.dsheirer.source.tuner.manager;
|
||||
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
@@ -56,6 +62,13 @@ public abstract class ChannelSourceManager implements ISourceEventProcessor
|
||||
*/
|
||||
public abstract TunerChannelSource getSource(TunerChannel tunerChannel, ChannelSpecification channelSpecification);
|
||||
|
||||
/**
|
||||
* Signals that the complex buffer provider has an error and can no long provider buffers. The subclass should
|
||||
* implement procedures to gracefully shutdown any tuner channel sources that have been provisioned.
|
||||
* @param errorMessage describing the error state
|
||||
*/
|
||||
public abstract void setErrorMessage(String errorMessage);
|
||||
|
||||
/**
|
||||
* Adds a listener to receive source events
|
||||
*/
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
*/
|
||||
package io.github.dsheirer.source.tuner.manager;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
|
||||
@@ -103,6 +109,15 @@ public class HeterodyneChannelSourceManager extends ChannelSourceManager
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setErrorMessage(String errorMessage)
|
||||
{
|
||||
for(TunerChannelSource tunerChannelSource: mChannelSources)
|
||||
{
|
||||
tunerChannelSource.setError(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a new center frequency and updates the tuner center frequency
|
||||
*/
|
||||
|
||||
@@ -33,17 +33,21 @@ import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
*
|
||||
* Pass through source manager for relatively small bandwidth complex streams that don't warrant the overhead of
|
||||
* a polyphase or heterodyne channelizer.
|
||||
*/
|
||||
public class PassThroughSourceManager extends ChannelSourceManager
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(PassThroughSourceManager.class);
|
||||
private TunerController mTunerController;
|
||||
private SortedSet<TunerChannel> mTunerChannels = new TreeSet<>();
|
||||
private List<TunerChannelSource> mTunerChannelSources = new CopyOnWriteArrayList<>();
|
||||
|
||||
public PassThroughSourceManager(TunerController tunerController)
|
||||
{
|
||||
@@ -69,6 +73,7 @@ public class PassThroughSourceManager extends ChannelSourceManager
|
||||
mTunerController, tunerChannel);
|
||||
|
||||
mTunerChannels.add(tunerChannel);
|
||||
mTunerChannelSources.add(channelSource);
|
||||
|
||||
return channelSource;
|
||||
}
|
||||
@@ -91,12 +96,22 @@ public class PassThroughSourceManager extends ChannelSourceManager
|
||||
PassThroughChannelSource source = (PassThroughChannelSource)event.getSource();
|
||||
mTunerController.removeBufferListener(source);
|
||||
mTunerChannels.remove(source.getTunerChannel());
|
||||
mTunerChannelSources.remove(source);
|
||||
broadcast(SourceEvent.channelCountChange(mTunerChannels.size()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setErrorMessage(String errorMessage)
|
||||
{
|
||||
for(TunerChannelSource tunerChannelSource: mTunerChannelSources)
|
||||
{
|
||||
tunerChannelSource.setError(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public class SourceEventProxy implements Listener<SourceEvent>
|
||||
{
|
||||
@Override
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
*/
|
||||
package io.github.dsheirer.source.tuner.manager;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.channelizer.PolyphaseChannelManager;
|
||||
@@ -259,6 +265,16 @@ public class PolyphaseChannelSourceManager extends ChannelSourceManager
|
||||
throw new IllegalArgumentException("Can't calculate valid center frequency for the channel set");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setErrorMessage(String errorMessage)
|
||||
{
|
||||
if(mPolyphaseChannelManager != null)
|
||||
{
|
||||
mPolyphaseChannelManager.setErrorMessage(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private long getChannelSetBandwidth(SortedSet<TunerChannel> channels)
|
||||
{
|
||||
return channels.last().getMaxFrequency() - channels.first().getMinFrequency();
|
||||
|
||||
@@ -1,29 +1,30 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
*
|
||||
* Java version based on librtlsdr
|
||||
* Copyright (C) 2012-2013 by Steve Markgraf <steve@steve-m.de>
|
||||
* Copyright (C) 2012 by Dimitri Stolnikov <horiz0n@gmx.net>
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
*/
|
||||
package io.github.dsheirer.source.tuner.rtl;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
import io.github.dsheirer.source.tuner.ITunerErrorListener;
|
||||
import io.github.dsheirer.source.tuner.TunerManager;
|
||||
import io.github.dsheirer.source.tuner.TunerType;
|
||||
import io.github.dsheirer.source.tuner.usb.USBTransferProcessor;
|
||||
@@ -160,7 +161,7 @@ public abstract class RTL2832TunerController extends USBTunerController
|
||||
String deviceName = getTunerType().getLabel() + " " + getUniqueID();
|
||||
|
||||
mUSBTransferProcessor = new RTL2832USBTransferProcessor(deviceName, mDeviceHandle, mNativeBufferConverter,
|
||||
USB_TRANSFER_BUFFER_SIZE_HIGH_SAMPLE_RATE);
|
||||
USB_TRANSFER_BUFFER_SIZE_HIGH_SAMPLE_RATE, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1563,10 +1564,13 @@ public abstract class RTL2832TunerController extends USBTunerController
|
||||
* @param deviceHandle to the USB bulk transfer device
|
||||
* @param nativeBufferConverter specific to the tuner's byte buffer format for converting to floating point I/Q samples
|
||||
* @param bufferSize in bytes. Should be a multiple of two: 65536, 131072 or 262144.
|
||||
* @param tunerErrorListener to receive error state message
|
||||
*/
|
||||
public RTL2832USBTransferProcessor(String deviceName, DeviceHandle deviceHandle, NativeBufferConverter nativeBufferConverter, int bufferSize)
|
||||
public RTL2832USBTransferProcessor(String deviceName, DeviceHandle deviceHandle,
|
||||
NativeBufferConverter nativeBufferConverter, int bufferSize,
|
||||
ITunerErrorListener tunerErrorListener)
|
||||
{
|
||||
super(deviceName, deviceHandle, nativeBufferConverter, bufferSize);
|
||||
super(deviceName, deviceHandle, nativeBufferConverter, bufferSize, tunerErrorListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 Dennis Sheirer
|
||||
/*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
*/
|
||||
package io.github.dsheirer.source.tuner.rtl.e4k;
|
||||
|
||||
import io.github.dsheirer.source.SourceException;
|
||||
@@ -253,7 +257,7 @@ public class E4KTunerController extends RTL2832TunerController
|
||||
String deviceName = getTunerType().getLabel() + " " + getUniqueID();
|
||||
|
||||
mUSBTransferProcessor = new RTL2832USBTransferProcessor(deviceName, mDeviceHandle, mNativeBufferConverter,
|
||||
USB_TRANSFER_BUFFER_SIZE_HIGH_SAMPLE_RATE);
|
||||
USB_TRANSFER_BUFFER_SIZE_HIGH_SAMPLE_RATE, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,30 +1,32 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
*/
|
||||
package io.github.dsheirer.source.tuner.usb;
|
||||
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.usb4java.LibUsb;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
@@ -38,10 +40,9 @@ public class USBMasterProcessor
|
||||
private static final long USB_TIMEOUT_MS = 2000l; //milliseconds
|
||||
|
||||
private List<USBTransferProcessor> mRegisteredProcessors = new CopyOnWriteArrayList<>();
|
||||
private ByteBuffer mStatusBuffer = ByteBuffer.allocateDirect(4);
|
||||
private AtomicBoolean mRunning = new AtomicBoolean();
|
||||
private Processor mProcessor = new Processor();
|
||||
private ScheduledFuture mProcessorFuture;
|
||||
private Thread mProcessorThread;
|
||||
|
||||
/**
|
||||
* Registers the transfer processor so that LibUSB timeout processing will auto-start.
|
||||
@@ -80,8 +81,25 @@ public class USBMasterProcessor
|
||||
{
|
||||
if(mRunning.compareAndSet(false, true))
|
||||
{
|
||||
//Set periodicity to an odd multiple to avoid contention with transfer buffer receivers
|
||||
mProcessorFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(mProcessor, 0L, 9L, TimeUnit.MILLISECONDS);
|
||||
mLog.warn("Starting USB master processor thread");
|
||||
if(mProcessorThread == null)
|
||||
{
|
||||
mProcessor.reset();
|
||||
mProcessorThread = new Thread(mProcessor);
|
||||
mProcessorThread.setName("USB Event Processor");
|
||||
mProcessorThread.setDaemon(true);
|
||||
|
||||
try
|
||||
{
|
||||
mProcessorThread.setPriority(Thread.MAX_PRIORITY);
|
||||
}
|
||||
catch(IllegalArgumentException iae)
|
||||
{
|
||||
//Do nothing ... couldn't set the priority
|
||||
}
|
||||
|
||||
mProcessorThread.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,10 +110,22 @@ public class USBMasterProcessor
|
||||
{
|
||||
if(mRunning.compareAndSet(true, false))
|
||||
{
|
||||
if(mProcessorFuture != null)
|
||||
mLog.warn("Stopping USB master processor thread");
|
||||
if(mProcessorThread != null)
|
||||
{
|
||||
mProcessorFuture.cancel(true);
|
||||
mProcessorFuture = null;
|
||||
mProcessor.stop();
|
||||
mProcessorThread.interrupt();
|
||||
|
||||
try
|
||||
{
|
||||
mProcessorThread.join(1000);
|
||||
}
|
||||
catch(InterruptedException ie)
|
||||
{
|
||||
//No action
|
||||
}
|
||||
|
||||
mProcessorThread = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,23 +144,37 @@ public class USBMasterProcessor
|
||||
*/
|
||||
class Processor implements Runnable
|
||||
{
|
||||
private boolean mRunning = true;
|
||||
|
||||
/**
|
||||
* Sets stop flag to signal to stop processing
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
mRunning = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets this processor so that it can be reused.
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
mRunning = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
while(mRunning)
|
||||
{
|
||||
int result = LibUsb.handleEventsTimeoutCompleted(null, USB_TIMEOUT_MS, mStatusBuffer.asIntBuffer());
|
||||
|
||||
if(result != LibUsb.SUCCESS)
|
||||
try
|
||||
{
|
||||
mLog.error("Error processing timeout events for LibUSB - error code:" + result);
|
||||
LibUsb.handleEvents(null);
|
||||
}
|
||||
catch(Throwable throwable)
|
||||
{
|
||||
mLog.error("Error while processing LibUSB timeout events", throwable);
|
||||
}
|
||||
|
||||
mStatusBuffer.rewind();
|
||||
}
|
||||
catch(Throwable throwable)
|
||||
{
|
||||
mLog.error("Error while processing LibUSB timeout events", throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* * ******************************************************************************
|
||||
* * Copyright (C) 2014-2020 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/>
|
||||
* * *****************************************************************************
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.source.tuner.usb;
|
||||
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.source.tuner.ITunerErrorListener;
|
||||
import io.github.dsheirer.source.tuner.TunerManager;
|
||||
import io.github.dsheirer.source.tuner.usb.converter.NativeBufferConverter;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
@@ -53,6 +56,7 @@ public class USBTransferProcessor implements TransferCallback
|
||||
private LinkedTransferQueue<Transfer> mAvailableTransfers = new LinkedTransferQueue<>();
|
||||
private LinkedTransferQueue<Transfer> mInProgressTransfers = new LinkedTransferQueue<>();
|
||||
private LinkedTransferQueue<Transfer> mCompletedTransfers = new LinkedTransferQueue<>();
|
||||
private List<Transfer> mTransfersToDispose = new ArrayList<>();
|
||||
private List<Transfer> mTransfersToSubmit = new ArrayList<>();
|
||||
|
||||
//Tuner format-specific byte buffer to IQ float sample converter
|
||||
@@ -66,14 +70,13 @@ public class USBTransferProcessor implements TransferCallback
|
||||
//Handle to the USB bulk transfer device
|
||||
private DeviceHandle mUsbBulkTransferDeviceHandle;
|
||||
private AtomicBoolean mRunning = new AtomicBoolean();
|
||||
private ByteBuffer mLibUsbHandlerStatus = ByteBuffer.allocateDirect(4);
|
||||
private AtomicBoolean mRestarting = new AtomicBoolean();
|
||||
private CompletedTransferProcessor mCompletedTransferProcessor = new CompletedTransferProcessor();
|
||||
private ScheduledFuture mBufferDispatcherFuture;
|
||||
private ScheduledFuture mRestartFuture;
|
||||
private String mDeviceName;
|
||||
|
||||
private int mTransferErrorLoggingCount = 0;
|
||||
|
||||
private int mRestartCount = 0;
|
||||
private ITunerErrorListener mITunerErrorListener;
|
||||
|
||||
/**
|
||||
* Manages stream of USB transfer buffers and converts buffers to complex buffer samples for distribution to
|
||||
@@ -85,12 +88,14 @@ public class USBTransferProcessor implements TransferCallback
|
||||
* @param bufferSize in bytes. Should be a multiple of two: 65536, 131072 or 262144.
|
||||
*/
|
||||
public USBTransferProcessor(String deviceName, DeviceHandle usbBulkTransferDeviceHandle,
|
||||
NativeBufferConverter nativeBufferConverter, int bufferSize)
|
||||
NativeBufferConverter nativeBufferConverter, int bufferSize,
|
||||
ITunerErrorListener tunerErrorListener)
|
||||
{
|
||||
mDeviceName = deviceName;
|
||||
mUsbBulkTransferDeviceHandle = usbBulkTransferDeviceHandle;
|
||||
mNativeBufferConverter = nativeBufferConverter;
|
||||
mBufferSize = bufferSize;
|
||||
mITunerErrorListener = tunerErrorListener;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,23 +126,31 @@ public class USBTransferProcessor implements TransferCallback
|
||||
|
||||
/**
|
||||
* Start USB transfer buffer processing. Subsequent calls to this method after started will be ignored.
|
||||
*
|
||||
* @return true if start successful with no errors or is already running. returns false if errors on startup.
|
||||
*/
|
||||
private void start()
|
||||
private boolean start()
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
if(mRunning.compareAndSet(false, true))
|
||||
{
|
||||
|
||||
prepareDeviceStart();
|
||||
prepareTransfers();
|
||||
submitTransfers();
|
||||
|
||||
//Start transferred buffer dispatcher
|
||||
mBufferDispatcherFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(mCompletedTransferProcessor,
|
||||
0, 6, TimeUnit.MILLISECONDS);
|
||||
if(submitTransfers())
|
||||
{
|
||||
success = true;
|
||||
//Start transferred buffer dispatcher
|
||||
mBufferDispatcherFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(mCompletedTransferProcessor,
|
||||
0, 6, TimeUnit.MILLISECONDS);
|
||||
|
||||
//Register with LibUSB processor so that it auto-starts LibUSB processing
|
||||
TunerManager.LIBUSB_TRANSFER_PROCESSOR.registerTransferProcessor(this);
|
||||
//Register with LibUSB processor so that it auto-starts LibUSB processing
|
||||
TunerManager.LIBUSB_TRANSFER_PROCESSOR.registerTransferProcessor(this);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,7 +160,11 @@ public class USBTransferProcessor implements TransferCallback
|
||||
{
|
||||
if(mRunning.compareAndSet(true, false))
|
||||
{
|
||||
mBufferDispatcherFuture.cancel(true);
|
||||
if(mBufferDispatcherFuture != null)
|
||||
{
|
||||
mBufferDispatcherFuture.cancel(true);
|
||||
mBufferDispatcherFuture = null;
|
||||
}
|
||||
|
||||
//Cancel all buffers that are currently in progress
|
||||
for(Transfer transfer : mInProgressTransfers)
|
||||
@@ -155,22 +172,37 @@ public class USBTransferProcessor implements TransferCallback
|
||||
LibUsb.cancelTransfer(transfer);
|
||||
}
|
||||
|
||||
//Await completion of all in-progress transfers
|
||||
int waitCycleCount = 0;
|
||||
while(!mInProgressTransfers.isEmpty() && waitCycleCount < 10)
|
||||
{
|
||||
waitCycleCount++;
|
||||
|
||||
try
|
||||
{
|
||||
Thread.sleep(10);
|
||||
}
|
||||
catch(InterruptedException ie)
|
||||
{
|
||||
//No - action
|
||||
}
|
||||
}
|
||||
|
||||
//Clear all completed buffers
|
||||
Transfer completedTransfer = mCompletedTransfers.poll();
|
||||
|
||||
while(completedTransfer != null)
|
||||
{
|
||||
completedTransfer.buffer().rewind();
|
||||
mAvailableTransfers.add(completedTransfer);
|
||||
completedTransfer = mCompletedTransfers.poll();
|
||||
}
|
||||
|
||||
//Unregister from LibUSB processor so that it auto-stops LibUSB processing
|
||||
//Unregister from LibUSB processor so that it auto-stops LibUSB event timeout processing
|
||||
TunerManager.LIBUSB_TRANSFER_PROCESSOR.unregisterTransferProcessor(this);
|
||||
|
||||
mLibUsbHandlerStatus.rewind();
|
||||
|
||||
executeDeviceStop();
|
||||
|
||||
disposeTransfers();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,28 +212,44 @@ public class USBTransferProcessor implements TransferCallback
|
||||
*/
|
||||
private void restart()
|
||||
{
|
||||
mLog.debug("Stopping for a restart ....");
|
||||
stop();
|
||||
|
||||
mLog.debug("Attempting to clear halt condition ...");
|
||||
//Attempt to clear any halt condition
|
||||
LibUsb.clearHalt(mUsbBulkTransferDeviceHandle, USB_BULK_TRANSFER_ENDPOINT);
|
||||
|
||||
mLog.warn("USB tuner [" + mDeviceName + "] stopped due to a buffer transfer error. Restarting in 10 milliseconds");
|
||||
|
||||
if(mRestartFuture == null)
|
||||
if(mRestarting.compareAndSet(false, true))
|
||||
{
|
||||
Runnable runnable = new Runnable()
|
||||
stop();
|
||||
|
||||
if(mRestartCount >= 3)
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
mLog.warn("[" + mDeviceName + "] - maximum restart attempts [" + mRestartCount +
|
||||
"] exceeded for tuner - stopping");
|
||||
|
||||
if(mITunerErrorListener != null)
|
||||
{
|
||||
start();
|
||||
mRestartFuture = null;
|
||||
mITunerErrorListener.setErrorMessage("USB ERROR");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
mRestartCount++;
|
||||
|
||||
//Attempt to clear any halt condition
|
||||
LibUsb.clearHalt(mUsbBulkTransferDeviceHandle, USB_BULK_TRANSFER_ENDPOINT);
|
||||
|
||||
mLog.info("[" + mDeviceName + "] - restart attempt [" + mRestartCount + "]");
|
||||
|
||||
Runnable runnable = () ->
|
||||
{
|
||||
mRestarting.set(false);
|
||||
|
||||
boolean success = start();
|
||||
|
||||
if(!success)
|
||||
{
|
||||
mLog.warn("[" + mDeviceName + "] - restart attempt [" + mRestartCount + "] failed - retrying");
|
||||
restart();
|
||||
}
|
||||
};
|
||||
|
||||
mRestartFuture = ThreadPool.SCHEDULED.schedule(runnable, 10, TimeUnit.MILLISECONDS);
|
||||
ThreadPool.SCHEDULED.schedule(runnable, 20, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,56 +258,85 @@ public class USBTransferProcessor implements TransferCallback
|
||||
* to another thread, there may be times when sufficient transfer buffers are not available to keep a level number
|
||||
* of transfer buffers in progress. Therefore, we track the transfer buffers to submit deficit number and attempt
|
||||
* to play catch-up each time this method is invoked.
|
||||
*
|
||||
* @return boolean true if there were no errors submitting transfer buffers. A false value indicates that there
|
||||
* were errors and that the device likely needs to be reset.
|
||||
*/
|
||||
private void submitTransfers()
|
||||
private boolean submitTransfers()
|
||||
{
|
||||
if(mRunning.get())
|
||||
{
|
||||
mAvailableTransfers.drainTo(mTransfersToSubmit);
|
||||
|
||||
for(Transfer transfer: mTransfersToSubmit)
|
||||
if(!mTransfersToSubmit.isEmpty())
|
||||
{
|
||||
int result = LibUsb.submitTransfer(transfer);
|
||||
Transfer transfer = mTransfersToSubmit.remove(0);
|
||||
|
||||
if(result == LibUsb.SUCCESS)
|
||||
while(transfer != null)
|
||||
{
|
||||
mInProgressTransfers.add(transfer);
|
||||
}
|
||||
else if(result == LibUsb.ERROR_PIPE)
|
||||
{
|
||||
mLog.warn("USB pipe error - attempting to clear halt on USB device [" + mDeviceName + "]");
|
||||
int status = LibUsb.submitTransfer(transfer);
|
||||
|
||||
int resetResult = LibUsb.clearHalt(mUsbBulkTransferDeviceHandle, USB_BULK_TRANSFER_ENDPOINT);
|
||||
|
||||
if(resetResult == LibUsb.SUCCESS)
|
||||
switch(status)
|
||||
{
|
||||
int resubmitResult = LibUsb.submitTransfer(transfer);
|
||||
|
||||
if(resubmitResult == LibUsb.SUCCESS)
|
||||
{
|
||||
case LibUsb.SUCCESS:
|
||||
mInProgressTransfers.add(transfer);
|
||||
}
|
||||
else
|
||||
{
|
||||
mAvailableTransfers.add(transfer);
|
||||
mLog.error(mDeviceName + " - error resubmitting transfer after endpoint clear halt");
|
||||
}
|
||||
|
||||
if(!mTransfersToSubmit.isEmpty())
|
||||
{
|
||||
transfer = mTransfersToSubmit.remove(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
transfer = null;
|
||||
}
|
||||
break;
|
||||
case LibUsb.ERROR_PIPE:
|
||||
mLog.warn("[" + mDeviceName + "] - USB Pipe Error while submitting transfer buffers");
|
||||
LibUsb.clearHalt(mUsbBulkTransferDeviceHandle, USB_BULK_TRANSFER_ENDPOINT);
|
||||
mTransfersToDispose.add(transfer);
|
||||
transfer = null;
|
||||
break;
|
||||
default:
|
||||
mLog.error("[" + mDeviceName + "] - " + getErrorStatus(status) + " while submitting transfer buffers");
|
||||
mTransfersToDispose.add(transfer);
|
||||
transfer = null;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
mAvailableTransfers.add(transfer);
|
||||
mLog.error(mDeviceName + " - unable to clear device endpoint halt");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mAvailableTransfers.add(transfer);
|
||||
mLog.error(mDeviceName + "- error submitting transfer [" + LibUsb.errorName(result) + "]");
|
||||
}
|
||||
}
|
||||
|
||||
mTransfersToSubmit.clear();
|
||||
//If we aborted submitting transfers or if we had an error while submitting, move the remaining transfers
|
||||
// back to the available queue and restart the device
|
||||
if(!mTransfersToSubmit.isEmpty())
|
||||
{
|
||||
mAvailableTransfers.addAll(mTransfersToSubmit);
|
||||
mTransfersToSubmit.clear();;
|
||||
}
|
||||
}
|
||||
|
||||
return mTransfersToDispose.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees all allocated transfers in preparation for shutdown
|
||||
*/
|
||||
private void disposeTransfers()
|
||||
{
|
||||
mAvailableTransfers.drainTo(mTransfersToDispose);
|
||||
|
||||
if(mTransfersToDispose.size() != TRANSFER_BUFFER_POOL_SIZE)
|
||||
{
|
||||
mLog.warn("[" + mDeviceName + "] - potential memory leak [" +
|
||||
mTransfersToDispose.size() + " of " + TRANSFER_BUFFER_POOL_SIZE +
|
||||
"] USB transfer buffers will be disposed during shutdown");
|
||||
}
|
||||
|
||||
for(Transfer transfer: mTransfersToDispose)
|
||||
{
|
||||
LibUsb.freeTransfer(transfer);
|
||||
}
|
||||
|
||||
mTransfersToDispose.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,8 +360,17 @@ public class USBTransferProcessor implements TransferCallback
|
||||
*/
|
||||
public void setListener(Listener<ReusableComplexBuffer> listener)
|
||||
{
|
||||
mComplexBufferListener = listener;
|
||||
start();
|
||||
if(mComplexBufferListener == null || !mComplexBufferListener.equals(listener))
|
||||
{
|
||||
mComplexBufferListener = listener;
|
||||
|
||||
boolean success = start();
|
||||
|
||||
if(!success)
|
||||
{
|
||||
restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,21 +445,19 @@ public class USBTransferProcessor implements TransferCallback
|
||||
{
|
||||
transfer.buffer().rewind();
|
||||
mAvailableTransfers.add(transfer);
|
||||
}
|
||||
|
||||
mTransferErrorLoggingCount++;
|
||||
mTransferErrorLoggingCount++;
|
||||
|
||||
if(mTransferErrorLoggingCount <= 5)
|
||||
{
|
||||
//TODO: this error situation should be raised/highlighted to the user for action in the gui ...
|
||||
mLog.warn("USB buffer transfer error detected. You should try using a different USB port for the usb-based tuner");
|
||||
|
||||
//Handle integer overflow
|
||||
if(mTransferErrorLoggingCount < 0)
|
||||
if(mTransferErrorLoggingCount <= 5)
|
||||
{
|
||||
mTransferErrorLoggingCount = 1;
|
||||
//Handle integer overflow
|
||||
if(mTransferErrorLoggingCount < 0)
|
||||
{
|
||||
mTransferErrorLoggingCount = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case LibUsb.TRANSFER_CANCELLED:
|
||||
transfer.buffer().rewind();
|
||||
@@ -381,7 +465,7 @@ public class USBTransferProcessor implements TransferCallback
|
||||
break;
|
||||
default:
|
||||
//Unexpected transfer error - need to reset the bulk transfer interface
|
||||
mLog.error(mDeviceName + " - transfer error [" + getTransferStatus(transfer.status()) +
|
||||
mLog.error("[" + mDeviceName + "] - transfer error [" + getTransferStatus(transfer.status()) +
|
||||
"] transferred actual: " + transfer.actualLength());
|
||||
transfer.buffer().rewind();
|
||||
mAvailableTransfers.add(transfer);
|
||||
@@ -390,6 +474,44 @@ public class USBTransferProcessor implements TransferCallback
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the error status code to a textual description
|
||||
*/
|
||||
public static String getErrorStatus(int status)
|
||||
{
|
||||
switch(status)
|
||||
{
|
||||
case LibUsb.SUCCESS:
|
||||
return "SUCCESS";
|
||||
case LibUsb.ERROR_IO:
|
||||
return "USB I/O ERROR";
|
||||
case LibUsb.ERROR_INVALID_PARAM:
|
||||
return "USB INVALID PARAMETERS ERROR";
|
||||
case LibUsb.ERROR_ACCESS:
|
||||
return "USB ACCESS ERROR";
|
||||
case LibUsb.ERROR_NO_DEVICE:
|
||||
return "USB NO DEVICE ERROR";
|
||||
case LibUsb.ERROR_NOT_FOUND:
|
||||
return "USB NOT FOUND ERROR";
|
||||
case LibUsb.ERROR_BUSY:
|
||||
return "USB BUSY ERROR";
|
||||
case LibUsb.ERROR_TIMEOUT:
|
||||
return "USB TIMEOUT ERROR";
|
||||
case LibUsb.ERROR_OVERFLOW:
|
||||
return "USB OVERFLOW ERROR";
|
||||
case LibUsb.ERROR_PIPE:
|
||||
return "USB PIPE ERROR";
|
||||
case LibUsb.ERROR_INTERRUPTED:
|
||||
return "USB INTERRUPTED ERROR";
|
||||
case LibUsb.ERROR_NO_MEM:
|
||||
return "USB NO MEMORY ERROR";
|
||||
case LibUsb.ERROR_NOT_SUPPORTED:
|
||||
return "USB NOT SUPPORTED ERROR";
|
||||
default:
|
||||
return "USB UNKNOWN [" + status + "] ERROR";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the USB transfer status number into a descriptive label
|
||||
*/
|
||||
@@ -447,15 +569,22 @@ public class USBTransferProcessor implements TransferCallback
|
||||
transfer.buffer().rewind();
|
||||
mAvailableTransfers.add(transfer);
|
||||
|
||||
submitTransfers();
|
||||
boolean success = submitTransfers();
|
||||
|
||||
//Fetch the next transfer to process
|
||||
transfer = mCompletedTransfers.poll();
|
||||
if(success)
|
||||
{
|
||||
transfer = mCompletedTransfers.poll();
|
||||
}
|
||||
else
|
||||
{
|
||||
ThreadPool.SCHEDULED.submit(() -> restart());
|
||||
transfer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Throwable throwable)
|
||||
{
|
||||
mLog.error("Error while processing USB transfer buffers", throwable);
|
||||
mLog.error("[" + mDeviceName + "] - error while processing USB transfer buffers", throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user