diff --git a/config/logback.xml b/config/logback.xml index 1a627792..f52b54fe 100644 --- a/config/logback.xml +++ b/config/logback.xml @@ -12,9 +12,19 @@ %-25(%d{ddMMyyyy HHmmss} [%thread]) %-5level %logger{30} - %msg%n - + - + + + + %-16(%d{HH:mm:ss.SSS} [%thread]) %-5level %logger{30} - %msg%n + + + + + + + \ No newline at end of file diff --git a/src/decode/am/AMDecoder.java b/src/decode/am/AMDecoder.java index 6cf33587..113e6d34 100644 --- a/src/decode/am/AMDecoder.java +++ b/src/decode/am/AMDecoder.java @@ -6,6 +6,9 @@ import decode.Decoder; import decode.DecoderType; import dsp.am.AMDemodulator; import dsp.filter.DCRemovalFilter2; +import dsp.filter.FilterFactory; +import dsp.filter.FloatFIRFilter; +import dsp.filter.Window.WindowType; public class AMDecoder extends Decoder { @@ -13,10 +16,11 @@ public class AMDecoder extends Decoder * This value determines how quickly the DC remove filter responds to * changes in frequency. */ - private static final double DC_REMOVAL_RATIO = 0.000003; + private static final double DC_REMOVAL_RATIO = 0.003; private AMDemodulator mDemodulator; private DCRemovalFilter2 mDCRemovalFilter; + private FloatFIRFilter mLowPassFilter; public AMDecoder( SampleType sampleType ) { @@ -50,7 +54,14 @@ public class AMDecoder extends Decoder * Route the demodulated, filtered samples back to this class to send * to all registered listeners */ - mDCRemovalFilter.setListener( this.getFloatReceiver() ); + + mLowPassFilter = new FloatFIRFilter( + FilterFactory.getLowPass( 48000, 3000, 31, + WindowType.COSINE ), 100.0 ); + + mDCRemovalFilter.setListener( mLowPassFilter ); + + mLowPassFilter.setListener( this.getFloatReceiver() ); } } diff --git a/src/dsp/am/AMDemodulator.java b/src/dsp/am/AMDemodulator.java index f70fd318..4dd03175 100644 --- a/src/dsp/am/AMDemodulator.java +++ b/src/dsp/am/AMDemodulator.java @@ -14,7 +14,7 @@ public class AMDemodulator implements Listener public AMDemodulator() { - this( FilterFactory.getLowPass( 48000, 2000, 73, WindowType.HAMMING ), + this( FilterFactory.getLowPass( 48000, 3000, 73, WindowType.HAMMING ), 1000.0 ); } @@ -53,8 +53,8 @@ public class AMDemodulator implements Listener public void receive( ComplexSample sample ) { float demodulated = (float)Math.abs( - Math.sqrt( ( sample.real() * sample.real() ) + - ( sample.imaginery() * sample.imaginery() ) ) ); + Math.sqrt( ( sample.real() * sample.real() ) + + ( sample.imaginery() * sample.imaginery() ) ) ); mBroadcaster.broadcast( demodulated * 30.0f ); } diff --git a/src/gui/control/JFrequencyControl.java b/src/gui/control/JFrequencyControl.java index 50a6fc59..b70ef0d9 100644 --- a/src/gui/control/JFrequencyControl.java +++ b/src/gui/control/JFrequencyControl.java @@ -138,7 +138,7 @@ public class JFrequencyControl extends JPanel implements FrequencyChangeListener { if( event.getAttribute() == Attribute.FREQUENCY ) { - setFrequency( (int)event.getValue(), false ); + setFrequency( (long)event.getValue(), false ); } } @@ -202,7 +202,7 @@ public class JFrequencyControl extends JPanel implements FrequencyChangeListener { private static final long serialVersionUID = 1L; private int mPower = 0; - private int mValue = 0; + private long mValue = 0; private Digit( int position ) throws ParseException { @@ -225,17 +225,17 @@ public class JFrequencyControl extends JPanel implements FrequencyChangeListener public void setFrequency( long frequency, boolean fireChangeEvent ) { //Strip the digits higher than this one - long lower = frequency % (int)( Math.pow( 10, mPower + 1) ); + long lower = frequency % (long)( Math.pow( 10, mPower + 1) ); //Set the value to int value of dividing by 10 to this power - int value = (int)( lower / (int)( Math.pow( 10, mPower ) ) ); + long value = (long)( lower / (long)( Math.pow( 10, mPower ) ) ); set( value, fireChangeEvent ); } public long getFrequency() { - return mValue * (int)Math.pow( 10, mPower ); + return mValue * (long)Math.pow( 10, mPower ); } public void increment() @@ -261,7 +261,7 @@ public class JFrequencyControl extends JPanel implements FrequencyChangeListener /** * Convenience wrapper to change amount and fire change event */ - private void set( int amount ) + private void set( long amount ) { set( amount, true ); } @@ -269,7 +269,7 @@ public class JFrequencyControl extends JPanel implements FrequencyChangeListener /** * Changes the value and optionally fires change event to listeners */ - private void set( int amount, boolean fireChangeEvent ) + private void set( long amount, boolean fireChangeEvent ) { mValue = amount; diff --git a/src/source/mixer/MixerManager.java b/src/source/mixer/MixerManager.java index c4a48f41..4948bf03 100644 --- a/src/source/mixer/MixerManager.java +++ b/src/source/mixer/MixerManager.java @@ -197,6 +197,11 @@ public class MixerManager mLog.info( sb.toString() ); } + public HashMap getMixerTuners() + { + return mMixerTuners; + } + private TargetDataLine getTargetDataLine( Mixer.Info mixerInfo, AudioFormat format ) { TargetDataLine retVal = null; diff --git a/src/source/mixer/SampleAdapter.java b/src/source/mixer/SampleAdapter.java index 1d73a0a1..d4ae6567 100644 --- a/src/source/mixer/SampleAdapter.java +++ b/src/source/mixer/SampleAdapter.java @@ -17,7 +17,6 @@ ******************************************************************************/ package source.mixer; -import source.Source.SampleType; /* * Adapter to convert byte data received from a data stream into float[] diff --git a/src/source/tuner/FrequencyController.java b/src/source/tuner/FrequencyController.java index cfcb0150..ccd1d2e7 100644 --- a/src/source/tuner/FrequencyController.java +++ b/src/source/tuner/FrequencyController.java @@ -38,7 +38,7 @@ public class FrequencyController public FrequencyController( Tunable tunable, long minFrequency, long maxFrequency, - double frequencyCorrection ) throws SourceException + double frequencyCorrection ) { mTunable = tunable; mMinimumFrequency = minFrequency; @@ -148,7 +148,7 @@ public class FrequencyController */ private long getCorrectedFrequency( long tunedFrequency ) { - return (int)( (double)tunedFrequency / + return (long)( (double)tunedFrequency / ( 1.0 - ( mFrequencyCorrection / 1000000.0 ) ) ); } diff --git a/src/source/tuner/MixerTuner.java b/src/source/tuner/MixerTuner.java index 00abe681..57d698fc 100644 --- a/src/source/tuner/MixerTuner.java +++ b/src/source/tuner/MixerTuner.java @@ -21,6 +21,9 @@ import java.util.ArrayList; import javax.sound.sampled.TargetDataLine; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import sample.Listener; import sample.complex.ComplexSampleListListener; import source.mixer.MixerSource; @@ -28,6 +31,9 @@ import source.mixer.SampleAdapter; public abstract class MixerTuner extends Tuner { + private final static Logger mLog = + LoggerFactory.getLogger( MixerTuner.class ); + private TargetDataLine mTargetDataLine; protected MixerTunerType mMixerTunerType; protected MixerSource mMixerSource; diff --git a/src/source/tuner/Tuner.java b/src/source/tuner/Tuner.java index 46392840..b8eb056e 100644 --- a/src/source/tuner/Tuner.java +++ b/src/source/tuner/Tuner.java @@ -48,6 +48,13 @@ public abstract class Tuner implements FrequencyChangeBroadcaster, mName = name; } + public String toString() + { + return mName; + } + + public abstract void dispose(); + public void setName( String name ) { mName = name; diff --git a/src/source/tuner/TunerController.java b/src/source/tuner/TunerController.java index 71b51287..27621896 100644 --- a/src/source/tuner/TunerController.java +++ b/src/source/tuner/TunerController.java @@ -51,7 +51,6 @@ public abstract class TunerController implements Tunable * class, tuning a frequency, or setting the bandwidth */ public TunerController( long minimumFrequency, long maximumFrequency ) - throws SourceException { mFrequencyController = new FrequencyController( this, minimumFrequency, diff --git a/src/source/tuner/TunerManager.java b/src/source/tuner/TunerManager.java index 0693e72b..01e0f7e3 100644 --- a/src/source/tuner/TunerManager.java +++ b/src/source/tuner/TunerManager.java @@ -23,20 +23,17 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.RejectedExecutionException; -import javax.usb.UsbDevice; -import javax.usb.UsbException; -import javax.usb.UsbHostManager; -import javax.usb.UsbHub; -import javax.usb.UsbServices; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.usb4java.Device; +import org.usb4java.DeviceDescriptor; +import org.usb4java.DeviceList; +import org.usb4java.LibUsb; import source.Source; import source.SourceException; import source.config.SourceConfigTuner; import source.mixer.MixerManager; -import source.tuner.ettus.B100Tuner; import source.tuner.fcd.FCDTuner; import source.tuner.fcd.proV1.FCD1TunerController; import source.tuner.fcd.proplusV2.FCD2TunerController; @@ -46,27 +43,34 @@ import source.tuner.rtl.RTL2832Tuner; import source.tuner.rtl.RTL2832TunerController; import source.tuner.rtl.e4k.E4KTunerController; import source.tuner.rtl.r820t.R820TTunerController; -import source.tuner.usb.USBTunerDevice; import controller.ResourceManager; import controller.channel.ProcessingChain; public class TunerManager { private final static Logger mLog = - LoggerFactory.getLogger( TunerManager.class ); - - private static final String sLOADED = "\t[LOADED]\t"; - private static final String sNOT_LOADED = "\t[NOT LOADED]\t"; + LoggerFactory.getLogger( TunerManager.class ); private ResourceManager mResourceManager; - private ArrayList mTuners = new ArrayList(); - + public TunerManager( ResourceManager resourceManager ) { mResourceManager = resourceManager; - loadTuners(); + + /* initialize mixers */ + MixerManager.getInstance(); + + initTuners(); } + + /** + * Performs cleanup of USB related issues + */ + public void dispose() + { + LibUsb.exit( null ); + } /** * Iterates current tuners to get a tuner channel source for the frequency @@ -121,127 +125,103 @@ public class TunerManager /** * Loads all USB tuners and USB/Mixer tuner devices */ - private void loadTuners() + private void initTuners() { - mTuners.clear(); + DeviceList deviceList = new DeviceList(); - //Get list of attached USB tuner devices - ArrayList devices = getUSBTunerDevices(); + int result = LibUsb.init( null ); - StringBuilder sb = new StringBuilder(); - - sb.append( "discovered and using [" + devices.size() + - "] available tuner devices\n" ); - - mLog.info( "inspecting [" + devices.size() + "] available usb tuner devices" ); - - int counter = 0; - - for( USBTunerDevice device: devices ) + if( result != LibUsb.SUCCESS ) { - counter++; + mLog.error( "unable to initialize libusb [" + + LibUsb.errorName( result ) + "]" ); + } + else + { + mLog.info( "LibUSB API Version: " + LibUsb.getApiVersion() ); + mLog.info( "LibUSB Version: " + LibUsb.getVersion() ); - mLog.info( "inspecting usb device [" + counter + "] tuner class: " - + device.getTunerClass().toString() ); + result = LibUsb.getDeviceList( null, deviceList ); - String status = sNOT_LOADED; - String name = "Unknown"; - String reason = "No device driver class available"; + if( result < 0 ) + { + mLog.error( "unable to get device list from libusb [" + result + " / " + + LibUsb.errorName( result ) + "]" ); + } + else + { + mLog.info( "discovered [" + result + "] attached USB devices" ); + } + } + + for( Device device: deviceList ) + { + DeviceDescriptor descriptor = new DeviceDescriptor(); - TunerClass tunerClass = device.getTunerClass(); + result = LibUsb.getDeviceDescriptor( device, descriptor ); + + if( result != LibUsb.SUCCESS ) + { + mLog.error( "unable to read device descriptor [" + + LibUsb.errorName( result ) + "]" ); + } + else + { + TunerInitStatus status = initTuner( device, descriptor ); + + StringBuilder sb = new StringBuilder(); + + sb.append( "usb device [" ); + sb.append( String.format( "%04X", descriptor.idVendor() ) ); + sb.append( ":" ); + sb.append( String.format( "%04X", descriptor.idProduct() ) ); + + if( status.isLoaded() ) + { + Tuner tuner = status.getTuner(); + sb.append( "] LOADED: " ); + sb.append( tuner.toString() ); + mTuners.add( tuner ); + } + else + { + sb.append( "] NOT LOADED: " ); + sb.append( status.getInfo() ); + } + + mLog.info( sb.toString() ); + } + } + + LibUsb.freeDeviceList( deviceList, true ); + } + + private TunerInitStatus initTuner( Device device, + DeviceDescriptor descriptor ) + { + if( device != null && descriptor != null ) + { + TunerClass tunerClass = TunerClass.valueOf( descriptor.idVendor(), + descriptor.idProduct() ); switch( tunerClass ) { + case ETTUS_USRP_B100: + return initEttusB100Tuner( device, descriptor ); case FUNCUBE_DONGLE_PRO: - //Locate the matching mixer tuner dataline - MixerTunerDataLine fcd1Dataline = - getMixerTunerDataLine( tunerClass.getTunerType() ); - if( fcd1Dataline != null ) - { - FCD1TunerController fcd1Controller; - - try - { - fcd1Controller = new FCD1TunerController( device ); - - FCDTuner fcd1Tuner = - new FCDTuner( fcd1Dataline, fcd1Controller ); - - TunerConfiguration config = - getTunerConfiguration( fcd1Tuner ); - - if( config != null ) - { - fcd1Tuner.apply( config ); - } - - mTuners.add( fcd1Tuner ); - - name = fcd1Tuner.getName(); - status = sLOADED; - reason = null; - } - catch ( SourceException e ) - { - reason = "Controller Source Exception: " + - e.getLocalizedMessage(); - } - - } - else - { - reason = "Couldn't locate matching mixer/sound card device"; - } - break; + return initFuncubeProTuner( device, descriptor ); case FUNCUBE_DONGLE_PRO_PLUS: - //Locate the matching mixer tuner dataline - MixerTunerDataLine fcd2Dataline = - getMixerTunerDataLine( tunerClass.getTunerType() ); - - if( fcd2Dataline != null ) - { - FCD2TunerController fcd2Controller; - - try - { - fcd2Controller = new FCD2TunerController( device ); - - FCDTuner fcd2Tuner = - new FCDTuner( fcd2Dataline, fcd2Controller ); - - TunerConfiguration config = - getTunerConfiguration( fcd2Tuner ); - - if( config != null ) - { - fcd2Tuner.apply( config ); - } - - mTuners.add( fcd2Tuner ); - - status = sLOADED; - name = fcd2Tuner.getName(); - reason = null; - } - catch ( SourceException e ) - { - reason = "Controller Source Exception: " + - e.getLocalizedMessage(); - } - } - else - { - reason = "Couldn't locate matching mixer/sound card device"; - } - break; - case GENERIC_2832: + return initFuncubeProPlusTuner( device, descriptor ); + case HACKRF_ONE: + return initHackRFTuner( device, descriptor ); case COMPRO_VIDEOMATE_U620F: case COMPRO_VIDEOMATE_U650F: case COMPRO_VIDEOMATE_U680F: + case GENERIC_2832: + case GENERIC_2838: case DEXATEK_5217_DVBT: case DEXATEK_DIGIVOX_MINI_II_REV3: case DEXATEK_LOGILINK_VG002A: - case GENERIC_2838: case GIGABYTE_GTU7300: case GTEK_T803: case LIFEVIEW_LV5T_DELUXE: @@ -259,254 +239,333 @@ public class TunerManager case TERRATEC_T_STICK_PLUS: case TWINTECH_UT40: case ZAAPA_ZTMINDVBZP: - TunerType tunerType = tunerClass.getTunerType(); - - if( tunerType == TunerType.RTL2832_VARIOUS ) - { - tunerType = RTL2832TunerController.identifyTunerType( device ); - } - - mLog.debug( "identified tuner class [" + - tunerClass.toString() + "] with tuner type [" + - tunerType.toString() + "]" ); - - switch( tunerType ) - { - case ELONICS_E4000: - try - { - E4KTunerController controller = - new E4KTunerController( device ); - - controller.init(); - - RTL2832Tuner rtlTuner = - new RTL2832Tuner( tunerClass, controller ); - - TunerConfiguration config = - getTunerConfiguration( rtlTuner ); - - if( config != null ) - { - rtlTuner.apply( config ); - } - - mTuners.add( rtlTuner ); - status = sLOADED; - name = rtlTuner.getName(); - reason = null; - } - catch( SourceException se ) - { - status = sNOT_LOADED; - reason = "Error constructing E4K tuner " - + "controller - " + se.getLocalizedMessage(); - } - break; - case RAFAELMICRO_R820T: - mLog.debug( "attempting to construct R820T " - + "tuner controller" ); - try - { - R820TTunerController controller = - new R820TTunerController( device ); - - mLog.debug( "initializing R820T tuner controller" ); - controller.init(); - - RTL2832Tuner rtlTuner = - new RTL2832Tuner( tunerClass, controller ); - - - TunerConfiguration config = - getTunerConfiguration( rtlTuner ); - - if( config != null ) - { - mLog.debug( "applying tuner config to R820T tuner" ); - rtlTuner.apply( config ); - } - else - { - mLog.debug( "R820T tuner config was " - + "null - not applied" ); - } - - mTuners.add( rtlTuner ); - status = sLOADED; - name = rtlTuner.getName(); - reason = null; - } - catch( SourceException se ) - { - status = sNOT_LOADED; - reason = "Error constructing R820T tuner " - + "controller - " + se.getLocalizedMessage(); - - mLog.error( "error constructing tuner", se ); - } - break; - case FITIPOWER_FC0012: - case FITIPOWER_FC0013: - case RAFAELMICRO_R828D: - case UNKNOWN: - default: - status = sNOT_LOADED; - reason = "SDRTRunk doesn't currently support RTL2832 " - + "Dongle with [" + tunerType.toString() + - "] tuner for tuner class[" + tunerClass.toString() + "]"; - break; - } - break; - case ETTUS_USRP_B100: - mTuners.add( new B100Tuner( device ) ); - status = sLOADED; - reason = null; - break; - case HACKRF_ONE: -// try -// { -// HackRFTunerController hackRFController = -// new HackRFTunerController( device ); -// -// hackRFController.init(); -// -// HackRFTuner hackRFTuner = -// new HackRFTuner( hackRFController ); -// -// mTuners.add( hackRFTuner ); -// name = hackRFTuner.getName(); -// status = sLOADED; -// reason = null; -// } -// catch( SourceException se ) -// { -// status = sNOT_LOADED; -// reason = "Error constructing HackRF tuner " -// + "controller - " + se.getLocalizedMessage(); -// } - break; + return initRTL2832Tuner( tunerClass, device, descriptor ); case UNKNOWN: default: break; } - - /** - * Log the tuner loading status - */ - sb.append( status ); - sb.append( String.format( "%04X", - device.getDevice().getUsbDeviceDescriptor().idVendor() ) ); - sb.append( ":" ); - sb.append( String.format( "%04X", - device.getDevice().getUsbDeviceDescriptor().idProduct() ) ); - sb.append( " " ); - - sb.append( name ); - - if( reason != null ) - { - sb.append( " - " ); - sb.append( reason ); - } - - sb.append( "\n" ); } - mLog.info( "Configuring USB Tuners" ); - mLog.info( sb.toString() ); + return new TunerInitStatus( null, "Unknown Device" ); } - /** - * Get all USB tuner devices - */ - private ArrayList getUSBTunerDevices() + private TunerInitStatus initEttusB100Tuner( Device device, + DeviceDescriptor descriptor ) { - StringBuilder sb = new StringBuilder(); + return new TunerInitStatus( null, "Ettus B100 tuner not currently " + + "supported" ); +// case ETTUS_USRP_B100: +// mTuners.add( new B100Tuner( device ) ); +// status = sLOADED; +// reason = null; +// break; + } + + private TunerInitStatus initFuncubeProTuner( Device device, + DeviceDescriptor descriptor ) + { + String reason = "NOT LOADED"; - List devices = getUSBDevices(); + MixerTunerDataLine dataline = getMixerTunerDataLine( + TunerClass.FUNCUBE_DONGLE_PRO.getTunerType() ); + + if( dataline != null ) + { + FCD1TunerController controller = + new FCD1TunerController( device, descriptor ); - sb.append( "discovered [" + devices.size() + - "] attached USB devices\n" ); - - ArrayList tuners = new ArrayList(); - - for (UsbDevice device : devices ) - { - String status = "\t[NOT RECOGNIZED]\t"; - - TunerClass type = TunerClass.valueOf( device.getUsbDeviceDescriptor() ); - - if( type != TunerClass.UNKNOWN ) + try { - status = "\t[RECOGNIZED] \t"; - tuners.add( new USBTunerDevice( device, type) ); + controller.init(); + + FCDTuner tuner = + new FCDTuner( dataline, controller ); + + TunerConfiguration config = getTunerConfiguration( tuner ); + + if( config != null ) + { + tuner.apply( config ); + } + + return new TunerInitStatus( tuner, "LOADED" ); } - - sb.append( status ); - sb.append( device.toString() ); - - if( type != TunerClass.UNKNOWN ) + catch ( SourceException e ) { - sb.append( " " ); - sb.append( type.getVendorDescription() ); - sb.append( " " ); - sb.append( type.getDeviceDescription() ); + mLog.error( "couldn't load funcube dongle pro tuner", e ); + + reason = "error during initialization - " + e.getLocalizedMessage(); } + } + else + { + reason = "couldn't find matching mixer dataline"; + } - sb.append( "\n" ); - } - - mLog.info( "USB Device Discovery" ); - mLog.info( sb.toString() ); - - return tuners; + return new TunerInitStatus( null, "Funcube Dongle Pro tuner not " + + "loaded - " + reason ); } - /** - * Gets all USB devices from the root hub downward, recursively, or - * returns empty list if none are discovered - */ - public static List getUSBDevices() - { - ArrayList devices = new ArrayList(); - - try - { - UsbServices services = UsbHostManager.getUsbServices(); - devices = getUsbChildDevices( services.getRootUsbHub() ); - } - catch( SecurityException e ) - { - mLog.error( "security exception while getting USB devices", e ); - } - catch( UsbException e ) - { - mLog.error( "usb exception while getting USB devices", e ); - } + private TunerInitStatus initFuncubeProPlusTuner( Device device, + DeviceDescriptor descriptor ) + { + String reason = "NOT LOADED"; + + MixerTunerDataLine dataline = getMixerTunerDataLine( + TunerClass.FUNCUBE_DONGLE_PRO_PLUS.getTunerType() ); + + if( dataline != null ) + { + FCD2TunerController controller = + new FCD2TunerController( device, descriptor ); - return devices; - } - - /** - * Get (recursively) all usb child devices below the usb hub - */ - public static ArrayList getUsbChildDevices( UsbHub hub ) - { - ArrayList devices = new ArrayList(); - - for ( UsbDevice device : (List) hub.getAttachedUsbDevices() ) - { - devices.add( device ); - - if ( device.isUsbHub() ) + try { - devices.addAll( getUsbChildDevices( (UsbHub)device ) ); + controller.init(); + + FCDTuner tuner = + new FCDTuner( dataline, controller ); + + TunerConfiguration config = getTunerConfiguration( tuner ); + + if( config != null ) + { + tuner.apply( config ); + } + + return new TunerInitStatus( tuner, "LOADED" ); } - } - - return devices; - } + catch ( SourceException e ) + { + mLog.error( "couldn't load funcube dongle pro plus tuner", e ); + + reason = "error during initialization - " + + e.getLocalizedMessage(); + } + } + else + { + reason = "couldn't find matching mixer dataline"; + } + + return new TunerInitStatus( null, "Funcube Dongle Pro tuner not " + + "loaded - " + reason ); + } + + private TunerInitStatus initHackRFTuner( Device device, + DeviceDescriptor descriptor ) + { + try + { + HackRFTunerController hackRFController = + new HackRFTunerController( device, descriptor ); + + hackRFController.init(); + + HackRFTuner tuner = new HackRFTuner( hackRFController ); + + return new TunerInitStatus( tuner, "LOADED" ); + } + catch( SourceException se ) + { + mLog.error( "couldn't construct HackRF controller/tuner", se ); + + return new TunerInitStatus( null, + "error constructing HackRF tuner controller" ); + } + } + + private TunerInitStatus initRTL2832Tuner( TunerClass tunerClass, + Device device, + DeviceDescriptor deviceDescriptor ) + { + String reason = "NOT LOADED"; + + TunerType tunerType = tunerClass.getTunerType(); + + if( tunerType == TunerType.RTL2832_VARIOUS ) + { + try + { + tunerType = RTL2832TunerController.identifyTunerType( device ); + } + catch( SourceException e ) + { + mLog.error( "couldn't determine RTL2832 tuner type", e ); + tunerType = TunerType.UNKNOWN; + } + } + + switch( tunerType ) + { + case ELONICS_E4000: + try + { + E4KTunerController controller = + new E4KTunerController( device, deviceDescriptor ); + + controller.init(); + + RTL2832Tuner rtlTuner = + new RTL2832Tuner( tunerClass, controller ); + + TunerConfiguration config = + getTunerConfiguration( rtlTuner ); + + if( config != null ) + { + rtlTuner.apply( config ); + } + + return new TunerInitStatus( rtlTuner, "LOADED" ); + } + catch( SourceException se ) + { + return new TunerInitStatus( null, "Error constructing E4K tuner " + + "controller - " + se.getLocalizedMessage() ); + } + case RAFAELMICRO_R820T: + mLog.debug( "attempting to construct R820T " + + "tuner controller" ); + try + { + R820TTunerController controller = + new R820TTunerController( device, deviceDescriptor ); + + mLog.debug( "initializing R820T tuner controller" ); + controller.init(); + + RTL2832Tuner rtlTuner = + new RTL2832Tuner( tunerClass, controller ); + + TunerConfiguration config = + getTunerConfiguration( rtlTuner ); + + if( config != null ) + { + mLog.debug( "applying tuner config to R820T tuner" ); + rtlTuner.apply( config ); + } + else + { + mLog.debug( "R820T tuner config was " + + "null - not applied" ); + } + + return new TunerInitStatus( rtlTuner, "LOADED" ); + } + catch( SourceException se ) + { + mLog.error( "error constructing tuner", se ); + + return new TunerInitStatus( null, "Error constructing R820T " + + "tuner controller - " + se.getLocalizedMessage() ); + } + case FITIPOWER_FC0012: + case FITIPOWER_FC0013: + case RAFAELMICRO_R828D: + case UNKNOWN: + default: + reason = "SDRTRunk doesn't currently support RTL2832 " + + "Dongle with [" + tunerType.toString() + + "] tuner for tuner class[" + tunerClass.toString() + "]"; + break; + } + + return new TunerInitStatus( null, reason ); + } + + +// /** +// * Get all USB tuner devices +// */ +// private ArrayList getUSBTunerDevices() +// { +// StringBuilder sb = new StringBuilder(); +// +// List devices = getUSBDevices(); +// +// sb.append( "discovered [" + devices.size() + +// "] attached USB devices\n" ); +// +// ArrayList tuners = new ArrayList(); +// +// for (UsbDevice device : devices ) +// { +// String status = "\t[NOT RECOGNIZED]\t"; +// +// TunerClass type = TunerClass.valueOf( device.getUsbDeviceDescriptor() ); +// +// if( type != TunerClass.UNKNOWN ) +// { +// status = "\t[RECOGNIZED] \t"; +// tuners.add( new USBTunerDevice( device, type) ); +// } +// +// sb.append( status ); +// sb.append( device.toString() ); +// +// if( type != TunerClass.UNKNOWN ) +// { +// sb.append( " " ); +// sb.append( type.getVendorDescription() ); +// sb.append( " " ); +// sb.append( type.getDeviceDescription() ); +// } +// +// sb.append( "\n" ); +// } +// +// mLog.info( "USB Device Discovery" ); +// mLog.info( sb.toString() ); +// +// return tuners; +// } +// +// /** +// * Gets all USB devices from the root hub downward, recursively, or +// * returns empty list if none are discovered +// */ +// public static List getUSBDevices() +// { +// ArrayList devices = new ArrayList(); +// +// try +// { +// UsbServices services = UsbHostManager.getUsbServices(); +// devices = getUsbChildDevices( services.getRootUsbHub() ); +// } +// catch( SecurityException e ) +// { +// mLog.error( "security exception while getting USB devices", e ); +// } +// catch( UsbException e ) +// { +// mLog.error( "usb exception while getting USB devices", e ); +// } +// +// return devices; +// } +// +// /** +// * Get (recursively) all usb child devices below the usb hub +// */ +// public static ArrayList getUsbChildDevices( UsbHub hub ) +// { +// ArrayList devices = new ArrayList(); +// +// for ( UsbDevice device : (List) hub.getAttachedUsbDevices() ) +// { +// devices.add( device ); +// +// if ( device.isUsbHub() ) +// { +// devices.addAll( getUsbChildDevices( (UsbHub)device ) ); +// } +// } +// +// return devices; +// } /** * Get a stored tuner configuration or create a default tuner configuration @@ -585,4 +644,31 @@ public class TunerManager return null; } + + public class TunerInitStatus + { + private Tuner mTuner; + private String mInfo; + + public TunerInitStatus( Tuner tuner, String info ) + { + mTuner = tuner; + mInfo = info; + } + + public Tuner getTuner() + { + return mTuner; + } + + public String getInfo() + { + return mInfo; + } + + public boolean isLoaded() + { + return mTuner != null; + } + } } diff --git a/src/source/tuner/ettus/B100Tuner.java b/src/source/tuner/ettus/B100Tuner.java index 9ea8476e..d80190bb 100644 --- a/src/source/tuner/ettus/B100Tuner.java +++ b/src/source/tuner/ettus/B100Tuner.java @@ -51,6 +51,11 @@ public class B100Tuner extends Tuner mDevice = device; } + public void dispose() + { + + } + @Override public TunerClass getTunerClass() { diff --git a/src/source/tuner/fcd/FCDTuner.java b/src/source/tuner/fcd/FCDTuner.java index 410ccfde..941ea4c7 100644 --- a/src/source/tuner/fcd/FCDTuner.java +++ b/src/source/tuner/fcd/FCDTuner.java @@ -50,6 +50,13 @@ public class FCDTuner extends MixerTuner mController.addListener( (FrequencyChangeListener)this ); } + public void dispose() + { + //TODO: release the mixer tuner data line as well + + mController.dispose(); + } + public FCDTunerController getController() { return mController; @@ -70,7 +77,7 @@ public class FCDTuner extends MixerTuner @Override public String getUniqueID() { - return mController.getAddress(); + return mController.getUSBAddress(); } @Override diff --git a/src/source/tuner/fcd/FCDTunerController.java b/src/source/tuner/fcd/FCDTunerController.java index cd1f9ca1..fbd4f1d6 100644 --- a/src/source/tuner/fcd/FCDTunerController.java +++ b/src/source/tuner/fcd/FCDTunerController.java @@ -17,18 +17,21 @@ ******************************************************************************/ package source.tuner.fcd; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; + import javax.swing.JPanel; import javax.usb.UsbClaimException; -import javax.usb.UsbConfiguration; -import javax.usb.UsbDevice; -import javax.usb.UsbEndpoint; import javax.usb.UsbException; -import javax.usb.UsbInterface; -import javax.usb.UsbInterfacePolicy; -import javax.usb.UsbPipe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.usb4java.Device; +import org.usb4java.DeviceDescriptor; +import org.usb4java.DeviceHandle; +import org.usb4java.LibUsb; +import org.usb4java.LibUsbException; import source.SourceException; import source.tuner.TunerClass; @@ -36,7 +39,6 @@ import source.tuner.TunerConfiguration; import source.tuner.TunerController; import source.tuner.TunerType; import source.tuner.fcd.proV1.FCD1TunerController.Block; -import source.tuner.usb.USBTunerDevice; import controller.ResourceManager; public abstract class FCDTunerController extends TunerController @@ -44,57 +46,105 @@ public abstract class FCDTunerController extends TunerController private final static Logger mLog = LoggerFactory.getLogger( FCDTunerController.class ); - public final static int sINT_NULL_VALUE = -1; - public final static long sLONG_NULL_VALUE = -1l; - public final static double sDOUBLE_NULL_VALUE = -1.0D; + public final static byte FCD_INTERFACE = (byte)0x2; + public final static byte FCD_ENDPOINT_IN = (byte)0x82; + public final static byte FCD_ENDPOINT_OUT = (byte)0x2; - public final static byte sFCD_INTERFACE = (byte)0x2; - public final static byte sFCD_ENDPOINT_IN = (byte)0x82; - public final static byte sFCD_ENDPOINT_OUT = (byte)0x2; + private Device mDevice; + private DeviceDescriptor mDeviceDescriptor; + private DeviceHandle mDeviceHandle; - public final static boolean sFCD_FORCE_CLAIM_HID_INTERFACE = true; - - private UsbDevice mFuncube; - private UsbConfiguration mUsbConfiguration; - private UsbInterface mFuncubeHID; - private UsbPipe mPipeIn; - private UsbPipe mPipeOut; private FCDConfiguration mConfiguration = new FCDConfiguration(); - - public FCDTunerController( USBTunerDevice device, + + /** + * Generic FCD tuner controller - contains functionality common across both + * funcube dongle tuners + * + * @param device + * @param descriptor + * @param minTunableFrequency + * @param maxTunableFrequency + */ + public FCDTunerController( Device device, + DeviceDescriptor descriptor, int minTunableFrequency, - int maxTunableFrequency ) throws SourceException + int maxTunableFrequency ) { super( minTunableFrequency, maxTunableFrequency ); - mFuncube = device.getDevice(); - mUsbConfiguration = mFuncube.getActiveUsbConfiguration(); - mFuncubeHID = mUsbConfiguration.getUsbInterface( sFCD_INTERFACE ); + mDevice = device; + mDeviceDescriptor = descriptor; } - + + /** + * Initializes the controller by opening the USB device and claiming the + * HID interface. + * + * Invoke this method after constructing this class to setup the + * controller. + * + * @throws SourceException if cannot open and claim the USB device + */ + public void init() throws SourceException + { + mDeviceHandle = new DeviceHandle(); + + int result = LibUsb.open( mDevice, mDeviceHandle ); + + if( result != LibUsb.SUCCESS ) + { + mDeviceHandle = null; + + throw new SourceException( "libusb couldn't open funcube usb " + + "device [" + LibUsb.errorName( result ) + "]" ); + } + + claimInterface(); + } + + /** + * Disposes of resources. Closes the USB device and interface. + */ + public void dispose() + { + if( mDeviceHandle != null ) + { + try + { + LibUsb.close( mDeviceHandle ); + } + catch( Exception e ) + { + mLog.error( "error while closing device handle", e ); + } + + mDeviceHandle = null; + } + + mDeviceDescriptor = null; + mDevice = null; + } + + /** + * Sample rate of the tuner + */ public abstract int getCurrentSampleRate() throws SourceException; /** - * Returns the tuner class. Since this is a generic container for both - * types of funcube, we let the controller self identify the class and type - * - * @return - tuner class + * Tuner class */ public abstract TunerClass getTunerClass(); /** - * Returns the tuner type. Since this is a generic container for both - * types of funcube, we let the controller self identify the class and type - * - * @return - tuner type + * Tuner type */ public abstract TunerType getTunerType(); /** - * FCD editor panel + * Editor panel (GUI) component. */ public abstract JPanel getEditor( FCDTuner tuner, - ResourceManager resourceManager ); + ResourceManager resourceManager ); /** * Applies the settings in the tuner configuration @@ -103,17 +153,81 @@ public abstract class FCDTunerController extends TunerController throws SourceException; /** - * Returns the applied tuner configuration or null if one hasn't yet been - * applied + * Returns the currently applied tuner configuration or null if one hasn't + * yet been applied */ public abstract TunerConfiguration getTunerConfiguration(); /** - * USB address + * USB address (bus/port) */ - public String getAddress() + public String getUSBAddress() { - return mFuncube.toString(); + if( mDevice != null ) + { + StringBuilder sb = new StringBuilder(); + + sb.append( "Bus:" ); + int bus = LibUsb.getBusNumber( mDevice ); + sb.append( bus ); + + sb.append( " Port:" ); + int port = LibUsb.getPortNumber( mDevice ); + sb.append( port ); + + return sb.toString(); + } + + return "UNKNOWN"; + } + + /** + * USB Vendor and Product ID + */ + public String getUSBID() + { + if( mDeviceDescriptor != null ) + { + StringBuilder sb = new StringBuilder(); + + sb.append( String.format( "%04X", + (int)( mDeviceDescriptor.idVendor() & 0xFFFF ) ) ); + + sb.append( ":" ); + + sb.append( String.format( "%04X", + (int)( mDeviceDescriptor.idProduct() & 0xFFFF ) ) ); + + return sb.toString(); + } + + return "UNKNOWN"; + } + + /** + * USB Port Speed. Should be 2.0 for both types of funcube dongles + */ + public String getUSBSpeed() + { + if( mDevice != null ) + { + int speed = LibUsb.getDeviceSpeed( mDevice ); + + switch( speed ) + { + case 0: + return "1.1 LOW"; + case 1: + return "1.1 FULL"; + case 2: + return "2.0 HIGH"; + case 3: + return "3.0 SUPER"; + default: + } + } + + return "UNKNOWN"; } /** @@ -121,20 +235,17 @@ public abstract class FCDTunerController extends TunerController */ public void setFCDMode( Mode mode ) throws UsbException, UsbClaimException { - byte[] response = null; + ByteBuffer response = null; switch( mode ) { case APPLICATION: - response = send( FCDCommand.BL_QUERY.getRequestTemplate(), - FCDCommand.BL_QUERY.getResponseTemplate() ); + response = send( FCDCommand.BL_QUERY ); break; case BOOTLOADER: - response = send( FCDCommand.APP_RESET.getRequestTemplate(), - FCDCommand.APP_RESET.getResponseTemplate() ); + response = send( FCDCommand.APP_RESET ); break; - case ERROR: - case UNKNOWN: + default: break; } @@ -171,7 +282,11 @@ public abstract class FCDTunerController extends TunerController { try { - return send( FCDCommand.APP_GET_FREQUENCY_HZ ); + ByteBuffer buffer = send( FCDCommand.APP_GET_FREQUENCY_HZ ); + + buffer.order( ByteOrder.LITTLE_ENDIAN ); + + return (int)( buffer.getInt( 2 ) & 0xFFFFFFFF ); } catch( Exception e ) { @@ -189,185 +304,206 @@ public abstract class FCDTunerController extends TunerController } /** - * Claims the FCD USB HID interface. If another application currently has - * the interface claimed, the sFCD_FORCE_CLAIM_HID_INTERFACE setting - * will dictate if the interface is forcibly claimed from the other - * application + * Claims the USB interface. Attempts to detach the active kernel driver if + * one is currently attached. */ - private boolean claim() throws UsbException, UsbClaimException + private void claimInterface() throws SourceException { - boolean claimed = false; - - if( !mFuncubeHID.isClaimed() ) + if( mDeviceHandle != null ) { - mFuncubeHID.claim( new UsbInterfacePolicy() - { - @Override - public boolean forceClaim( UsbInterface arg0 ) - { - return sFCD_FORCE_CLAIM_HID_INTERFACE; - } - } ); + int result = LibUsb.kernelDriverActive( mDeviceHandle, FCD_INTERFACE ); - claimed = true; - } - else - { - mLog.info( "Attempted to claim the Funcube HID interface, but " - + "it's in use by another program" ); - } - - return claimed; - } - - /** - * Releases the claimed USB (FCD) interface - */ - private void release() - { - mPipeIn = null; - mPipeOut = null; - - try - { - mFuncubeHID.release(); - } - catch ( Exception e ) - { - mLog.error( "Exception thrown while releasing the funcube HID " - + "interface", e ); - } - } - - /** - * Convenience wrapper for commands that don't take arguments - */ - public long send( FCDCommand command ) throws UsbException, UsbClaimException - { - return send( command, sLONG_NULL_VALUE ); - } - - /** - * Sends the command, optionally placing the argument value parsed into - * little endian bytes in the request array. Returns any integer value that - * part of the response, or sINT_NULL_VALUE (-1) if it fails. - * - * Note: we use a long return value to avoid any issues with the MSB of a - * 32-bit response value being misinterpreted as the integer sign bit. - * - * @param command - * @param commandArgument - command argument. Use -1 for no-argument commands - * @return - response long value, or -1 if fails - * @throws UsbException - * @throws UsbClaimException - */ - public long send( FCDCommand command, long commandArgument ) throws UsbException, - UsbClaimException - { - long retVal = sLONG_NULL_VALUE; - - byte[] request = command.getRequestTemplate(); - - if( commandArgument != sLONG_NULL_VALUE ) - { - //Parse the value argument into the request byte indices, according to command length - for( int x = 1; x < command.getArrayLength(); x++ ) + if( result == 1 ) { - //Little endian - request[ x ] = (byte)( 0xFF & - Long.rotateRight( commandArgument, ( x - 1 ) * 8 ) ); + result = LibUsb.detachKernelDriver( mDeviceHandle, + FCD_INTERFACE ); + + if( result != LibUsb.SUCCESS ) + { + mLog.error( "failed attempt to detach kernel driver [" + + LibUsb.errorName( result ) + "]" ); + } } - } - - byte[] response = send( request, command.getResponseTemplate() ); - - if( response != null ) - { - retVal = parseResponse( command, response ); - } - - return retVal; - } - - /** - * Sends the request byte array to the device and returns the response array - * filled with the response bytes from the device, or returns null if - * something failed along the way - */ - private byte[] send( byte[] request, byte[] response ) - throws UsbException, UsbClaimException - { - byte[] retVal = null; - - if( mPipeIn != null && mPipeOut != null ) - { - mPipeOut.syncSubmit( request ); - - mPipeIn.syncSubmit( response ); - retVal = response; - } - - return retVal; - } - - /** - * Parses a multi-byte integer response value from a byte array that is - * 2 or more bytes long - */ - private long parseResponse( FCDCommand command, byte[] response ) - { - long retVal = 0; - - //Parse the value argument into the request byte indices, according to command length - for( int x = 2; x < command.getArrayLength(); x++ ) - { - retVal += Long.rotateLeft( ( response[ x ] & 0xFF ), ( x - 2 ) * 8 ); - } - - return retVal; - } - - protected void open() throws UsbException, UsbClaimException - { - if( claim() ) - { - //Get the USB endpoints - UsbEndpoint endpointIn = - mFuncubeHID.getUsbEndpoint( sFCD_ENDPOINT_IN ); - - UsbEndpoint endpointOut = - mFuncubeHID.getUsbEndpoint( sFCD_ENDPOINT_OUT ); - - //Setup the pipes - if( endpointIn != null && endpointOut != null ) + result = LibUsb.claimInterface( mDeviceHandle, FCD_INTERFACE ); + + if( result != LibUsb.SUCCESS ) { - mPipeOut = endpointOut.getUsbPipe(); - mPipeOut.open(); - - mPipeIn = endpointIn.getUsbPipe(); - mPipeIn.open(); - - setFCDMode( Mode.APPLICATION ); - } - else - { - mLog.error( "FCD Pro Tuner Controller - couldn't gain access " + - "to the USB in/out endpoints or pipes." ); + throw new SourceException( "couldn't claim usb interface [" + + LibUsb.errorName( result ) + "]" ); } } else { - mLog.error( "FCD Pro Tuner Controller - couldn't claim the USB " + - "interface. Check to see if another program is using it." ); + throw new SourceException( "couldn't claim usb hid interface - no " + + "device handle" ); + } + } + + /** + * Performs an interrupt write to the OUT endpoint. + * @param buffer - direct allocated buffer. Must be 64 bytes in length. + * + * @throws LibUsbException on error + */ + private void write( ByteBuffer buffer ) throws LibUsbException + { + if( mDeviceHandle != null ) + { + IntBuffer transferred = IntBuffer.allocate( 1 ); + + int result = LibUsb.interruptTransfer( mDeviceHandle, + FCD_ENDPOINT_OUT, + buffer, + transferred, + 500l ); + + if( result != LibUsb.SUCCESS ) + { + throw new LibUsbException( "error writing byte buffer", + result ); + } + else if( transferred.get() != buffer.capacity() ) + { + throw new LibUsbException( "transferred bytes [" + + transferred.get( 0 ) + "] is not what was expected [" + + buffer.capacity() + "]", result ); + } + } + else + { + throw new LibUsbException( "device handle is null", + LibUsb.ERROR_NO_DEVICE ); } } - protected void close() + /** + * Performs an interrupt write to the OUT endpoint for the FCD command. + * @param command - no-argument command to write + * @throws LibUsbException - on error + */ + private void write( FCDCommand command ) throws LibUsbException { - release(); + ByteBuffer buffer = ByteBuffer.allocateDirect( 64 ); + + buffer.put( 0, command.getCommand() ); + buffer.put( 1, (byte)0x00 ); + + write( buffer ); } + /** + * Convenience logger for debugging read/write operations + */ + @SuppressWarnings( "unused" ) + private void log( String label, ByteBuffer buffer ) + { + StringBuilder sb = new StringBuilder(); + + sb.append( label ); + + sb.append( " " ); + + sb.append( buffer.get( 0 ) ); + sb.append( " | " ); + + for( int x = 0; x < 64; x++ ) + { + sb.append( String.format( "%02X", (int)( buffer.get( x ) & 0xFF ) ) ); + sb.append( " " ); + } + + mLog.debug( sb.toString() ); + } + + /** + * Performs an interrupt write to the OUT endpoint for the FCD command. + * @param command - command to write + * @param argument - value to write with the command + * @throws LibUsbException - on error + */ + private void write( FCDCommand command, long argument ) throws LibUsbException + { + ByteBuffer buffer = ByteBuffer.allocateDirect( 64 ); + + /* The FCD expects little-endian formatted values */ + buffer.order( ByteOrder.LITTLE_ENDIAN ); + + buffer.put( 0, command.getCommand() ); + buffer.putLong( 1, argument ); + + write( buffer ); + } + + /** + * Performs an interrupt read against the endpoint + * @return buffer read from FCD + * @throws LibUsbException on error + */ + private ByteBuffer read() throws LibUsbException + { + if( mDeviceHandle != null ) + { + ByteBuffer buffer = ByteBuffer.allocateDirect( 64 ); + + IntBuffer transferred = IntBuffer.allocate( 1 ); + + + int result = LibUsb.interruptTransfer( mDeviceHandle, + FCD_ENDPOINT_IN, + buffer, + transferred, + 500l ); + + if( result != LibUsb.SUCCESS ) + { + throw new LibUsbException( "error reading byte buffer", + result ); + } + else if( transferred.get( 0 ) != buffer.capacity() ) + { + throw new LibUsbException( "received bytes [" + + transferred.get( 0 ) + "] didn't match expected " + + "length [" + buffer.capacity() + "]", result ); + } + + return buffer; + } + + throw new LibUsbException( "device handle is null", + LibUsb.ERROR_NO_DEVICE ); + } + + /** + * Sends the FCD command and argument. Performs a read to complete the + * command. + * + * @param command - command to send + * @param argument - command argument to send + * @throws LibUsbException - on error + */ + protected void send( FCDCommand command, long argument ) throws LibUsbException + { + write( command, argument ); + read(); + } + + /** + * Sends the no-argument FCD command. Performs a read to complete the + * command. + * + * @param command - command to send + * @throws LibUsbException - on error + */ + protected ByteBuffer send( FCDCommand command ) throws LibUsbException + { + write( command ); + return read(); + } + + /** + * FCD configuration string parsing class + */ public class FCDConfiguration { private String mConfig; @@ -385,11 +521,20 @@ public abstract class FCDTunerController extends TunerController mMode = Mode.UNKNOWN; } - public void set( byte[] data ) + /** + * Extracts the configuration string from the buffer + */ + public void set( ByteBuffer buffer ) { - if( FCDCommand.checkResponse( FCDCommand.BL_QUERY, data ) || - FCDCommand.checkResponse( FCDCommand.APP_RESET, data ) ) + if( buffer.capacity() == 64 ) { + byte[] data = new byte[ 64 ]; + + for( int x = 0; x < 64; x++ ) + { + data[ x ] = buffer.get( x ); + } + mConfig = new String( data ); mMode = Mode.getMode( mConfig ); } diff --git a/src/source/tuner/fcd/FCDTunerDetailsPanel.java b/src/source/tuner/fcd/FCDTunerDetailsPanel.java index 1e020d72..05e3b51f 100644 --- a/src/source/tuner/fcd/FCDTunerDetailsPanel.java +++ b/src/source/tuner/fcd/FCDTunerDetailsPanel.java @@ -17,26 +17,27 @@ ******************************************************************************/ package source.tuner.fcd; -import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JPanel; -import source.tuner.rtl.RTL2832TunerController.Descriptor; import net.miginfocom.swing.MigLayout; public class FCDTunerDetailsPanel extends JPanel { private static final long serialVersionUID = 1L; - private JLabel mAddress; - private JLabel mCellBlock; - private JLabel mFirmware; public FCDTunerDetailsPanel( FCDTunerController controller ) { - setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][][grow]" ) ); + setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][][][][grow]" ) ); + add( new JLabel( "USB ID:" ) ); + add( new JLabel( controller.getUSBID() ) ); + add( new JLabel( "USB Address:" ) ); - add( new JLabel( controller.getAddress() ) ); + add( new JLabel( controller.getUSBAddress() ) ); + + add( new JLabel( "USB Speed:" ) ); + add( new JLabel( controller.getUSBSpeed() ) ); add( new JLabel( "Cellular Band:" ) ); add( new JLabel( controller.getConfiguration().getBandBlocking() diff --git a/src/source/tuner/fcd/proV1/FCD1TunerConfigurationPanel.java b/src/source/tuner/fcd/proV1/FCD1TunerConfigurationPanel.java index 417012c8..bfbe7fbb 100644 --- a/src/source/tuner/fcd/proV1/FCD1TunerConfigurationPanel.java +++ b/src/source/tuner/fcd/proV1/FCD1TunerConfigurationPanel.java @@ -511,7 +511,7 @@ public class FCD1TunerConfigurationPanel extends JPanel mResourceManager.getSettingsManager() .setSelectedTunerConfiguration( TunerType.FUNCUBE_DONGLE_PRO, - mController.getAddress(), config ); + mController.getUSBAddress(), config ); } catch ( SourceException e1 ) { diff --git a/src/source/tuner/fcd/proV1/FCD1TunerController.java b/src/source/tuner/fcd/proV1/FCD1TunerController.java index 11f267e7..9d56b0f4 100644 --- a/src/source/tuner/fcd/proV1/FCD1TunerController.java +++ b/src/source/tuner/fcd/proV1/FCD1TunerController.java @@ -17,12 +17,17 @@ ******************************************************************************/ package source.tuner.fcd.proV1; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + import javax.swing.JPanel; import javax.usb.UsbClaimException; import javax.usb.UsbException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.usb4java.Device; +import org.usb4java.DeviceDescriptor; import source.SourceException; import source.tuner.TunerClass; @@ -31,7 +36,6 @@ import source.tuner.TunerType; import source.tuner.fcd.FCDCommand; import source.tuner.fcd.FCDTuner; import source.tuner.fcd.FCDTunerController; -import source.tuner.usb.USBTunerDevice; import controller.ResourceManager; public class FCD1TunerController extends FCDTunerController @@ -53,19 +57,22 @@ public class FCD1TunerController extends FCDTunerController private FCD1TunerConfiguration mTunerConfiguration; private FCD1TunerEditorPanel mEditor; - public FCD1TunerController( USBTunerDevice device ) - throws SourceException + public FCD1TunerController( Device device, DeviceDescriptor descriptor ) { - super( device, + super( device, + descriptor, sMINIMUM_TUNABLE_FREQUENCY, sMAXIMUM_TUNABLE_FREQUENCY ); + } + + public void init() throws SourceException + { + super.init(); mFrequencyController.setSampleRate( sSAMPLE_RATE ); try { - open(); - setFCDMode( Mode.APPLICATION ); getPhaseAndGainCorrection(); getDCIQCorrection(); @@ -73,7 +80,7 @@ public class FCD1TunerController extends FCDTunerController getLNAEnhanceSetting(); getMixerGainSetting(); - send( FCDCommand.APP_SET_MIXER_GAIN, 1 ); + send( FCDCommand.APP_SET_MIXER_GAIN, 1l ); } catch( Exception e ) { @@ -156,10 +163,12 @@ public class FCD1TunerController extends FCDTunerController */ private void getLNAGainSetting() throws UsbClaimException, UsbException { - int gain = (int)send( FCDCommand.APP_GET_LNA_GAIN ); - - mLog.info( "FCD1: lna gain setting is:" + gain ); + ByteBuffer buffer = send( FCDCommand.APP_GET_LNA_GAIN ); + buffer.order( ByteOrder.LITTLE_ENDIAN ); + + int gain = buffer.getInt( 2 ); + mLNAGain = LNAGain.valueOf( gain ); } @@ -286,7 +295,11 @@ public class FCD1TunerController extends FCDTunerController private void getPhaseAndGainCorrection() throws UsbClaimException, UsbException { - long correction = send( FCDCommand.APP_GET_IQ_CORRECTION ); + ByteBuffer buffer = send( FCDCommand.APP_GET_IQ_CORRECTION ); + + buffer.order( ByteOrder.LITTLE_ENDIAN ); + + int correction = buffer.getInt( 2 ); /** * Gain: mask the upper 16 phase bits and right shift to get the @@ -305,8 +318,6 @@ public class FCD1TunerController extends FCDTunerController short phase = (short)( correction & 0x0000FFFF ); mPhaseCorrection = ( (double)phase / (double)Short.MAX_VALUE ); - - mLog.info( "FCD1: correction:" + correction + " gain:" + gain + " phase:" + phase ); } /** @@ -413,7 +424,11 @@ public class FCD1TunerController extends FCDTunerController private void getDCIQCorrection() throws UsbClaimException, UsbException { - long correction = send( FCDCommand.APP_GET_DC_CORRECTION ); + ByteBuffer buffer = send( FCDCommand.APP_GET_DC_CORRECTION ); + + buffer.order( ByteOrder.LITTLE_ENDIAN ); + + int correction = buffer.getInt( 2 ); /** * Quadrature: mask the upper 16 bits and divide by 32768 to get the @@ -443,9 +458,11 @@ public class FCD1TunerController extends FCDTunerController private void getLNAEnhanceSetting() throws UsbClaimException, UsbException { - int enhance = (int)send( FCDCommand.APP_GET_LNA_ENHANCE ); - - mLog.info( "FCD1: lna enhance setting is: " + enhance ); + ByteBuffer buffer = send( FCDCommand.APP_GET_LNA_ENHANCE ); + + buffer.order( ByteOrder.LITTLE_ENDIAN ); + + int enhance = buffer.getInt( 2 ); mLNAEnhance = LNAEnhance.valueOf( enhance ); } @@ -463,9 +480,11 @@ public class FCD1TunerController extends FCDTunerController private void getMixerGainSetting() throws UsbClaimException, UsbException { - int gain = (int)send( FCDCommand.APP_GET_MIXER_GAIN ); + ByteBuffer buffer = send( FCDCommand.APP_GET_MIXER_GAIN ); - mLog.info( "FCD1: mixer gain setting is:" + gain ); + buffer.order( ByteOrder.LITTLE_ENDIAN ); + + int gain = buffer.getInt( 2 ); mMixerGain = MixerGain.valueOf( gain ); } diff --git a/src/source/tuner/fcd/proplusV2/FCD2TunerConfigurationPanel.java b/src/source/tuner/fcd/proplusV2/FCD2TunerConfigurationPanel.java index 049d8a56..bb6acbea 100644 --- a/src/source/tuner/fcd/proplusV2/FCD2TunerConfigurationPanel.java +++ b/src/source/tuner/fcd/proplusV2/FCD2TunerConfigurationPanel.java @@ -221,7 +221,7 @@ public class FCD2TunerConfigurationPanel extends JPanel TunerConfigurationAssignment savedConfig = mResourceManager .getSettingsManager().getSelectedTunerConfiguration( TunerType.FUNCUBE_DONGLE_PRO_PLUS, - mController.getAddress() ); + mController.getUSBAddress() ); if( savedConfig != null ) { @@ -237,7 +237,7 @@ public class FCD2TunerConfigurationPanel extends JPanel mResourceManager.getSettingsManager() .setSelectedTunerConfiguration( TunerType.FUNCUBE_DONGLE_PRO_PLUS, - mController.getAddress(), mSelectedConfig ); + mController.getUSBAddress(), mSelectedConfig ); } mComboConfigurations.setSelectedItem( mSelectedConfig ); @@ -324,7 +324,7 @@ public class FCD2TunerConfigurationPanel extends JPanel mResourceManager.getSettingsManager().setSelectedTunerConfiguration( TunerType.FUNCUBE_DONGLE_PRO_PLUS, - mController.getAddress(), config ); + mController.getUSBAddress(), config ); } catch ( SourceException e1 ) { diff --git a/src/source/tuner/fcd/proplusV2/FCD2TunerController.java b/src/source/tuner/fcd/proplusV2/FCD2TunerController.java index f6e27f42..8640ea50 100644 --- a/src/source/tuner/fcd/proplusV2/FCD2TunerController.java +++ b/src/source/tuner/fcd/proplusV2/FCD2TunerController.java @@ -17,12 +17,15 @@ ******************************************************************************/ package source.tuner.fcd.proplusV2; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + import javax.swing.JPanel; -import javax.usb.UsbClaimException; -import javax.usb.UsbException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.usb4java.Device; +import org.usb4java.DeviceDescriptor; import source.SourceException; import source.tuner.TunerClass; @@ -31,7 +34,6 @@ import source.tuner.TunerType; import source.tuner.fcd.FCDCommand; import source.tuner.fcd.FCDTuner; import source.tuner.fcd.FCDTunerController; -import source.tuner.usb.USBTunerDevice; import controller.ResourceManager; public class FCD2TunerController extends FCDTunerController @@ -46,25 +48,27 @@ public class FCD2TunerController extends FCDTunerController private FCD2TunerConfiguration mTunerConfiguration; private FCD2TunerEditorPanel mEditor; - public FCD2TunerController( USBTunerDevice device ) - throws SourceException + public FCD2TunerController( Device device, DeviceDescriptor descriptor ) { super( device, + descriptor, sMINIMUM_TUNABLE_FREQUENCY, sMAXIMUM_TUNABLE_FREQUENCY ); + } + + public void init() throws SourceException + { + super.init(); mFrequencyController.setSampleRate( sSAMPLE_RATE ); try { - open(); - setFCDMode( Mode.APPLICATION ); } catch( Exception e ) { - throw new SourceException( "FCDTunerController error " + - "during construction", e ); + throw new SourceException( "error setting Mode to APPLICATION", e ); } } @@ -109,7 +113,7 @@ public class FCD2TunerController extends FCDTunerController { if( plusConfig.getGainLNA() ) { - send( FCDCommand.APP_SET_LNA_GAIN, 1 ); + send( FCDCommand.APP_SET_LNA_GAIN, 1 ); } else @@ -117,34 +121,26 @@ public class FCD2TunerController extends FCDTunerController send( FCDCommand.APP_SET_LNA_GAIN, 0 ); } } - catch ( UsbClaimException e ) + catch ( Exception e ) { - throw new SourceException( "Exception while setting LNA Gain", e ); - } - catch ( UsbException e ) - { - throw new SourceException( "Exception while setting LNA Gain", e ); + throw new SourceException( "error while setting LNA Gain", e ); } try { if( plusConfig.getGainMixer() ) { - send( FCDCommand.APP_SET_MIXER_GAIN, 1 ); - + send( FCDCommand.APP_SET_MIXER_GAIN, 1 ); + } else { send( FCDCommand.APP_SET_MIXER_GAIN, 0 ); } } - catch ( UsbClaimException e ) + catch ( Exception e ) { - throw new SourceException( "Exception while setting mixer gain", e ); - } - catch ( UsbException e ) - { - throw new SourceException( "Exception while setting mixer gain", e ); + throw new SourceException( "error while setting Mixer Gain", e ); } mTunerConfiguration = plusConfig; @@ -163,17 +159,15 @@ public class FCD2TunerController extends FCDTunerController try { - dcCorrection = (int)send( FCDCommand.APP_GET_DC_CORRECTION ); + ByteBuffer buffer = send( FCDCommand.APP_GET_DC_CORRECTION ); + + buffer.order( ByteOrder.LITTLE_ENDIAN ); + + return buffer.getInt( 2 ); } - catch ( UsbClaimException e ) + catch ( Exception e ) { - mLog.error( "FCTTunerController - couldn't claim funcube HID to" - + " get dc correction value", e ); - } - catch ( UsbException e ) - { - mLog.error( "FCTTunerController - error getting dc correction " - + "value", e ); + mLog.error( "error getting dc correction value", e ); } return dcCorrection; @@ -183,17 +177,11 @@ public class FCD2TunerController extends FCDTunerController { try { - send( FCDCommand.APP_SET_DC_CORRECTION, value ); + send( FCDCommand.APP_SET_DC_CORRECTION, value ); } - catch ( UsbClaimException e ) + catch ( Exception e ) { - mLog.error( "FCDTunerController - error claiming usb hid while " - + "trying to set dc correction to [" + value + "]", e ); - } - catch ( UsbException e ) - { - mLog.error( "FCDTunerController - error while " - + "trying to set dc correction to [" + value + "]", e ); + mLog.error( "error setting dc correction to [" + value + "]", e ); } } @@ -203,20 +191,17 @@ public class FCD2TunerController extends FCDTunerController try { - iqCorrection = (int)send( FCDCommand.APP_GET_IQ_CORRECTION ); + ByteBuffer buffer = send( FCDCommand.APP_GET_IQ_CORRECTION ); + + buffer.order( ByteOrder.LITTLE_ENDIAN ); + + return buffer.getInt( 2 ); } - catch ( UsbClaimException e ) + catch ( Exception e ) { - mLog.error( "FCTTunerController - couldn't claim funcube HID to" - + " get iq correction value", e ); + mLog.error( "error reading IQ correction value", e ); } - catch ( UsbException e ) - { - mLog.error( "FCTTunerController - error getting iq correction " - + "value", e ); - } - return iqCorrection; } @@ -226,15 +211,9 @@ public class FCD2TunerController extends FCDTunerController { send( FCDCommand.APP_SET_IQ_CORRECTION, value ); } - catch ( UsbClaimException e ) + catch ( Exception e ) { - mLog.error( "FCDTunerController - error claiming usb hid while " - + "trying to set iq correction to [" + value + "]", e ); - } - catch ( UsbException e ) - { - mLog.error( "FCDTunerController - error while " - + "trying to set iq correction to [" + value + "]", e ); + mLog.error( "error setting IQ correction to [" + value + "]", e ); } } @@ -272,98 +251,4 @@ public class FCD2TunerController extends FCDTunerController return retVal; } } - - public enum TunerRFFilter - { - TRF_0_4, - TRF_4_8, - TRF_8_16, - TRF_16_32, - TRF_32_75, - TRF_75_125, - TRF_125_250, - TRF_145, - TRF_410_875, - TRF_435, - TRF_875_2000, - UNKNOWN; - - public static TunerRFFilter get( int value ) - { - TunerRFFilter retVal = UNKNOWN; - - if( 0 <= value && value <= 10 ) - { - retVal = values()[ value ]; - } - - return retVal; - } - } - - public enum TunerIFFilter - { - TIF_200KHZ, - TIF_300KHZ, - TIF_600KHZ, - TIF_1536KHZ, - TIF_5MHZ, - TIF_6MHZ, - TIF_7MHZ, - TIF_8MHZ, - UNKNOWN; - - public static TunerIFFilter get( int value ) - { - TunerIFFilter retVal = UNKNOWN; - - if( 0 <= value && value <= 7 ) - { - retVal = values()[ value ]; - } - - return retVal; - } - } - - public enum LNAGain - { - LNA_GAIN_MINUS_5_0( 0, "-5.0 dB" ), - LNA_GAIN_MINUS_2_5( 1, "-2.5 dB" ), - LNA_GAIN_PLUS_0_0( 4, "0.0 dB" ), - LNA_GAIN_PLUS_2_5( 5, "2.5 dB" ), - LNA_GAIN_PLUS_5_0( 6, "5.0 dB" ), - LNA_GAIN_PLUS_7_5( 7, "7.5 dB" ), - LNA_GAIN_PLUS_10_0( 8, "10.0 dB" ), - LNA_GAIN_PLUS_12_5( 9, "12.5 dB" ), - LNA_GAIN_PLUS_15_0( 10, "15.0 dB" ), - LNA_GAIN_PLUS_17_5( 11, "17.5 dB" ), - LNA_GAIN_PLUS_20_0( 12, "20.0 dB" ), - LNA_GAIN_PLUS_25_0( 13, "25.0 dB" ), - LNA_GAIN_PLUS_30_0( 14, "30.0 dB" ); - - private int mSetting; - private String mLabel; - - private LNAGain( int setting, String label ) - { - mSetting = setting; - mLabel = label; - } - - public int getSetting() - { - return mSetting; - } - - public String getLabel() - { - return mLabel; - } - - public String toString() - { - return getLabel(); - } - } } diff --git a/src/source/tuner/hackrf/HackRFTuner.java b/src/source/tuner/hackrf/HackRFTuner.java index c7204b54..8ac701a4 100644 --- a/src/source/tuner/hackrf/HackRFTuner.java +++ b/src/source/tuner/hackrf/HackRFTuner.java @@ -70,6 +70,11 @@ public class HackRFTuner extends Tuner mLog.error( "couldn't read HackRF board id", e ); } } + + public void dispose() + { + //TODO: dispose of something here + } public HackRFTunerController getController() { diff --git a/src/source/tuner/hackrf/HackRFTunerConfiguration.java b/src/source/tuner/hackrf/HackRFTunerConfiguration.java index c3d5736f..a76ce581 100644 --- a/src/source/tuner/hackrf/HackRFTunerConfiguration.java +++ b/src/source/tuner/hackrf/HackRFTunerConfiguration.java @@ -31,6 +31,7 @@ public class HackRFTunerConfiguration extends TunerConfiguration private HackRFSampleRate mSampleRate = HackRFSampleRate.RATE2_016MHZ; private HackRFLNAGain mLNAGain = HackRFLNAGain.GAIN_0; private HackRFVGAGain mVGAGain = HackRFVGAGain.GAIN_10; + private boolean mAmplifierEnabled = false; private double mFrequencyCorrection = 0.0d; /** @@ -52,6 +53,17 @@ public class HackRFTunerConfiguration extends TunerConfiguration return TunerType.HACKRF; } + @XmlAttribute( name = "amplifier_enabled" ) + public boolean getAmplifierEnabled() + { + return mAmplifierEnabled; + } + + public void setAmplifierEnabled( boolean enabled ) + { + mAmplifierEnabled = enabled; + } + @XmlAttribute( name = "lna_gain" ) public HackRFLNAGain getLNAGain() { diff --git a/src/source/tuner/hackrf/HackRFTunerConfigurationPanel.java b/src/source/tuner/hackrf/HackRFTunerConfigurationPanel.java index 462321bc..b5ec8acb 100644 --- a/src/source/tuner/hackrf/HackRFTunerConfigurationPanel.java +++ b/src/source/tuner/hackrf/HackRFTunerConfigurationPanel.java @@ -35,6 +35,7 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.JTextField; +import javax.swing.JToggleButton; import javax.swing.SpinnerModel; import javax.swing.SpinnerNumberModel; import javax.swing.SwingConstants; @@ -74,6 +75,7 @@ public class HackRFTunerConfigurationPanel extends JPanel private JTextField mName; private JSpinner mFrequencyCorrection; + private JToggleButton mAmplifier; private JComboBox mComboLNAGain; private JComboBox mComboVGAGain; @@ -284,8 +286,38 @@ public class HackRFTunerConfigurationPanel extends JPanel * Gain Controls */ JPanel gainPanel = new JPanel(); - gainPanel.setLayout( new MigLayout( "", "[grow,fill]", "[grow,fill]" ) ); + gainPanel.setLayout( new MigLayout( "", + "[][right][grow,fill][right][grow,fill]", "[grow,fill]" ) ); gainPanel.setBorder( BorderFactory.createTitledBorder( "Gain" ) ); + + /* Amplifier */ + mAmplifier = new JToggleButton( "Amp" ); + mAmplifier.setSelected( mSelectedConfig.getAmplifierEnabled() ); + mAmplifier.addActionListener( new ActionListener() + { + @Override + public void actionPerformed( ActionEvent arg0 ) + { + try + { + mController.setAmplifierEnabled( mAmplifier.isSelected() ); + mSelectedConfig.setAmplifierEnabled( mAmplifier.isSelected() ); + save(); + } + catch ( UsbException e ) + { + mLog.error( "couldn't enable/disable amplifier", e ); + mAmplifier.setEnabled( !mAmplifier.isSelected() ); + + JOptionPane.showMessageDialog( + HackRFTunerConfigurationPanel.this, + "Couldn't change amplifier setting", + "Error changing amplifier setting", + JOptionPane.ERROR_MESSAGE ); + } + } + } ); + gainPanel.add( mAmplifier ); /* LNA Gain Control */ mComboLNAGain = new JComboBox( HackRFLNAGain.values() ); @@ -311,6 +343,7 @@ public class HackRFTunerConfigurationPanel extends JPanel } mSelectedConfig.setLNAGain( lnaGain ); + save(); } catch ( UsbException e ) @@ -325,8 +358,8 @@ public class HackRFTunerConfigurationPanel extends JPanel } } } ); - mComboLNAGain.setToolTipText( "LNA Gain. Set master gain " - + "to MANUAL to enable adjustment" ); + mComboLNAGain.setToolTipText( "LNA Gain. Adjust to set " + + "the IF gain" ); gainPanel.add( new JLabel( "LNA" ) ); gainPanel.add( mComboLNAGain ); @@ -367,12 +400,12 @@ public class HackRFTunerConfigurationPanel extends JPanel } } } ); - mComboVGAGain.setToolTipText( "VGA Gain. Set master gain " - + "to MANUAL to enable adjustment" ); + mComboVGAGain.setToolTipText( "VGA Gain. Adjust to set the " + + "baseband gain" ); gainPanel.add( new JLabel( "VGA" ) ); gainPanel.add( mComboVGAGain, "wrap" ); - add( gainPanel, "span" ); + add( gainPanel, "span,growx" ); /** * Create a new configuration diff --git a/src/source/tuner/hackrf/HackRFTunerController.java b/src/source/tuner/hackrf/HackRFTunerController.java index 38555d3e..5270e98f 100644 --- a/src/source/tuner/hackrf/HackRFTunerController.java +++ b/src/source/tuner/hackrf/HackRFTunerController.java @@ -1,5 +1,7 @@ package source.tuner.hackrf; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; @@ -10,46 +12,34 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import javax.usb.UsbClaimException; -import javax.usb.UsbConfiguration; -import javax.usb.UsbControlIrp; -import javax.usb.UsbDevice; -import javax.usb.UsbDisconnectedException; -import javax.usb.UsbEndpoint; -import javax.usb.UsbEndpointDescriptor; import javax.usb.UsbException; -import javax.usb.UsbInterface; -import javax.usb.UsbInterfacePolicy; -import javax.usb.UsbIrp; -import javax.usb.UsbNotActiveException; -import javax.usb.UsbNotOpenException; -import javax.usb.UsbPipe; -import javax.usb.event.UsbPipeDataEvent; -import javax.usb.event.UsbPipeErrorEvent; -import javax.usb.event.UsbPipeListener; import org.apache.commons.io.EndianUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.usb4java.Device; +import org.usb4java.DeviceDescriptor; +import org.usb4java.DeviceHandle; import org.usb4java.LibUsb; +import org.usb4java.LibUsbException; +import org.usb4java.Transfer; +import org.usb4java.TransferCallback; import sample.Listener; import source.SourceException; import source.tuner.TunerConfiguration; import source.tuner.TunerController; import source.tuner.rtl.ByteSampleAdapter; -import source.tuner.usb.USBTunerDevice; public class HackRFTunerController extends TunerController { private final static Logger mLog = LoggerFactory.getLogger( HackRFTunerController.class ); + public final static long TIMEOUT_US = 1000000l; //uSeconds public static final byte USB_ENDPOINT = (byte)0x81; public static final byte USB_INTERFACE = (byte)0x0; - public static final boolean USB_FORCE_CLAIM_INTERFACE = true; public static final byte REQUEST_TYPE_IN = (byte)( LibUsb.ENDPOINT_IN | @@ -65,10 +55,10 @@ public class HackRFTunerController extends TunerController public static final long MAX_FREQUENCY = 6000000000l; public static final long DEFAULT_FREQUENCY = 101100000; - public final static int USB_IRP_POOL_SIZE = 10; + public final static int TRANSFER_BUFFER_POOL_SIZE = 16; - private LinkedTransferQueue mReceivedBuffers = - new LinkedTransferQueue(); + private LinkedTransferQueue mFilledBuffers = + new LinkedTransferQueue(); private CopyOnWriteArrayList> mSampleListeners = new CopyOnWriteArrayList>(); @@ -76,63 +66,42 @@ public class HackRFTunerController extends TunerController private ByteSampleAdapter mSampleAdapter = new ByteSampleAdapter(); private BufferProcessor mBufferProcessor = new BufferProcessor(); - private UsbDevice mUSBDevice; - private UsbInterface mUSBInterface; - private UsbPipe mUSBPipe; + private HackRFSampleRate mSampleRate = HackRFSampleRate.RATE2_016MHZ; + public int mBufferSize = 262144; + private boolean mAmplifierEnabled = false; - private HackRFSampleRate mSampleRate = HackRFSampleRate.RATE4_464MHZ; - public int mBufferSize = mSampleRate.getBufferSize(); + private Device mDevice; + private DeviceDescriptor mDeviceDescriptor; + private DeviceHandle mDeviceHandle; - public HackRFTunerController( USBTunerDevice tunerDevice ) + public HackRFTunerController( Device device, DeviceDescriptor descriptor ) throws SourceException { super( MIN_FREQUENCY, MAX_FREQUENCY ); - - mUSBDevice = tunerDevice.getDevice(); + + mDevice = device; + mDeviceDescriptor = descriptor; } public void init() throws SourceException { - mLog.info( "HackRF Tuner Controller init() starting" ); - - UsbConfiguration config = mUSBDevice.getActiveUsbConfiguration(); + mDeviceHandle = new DeviceHandle(); + + LibUsb.open( mDevice, mDeviceHandle ); - mUSBInterface = config.getUsbInterface( USB_INTERFACE ); - try { - if( claim( mUSBInterface ) ) - { - /* Get the USB endpoint */ - UsbEndpoint endpoint = mUSBInterface.getUsbEndpoint( USB_ENDPOINT ); - - UsbEndpointDescriptor d = endpoint.getUsbEndpointDescriptor(); - System.out.println( "Endpoint max packet size:" + d.wMaxPacketSize() ); - - mUSBPipe = endpoint.getUsbPipe(); - - setMode( Mode.RECEIVE ); - - setFrequency( DEFAULT_FREQUENCY ); - } - else - { - throw new SourceException( "HackRF Tuner Controller - couldn't " - + "claim USB interface" ); - } + claimInterface(); + + setMode( Mode.RECEIVE ); + + setFrequency( DEFAULT_FREQUENCY ); } - catch( UsbException e ) + catch( Exception e ) { throw new SourceException( "HackRF Tuner Controller - couldn't " + "claim USB interface or get endpoint or pipe", e ); } - catch ( UsbDisconnectedException e ) - { - throw new SourceException( "HackRF Tuner Controller - usb device " - + "is disconnected", e ); - } - - mLog.info( "HackRF Tuner Controller init() complete" ); } /** @@ -141,29 +110,39 @@ public class HackRFTunerController extends TunerController * will dictate if the interface is forcibly claimed from the other * application */ - public static boolean claim( UsbInterface iface ) throws UsbException, - UsbClaimException + private void claimInterface() throws SourceException { - if( !iface.isClaimed() ) + if( mDeviceHandle != null ) { - iface.claim( new UsbInterfacePolicy() + int result = LibUsb.kernelDriverActive( mDeviceHandle, USB_INTERFACE ); + + if( result == 1 ) { - @Override - public boolean forceClaim( UsbInterface arg0 ) - { - return USB_FORCE_CLAIM_INTERFACE; - } - } ); + result = LibUsb.detachKernelDriver( mDeviceHandle, USB_INTERFACE ); + + if( result != LibUsb.SUCCESS ) + { + mLog.error( "failed attempt to detach kernel driver [" + + LibUsb.errorName( result ) + "]" ); + + throw new SourceException( "couldn't detach kernel driver " + + "from device" ); + } + } - return iface.isClaimed(); + result = LibUsb.claimInterface( mDeviceHandle, USB_INTERFACE ); + + if( result != LibUsb.SUCCESS ) + { + throw new SourceException( "couldn't claim usb interface [" + + LibUsb.errorName( result ) + "]" ); + } } else { - mLog.error( "attempt to claim USB interface failed - in use by " - + "another application" ); + throw new SourceException( "couldn't claim usb interface - no " + + "device handle" ); } - - return false; } /** @@ -181,19 +160,13 @@ public class HackRFTunerController extends TunerController */ public String getFirmwareVersion() throws UsbException { - byte[] data = readArray( Request.VERSION_STRING_READ, 0, 0, 255 ); + ByteBuffer buffer = readArray( Request.VERSION_STRING_READ, 0, 0, 255 ); + + byte[] data = new byte[ 255 ]; - StringBuilder sb = new StringBuilder(); - - for( byte b: data ) - { - if( b != (byte)0 ) - { - sb.append( (char)b ); - } - } - - return sb.toString(); + buffer.get( data ); + + return new String( data ); } /** @@ -201,9 +174,9 @@ public class HackRFTunerController extends TunerController */ public Serial getSerial() throws UsbException { - byte[] data = readArray( Request.BOARD_PARTID_SERIALNO_READ, 0, 0, 24 ); + ByteBuffer buffer = readArray( Request.BOARD_PARTID_SERIALNO_READ, 0, 0, 24 ); - return new Serial( data ); + return new Serial( buffer ); } /** @@ -230,6 +203,13 @@ public class HackRFTunerController extends TunerController public void setAmplifierEnabled( boolean enabled ) throws UsbException { write( Request.AMP_ENABLE, ( enabled ? 1 : 0 ), 0 ); + + mAmplifierEnabled = enabled; + } + + public boolean getAmplifier() + { + return mAmplifierEnabled; } /** @@ -269,17 +249,20 @@ public class HackRFTunerController extends TunerController @Override public void setTunedFrequency( long frequency ) throws SourceException { + ByteBuffer buffer = ByteBuffer.allocateDirect( 8 ); + buffer.order( ByteOrder.LITTLE_ENDIAN ); + int mhz = (int)( frequency / 1E6 ); int hz = (int)( frequency - ( mhz * 1E6 ) ); - - byte[] data = new byte[ 8 ]; - - EndianUtils.writeSwappedInteger( data, 0, mhz ); - EndianUtils.writeSwappedInteger( data, 4, hz ); + + buffer.putInt( mhz ); + buffer.putInt( hz ); + + buffer.rewind(); try { - write( Request.SET_FREQUENCY, 0, 0, data ); + write( Request.SET_FREQUENCY, 0, 0, buffer ); } catch( UsbException e ) { @@ -288,7 +271,6 @@ public class HackRFTunerController extends TunerController throw new SourceException( "error setting frequency [" + frequency + "]", e ); } - } @Override @@ -302,15 +284,15 @@ public class HackRFTunerController extends TunerController { if( config instanceof HackRFTunerConfiguration ) { - HackRFTunerConfiguration hackConfig = + HackRFTunerConfiguration hackRFConfig = (HackRFTunerConfiguration)config; try { - setSampleRate( hackConfig.getSampleRate() ); - setFrequencyCorrection( hackConfig.getFrequencyCorrection() ); - setLNAGain( hackConfig.getLNAGain() ); - setVGAGain( hackConfig.getVGAGain() ); + setSampleRate( hackRFConfig.getSampleRate() ); + setFrequencyCorrection( hackRFConfig.getFrequencyCorrection() ); + setLNAGain( hackRFConfig.getLNAGain() ); + setVGAGain( hackRFConfig.getVGAGain() ); setFrequency( getFrequency() ); } catch ( UsbException e ) @@ -326,21 +308,35 @@ public class HackRFTunerController extends TunerController } } - public byte[] readArray( Request request, + public ByteBuffer readArray( Request request, int value, int index, int length ) throws UsbException { - UsbControlIrp irp = mUSBDevice.createUsbControlIrp( REQUEST_TYPE_IN, - request.getRequestNumber(), (short)value, (short)index ); + if( mDeviceHandle != null ) + { + ByteBuffer buffer = ByteBuffer.allocateDirect( length ); + + int transferred = LibUsb.controlTransfer( mDeviceHandle, + REQUEST_TYPE_IN, + request.getRequestNumber(), + (short)value, + (short)index, + buffer, + TIMEOUT_US ); - byte[] data = new byte[ length ]; - - irp.setData( data ); - - mUSBDevice.syncSubmit( irp ); - - return data; + if( transferred < 0 ) + { + throw new LibUsbException( "read error", transferred ); + } + + return buffer; + } + else + { + throw new LibUsbException( "device handle is null", + LibUsb.ERROR_NO_DEVICE ); + } } public int read( Request request, int value, int index, int length ) @@ -349,10 +345,14 @@ public class HackRFTunerController extends TunerController if( !( length == 1 || length == 2 || length == 4 ) ) { throw new IllegalArgumentException( "invalid length [" + length + - "] must be: byte=1, short=2, int=3 to read a primitive" ); + "] must be: byte=1, short=2, int=4 to read a primitive" ); } - byte[] data = readArray( request, value, index, length ); + ByteBuffer buffer = readArray( request, value, index, length ); + + byte[] data = new byte[ buffer.capacity() ]; + + buffer.get( data ); switch( data.length ) { @@ -371,29 +371,50 @@ public class HackRFTunerController extends TunerController public int readByte( Request request, int value, int index, boolean signed ) throws UsbException { - byte[] data = readArray( request, value, index, 1 ); + ByteBuffer buffer = readArray( request, value, index, 1 ); if( signed ) { - return (int)( data[ 0 ] ); + return (int)( buffer.get() ); } else { - return (int)( data[ 0 ] & 0xFF ); + return (int)( buffer.get() & 0xFF ); } } public void write( Request request, int value, int index, - byte[] data ) throws UsbException + ByteBuffer buffer ) throws UsbException { - UsbControlIrp irp = mUSBDevice.createUsbControlIrp( REQUEST_TYPE_OUT, - request.getRequestNumber(), (short)value, (short)index ); + if( mDeviceHandle != null ) + { + int transferred = LibUsb.controlTransfer( mDeviceHandle, + REQUEST_TYPE_OUT, + request.getRequestNumber(), + (short)value, + (short)index, + buffer, + TIMEOUT_US ); - irp.setData( data ); - - mUSBDevice.syncSubmit( irp ); + if( transferred < 0 ) + { + throw new LibUsbException( "error writing byte buffer", + transferred ); + } + else if( transferred != buffer.capacity() ) + { + throw new LibUsbException( "transferred bytes [" + + transferred + "] is not what was expected [" + + buffer.capacity() + "]", transferred ); + } + } + else + { + throw new LibUsbException( "device handle is null", + LibUsb.ERROR_NO_DEVICE ); + } } /** @@ -403,64 +424,22 @@ public class HackRFTunerController extends TunerController int value, int index ) throws UsbException { - write( request, value, index, new byte[ 0 ] ); + write( request, value, index, ByteBuffer.allocateDirect( 0 ) ); } /** * Sample Rate * - * Note: this is direct translation of the libhackrf code, because I still - * can't figure out how it works ... one day, maybe. + * Note: the libhackrf set sample rate method is designed to allow fractional + * sample rates. However, since we're only using integral sample rates, we + * simply invoke the setSampleRateManual method directly. */ public void setSampleRate( HackRFSampleRate rate ) throws UsbException { -// int MAX_N = 32; -// -// double freq = (double)rate.getRate() / 1E6d; -// -// double freq_frac = 1.0d + freq - (int)freq; -// -// long u64 = Double.doubleToLongBits( freq ); -// -// int e = (int)( ( u64 >> 52 ) - 1023 ); -// -// long m = (long)( 1l << 52 ) - 1l; -// -// u64 = Double.doubleToLongBits( freq_frac ); -// -// u64 &= m; -// -// m &= ~( ( 1 << ( e + 4 ) ) - 1 ); -// -// long a = 0; -// -// int x; -// -// for( x = 1; x < MAX_N; x++ ) -// { -// a += u64; -// -// if( ( ( a & m ) == 0 ) || ( ( ~a & m ) == 0 ) ) -// { -// break; -// } -// } -// -// if( x == MAX_N ) -// { -// x = 1; -// } -// -// int freq_hz = (int)( freq * (double)x * 0.5d ); -// -// setSampleRateManual( freq_hz, x ); - setSampleRateManual( rate.getRate(), 1 ); mFrequencyController.setSampleRate( rate.getRate() ); - mBufferSize = rate.getBufferSize(); - setBasebandFilter( rate.getFilter() ); mSampleRate = rate; @@ -469,12 +448,14 @@ public class HackRFTunerController extends TunerController public void setSampleRateManual( int frequency, int divider ) throws UsbException { - byte[] data = new byte[ 8 ]; - - EndianUtils.writeSwappedInteger( data, 0, frequency ); - EndianUtils.writeSwappedInteger( data, 4, divider ); + ByteBuffer buffer = ByteBuffer.allocateDirect( 8 ); - write( Request.SET_SAMPLE_RATE, 0, 0, data ); + buffer.order( ByteOrder.LITTLE_ENDIAN ); + + buffer.putInt( frequency ); + buffer.putInt( divider ); + + write( Request.SET_SAMPLE_RATE, 0, 0, buffer ); } public int getSampleRate() @@ -522,29 +503,26 @@ public class HackRFTunerController extends TunerController public enum HackRFSampleRate { - RATE2_016MHZ( 2016000, 65536, "2.016 MHz", BasebandFilter.F2_50 ), - RATE3_024MHZ( 3024000, 98304, "3.024 MHz", BasebandFilter.F3_50 ), - RATE4_464MHZ( 4464000, 131072, "4.464 MHz", BasebandFilter.F5_00 ), - RATE5_472MHZ( 5472000, 196608, "5.472 MHz", BasebandFilter.F6_00 ), - RATE7_488MHZ( 7488000, 262144, "7.488 MHz", BasebandFilter.F8_00 ), - RATE10_032MHZ( 9984000, 131072, " 9.984 MHz", BasebandFilter.F10_00 ), - RATE12_000MHZ( 12000000, 262144, "12.000 MHz", BasebandFilter.F12_00 ), - RATE13_488MHZ( 13488000, 262144, "13.488 MHz", BasebandFilter.F14_00 ), - RATE14_976MHZ( 14976000, 262144, "14.976 MHz", BasebandFilter.F15_00 ), - RATE19_968MHZ( 19968000, 262144, "19.968 MHz", BasebandFilter.F20_00 ); + RATE2_016MHZ( 2016000, "2.016 MHz", BasebandFilter.F3_50 ), + RATE3_024MHZ( 3024000, "3.024 MHz", BasebandFilter.F5_00 ), + RATE4_464MHZ( 4464000, "4.464 MHz", BasebandFilter.F6_00 ), + RATE5_472MHZ( 5472000, "5.472 MHz", BasebandFilter.F7_00 ), + RATE7_488MHZ( 7488000, "7.488 MHz", BasebandFilter.F9_00 ), + RATE10_032MHZ( 9984000, " 9.984 MHz", BasebandFilter.F12_00 ), + RATE12_000MHZ( 12000000, "12.000 MHz", BasebandFilter.F14_00 ), + RATE13_488MHZ( 13488000, "13.488 MHz", BasebandFilter.F15_00 ), + RATE14_976MHZ( 14976000, "14.976 MHz", BasebandFilter.F20_00 ), + RATE19_968MHZ( 19968000, "19.968 MHz", BasebandFilter.F24_00 ); private int mRate; - private int mBufferSize; private String mLabel; private BasebandFilter mFilter; private HackRFSampleRate( int rate, - int bufferSize, String label, BasebandFilter filter ) { mRate = rate; - mBufferSize = bufferSize; mLabel = label; mFilter = filter; } @@ -554,11 +532,6 @@ public class HackRFTunerController extends TunerController return mRate; } - public int getBufferSize() - { - return mBufferSize; - } - public String getLabel() { return mLabel; @@ -577,6 +550,7 @@ public class HackRFTunerController extends TunerController public enum BasebandFilter { + FAUTO( 0, "AUTO" ), F1_75( 1750000, "1.75 MHz" ), F2_50( 2500000, "2.50 MHz" ), F3_50( 3500000, "3.50 MHz" ), @@ -793,9 +767,11 @@ public class HackRFTunerController extends TunerController { private byte[] mData; - public Serial( byte[] data ) + public Serial( ByteBuffer buffer ) { - mData = data; + mData = new byte[ buffer.capacity() ]; + + buffer.get( mData ); } public String getPartID() @@ -841,8 +817,16 @@ public class HackRFTunerController extends TunerController { mSampleListeners.add( listener ); - System.out.println( "HackRF - listener added - count:" + mSampleListeners.size() ); - mBufferProcessor.start(); + if( mBufferProcessor == null || !mBufferProcessor.isRunning() ) + { + mBufferProcessor = new BufferProcessor(); + + Thread thread = new Thread( mBufferProcessor ); + thread.setDaemon( true ); + thread.setName( "Sample Processor" ); + + thread.start(); + } } /** @@ -889,93 +873,72 @@ public class HackRFTunerController extends TunerController } /** - * Buffer processing thread. Fetches samples from the RTL2832 Tuner and + * Buffer processing thread. Fetches samples from the HackRF Tuner and * dispatches them to all registered listeners */ - public class BufferProcessor implements UsbPipeListener + public class BufferProcessor implements Runnable, TransferCallback { private ScheduledExecutorService mExecutor = - Executors.newScheduledThreadPool( 2 ); + Executors.newScheduledThreadPool( 1 ); private ScheduledFuture mSampleDispatcherTask; -// private ScheduledFuture mSampleRateCounterTask; - + private ArrayList mTransfers; private AtomicBoolean mRunning = new AtomicBoolean(); - private AtomicBoolean mResetting = new AtomicBoolean(); - private Boolean mTransitioning = false; - public void start() + @Override + public void run() { - synchronized( mTransitioning ) + if( mRunning.compareAndSet( false, true ) ) { - if( mRunning.compareAndSet( false, true ) ) + mLog.debug( "starting sample fetch thread" ); + + prepareTransfers(); + + for( Transfer transfer: mTransfers ) { - mLog.debug( "HackRF - starting sample fetch thread" ); - - ArrayList irps = new ArrayList(); + int result = LibUsb.submitTransfer( transfer ); - for( int x = 0; x < USB_IRP_POOL_SIZE; x++ ) + if( result != LibUsb.SUCCESS ) { - UsbIrp irp = mUSBPipe.createUsbIrp(); - irp.setData( new byte[ mBufferSize ] ); - irps.add( irp ); + mLog.error( "error submitting transfer [" + + LibUsb.errorName( result ) + "]" ); + break; } - - try - { - if( mUSBPipe.isActive() ) - { - if( !mUSBPipe.isOpen() ) - { - mUSBPipe.open(); - - mUSBPipe.addUsbPipeListener( this ); - } - - if( mUSBPipe.isOpen() ) - { - mSampleDispatcherTask = mExecutor - .scheduleAtFixedRate( new BufferDispatcher(), - 0, 20, TimeUnit.MILLISECONDS ); - -// mSampleRateMonitor = -// new SampleRateMonitor( mSampleRate.getRate() ); - -// mSampleRateCounterTask = mExecutor -// .scheduleAtFixedRate( mSampleRateMonitor, -// 10, 10, TimeUnit.SECONDS ); - - mUSBPipe.asyncSubmit( irps ); - } - } - } - catch ( Exception e ) - { - mLog.error( "Error in buffer processor thread", e ); - } } - } - } + + mSampleDispatcherTask = mExecutor + .scheduleAtFixedRate( new BufferDispatcher(), + 0, 20, TimeUnit.MILLISECONDS ); + + while( mRunning.get() ) + { + ByteBuffer completed = ByteBuffer.allocateDirect( 4 ); + + int result = LibUsb.handleEventsTimeoutCompleted( + null, TIMEOUT_US, completed.asIntBuffer() ); + + if( result != LibUsb.SUCCESS ) + { + mLog.error( "error handling events for libusb" ); + } + } + } + } /** * Stops the sample fetching thread */ public void stop() { - synchronized( mTransitioning ) + if( mRunning.compareAndSet( true, false ) ) { - if( mRunning.compareAndSet( true, false ) ) - { - mLog.debug( "HackRF - stopping sample fetch thread" ); + mLog.debug( "stopping sample fetch thread" ); - mUSBPipe.abortAllSubmissions(); - - if( mSampleDispatcherTask != null ) - { - mSampleDispatcherTask.cancel( true ); -// mSampleRateCounterTask.cancel( true ); -// mRawSampleBuffer.clear(); -// mSampleCounter.set( 0 ); - } + cancel(); + + if( mSampleDispatcherTask != null ) + { + mSampleDispatcherTask.cancel( true ); + mFilledBuffers.clear(); } } } @@ -987,85 +950,150 @@ public class HackRFTunerController extends TunerController { return mRunning.get(); } - - /** - * Receives filled data buffers and places them in the queue for the - * BufferDispatcher to process - */ + @Override - public synchronized void dataEventOccurred( UsbPipeDataEvent event ) - { - mReceivedBuffers.add( event.getUsbIrp() ); - } - - @Override - public void errorEventOccurred( UsbPipeErrorEvent e ) - { - /* When an error occurs, we'll get errors on all of the - * queued IRPS in succession. We use the mResetting to control - * the reset process and ignore all subsequent errors */ - if( mResetting.compareAndSet( false, true ) ) + public void processTransfer( Transfer transfer ) + { + if( transfer.status() == LibUsb.TRANSFER_COMPLETED ) { - mLog.error( "error during data transfer resetting USB pipe to " - + "HackRF", e ); + ByteBuffer buffer = transfer.buffer(); - stop(); - - if( !mSampleListeners.isEmpty() ) - { - start(); - } + byte[] data = new byte[ transfer.actualLength() ]; + + buffer.get( data ); - mResetting.set( false ); + buffer.rewind(); + + mFilledBuffers.add( data ); + + if( !isRunning() ) + { + LibUsb.cancelTransfer( transfer ); + } } - } + + switch( transfer.status() ) + { + case LibUsb.TRANSFER_COMPLETED: + /* resubmit the transfer */ + int result = LibUsb.submitTransfer( transfer ); + + if( result != LibUsb.SUCCESS ) + { + mLog.error( "couldn't resubmit buffer transfer to tuner" ); + LibUsb.freeTransfer( transfer ); + mTransfers.remove( transfer ); + } + break; + case LibUsb.TRANSFER_CANCELLED: + /* free the transfer and remove it */ + LibUsb.freeTransfer( transfer ); + mTransfers.remove( transfer ); + break; + default: + /* unexpected error */ + mLog.error( "transfer error [" + + getTransferStatus( transfer.status() ) + + "] transferred actual: " + transfer.actualLength() ); + } + } + + private void cancel() + { + for( Transfer transfer: mTransfers ) + { + LibUsb.cancelTransfer( transfer ); + } + + ByteBuffer completed = ByteBuffer.allocateDirect( 4 ); + + int result = LibUsb.handleEventsTimeoutCompleted( + null, TIMEOUT_US, completed.asIntBuffer() ); + + if( result != LibUsb.SUCCESS ) + { + mLog.error( "error handling usb events during cancel [" + + LibUsb.errorName( result ) + "]" ); + } + } + + /** + * Prepares (allocates) a set of transfer buffers for use in + * transferring data from the tuner via the bulk interface + */ + private void prepareTransfers() throws LibUsbException + { + mTransfers = new ArrayList(); + + for( int x = 0; x < TRANSFER_BUFFER_POOL_SIZE; x++ ) + { + Transfer transfer = LibUsb.allocTransfer(); + + if( transfer == null ) + { + throw new LibUsbException( "couldn't allocate transfer", + LibUsb.ERROR_NO_MEM ); + } + + final ByteBuffer buffer = + ByteBuffer.allocateDirect( mBufferSize ); + + LibUsb.fillBulkTransfer( transfer, + mDeviceHandle, + USB_ENDPOINT, + buffer, + BufferProcessor.this, + "Buffer #" + x, + TIMEOUT_US ); + + mTransfers.add( transfer ); + } + } } /** - * Fetches received UsbIrp buffers from the received queue, dispatches them - * and resubmits the processed buffer for more samples + * Fetches byte[] chunks from the raw sample buffer. Converts each byte + * array and broadcasts the array to all registered listeners */ public class BufferDispatcher implements Runnable { @Override public void run() { - ArrayList buffers = new ArrayList(); + ArrayList buffers = new ArrayList(); - mReceivedBuffers.drainTo( buffers ); - - for( UsbIrp buffer: buffers ) + mFilledBuffers.drainTo( buffers ); + + for( byte[] buffer: buffers ) { - Float[] samples = mSampleAdapter.convert( buffer.getData() ); + //TODO: convert this to float primitive + Float[] samples = mSampleAdapter.convert( buffer ); broadcast( samples ); - - if( mBufferProcessor != null && mBufferProcessor.isRunning() ) - { - try - { - /* We adjust the buffer size according to sample rate. - * If this byte array matches the current buffer size - * then we reuse the byte array, otherwise create a - * new one. */ - if( buffer.getData().length == mBufferSize ) - { - mUSBPipe.asyncSubmit( buffer.getData() ); - } - else - { - mUSBPipe.asyncSubmit( new byte[ mBufferSize ] ); - } - } - catch ( UsbNotActiveException | UsbNotOpenException - | IllegalArgumentException | UsbDisconnectedException - | UsbException e ) - { - mLog.error( "error submitting a byte array to the usb " - + "pipe for samples", e ); - } - } } } } + + public static String getTransferStatus( int status ) + { + switch( status ) + { + case 0: + return "TRANSFER COMPLETED (0)"; + case 1: + return "TRANSFER ERROR (1)"; + case 2: + return "TRANSFER TIMED OUT (2)"; + case 3: + return "TRANSFER CANCELLED (3)"; + case 4: + return "TRANSFER STALL (4)"; + case 5: + return "TRANSFER NO DEVICE (5)"; + case 6: + return "TRANSFER OVERFLOW (6)"; + default: + return "UNKNOWN TRANSFER STATUS (" + status + ")"; + } + } } diff --git a/src/source/tuner/rtl/RTL2832Tuner.java b/src/source/tuner/rtl/RTL2832Tuner.java index a72a0312..0e70a26b 100644 --- a/src/source/tuner/rtl/RTL2832Tuner.java +++ b/src/source/tuner/rtl/RTL2832Tuner.java @@ -20,10 +20,10 @@ package source.tuner.rtl; import java.util.concurrent.RejectedExecutionException; import javax.swing.JPanel; -import javax.usb.UsbException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.usb4java.LibUsbException; import sample.Listener; import source.SourceException; @@ -59,6 +59,11 @@ public class RTL2832Tuner extends Tuner mController.addListener( (FrequencyChangeListener)this ); } + public void dispose() + { + //TODO: dispose of something here + } + public RTL2832TunerController getController() { return mController; @@ -115,7 +120,7 @@ public class RTL2832Tuner extends Tuner { mController.setSampleRate( sampleRate ); } - catch( UsbException e ) + catch( LibUsbException e ) { throw new SourceException( "RTL2832 Tuner - error setting " + "sample rate", e ); @@ -139,7 +144,18 @@ public class RTL2832Tuner extends Tuner throws RejectedExecutionException, SourceException { - return mController.getChannel( threadPoolManager, this, channel ); + TunerChannelSource source = null; + + try + { + source = mController.getChannel( threadPoolManager, this, channel ); + } + catch( Exception e ) + { + mLog.error( "couldn't provide source channel", e ); + } + + return source; } /** * Releases the tuned channel so that the tuner controller can tune to diff --git a/src/source/tuner/rtl/RTL2832TunerController.java b/src/source/tuner/rtl/RTL2832TunerController.java index 0ea89eb1..51eee6cd 100644 --- a/src/source/tuner/rtl/RTL2832TunerController.java +++ b/src/source/tuner/rtl/RTL2832TunerController.java @@ -21,6 +21,8 @@ ******************************************************************************/ package source.tuner.rtl; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.nio.charset.Charset; import java.text.DecimalFormat; import java.util.ArrayList; @@ -36,27 +38,18 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import javax.swing.JPanel; -import javax.usb.UsbClaimException; -import javax.usb.UsbConfiguration; -import javax.usb.UsbControlIrp; -import javax.usb.UsbDevice; import javax.usb.UsbDisconnectedException; -import javax.usb.UsbEndpoint; import javax.usb.UsbException; -import javax.usb.UsbInterface; -import javax.usb.UsbInterfacePolicy; -import javax.usb.UsbIrp; -import javax.usb.UsbNotActiveException; -import javax.usb.UsbNotOpenException; -import javax.usb.UsbPipe; -import javax.usb.event.UsbPipeDataEvent; -import javax.usb.event.UsbPipeErrorEvent; -import javax.usb.event.UsbPipeListener; -import javax.usb.util.DefaultUsbControlIrp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.usb4java.Device; +import org.usb4java.DeviceDescriptor; +import org.usb4java.DeviceHandle; import org.usb4java.LibUsb; +import org.usb4java.LibUsbException; +import org.usb4java.Transfer; +import org.usb4java.TransferCallback; import sample.Listener; import source.SourceException; @@ -64,7 +57,6 @@ import source.tuner.FrequencyChangeEvent; import source.tuner.FrequencyChangeEvent.Attribute; import source.tuner.TunerController; import source.tuner.TunerType; -import source.tuner.usb.USBTunerDevice; import util.TimeStamp; import buffer.FloatAveragingBuffer; import controller.ResourceManager; @@ -74,60 +66,26 @@ public abstract class RTL2832TunerController extends TunerController private final static Logger mLog = LoggerFactory.getLogger( RTL2832TunerController.class ); - public final static int sINT_NULL_VALUE = -1; - public final static long sLONG_NULL_VALUE = -1l; - public final static double sDOUBLE_NULL_VALUE = -1.0D; + public final static int INT_NULL_VALUE = -1; + public final static long LONG_NULL_VALUE = -1l; + public final static double DOUBLE_NULL_VALUE = -1.0D; + public final static int TWO_TO_22_POWER = 4194304; - public final static byte sUSB_INTERFACE = (byte)0x0; - public final static byte sUSB_ENDPOINT = (byte)0x81; - public final static boolean sUSB_FORCE_CLAIM_INTERFACE = true; - - public final static byte sREQUEST_TYPE_IN = + public final static byte USB_INTERFACE = (byte)0x0; + public final static byte BULK_ENDPOINT_IN = (byte)0x81; + public final static byte CONTROL_ENDPOINT_IN = (byte)( LibUsb.ENDPOINT_IN | LibUsb.REQUEST_TYPE_VENDOR ); - public final static byte sREQUEST_TYPE_OUT = + public final static byte CONTROL_ENDPOINT_OUT = (byte)( LibUsb.ENDPOINT_OUT | LibUsb.REQUEST_TYPE_VENDOR ); - public final static byte sREQUEST_ZERO = (byte)0; + + public final static long TIMEOUT_US = 1000000l; //uSeconds + + public final static byte REQUEST_ZERO = (byte)0; - public final static int sUSB_IRP_POOL_SIZE = 10; + public final static int TRANSFER_BUFFER_POOL_SIZE = 16; public final static byte EEPROM_ADDRESS = (byte)0xA0; - public final static byte BIT_0 = (byte)0x01; - public final static byte BIT_1 = (byte)0x02; - public final static byte BIT_2 = (byte)0x04; - public final static byte BIT_3 = (byte)0x08; - public final static byte BIT_4 = (byte)0x10; - public final static byte BIT_5 = (byte)0x20; - public final static byte BIT_6 = (byte)0x40; - public final static byte BIT_7 = (byte)0x80; - - public final static byte E4K_I2C_ADDRESS = (byte)0xC8; - public final static byte E4K_CHECK_ADDRESS = (byte)0x02; - public final static byte E4K_CHECK_VALUE = (byte)0x40; - - public final static byte FC0012_I2C_ADDRESS = (byte)0xC6; - public final static byte FC0012_CHECK_ADDRESS = (byte)0x00; - public final static byte FC0012_CHECK_VALUE = (byte)0xA1; - - public final static byte FC0013_I2C_ADDRESS = (byte)0xC6; - public final static byte FC0013_CHECK_ADDRESS = (byte)0x00; - public final static byte FC0013_CHECK_VALUE = (byte)0xA3; - - public final static byte FC2580_I2C_ADDRESS = (byte)0xAC; - public final static byte FC2580_CHECK_ADDRESS = (byte)0x01; - public final static byte FC2580_CHECK_VALUE = (byte)0x56; - - public final static byte R820T_I2C_ADDRESS = (byte)0x34; - public final static byte R820T_CHECK_ADDRESS = (byte)0x00; - public final static byte R820T_CHECK_VALUE = (byte)0x69; - - public final static byte R828D_I2C_ADDRESS = (byte)0x74; - public final static byte R828D_CHECK_ADDRESS = (byte)0x00; - public final static byte R828D_CHECK_VALUE = (byte)0x69; - - public static final int sMIN_OSCILLATOR_FREQUENCY = 28799000; - public static final int sMAX_OSCILLATOR_FREQUENCY = 28801000; - public final static byte[] sFIR_COEFFICIENTS = { (byte)0xCA, (byte)0xDC, (byte)0xD7, (byte)0xD8, (byte)0xE0, @@ -136,22 +94,14 @@ public abstract class RTL2832TunerController extends TunerController (byte)0x71, (byte)0x74, (byte)0x19, (byte)0x41, (byte)0xA5 }; - private static final DecimalFormat mDecimalFormatter = - new DecimalFormat( "###,###,###.0" ); - private static final DecimalFormat mPercentFormatter = - new DecimalFormat( "###.00" ); - - private USBTunerDevice mUSBTunerDevice; - protected UsbDevice mUSBDevice; - private UsbConfiguration mUSBConfiguration; - protected UsbInterface mUSBInterface; - private UsbPipe mUSBPipe; - private Descriptor mDescriptor; + public static final SampleRate DEFAULT_SAMPLE_RATE = + SampleRate.RATE_0_960MHZ; - public static final int sTWO_TO_22_POWER = 4194304; - public static final SampleRate sDEFAULT_SAMPLE_RATE = SampleRate.RATE_0_960MHZ; + protected Device mDevice; + protected DeviceDescriptor mDeviceDescriptor; + protected DeviceHandle mDeviceHandle; - private SampleRate mSampleRate = sDEFAULT_SAMPLE_RATE; + private SampleRate mSampleRate = DEFAULT_SAMPLE_RATE; private BufferProcessor mBufferProcessor = new BufferProcessor(); @@ -160,64 +110,58 @@ public abstract class RTL2832TunerController extends TunerController private CopyOnWriteArrayList> mSampleListeners = new CopyOnWriteArrayList>(); - private LinkedTransferQueue mRawSampleBuffer = + private LinkedTransferQueue mFilledBuffers = new LinkedTransferQueue(); - private AtomicInteger mSampleCounter = new AtomicInteger(); - private double mSampleRateAverageSum; - private int mSampleRateAverageCount; - protected int mOscillatorFrequency = 28800000; //28.8 MHz - + private SampleRateMonitor mSampleRateMonitor; - public int mBufferSize = 16384; + private AtomicInteger mSampleCounter = new AtomicInteger(); + private double mSampleRateAverageSum; + private int mSampleRateAverageCount; + private static final DecimalFormat mDecimalFormatter = + new DecimalFormat( "###,###,###.0" ); + private static final DecimalFormat mPercentFormatter = + new DecimalFormat( "###.00" ); + + protected int mOscillatorFrequency = 28800000; //28.8 MHz + public int mBufferSize = 131072; + + protected Descriptor mDescriptor; /** * Abstract tuner controller device. Use the static getTunerClass() method * to determine the tuner type, and construct the corresponding child * tuner controller class for that tuner type. */ - public RTL2832TunerController( USBTunerDevice tunerDevice, + public RTL2832TunerController( Device device, + DeviceDescriptor deviceDescriptor, long minTunableFrequency, long maxTunableFrequency ) throws SourceException { super( minTunableFrequency, maxTunableFrequency ); - mUSBTunerDevice = tunerDevice; - mUSBDevice = tunerDevice.getDevice(); - mUSBConfiguration = mUSBDevice.getActiveUsbConfiguration(); - mUSBInterface = mUSBConfiguration.getUsbInterface( sUSB_INTERFACE ); - - try - { - if( claim( mUSBInterface ) ) - { - /* Get the USB endpoint */ - UsbEndpoint endpoint = mUSBInterface.getUsbEndpoint( sUSB_ENDPOINT ); - mUSBPipe = endpoint.getUsbPipe(); - } - else - { - throw new SourceException( "RTL2832 Tuner Controller - couldn't " - + "claim USB interface" ); - } - } - catch( UsbException e ) - { - throw new SourceException( "RTL2832 Tuner Controller - couldn't " - + "claim USB interface or get endpoint or pipe", e ); - } - catch ( UsbDisconnectedException e ) - { - throw new SourceException( "RTL2832 Tuner Controller - usb device " - + "is disconnected", e ); - } - + mDevice = device; + mDeviceDescriptor = deviceDescriptor; } public void init() throws SourceException { + mDeviceHandle = new DeviceHandle(); + + int result = LibUsb.open( mDevice, mDeviceHandle ); + + if( result != LibUsb.SUCCESS ) + { + mDeviceHandle = null; + + throw new SourceException( "libusb couldn't open RTL2832 usb " + + "device [" + LibUsb.errorName( result ) + "]" ); + } + + claimInterface( mDeviceHandle ); + try { - setSampleRate( sDEFAULT_SAMPLE_RATE ); + setSampleRate( DEFAULT_SAMPLE_RATE ); } catch( Exception e ) { @@ -230,7 +174,7 @@ public abstract class RTL2832TunerController extends TunerController try { /* Read the contents of the 256-byte EEPROM */ - eeprom = readEEPROM( mUSBDevice, (short)0, 256 ); + eeprom = readEEPROM( mDeviceHandle, (short)0, 256 ); } catch( Exception e ) { @@ -254,6 +198,57 @@ public abstract class RTL2832TunerController extends TunerController ( eeprom == null ? "[null]" : Arrays.toString( eeprom )), e ); } } + + /** + * Claims the USB interface. Attempts to detach the active kernel driver + * if one is currently attached. + */ + public static void claimInterface( DeviceHandle handle ) throws SourceException + { + if( handle != null ) + { + int result = LibUsb.kernelDriverActive( handle, USB_INTERFACE ); + + if( result == 1 ) + { + result = LibUsb.detachKernelDriver( handle, USB_INTERFACE ); + + if( result != LibUsb.SUCCESS ) + { + mLog.error( "failed attempt to detach kernel driver [" + + LibUsb.errorName( result ) + "]" ); + + throw new SourceException( "couldn't detach kernel driver " + + "from device" ); + } + } + + result = LibUsb.claimInterface( handle, USB_INTERFACE ); + + if( result != LibUsb.SUCCESS ) + { + throw new SourceException( "couldn't claim usb interface [" + + LibUsb.errorName( result ) + "]" ); + } + } + else + { + throw new SourceException( "couldn't claim usb interface - no " + + "device handle" ); + } + } + + public static void releaseInterface( DeviceHandle handle ) + throws SourceException + { + int result = LibUsb.releaseInterface( handle, USB_INTERFACE ); + + if( result != LibUsb.SUCCESS ) + { + throw new SourceException( "couldn't release interface [" + + LibUsb.errorName( result ) + "]" ); + } + } /** * Descriptor contains all identifiers and labels parsed from the EEPROM. @@ -272,28 +267,7 @@ public abstract class RTL2832TunerController extends TunerController return null; } -// public void start() -// { -// if( !mBufferProcessor.isRunning() ) -// { -// try -// { -// resetUSBBuffer(); -// -// /* Open the USB pipe */ -// openPipe(); -// -// mBufferProcessor.start(); -// } -// catch ( UsbException e ) -// { -// Log.error( "RTL2832TunerController - error starting sample " -// + "buffer processor - " + e.getLocalizedMessage() ); -// } -// } -// } - - public void setSamplingMode( SampleMode mode ) throws UsbException + public void setSamplingMode( SampleMode mode ) throws LibUsbException { switch( mode ) { @@ -302,56 +276,54 @@ public abstract class RTL2832TunerController extends TunerController setIFFrequency( 0 ); /* Enable I/Q ADC Input */ - writeDemodRegister( mUSBDevice, + writeDemodRegister( mDeviceHandle, Page.ZERO, (short)0x08, (short)0xCD, 1 ); /* Enable zero-IF mode */ - writeDemodRegister( mUSBDevice, + writeDemodRegister( mDeviceHandle, Page.ONE, (short)0xB1, (short)0x1B, 1 ); /* Set default i/q path */ - writeDemodRegister( mUSBDevice, + writeDemodRegister( mDeviceHandle, Page.ZERO, (short)0x06, (short)0x80, 1 ); break; case DIRECT: - //TODO: add code for direct sampling - break; default: - break; - + throw new LibUsbException( "QUADRATURE mode is the only mode " + + "currently supported", LibUsb.ERROR_NOT_SUPPORTED ); } } - public void setIFFrequency( int frequency ) throws UsbException + public void setIFFrequency( int frequency ) throws LibUsbException { - long ifFrequency = ( (long)sTWO_TO_22_POWER * (long)frequency ) / + long ifFrequency = ( (long)TWO_TO_22_POWER * (long)frequency ) / (long)mOscillatorFrequency * -1; /* Write byte 2 (high) */ - writeDemodRegister( mUSBDevice, + writeDemodRegister( mDeviceHandle, Page.ONE, (short)0x19, (short)( Long.rotateRight( ifFrequency, 16 ) & 0x3F ), 1 ); /* Write byte 1 (middle) */ - writeDemodRegister( mUSBDevice, + writeDemodRegister( mDeviceHandle, Page.ONE, (short)0x1A, (short)( Long.rotateRight( ifFrequency, 8 ) & 0xFF ), 1 ); /* Write byte 0 (low) */ - writeDemodRegister( mUSBDevice, + writeDemodRegister( mDeviceHandle, Page.ONE, (short)0x1B, (short)( ifFrequency & 0xFF ), @@ -377,7 +349,7 @@ public abstract class RTL2832TunerController extends TunerController else { int serial = - ( 0xFF & mUSBDevice.getUsbDeviceDescriptor().iSerialNumber() ); + ( 0xFF & mDeviceDescriptor.iSerialNumber() ); return "SER#" + serial; } @@ -385,74 +357,118 @@ public abstract class RTL2832TunerController extends TunerController public abstract JPanel getEditor( ResourceManager resourceManager ); - public abstract void setSampleRateFilters( int sampleRate ) throws UsbException; + public abstract void setSampleRateFilters( int sampleRate ) + throws SourceException; public abstract TunerType getTunerType(); - public static TunerType identifyTunerType( USBTunerDevice tunerDevice ) + public static TunerType identifyTunerType( Device device ) + throws SourceException { + DeviceHandle handle = new DeviceHandle(); + + int reason = LibUsb.open( device, handle ); + + if( reason != LibUsb.SUCCESS ) + { + throw new SourceException( "couldn't open device - check permissions" + + " (udev.rule) [" + LibUsb.errorName( reason ) + "]" ); + } + TunerType tunerClass = TunerType.UNKNOWN; try { - UsbDevice device = tunerDevice.getDevice(); - UsbConfiguration config = device.getActiveUsbConfiguration(); - UsbInterface iface = config.getUsbInterface( sUSB_INTERFACE ); + claimInterface( handle ); - if( claim( iface ) ) + /* Perform a dummy write to see if the device needs reset */ + boolean resetRequired = false; + + try { - mLog.debug( "usb interface claimed" ); - - /* Perform a dummy write to see if the device needs reset */ - writeRegister( device, Block.USB, Address.USB_SYSCTL.getAddress(), 0x09, 1 ); - - mLog.debug( "initializing baseband" ); - - /* Initialize the baseband */ - initBaseband( device ); - - mLog.debug( "enabling I2C repeater" ); - - enableI2CRepeater( device, true ); - - boolean controlI2CRepeater = false; - - mLog.debug( "testing for tuner types" ); - - /* Test for each tuner type until we find the correct one */ - if( isE4000Tuner( device, controlI2CRepeater ) ) - { - tunerClass = TunerType.ELONICS_E4000; - } - else if( isFC0013Tuner( device, controlI2CRepeater ) ) - { - tunerClass = TunerType.FITIPOWER_FC0013; - } - else if( isR820TTuner( device, controlI2CRepeater ) ) - { - tunerClass = TunerType.RAFAELMICRO_R820T; - } - else if( isR828DTuner( device, controlI2CRepeater ) ) - { - tunerClass = TunerType.RAFAELMICRO_R828D; - } - else if( isFC2580Tuner( device, controlI2CRepeater ) ) - { - tunerClass = TunerType.FCI_FC2580; - } - else if( isFC0012Tuner( device, controlI2CRepeater ) ) - { - tunerClass = TunerType.FITIPOWER_FC0012; - } - - mLog.debug( "disabling I2C repeater -- detected tuner type:" + tunerClass.toString() ); - - enableI2CRepeater( device, false ); - - mLog.debug( "releasing USB interface" ); - - iface.release(); + writeRegister( handle, + Block.USB, + Address.USB_SYSCTL.getAddress(), + 0x09, + 1 ); } + catch( LibUsbException e ) + { + + if( e.getErrorCode() < 0 ) + { + mLog.error( "error performing dummy write - attempting " + + "device reset", e ); + + resetRequired = true; + } + else + { + throw new SourceException( "error performing dummy write " + + "to device [" + LibUsb.errorName( + e.getErrorCode() ) + "]", e ); + } + } + + if( resetRequired ) + { + reason = LibUsb.resetDevice( handle ); + + try + { + writeRegister( handle, + Block.USB, + Address.USB_SYSCTL.getAddress(), + 0x09, + 1 ); + } + catch( LibUsbException e2 ) + { + mLog.error( "device reset attempted, but lost device handle. " + + "Try restarting the application to use this device" ); + + throw new SourceException( "couldn't reset device" ); + } + } + + /* Initialize the baseband */ + initBaseband( handle ); + + enableI2CRepeater( handle, true ); + + boolean controlI2CRepeater = false; + + /* Test for each tuner type until we find the correct one */ + if( isTuner( TunerTypeCheck.E4K, handle, controlI2CRepeater ) ) + { + tunerClass = TunerType.ELONICS_E4000; + } + else if( isTuner( TunerTypeCheck.FC0013, handle, controlI2CRepeater ) ) + { + tunerClass = TunerType.FITIPOWER_FC0013; + } + else if( isTuner( TunerTypeCheck.R820T, handle, controlI2CRepeater ) ) + { + tunerClass = TunerType.RAFAELMICRO_R820T; + } + else if( isTuner( TunerTypeCheck.R828D, handle, controlI2CRepeater ) ) + { + tunerClass = TunerType.RAFAELMICRO_R828D; + } + else if( isTuner( TunerTypeCheck.FC2580, handle, controlI2CRepeater ) ) + { + tunerClass = TunerType.FCI_FC2580; + } + else if( isTuner( TunerTypeCheck.FC0012, handle, controlI2CRepeater ) ) + { + tunerClass = TunerType.FITIPOWER_FC0012; + } + + enableI2CRepeater( handle, false ); + + releaseInterface( handle ); + + LibUsb.close( handle ); } catch( Exception e ) { @@ -462,88 +478,6 @@ public abstract class RTL2832TunerController extends TunerController return tunerClass; } - public USBTunerDevice getUSBTunerDevice() - { - return mUSBTunerDevice; - } - -// protected void openPipe() throws UsbException, UsbClaimException -// { -// /* Get the USB endpoint */ -// UsbEndpoint endpoint = mUSBInterface.getUsbEndpoint( sUSB_ENDPOINT ); -// -// /* Get the pipe from the endpoint */ -// if( endpoint != null ) -// { -// mUSBPipe = endpoint.getUsbPipe(); -// -// if( mUSBPipe != null ) -// { -// if( !mUSBPipe.isOpen() ) -// { -// try -// { -// resetUSBBuffer(); -// -// mUSBPipe.open(); -// } -// catch( Exception e ) -// { -// Log.error( "RTL2832 Tuner Controller - exception while " + -// "opening the endpoint pipe." + -// e.getLocalizedMessage() ); -// } -// } -// } -// else -// { -// Log.error( "RTL2832 Tuner Controller - returned endpoint " -// + "OUT pipe is null" ); -// } -// } -// } -// - /** - * Claims the USB interface. If another application currently has - * the interface claimed, the sFCD_FORCE_CLAIM_HID_INTERFACE setting - * will dictate if the interface is forcibly claimed from the other - * application - */ - public static boolean claim( UsbInterface iface ) throws UsbException, - UsbClaimException - { - if( !iface.isClaimed() ) - { - iface.claim( new UsbInterfacePolicy() - { - @Override - public boolean forceClaim( UsbInterface arg0 ) - { - return sUSB_FORCE_CLAIM_INTERFACE; - } - } ); - - return iface.isClaimed(); - } - else - { - mLog.error( "attempt to claim USB interface failed - in use by " - + "another application" ); - } - - return false; - } - - /** - * Releases the claimed USB interface - */ - private void closePipe() throws UsbException - { - mBufferProcessor.stop(); - - mUSBPipe.close(); - } - /** * Releases the USB interface */ @@ -556,12 +490,9 @@ public abstract class RTL2832TunerController extends TunerController mBufferProcessor.stop(); } - if( mUSBPipe.isOpen() ) - { - mUSBPipe.close(); - } - - mUSBInterface.release(); + LibUsb.releaseInterface( mDeviceHandle, USB_INTERFACE ); + + LibUsb.exit( null ); } catch ( Exception e ) { @@ -569,44 +500,43 @@ public abstract class RTL2832TunerController extends TunerController } } - public void resetUSBBuffer() throws UsbException + public void resetUSBBuffer() throws LibUsbException { - writeRegister( mUSBDevice, Block.USB, Address.USB_EPA_CTL.getAddress(), 0x1002, 2 ); - writeRegister( mUSBDevice, Block.USB, Address.USB_EPA_CTL.getAddress(), 0x0000, 2 ); + writeRegister( mDeviceHandle, Block.USB, Address.USB_EPA_CTL.getAddress(), 0x1002, 2 ); + writeRegister( mDeviceHandle, Block.USB, Address.USB_EPA_CTL.getAddress(), 0x0000, 2 ); } - public static void initBaseband( UsbDevice device ) - throws IllegalArgumentException, UsbDisconnectedException, UsbException + public static void initBaseband( DeviceHandle handle ) throws LibUsbException { /* Initialize USB */ - writeRegister( device, Block.USB, Address.USB_SYSCTL.getAddress(), 0x09, 1 ); - writeRegister( device, Block.USB, Address.USB_EPA_MAXPKT.getAddress(), 0x0002, 2 ); - writeRegister( device, Block.USB, Address.USB_EPA_CTL.getAddress(), 0x1002, 2 ); + writeRegister( handle, Block.USB, Address.USB_SYSCTL.getAddress(), 0x09, 1 ); + writeRegister( handle, Block.USB, Address.USB_EPA_MAXPKT.getAddress(), 0x0002, 2 ); + writeRegister( handle, Block.USB, Address.USB_EPA_CTL.getAddress(), 0x1002, 2 ); /* Power on demod */ - writeRegister( device, Block.SYS, Address.DEMOD_CTL_1.getAddress(), 0x22, 1 ); - writeRegister( device, Block.SYS, Address.DEMOD_CTL.getAddress(), 0xE8, 1 ); + writeRegister( handle, Block.SYS, Address.DEMOD_CTL_1.getAddress(), 0x22, 1 ); + writeRegister( handle, Block.SYS, Address.DEMOD_CTL.getAddress(), 0xE8, 1 ); /* Reset demod */ - writeDemodRegister( device, Page.ONE, (short)0x01, 0x14, 1 ); //Bit 3 = soft reset - writeDemodRegister( device, Page.ONE, (short)0x01, 0x10, 1 ); + writeDemodRegister( handle, Page.ONE, (short)0x01, 0x14, 1 ); //Bit 3 = soft reset + writeDemodRegister( handle, Page.ONE, (short)0x01, 0x10, 1 ); /* Disable spectrum inversion and adjacent channel rejection */ - writeDemodRegister( device, Page.ONE, (short)0x15, 0x00, 1 ); - writeDemodRegister( device, Page.ONE, (short)0x16, 0x0000, 2 ); + writeDemodRegister( handle, Page.ONE, (short)0x15, 0x00, 1 ); + writeDemodRegister( handle, Page.ONE, (short)0x16, 0x0000, 2 ); /* Clear DDC shift and IF frequency registers */ - writeDemodRegister( device, Page.ONE, (short)0x16, 0x00, 1 ); - writeDemodRegister( device, Page.ONE, (short)0x17, 0x00, 1 ); - writeDemodRegister( device, Page.ONE, (short)0x18, 0x00, 1 ); - writeDemodRegister( device, Page.ONE, (short)0x19, 0x00, 1 ); - writeDemodRegister( device, Page.ONE, (short)0x1A, 0x00, 1 ); - writeDemodRegister( device, Page.ONE, (short)0x1B, 0x00, 1 ); + writeDemodRegister( handle, Page.ONE, (short)0x16, 0x00, 1 ); + writeDemodRegister( handle, Page.ONE, (short)0x17, 0x00, 1 ); + writeDemodRegister( handle, Page.ONE, (short)0x18, 0x00, 1 ); + writeDemodRegister( handle, Page.ONE, (short)0x19, 0x00, 1 ); + writeDemodRegister( handle, Page.ONE, (short)0x1A, 0x00, 1 ); + writeDemodRegister( handle, Page.ONE, (short)0x1B, 0x00, 1 ); /* Set FIR coefficients */ for( int x = 0; x < sFIR_COEFFICIENTS.length; x++ ) { - writeDemodRegister( device, + writeDemodRegister( handle, Page.ONE, (short)( 0x1C + x ), sFIR_COEFFICIENTS[ x ], @@ -614,47 +544,43 @@ public abstract class RTL2832TunerController extends TunerController } /* Enable SDR mode, disable DAGC (bit 5) */ - writeDemodRegister( device, Page.ZERO, (short)0x19, 0x05, 1 ); + writeDemodRegister( handle, Page.ZERO, (short)0x19, 0x05, 1 ); /* Init FSM state-holding register */ - writeDemodRegister( device, Page.ONE, (short)0x93, 0xF0, 1 ); - writeDemodRegister( device, Page.ONE, (short)0x94, 0x0F, 1 ); + writeDemodRegister( handle, Page.ONE, (short)0x93, 0xF0, 1 ); + writeDemodRegister( handle, Page.ONE, (short)0x94, 0x0F, 1 ); /* Disable AGC (en_dagc, bit 0) (seems to have no effect) */ - writeDemodRegister( device, Page.ONE, (short)0x11, 0x00, 1 ); + writeDemodRegister( handle, Page.ONE, (short)0x11, 0x00, 1 ); /* Disable RF and IF AGC loop */ - writeDemodRegister( device, Page.ONE, (short)0x04, 0x00, 1 ); + writeDemodRegister( handle, Page.ONE, (short)0x04, 0x00, 1 ); /* Disable PID filter */ - writeDemodRegister( device, Page.ZERO, (short)0x61, 0x60, 1 ); + writeDemodRegister( handle, Page.ZERO, (short)0x61, 0x60, 1 ); /* opt_adc_iq = 0, default ADC_I/ADC_Q datapath */ - writeDemodRegister( device, Page.ZERO, (short)0x06, 0x80, 1 ); + writeDemodRegister( handle, Page.ZERO, (short)0x06, 0x80, 1 ); /* Enable Zero-if mode (en_bbin bit), * DC cancellation (en_dc_est), * IQ estimation/compensation (en_iq_comp, en_iq_est) */ - writeDemodRegister( device, Page.ONE, (short)0xB1, 0x1B, 1 ); + writeDemodRegister( handle, Page.ONE, (short)0xB1, 0x1B, 1 ); /* Disable 4.096 MHz clock output on pin TP_CK0 */ - writeDemodRegister( device, Page.ZERO, (short)0x0D, 0x83, 1 ); + writeDemodRegister( handle, Page.ZERO, (short)0x0D, 0x83, 1 ); } - protected void deinitBaseband( UsbDevice device ) + protected void deinitBaseband( DeviceHandle handle ) throws IllegalArgumentException, UsbDisconnectedException, UsbException { -// setI2CRepeater( device, true ); - - writeRegister( device, Block.SYS, Address.DEMOD_CTL.getAddress(), 0x20, 1); - -// setI2CRepeater( device, false ); + writeRegister( handle, Block.SYS, Address.DEMOD_CTL.getAddress(), 0x20, 1); } /** * Sets the General Purpose Input/Output (GPIO) register bit * - * @param device - USB tuner device + * @param handle - USB tuner device * @param bitMask - bit mask with one for targeted register bits and zero * for the non-targeted register bits * @param enabled - true to set the bit and false to clear the bit @@ -662,11 +588,12 @@ public abstract class RTL2832TunerController extends TunerController * @throws UsbException - if there is a USB error while communicating with * the device */ - protected static void setGPIOBit( UsbDevice device, byte bitMask, boolean enabled ) - throws UsbDisconnectedException, UsbException + protected static void setGPIOBit( DeviceHandle handle, + byte bitMask, + boolean enabled ) throws LibUsbException { //Get current register value - int value = readRegister( device, Block.SYS, Address.GPO.getAddress(), 1 ); + int value = readRegister( handle, Block.SYS, Address.GPO.getAddress(), 1 ); //Update the masked bits if( enabled ) @@ -679,36 +606,37 @@ public abstract class RTL2832TunerController extends TunerController } //Write the change back to the device - writeRegister( device, Block.SYS, Address.GPO.getAddress(), value, 1 ); + writeRegister( handle, Block.SYS, Address.GPO.getAddress(), value, 1 ); } /** * Enables GPIO Output - * @param device - usb tuner device + * @param handle - usb tuner device * @param bitMask - mask containing one bit value in targeted bit field(s) * @throws UsbDisconnectedException * @throws UsbException */ - protected static void setGPIOOutput( UsbDevice device, byte bitMask ) - throws UsbDisconnectedException, UsbException + protected static void setGPIOOutput( DeviceHandle handle, byte bitMask ) + throws LibUsbException { //Get current register value - int value = readRegister( device, Block.SYS, Address.GPD.getAddress(), 1 ); + int value = readRegister( handle, Block.SYS, Address.GPD.getAddress(), 1 ); //Mask the value and rewrite it - writeRegister( device, Block.SYS, Address.GPO.getAddress(), + writeRegister( handle, Block.SYS, Address.GPO.getAddress(), value & ~bitMask, 1 ); //Get current register value - value = readRegister( device, Block.SYS, Address.GPOE.getAddress(), 1 ); + value = readRegister( handle, Block.SYS, Address.GPOE.getAddress(), 1 ); //Mask the value and rewrite it - writeRegister( device, Block.SYS, Address.GPOE.getAddress(), + writeRegister( handle, Block.SYS, Address.GPOE.getAddress(), value | bitMask, 1 ); } - protected static void enableI2CRepeater( UsbDevice device, boolean enabled ) - throws IllegalArgumentException, UsbDisconnectedException, UsbException + protected static void enableI2CRepeater( DeviceHandle handle, + boolean enabled ) + throws LibUsbException { Page page = Page.ONE; short address = 1; @@ -723,89 +651,91 @@ public abstract class RTL2832TunerController extends TunerController value = 0x10; //OFF } - writeDemodRegister( device, page, address, value, 1 ); + writeDemodRegister( handle, page, address, value, 1 ); } - protected boolean isI2CRepeaterEnabled() throws UsbException + protected boolean isI2CRepeaterEnabled() throws SourceException { - int register = readDemodRegister( mUSBDevice, Page.ONE, (short)0x1, 1 ); + int register = readDemodRegister( mDeviceHandle, Page.ONE, (short)0x1, 1 ); return register == 0x18; } - protected static int readI2CRegister( UsbDevice device, + protected static int readI2CRegister( DeviceHandle handle, byte i2CAddress, byte i2CRegister, boolean controlI2CRepeater ) - throws IllegalArgumentException, UsbDisconnectedException, UsbException + throws LibUsbException { short address = (short)( i2CAddress & 0xFF ); - byte[] writeData = new byte[ 1 ]; - writeData[ 0 ] = i2CRegister; + ByteBuffer buffer = ByteBuffer.allocateDirect( 1 ); + buffer.put( i2CRegister ); + buffer.rewind(); - byte[] readData = new byte[ 1 ]; + ByteBuffer data = ByteBuffer.allocateDirect( 1 ); if( controlI2CRepeater ) { - enableI2CRepeater( device, true ); + enableI2CRepeater( handle, true ); - write( device, Block.IIC, address, writeData ); - read( device, Block.IIC, address, readData ); + write( handle, address, Block.I2C, buffer ); + read( handle, address, Block.I2C, data ); - enableI2CRepeater( device, false ); + enableI2CRepeater( handle, false ); } else { - write( device, Block.IIC, address, writeData ); - read( device, Block.IIC, address, readData ); + write( handle, address, Block.I2C, buffer ); + read( handle, address, Block.I2C, data ); } - - return (int)( readData[ 0 ] & 0xFF ); + + return (int)( data.get() & 0xFF ); } - protected void writeI2CRegister( UsbDevice device, + protected void writeI2CRegister( DeviceHandle handle, byte i2CAddress, byte i2CRegister, byte value, - boolean controlI2CRepeater ) throws UsbException + boolean controlI2CRepeater ) throws LibUsbException { short address = (short)( i2CAddress & 0xFF ); - byte[] data = new byte[ 2 ]; - - data[ 0 ] = i2CRegister; - data[ 1 ] = value; + ByteBuffer buffer = ByteBuffer.allocateDirect( 2 ); + buffer.put( i2CRegister ); + buffer.put( value ); + + buffer.rewind(); if( controlI2CRepeater ) { - enableI2CRepeater( device, true ); - write( mUSBDevice, Block.IIC, address, data ); - enableI2CRepeater( device, false ); + enableI2CRepeater( handle, true ); + write( handle, address, Block.I2C, buffer ); + enableI2CRepeater( handle, false ); } else { - write( mUSBDevice, Block.IIC, address, data ); + write( handle, address, Block.I2C, buffer ); } } - protected static void writeDemodRegister( UsbDevice device, Page page, - short address, int value, int length ) - throws IllegalArgumentException, UsbDisconnectedException, UsbException + protected static void writeDemodRegister( DeviceHandle handle, + Page page, + short address, + int value, + int length ) throws LibUsbException { - byte[] data; + ByteBuffer buffer = ByteBuffer.allocateDirect( length ); + buffer.order( ByteOrder.BIG_ENDIAN ); if( length == 1 ) { - data = new byte[ 1 ]; - data[0] = (byte)( value & 0xFF ); + buffer.put( (byte)( value & 0xFF ) ); } else if( length == 2 ) { - data = new byte[ 2 ]; - data[1] = (byte)( value & 0xFF ); //LSB - data[0] = (byte)( ( value >> 8 ) & 0xFF ); //MSB + buffer.putShort( (short)( value & 0xFFFF ) ); } else { @@ -817,301 +747,224 @@ public abstract class RTL2832TunerController extends TunerController short newAddress = (short)( address << 8 | 0x20 ); - write( device, newAddress, index, data ); + write( handle, newAddress, index, buffer ); - readDemodRegister( device, Page.TEN, (short)1, length ); + readDemodRegister( handle, Page.TEN, (short)1, length ); } - protected static int readDemodRegister( UsbDevice device, + protected static int readDemodRegister( DeviceHandle handle, Page page, short address, - int length ) - throws IllegalArgumentException, UsbDisconnectedException, UsbException + int length ) throws LibUsbException { short index = page.getPage(); short newAddress = (short)( ( address << 8 ) | 0x20 ); - byte[] empty = new byte[ 2 ]; - byte[] data = read( device, newAddress, index, empty ); + ByteBuffer buffer = ByteBuffer.allocateDirect( length ); + + read( handle, newAddress, index, buffer ); + buffer.order( ByteOrder.LITTLE_ENDIAN ); if( length == 2 ) { - return (int)( ( data[ 1 ] << 8 | data[ 0 ] ) & 0xFFFF ); + return (int)( buffer.getShort() & 0xFFFF ); } else { - return (int)( data[ 0 ] & 0xFF ); + return (int)( buffer.get() & 0xFF ); } } - protected static void writeRegister( UsbDevice device, Block block, short address, - int value, int length ) - throws IllegalArgumentException, UsbDisconnectedException, UsbException + protected static void writeRegister( DeviceHandle handle, + Block block, + short address, + int value, + int length ) throws LibUsbException { - byte[] data; + ByteBuffer buffer = ByteBuffer.allocateDirect( length ); + buffer.order( ByteOrder.BIG_ENDIAN ); if( length == 1 ) { - data = new byte[ 1 ]; - data[0] = (byte)( value & 0xFF ); + buffer.put( (byte)( value & 0xFF ) ) ; } else if( length == 2 ) { - data = new byte[ 2 ]; - data[1] = (byte)( value & 0xFF ); //LSB - data[0] = (byte)( ( value >> 8 ) & 0xFF ); //MSB + buffer.putShort( (short)value ); } else { throw new IllegalArgumentException( "Cannot write value greater " + "than 16 bits to the register - length [" + length + "]" ); } + + buffer.rewind(); - write( device, block, address, data ); + write( handle, address, block, buffer ); } - protected static int readRegister( UsbDevice device, Block block, short address, int length ) - throws IllegalArgumentException, UsbDisconnectedException, UsbException + protected static int readRegister( DeviceHandle handle, + Block block, + short address, + int length ) throws LibUsbException { - byte[] empty = new byte[ 2 ]; + ByteBuffer buffer = ByteBuffer.allocateDirect( 2 ); - byte[] data = read( device, block, address, empty ); + read( handle, address, block, buffer ); + + buffer.order( ByteOrder.LITTLE_ENDIAN ); if( length == 2 ) { - return (int)( ( data[ 1 ] << 8 | data[ 0 ] ) & 0xFFFF ); + return (int)( buffer.getShort() & 0xFFFF ); } else { - return (int)( data[ 0 ] & 0xFF ); + return (int)( buffer.get() & 0xFF ); } } /** - * Write array convenience method. Allow you to specify the Block that you - * are writing to. - * - * @param device - * @param block - * @param address - * @param data - * @throws IllegalArgumentException - * @throws UsbDisconnectedException - * @throws UsbException */ - protected static void write( UsbDevice device, Block block, short address, byte[] data ) - throws IllegalArgumentException, UsbDisconnectedException, UsbException + protected static void write( DeviceHandle handle, + short address, + Block block, + ByteBuffer buffer ) throws LibUsbException { - write( device, address, block.getWriteIndex(), data ); + write( handle, address, block.getWriteIndex(), buffer ); } - /** - * Write byte array - * @param device - tuner - * @param value - - * @param index - start - * @param data - to write - * @throws IllegalArgumentException - * @throws UsbDisconnectedException - * @throws UsbException - */ - protected static void write( UsbDevice device, short value, short index, byte[] data ) - throws IllegalArgumentException, UsbDisconnectedException, UsbException + protected static void write( DeviceHandle handle, + short value, + short index, + ByteBuffer buffer ) throws LibUsbException { - UsbControlIrp irp = - device.createUsbControlIrp( sREQUEST_TYPE_OUT, - sREQUEST_ZERO, - value, - index ); + if( handle != null ) + { + int transferred = LibUsb.controlTransfer( handle, + CONTROL_ENDPOINT_OUT, + REQUEST_ZERO, + value, + index, + buffer, + TIMEOUT_US ); - irp.setData( data ); - - device.syncSubmit( irp ); + if( transferred < 0 ) + { + throw new LibUsbException( "error writing byte buffer", + transferred ); + } + else if( transferred != buffer.capacity() ) + { + throw new LibUsbException( "transferred bytes [" + + transferred + "] is not what was expected [" + + buffer.capacity() + "]", transferred ); + } + } + else + { + throw new LibUsbException( "device handle is null", + LibUsb.ERROR_NO_DEVICE ); + } } + /** + * Performs a control type read + */ + protected static void read( DeviceHandle handle, + short address, + short index, + ByteBuffer buffer ) throws LibUsbException + { + if( handle != null ) + { + int transferred = LibUsb.controlTransfer( handle, + CONTROL_ENDPOINT_IN, + REQUEST_ZERO, + address, + index, + buffer, + TIMEOUT_US ); + + if( transferred < 0 ) + { + throw new LibUsbException( "read error", transferred ); + } + else if( transferred != buffer.capacity() ) + { + throw new LibUsbException( "transferred bytes [" + + transferred + "] is not what was expected [" + + buffer.capacity() + "]", transferred ); + } + } + else + { + throw new LibUsbException( "device handle is null", + LibUsb.ERROR_NO_DEVICE ); + } + } + /** * Reads byte array from index at the address. * * @return big-endian byte array (needs to be swapped to be usable) * */ - protected static byte[] read( UsbDevice device, Block block, short address, byte[] data ) - throws IllegalArgumentException, UsbDisconnectedException, UsbException + protected static void read( DeviceHandle handle, + short address, + Block block, + ByteBuffer buffer ) throws LibUsbException { - byte[] retVal; - - retVal = read( device, address, block.getReadIndex(), data ); - - return retVal; + read( handle, address, block.getReadIndex(), buffer ); } /** - * Reads the byte array from the index at the address with the length of the - * read determined by the size of the data array + * Tests if the specified tuner type is contained in the usb tuner device. * - * @return - big-endian byte array (needs to be swapped to be usable) + * @param type - tuner type to test for + * @param handle - handle to the usb tuner device + * @param controlI2CRepeater - indicates if the method should control the + * I2C repeater independently + * + * @return - true if the device is the specified tuner type */ - protected static byte[] read( UsbDevice device, short address, short index, byte[] data ) - throws IllegalArgumentException, UsbDisconnectedException, UsbException + protected static boolean isTuner( TunerTypeCheck type, + DeviceHandle handle, + boolean controlI2CRepeater ) { - DefaultUsbControlIrp irp = - new DefaultUsbControlIrp( sREQUEST_TYPE_IN, - (byte)0, - address, - index ); - - irp.setData( data ); - - device.syncSubmit( irp ); - - return irp.getData(); - } - - protected static boolean isE4000Tuner( UsbDevice device, - boolean controlI2CRepeater ) throws UsbClaimException - { - mLog.debug( "testing for E4000 tuner" ); - try { - int value = readI2CRegister( device, E4K_I2C_ADDRESS, - E4K_CHECK_ADDRESS, controlI2CRepeater ); + if( type == TunerTypeCheck.FC0012 || + type == TunerTypeCheck.FC2580 ) + { + /* Initialize the GPIOs */ + setGPIOOutput( handle, (byte)0x20 ); + + /* Reset tuner before probing */ + setGPIOBit( handle, (byte)0x20, true ); + setGPIOBit( handle, (byte)0x20, false ); + } - return ( value == E4K_CHECK_VALUE ); + int value = readI2CRegister( handle, type.getI2CAddress(), + type.getCheckAddress(), controlI2CRepeater ); + + if( type == TunerTypeCheck.FC2580 ) + { + return ( ( value & 0x7F ) == type.getCheckValue() ); + } + else + { + return ( value == type.getCheckValue() ); + } } - catch( UsbException e ) + catch( LibUsbException e ) { - //Do nothing ... it's not an E4000 + //Do nothing ... it's not the specified tuner } return false; } - - protected static boolean isFC0012Tuner( UsbDevice device, - boolean controlI2CRepeater ) throws UsbClaimException - { - try - { - /* Initialize the GPIOs */ - setGPIOOutput( device, BIT_5 ); - /* Reset tuner before probing */ - setGPIOBit( device, BIT_5, true ); - setGPIOBit( device, BIT_5, false ); - - - int value = readI2CRegister( device, - FC0012_I2C_ADDRESS, - FC0012_CHECK_ADDRESS, - controlI2CRepeater ); - - return ( value == FC0012_CHECK_VALUE ); - } - catch( UsbException e ) - { - //Do nothing, it's not an FC0012 - } - - return false; - } - - protected static boolean isFC0013Tuner( UsbDevice device, - boolean controlI2CRepeater ) - throws UsbClaimException - { - mLog.debug( "testing for F0013 tuner" ); - - try - { - int value = readI2CRegister( device, FC0013_I2C_ADDRESS, - FC0013_CHECK_ADDRESS, controlI2CRepeater ); - - return ( value == FC0013_CHECK_VALUE ); - } - catch( UsbException e ) - { - //Do nothing ... it's probably not an FC0013 - } - - return false; - } - - /** - * Determines if the device's tuner is an FC2580 Tuner. - * - * Note: call initBaseband(device) prior to calling this method. - * - * @param device - usb tuner device - * @return true if the tuner is an FC2580 - * @throws UsbException - * @throws UsbClaimException - */ - protected static boolean isFC2580Tuner( UsbDevice device, - boolean controlI2CRepeater ) throws UsbClaimException - { - try - { - /* Initialize the GPIOs */ - setGPIOOutput( device, BIT_5 ); - - /* Reset tuner before probing */ - setGPIOBit( device, BIT_5, true ); - setGPIOBit( device, BIT_5, false ); - - - /* Read the check value */ - int value = readI2CRegister( device, FC2580_I2C_ADDRESS, - FC2580_CHECK_ADDRESS, controlI2CRepeater ); - - /* Compare masked return value to the known check value */ - return ( ( value & 0x7F ) == FC2580_CHECK_VALUE ); - } - catch( UsbException e ) - { - //Do nothing, it's not an FC2580 - } - - return false; - } - - protected static boolean isR820TTuner( UsbDevice device, - boolean controlI2CRepeater ) throws UsbClaimException - { - mLog.debug( "testing for R820T tuner" ); - - try - { - int value = readI2CRegister( device, R820T_I2C_ADDRESS, - R820T_CHECK_ADDRESS, controlI2CRepeater ); - - return ( value == R820T_CHECK_VALUE ); - } - catch( UsbException e ) - { - //Do nothing, it's not an R820T - } - - return false; - } - - protected static boolean isR828DTuner( UsbDevice device, - boolean controlI2CRepeater ) throws UsbClaimException - { - try - { - int value = readI2CRegister( device, R828D_I2C_ADDRESS, - R828D_CHECK_ADDRESS, controlI2CRepeater ); - - return ( value == R828D_CHECK_VALUE ); - } - catch( UsbException e ) - { - //Do nothing, it's not an R828D - } - - return false; - } - public int getCurrentSampleRate() throws SourceException { return mSampleRate.getRate(); @@ -1121,12 +974,12 @@ public abstract class RTL2832TunerController extends TunerController { try { - int high= readDemodRegister( mUSBDevice, Page.ONE, (short)0x9F, 2 ); - int low = readDemodRegister( mUSBDevice, Page.ONE, (short)0xA1, 2 ); + int high= readDemodRegister( mDeviceHandle, Page.ONE, (short)0x9F, 2 ); + int low = readDemodRegister( mDeviceHandle, Page.ONE, (short)0xA1, 2 ); int ratio = Integer.rotateLeft( high, 16 ) | low; - int rate = (int)( mOscillatorFrequency * sTWO_TO_22_POWER / ratio ); + int rate = (int)( mOscillatorFrequency * TWO_TO_22_POWER / ratio ); SampleRate sampleRate = SampleRate.getClosest( rate ); @@ -1144,37 +997,31 @@ public abstract class RTL2832TunerController extends TunerController + "current sample rate", e ); } - return sDEFAULT_SAMPLE_RATE.getRate(); + return DEFAULT_SAMPLE_RATE.getRate(); } - public void setSampleRate( SampleRate sampleRate ) - throws SourceException, UsbException + public void setSampleRate( SampleRate sampleRate ) throws SourceException { /* Write high-order 16-bits of sample rate ratio to demod register */ - writeDemodRegister( mUSBDevice, Page.ONE, (short)0x9F, + writeDemodRegister( mDeviceHandle, Page.ONE, (short)0x9F, sampleRate.getRatioHighBits(), 2 ); /* Write low-order 16-bits of sample rate ratio to demod register */ - writeDemodRegister( mUSBDevice, Page.ONE, (short)0xA1, + writeDemodRegister( mDeviceHandle, Page.ONE, (short)0xA1, sampleRate.getRatioLowBits(), 2 ); /* Set sample rate correction to 0 */ setSampleRateFrequencyCorrection( 0 ); /* Reset the demod for the changes to take effect */ - writeDemodRegister( mUSBDevice, Page.ONE, (short)0x01, 0x14, 1 ); - writeDemodRegister( mUSBDevice, Page.ONE, (short)0x01, 0x10, 1 ); + writeDemodRegister( mDeviceHandle, Page.ONE, (short)0x01, 0x14, 1 ); + writeDemodRegister( mDeviceHandle, Page.ONE, (short)0x01, 0x10, 1 ); /* Apply any tuner specific sample rate filter settings */ setSampleRateFilters( sampleRate.getRate() ); mSampleRate = sampleRate; - /** - * Adjust the size of the byte array buffers sent over the USB bus - */ - mBufferSize = mSampleRate.getBufferSize(); - mFrequencyController.setSampleRate( sampleRate.getRate() ); if( mSampleRateMonitor != null ) @@ -1183,29 +1030,35 @@ public abstract class RTL2832TunerController extends TunerController } } - public void setSampleRateFrequencyCorrection( int ppm ) - throws SourceException, UsbException + public void setSampleRateFrequencyCorrection( int ppm ) throws SourceException { - int offset = -ppm * sTWO_TO_22_POWER / 1000000; + int offset = -ppm * TWO_TO_22_POWER / 1000000; - writeDemodRegister( mUSBDevice, + writeDemodRegister( mDeviceHandle, Page.ONE, (short)0x3F, ( offset & 0xFF ), 1 ); - writeDemodRegister( mUSBDevice, + writeDemodRegister( mDeviceHandle, Page.ONE, (short)0x3E, ( Integer.rotateRight( offset, 8 ) & 0xFF ), 1 ); /* Test to retune controller to apply frequency correction */ - mFrequencyController.setFrequency( mFrequencyController.getFrequency() ); + try + { + mFrequencyController.setFrequency( mFrequencyController.getFrequency() ); + } + catch( Exception e ) + { + throw new SourceException( "couldn't set sample rate frequency correction", e ); + } } public int getSampleRateFrequencyCorrection() throws UsbException { - int high = readDemodRegister( mUSBDevice, Page.ONE, (short)0x3E, 1 ); - int low = readDemodRegister( mUSBDevice, Page.ONE, (short)0x3F, 1 ); + int high = readDemodRegister( mDeviceHandle, Page.ONE, (short)0x3E, 1 ); + int low = readDemodRegister( mDeviceHandle, Page.ONE, (short)0x3F, 1 ); return ( Integer.rotateLeft( high, 8 ) | low ); } @@ -1229,7 +1082,7 @@ public abstract class RTL2832TunerController extends TunerController * Label 3: serial * Label 4,5 ... (user defined) */ - public byte[] readEEPROM( UsbDevice device, short offset, int length ) + public byte[] readEEPROM( DeviceHandle handle, short offset, int length ) throws IllegalArgumentException { if( offset + length > 256 ) @@ -1240,14 +1093,14 @@ public abstract class RTL2832TunerController extends TunerController } byte[] data = new byte[ length ]; - byte[] onebyte = new byte[ 1 ]; + ByteBuffer buffer = ByteBuffer.allocateDirect( 1 ); try { /* Tell the RTL-2832 to address the EEPROM */ - writeRegister( device, Block.IIC, EEPROM_ADDRESS, (byte)offset, 1 ); + writeRegister( handle, Block.I2C, EEPROM_ADDRESS, (byte)offset, 1 ); } - catch( UsbException e ) + catch( LibUsbException e ) { mLog.error( "usb error while attempting to set read address to " + "EEPROM register, prior to reading the EEPROM device " @@ -1258,8 +1111,9 @@ public abstract class RTL2832TunerController extends TunerController { try { - byte[] temp = read( device, Block.IIC, EEPROM_ADDRESS, onebyte ); - data[ x ] = temp[ 0 ]; + read( handle, EEPROM_ADDRESS, Block.I2C, buffer ); + data[ x ] = buffer.get(); + buffer.rewind(); } catch( Exception e ) { @@ -1279,7 +1133,7 @@ public abstract class RTL2832TunerController extends TunerController * Note: introduce a 5 millisecond delay between each successive write to * the EEPROM or subsequent writes may fail. */ - public void writeEEPROMByte( UsbDevice device, byte offset, byte value ) + public void writeEEPROMByte( DeviceHandle handle, byte offset, byte value ) throws IllegalArgumentException, UsbDisconnectedException, UsbException { if( offset < 0 || offset > 255 ) @@ -1291,7 +1145,7 @@ public abstract class RTL2832TunerController extends TunerController int offsetAndValue = Integer.rotateLeft( ( 0xFF & offset ), 8 ) | ( 0xFF & value ); - writeRegister( device, Block.IIC, EEPROM_ADDRESS, offsetAndValue, 2 ); + writeRegister( handle, Block.I2C, EEPROM_ADDRESS, offsetAndValue, 2 ); } public enum Address @@ -1363,7 +1217,7 @@ public abstract class RTL2832TunerController extends TunerController TUN( 3 ), ROM( 4 ), IR( 5 ), - IIC( 6 ); //I2C controller + I2C( 6 ); //I2C controller private int mValue; @@ -1409,37 +1263,34 @@ public abstract class RTL2832TunerController extends TunerController public enum SampleRate { /* Note: sample rates below 1.0MHz are subject to aliasing */ - RATE_0_240MHZ( 0x0DFC, 0x0000, 240000, "0.240 MHz", 16384 ), - RATE_0_288MHZ( 0x08FC, 0x0000, 288000, "0.288 MHz", 16384 ), - RATE_0_912MHZ( 0x07E4, 0x0000, 912000, "0.912 MHz", 32768 ), - RATE_0_960MHZ( 0x0778, 0x0000, 960000, "0.960 MHz", 32768 ), - RATE_1_200MHZ( 0x05F4, 0x0000, 1200000, "1.200 MHz", 65536 ), - RATE_1_440MHZ( 0x04FC, 0x0000, 1440000, "1.440 MHz", 65536 ), - RATE_1_680MHZ( 0x0448, 0x0000, 1680000, "1.680 MHz", 65536 ), - RATE_1_824MHZ( 0x03F0, 0x0000, 1824000, "1.824 MHz", 65536 ), - RATE_2_016MHZ( 0x038C, 0x0000, 2016000, "2.016 MHz", 131072 ), - RATE_2_208MHZ( 0x0340, 0x0000, 2208000, "2.208 MHz", 131072 ), - RATE_2_400MHZ( 0x02FC, 0x0000, 2400000, "2.400 MHz", 131072 ), - RATE_2_640MHZ( 0x02B4, 0x8000, 2640000, "2.640 MHz", 262144 ), - RATE_2_880MHZ( 0x027C, 0x0000, 2880000, "2.880 MHz", 262144 ); + RATE_0_240MHZ( 0x0DFC, 0x0000, 240000, "0.240 MHz" ), + RATE_0_288MHZ( 0x08FC, 0x0000, 288000, "0.288 MHz" ), + RATE_0_912MHZ( 0x07E4, 0x0000, 912000, "0.912 MHz" ), + RATE_0_960MHZ( 0x0778, 0x0000, 960000, "0.960 MHz" ), + RATE_1_200MHZ( 0x05F4, 0x0000, 1200000, "1.200 MHz" ), + RATE_1_440MHZ( 0x04FC, 0x0000, 1440000, "1.440 MHz" ), + RATE_1_680MHZ( 0x0448, 0x0000, 1680000, "1.680 MHz" ), + RATE_1_824MHZ( 0x03F0, 0x0000, 1824000, "1.824 MHz" ), + RATE_2_016MHZ( 0x038C, 0x0000, 2016000, "2.016 MHz" ), + RATE_2_208MHZ( 0x0340, 0x0000, 2208000, "2.208 MHz" ), + RATE_2_400MHZ( 0x02FC, 0x0000, 2400000, "2.400 MHz" ), + RATE_2_640MHZ( 0x02B4, 0x8000, 2640000, "2.640 MHz" ), + RATE_2_880MHZ( 0x027C, 0x0000, 2880000, "2.880 MHz" ); private int mRatioHigh; private int mRatioLow; private int mRate; private String mLabel; - private int mBufferSize; private SampleRate( int ratioHigh, int ratioLow, int rate, - String label, - int bufferSize ) + String label ) { mRatioHigh = ratioHigh; mRatioLow = ratioLow; mRate = rate; mLabel = label; - mBufferSize = bufferSize; } public int getRatioHighBits() @@ -1467,11 +1318,6 @@ public abstract class RTL2832TunerController extends TunerController return mLabel; } - public int getBufferSize() - { - return mBufferSize; - } - /** * Returns the sample rate that is equal to the argument or the next * higher sample rate @@ -1488,7 +1334,7 @@ public abstract class RTL2832TunerController extends TunerController } } - return sDEFAULT_SAMPLE_RATE; + return DEFAULT_SAMPLE_RATE; } } @@ -1500,7 +1346,16 @@ public abstract class RTL2832TunerController extends TunerController { mSampleListeners.add( listener ); - mBufferProcessor.start(); + if( mBufferProcessor == null || !mBufferProcessor.isRunning() ) + { + mBufferProcessor = new BufferProcessor(); + + Thread thread = new Thread( mBufferProcessor ); + thread.setDaemon( true ); + thread.setName( "Sample Processor" ); + + thread.start(); + } } /** @@ -1545,95 +1400,93 @@ public abstract class RTL2832TunerController extends TunerController * Buffer processing thread. Fetches samples from the RTL2832 Tuner and * dispatches them to all registered listeners */ - public class BufferProcessor implements UsbPipeListener + public class BufferProcessor implements Runnable, TransferCallback { private ScheduledExecutorService mExecutor = Executors.newScheduledThreadPool( 2 ); private ScheduledFuture mSampleDispatcherTask; - private ScheduledFuture mSampleRateCounterTask; - + private ScheduledFuture mSampleRateCounterTask; + private ArrayList mTransfers; private AtomicBoolean mRunning = new AtomicBoolean(); - private AtomicBoolean mResetting = new AtomicBoolean(); - private Boolean mTransitioning = false; - public void start() + @Override + public void run() { - synchronized( mTransitioning ) + if( mRunning.compareAndSet( false, true ) ) { - if( mRunning.compareAndSet( false, true ) ) + mLog.debug( "rtl2832 [" + getUniqueID() + + "] - starting sample fetch thread" ); + + try { - mLog.debug( "rtl2832 [" + getUniqueID() + - "] - starting sample fetch thread" ); + setSampleRate( mSampleRate ); - ArrayList irps = new ArrayList(); - - for( int x = 0; x < sUSB_IRP_POOL_SIZE; x++ ) - { - UsbIrp irp = mUSBPipe.createUsbIrp(); - irp.setData( new byte[ mBufferSize ] ); - irps.add( irp ); - } - - try - { - if( mUSBPipe.isActive() ) - { - if( !mUSBPipe.isOpen() ) - { - resetUSBBuffer(); - - mUSBPipe.open(); - - //TODO: move this to the constructor - mUSBPipe.addUsbPipeListener( this ); - } - - if( mUSBPipe.isOpen() ) - { - mSampleDispatcherTask = mExecutor - .scheduleAtFixedRate( new BufferDispatcher(), - 0, 20, TimeUnit.MILLISECONDS ); - - mSampleRateMonitor = - new SampleRateMonitor( mSampleRate.getRate() ); - - mSampleRateCounterTask = mExecutor - .scheduleAtFixedRate( mSampleRateMonitor, - 10, 10, TimeUnit.SECONDS ); - - mUSBPipe.asyncSubmit( irps ); - } - } - } - catch ( Exception e ) - { - e.printStackTrace(); - } + resetUSBBuffer(); } - } - } + catch( SourceException e ) + { + mLog.error( "couldn't start buffer processor", e ); + + mRunning.set( false ); + } + + prepareTransfers(); + + for( Transfer transfer: mTransfers ) + { + int result = LibUsb.submitTransfer( transfer ); + + if( result != LibUsb.SUCCESS ) + { + mLog.error( "error submitting transfer [" + + LibUsb.errorName( result ) + "]" ); + break; + } + } + + mSampleDispatcherTask = mExecutor + .scheduleAtFixedRate( new BufferDispatcher(), + 0, 20, TimeUnit.MILLISECONDS ); + + mSampleRateMonitor = + new SampleRateMonitor( mSampleRate.getRate() ); + + mSampleRateCounterTask = mExecutor + .scheduleAtFixedRate( mSampleRateMonitor, + 10, 10, TimeUnit.SECONDS ); + + while( mRunning.get() ) + { + ByteBuffer completed = ByteBuffer.allocateDirect( 4 ); + + int result = LibUsb.handleEventsTimeoutCompleted( + null, TIMEOUT_US, completed.asIntBuffer() ); + + if( result != LibUsb.SUCCESS ) + { + mLog.error( "error handling events for libusb" ); + } + } + } + } /** * Stops the sample fetching thread */ public void stop() { - synchronized( mTransitioning ) + if( mRunning.compareAndSet( true, false ) ) { - if( mRunning.compareAndSet( true, false ) ) - { - mLog.debug( "rtl2832 [" + getUniqueID() + - "] - stopping sample fetch thread" ); + mLog.debug( "rtl2832 [" + getUniqueID() + + "] - stopping sample fetch thread" ); - mUSBPipe.abortAllSubmissions(); - - if( mSampleDispatcherTask != null ) - { - mSampleDispatcherTask.cancel( true ); - mSampleRateCounterTask.cancel( true ); - mRawSampleBuffer.clear(); - mSampleCounter.set( 0 ); - } + cancel(); + + if( mSampleDispatcherTask != null ) + { + mSampleDispatcherTask.cancel( true ); + mSampleRateCounterTask.cancel( true ); + mFilledBuffers.clear(); } } } @@ -1645,66 +1498,107 @@ public abstract class RTL2832TunerController extends TunerController { return mRunning.get(); } - - /** - * This method is invoked by the usb pipe when a response is returned - * from the data request. If there is byte sample data in the response - * then we will buffer it and allow the buffer processor to convert it - * and dispatch it to listeners. We automatically insert another - * irp to get more data. - * - * This method runs on the usb4java library processing thread, so we - * don't want to weigh it down. - */ + @Override - public synchronized void dataEventOccurred( UsbPipeDataEvent event ) - { - UsbIrp irp = event.getUsbIrp(); - - byte[] data = irp.getData(); - - if( data.length > 0 ) + public void processTransfer( Transfer transfer ) + { + if( transfer.status() == LibUsb.TRANSFER_COMPLETED ) { - mRawSampleBuffer.add( data ); - mSampleCounter.addAndGet( data.length ); - } - - if( mRunning.get() ) - { - try - { - mUSBPipe.asyncSubmit( new byte[ mBufferSize ] ); - } - catch ( UsbNotActiveException | UsbNotOpenException - | IllegalArgumentException | UsbDisconnectedException - | UsbException e ) - { - mLog.error( "error while processing samples", e ); - } - } - } - - @Override - public void errorEventOccurred( UsbPipeErrorEvent e ) - { - /* When an error occurs, we'll get errors on all of the - * queued IRPS in succession. We use the mResetting to control - * the reset process and ignore all subsequent errors */ - if( mResetting.compareAndSet( false, true ) ) - { - mLog.error( "error during data transfer resetting USB pipe to " - + "RTL-2832", e ); + ByteBuffer buffer = transfer.buffer(); - stop(); - - if( !mSampleListeners.isEmpty() ) - { - start(); - } + byte[] data = new byte[ transfer.actualLength() ]; + + buffer.get( data ); - mResetting.set( false ); + buffer.rewind(); + + mFilledBuffers.add( data ); + + mSampleCounter.addAndGet( transfer.actualLength() ); + + if( !isRunning() ) + { + LibUsb.cancelTransfer( transfer ); + } } - } + + switch( transfer.status() ) + { + case LibUsb.TRANSFER_COMPLETED: + /* resubmit the transfer */ + int result = LibUsb.submitTransfer( transfer ); + + if( result != LibUsb.SUCCESS ) + { + mLog.error( "couldn't resubmit buffer transfer to tuner" ); + LibUsb.freeTransfer( transfer ); + mTransfers.remove( transfer ); + } + break; + case LibUsb.TRANSFER_CANCELLED: + /* free the transfer and remove it */ + LibUsb.freeTransfer( transfer ); + mTransfers.remove( transfer ); + break; + default: + /* unexpected error */ + mLog.error( "transfer error [" + + getTransferStatus( transfer.status() ) + + "] transferred actual: " + transfer.actualLength() ); + } + } + + private void cancel() + { + for( Transfer transfer: mTransfers ) + { + LibUsb.cancelTransfer( transfer ); + } + + ByteBuffer completed = ByteBuffer.allocateDirect( 4 ); + + int result = LibUsb.handleEventsTimeoutCompleted( + null, TIMEOUT_US, completed.asIntBuffer() ); + + if( result != LibUsb.SUCCESS ) + { + mLog.error( "error handling usb events during cancel [" + + LibUsb.errorName( result ) + "]" ); + } + } + + /** + * Prepares (allocates) a set of transfer buffers for use in + * transferring data from the tuner via the bulk interface + */ + private void prepareTransfers() throws LibUsbException + { + mTransfers = new ArrayList(); + + for( int x = 0; x < TRANSFER_BUFFER_POOL_SIZE; x++ ) + { + Transfer transfer = LibUsb.allocTransfer(); + + if( transfer == null ) + { + throw new LibUsbException( "couldn't allocate transfer", + LibUsb.ERROR_NO_MEM ); + } + + final ByteBuffer buffer = + ByteBuffer.allocateDirect( mBufferSize ); + + LibUsb.fillBulkTransfer( transfer, + mDeviceHandle, + BULK_ENDPOINT_IN, + buffer, + BufferProcessor.this, + "Buffer #" + x, + TIMEOUT_US ); + + mTransfers.add( transfer ); + } + } } /** @@ -1718,16 +1612,41 @@ public abstract class RTL2832TunerController extends TunerController { ArrayList buffers = new ArrayList(); - mRawSampleBuffer.drainTo( buffers ); - + mFilledBuffers.drainTo( buffers ); + for( byte[] buffer: buffers ) { + //TODO: convert this to float primitive Float[] samples = mSampleAdapter.convert( buffer ); + broadcast( samples ); } } } - + + public static String getTransferStatus( int status ) + { + switch( status ) + { + case 0: + return "TRANSFER COMPLETED (0)"; + case 1: + return "TRANSFER ERROR (1)"; + case 2: + return "TRANSFER TIMED OUT (2)"; + case 3: + return "TRANSFER CANCELLED (3)"; + case 4: + return "TRANSFER STALL (4)"; + case 5: + return "TRANSFER NO DEVICE (5)"; + case 6: + return "TRANSFER OVERFLOW (6)"; + default: + return "UNKNOWN TRANSFER STATUS (" + status + ")"; + } + } + /** * Averages the sample rate over a 10-second period. The count is for the * number of bytes received from the tuner. There are two bytes for each @@ -1778,7 +1697,6 @@ public abstract class RTL2832TunerController extends TunerController mSampleCounter.set( 0 ); mLog.info( "monitor reset for new sample rate [" + mTargetSampleRate + "]" ); - System.out.println( "monitor reset for new sample rate [" + mTargetSampleRate + "]" ); } else { @@ -1809,8 +1727,7 @@ public abstract class RTL2832TunerController extends TunerController } StringBuilder sb = new StringBuilder(); - sb.append( TimeStamp.getTimeStamp( " " ) ); - sb.append( " RTL-2832 [" ); + sb.append( "[" ); if( mDescriptor != null ) { sb.append( mDescriptor.getSerial() ); @@ -1823,12 +1740,10 @@ public abstract class RTL2832TunerController extends TunerController sb.append( mDecimalFormatter.format( current ) ); sb.append( " Hz " ); sb.append( mPercentFormatter.format( 100.0f * ( current / (float)mTargetSampleRate ) ) ); - sb.append( "% ] average error [" ); + sb.append( "% ] error [" ); sb.append( average ); sb.append( " Hz ] target " ); - sb.append( mTargetSampleRate ); - - System.out.println( sb.toString() ); + sb.append( mDecimalFormatter.format( mTargetSampleRate ) ); mLog.info( sb.toString() ); } @@ -2004,4 +1919,75 @@ public abstract class RTL2832TunerController extends TunerController return sb.toString(); } } + + public class USBEventHandlingThread implements Runnable + { + /** If thread should abort. */ + private volatile boolean mAbort; + + /** + * Aborts the event handling thread. + */ + public void abort() + { + mAbort = true; + } + + @Override + public void run() + { + while ( !mAbort ) + { + int result = LibUsb.handleEventsTimeout( null, 1000 ); + + if ( result != LibUsb.SUCCESS ) + { + mAbort = true; + + mLog.error( "error handling usb events [" + + LibUsb.errorName( result ) + "]" ); + + throw new LibUsbException("Unable to handle USB " + + "events", result ); + } + } + } + } + + public enum TunerTypeCheck + { + E4K( 0xC8, 0x02, 0x40 ), + FC0012( 0xC6, 0x00, 0xA1 ), + FC0013( 0xC6, 0x00, 0xA3 ), + FC2580( 0xAC, 0x01, 0x56 ), + R820T( 0x34, 0x00, 0x69 ), + R828D( 0x74, 0x00, 0x69 ); + + private int mI2CAddress; + private int mCheckAddress; + private int mCheckValue; + + private TunerTypeCheck( int i2c, int address, int value ) + { + mI2CAddress = i2c; + mCheckAddress = address; + mCheckValue = value; + } + + public byte getI2CAddress() + { + return (byte)mI2CAddress; + } + + public byte getCheckAddress() + { + return (byte)mCheckAddress; + } + + public byte getCheckValue() + { + return (byte)mCheckValue; + } + } + } diff --git a/src/source/tuner/rtl/e4k/E4KTunerConfigurationPanel.java b/src/source/tuner/rtl/e4k/E4KTunerConfigurationPanel.java index d9d675d3..cce675b4 100644 --- a/src/source/tuner/rtl/e4k/E4KTunerConfigurationPanel.java +++ b/src/source/tuner/rtl/e4k/E4KTunerConfigurationPanel.java @@ -46,6 +46,7 @@ import net.miginfocom.swing.MigLayout; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.usb4java.LibUsbException; import source.SourceException; import source.tuner.TunerConfiguration; @@ -258,7 +259,7 @@ public class E4KTunerConfigurationPanel extends JPanel mSelectedConfig.setSampleRate( sampleRate ); save(); } - catch ( SourceException | UsbException eSampleRate ) + catch ( SourceException | LibUsbException eSampleRate ) { JOptionPane.showMessageDialog( E4KTunerConfigurationPanel.this, diff --git a/src/source/tuner/rtl/e4k/E4KTunerController.java b/src/source/tuner/rtl/e4k/E4KTunerController.java index 76a0ba42..09577e01 100644 --- a/src/source/tuner/rtl/e4k/E4KTunerController.java +++ b/src/source/tuner/rtl/e4k/E4KTunerController.java @@ -17,37 +17,39 @@ ******************************************************************************/ package source.tuner.rtl.e4k; +import java.util.Arrays; + import javax.swing.JPanel; import javax.usb.UsbException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.usb4java.Device; +import org.usb4java.DeviceDescriptor; +import org.usb4java.DeviceHandle; +import org.usb4java.LibUsb; +import org.usb4java.LibUsbException; + import source.SourceException; import source.tuner.TunerConfiguration; import source.tuner.TunerType; import source.tuner.rtl.RTL2832TunerController; -import source.tuner.usb.USBTunerDevice; +import source.tuner.rtl.RTL2832TunerController.Descriptor; import controller.ResourceManager; public class E4KTunerController extends RTL2832TunerController { - /** - * Note: E4K tuner max frequency range is 2200 MHz, but the - * max value that can be assigned to a signed integer is - * 2147xxxxxx, so we constrain the E4K to the max integer value, for now - * - * TODO: change frequency to a long primitive type - */ - public static final long sMIN_FREQUENCY = 52000000; - public static final long sMIN_FREQUENCY_EXTENDED = 52000000; - public static final long sMAX_FREQUENCY = 2200000000l; - public static final long sMAX_FREQUENCY_EXTENDED = 2200000000l; - public static final long sMIN_VCO = 2600000000l; //2.6 GHz - public static final long sMAX_VCO = 3900000000l; //3.9 GHz + private final static Logger mLog = + LoggerFactory.getLogger( E4KTunerController.class ); + + public static final long MIN_FREQUENCY = 52000000; + public static final long MAX_FREQUENCY = 2200000000l; /* The local oscillator is defined by whole (integer) units of the oscillator * frequency and fractional units representing 1/65536th of the oscillator * frequency, meaning we can only tune the local oscillator in units of * 439.453125 hertz. */ - public static final long sE4K_PLL_Y = 65536l; /* 16-bit fractional register */ + public static final long E4K_PLL_Y = 65536l; /* 16-bit fractional register */ public static final byte MASTER1_RESET = (byte)0x01; public static final byte MASTER1_NORM_STBY = (byte)0x02; public static final byte MASTER1_POR_DET = (byte)0x04; @@ -108,9 +110,11 @@ public class E4KTunerController extends RTL2832TunerController private E4KTunerEditorPanel mEditor; - public E4KTunerController( USBTunerDevice device ) throws SourceException + public E4KTunerController( Device device, + DeviceDescriptor deviceDescriptor ) + throws SourceException { - super( device, sMIN_FREQUENCY, sMAX_FREQUENCY ); + super( device, deviceDescriptor, MIN_FREQUENCY, MAX_FREQUENCY ); } @Override @@ -166,24 +170,75 @@ public class E4KTunerController extends RTL2832TunerController public void init() throws SourceException { + mDeviceHandle = new DeviceHandle(); + + int result = LibUsb.open( mDevice, mDeviceHandle ); + + if( result != LibUsb.SUCCESS ) + { + mDeviceHandle = null; + + throw new SourceException( "libusb couldn't open RTL2832 usb " + + "device [" + LibUsb.errorName( result ) + "]" ); + } + + claimInterface( mDeviceHandle ); + + byte[] eeprom = null; + + try + { + /* Read the contents of the 256-byte EEPROM */ + eeprom = readEEPROM( mDeviceHandle, (short)0, 256 ); + } + catch( Exception e ) + { + mLog.error( "error while reading the EEPROM device descriptor", e ); + } + + try + { + mDescriptor = new Descriptor( eeprom ); + + if( eeprom == null ) + { + mLog.error( "eeprom byte array was null - constructed " + + "empty descriptor object" ); + } + } + catch( Exception e ) + { + mLog.error( "error while constructing device descriptor using " + + "descriptor byte array " + + ( eeprom == null ? "[null]" : Arrays.toString( eeprom )), e ); + } + try { /* Dummy write to test USB interface */ - writeRegister( mUSBDevice, Block.USB, + writeRegister( mDeviceHandle, Block.USB, Address.USB_SYSCTL.getAddress(), (short)0x09, 1 ); - initBaseband( mUSBDevice ); + initBaseband( mDeviceHandle ); - enableI2CRepeater( mUSBDevice, true ); + enableI2CRepeater( mDeviceHandle, true ); boolean i2CRepeaterControl = false; initTuner( i2CRepeaterControl ); - enableI2CRepeater( mUSBDevice, false ); + enableI2CRepeater( mDeviceHandle, false ); - /* Initialize the super class */ - super.init(); + try + { + setSampleRate( DEFAULT_SAMPLE_RATE ); + } + catch( Exception e ) + { + throw new SourceException( "RTL2832 Tuner Controller - couldn't " + + "set default sample rate", e ); + } + } catch( UsbException e ) { @@ -208,14 +263,14 @@ public class E4KTunerController extends RTL2832TunerController * for the selected bandwidth/sample rate */ @Override - public void setSampleRateFilters( int bandwidth ) throws UsbException + public void setSampleRateFilters( int bandwidth ) throws SourceException { /* Determine repeater state so we can restore it when done */ boolean i2CRepeaterEnabled = isI2CRepeaterEnabled(); if( !i2CRepeaterEnabled ) { - enableI2CRepeater( mUSBDevice, true ); + enableI2CRepeater( mDeviceHandle, true ); } boolean controlI2CRepeater = false; @@ -231,7 +286,7 @@ public class E4KTunerController extends RTL2832TunerController if( !i2CRepeaterEnabled ) { - enableI2CRepeater( mUSBDevice, false ); + enableI2CRepeater( mDeviceHandle, false ); } } @@ -245,7 +300,7 @@ public class E4KTunerController extends RTL2832TunerController if( !i2CRepeaterEnabled ) { - enableI2CRepeater( mUSBDevice, true ); + enableI2CRepeater( mDeviceHandle, true ); } boolean controlI2CRepeater = false; @@ -263,12 +318,12 @@ public class E4KTunerController extends RTL2832TunerController /* Return the repeater to its previous state */ if( !i2CRepeaterEnabled ) { - enableI2CRepeater( mUSBDevice, false ); + enableI2CRepeater( mDeviceHandle, false ); } return calculateActualFrequency( pll, z, x ); } - catch( UsbException e ) + catch( LibUsbException e ) { throw new SourceException( "E4K tuner controller - couldn't get " + "tuned frequency", e ); @@ -291,7 +346,7 @@ public class E4KTunerController extends RTL2832TunerController int remainder = (int)( frequency - ( ( z & 0xFF ) * pll.getScaledOscillator() ) ); /* X is a 16-bit representation of the remainder */ - int x = (int)( (double)remainder / (double)pll.getScaledOscillator() * sE4K_PLL_Y ); + int x = (int)( (double)remainder / (double)pll.getScaledOscillator() * E4K_PLL_Y ); /* Calculate the exact (tunable) frequency and apply that to the tuner */ long actualFrequency = calculateActualFrequency( pll, z, x ); @@ -310,7 +365,7 @@ public class E4KTunerController extends RTL2832TunerController /* Apply the actual frequency */ try { - enableI2CRepeater( mUSBDevice, true ); + enableI2CRepeater( mDeviceHandle, true ); boolean controlI2CRepeater = false; @@ -341,10 +396,10 @@ public class E4KTunerController extends RTL2832TunerController { throw new SourceException( "E4K tuner controller - couldn't " + "achieve PLL lock for frequency [" + - actualFrequency + "]" ); + actualFrequency + "] lock value [" + lock + "]" ); } - enableI2CRepeater( mUSBDevice, false ); + enableI2CRepeater( mDeviceHandle, false ); } catch( UsbException e ) { @@ -358,7 +413,7 @@ public class E4KTunerController extends RTL2832TunerController long whole = pll.getScaledOscillator() * ( z & 0xFF ); int fractional = (int)( pll.getScaledOscillator() * - ( (double)x / (double)sE4K_PLL_Y ) ); + ( (double)x / (double)E4K_PLL_Y ) ); return whole + fractional; } @@ -367,7 +422,7 @@ public class E4KTunerController extends RTL2832TunerController { if( controlI2CRepeater ) { - enableI2CRepeater( mUSBDevice, true ); + enableI2CRepeater( mDeviceHandle, true ); } boolean i2CRepeaterControl = false; @@ -473,7 +528,7 @@ public class E4KTunerController extends RTL2832TunerController if( controlI2CRepeater ) { - enableI2CRepeater( mUSBDevice, false ); + enableI2CRepeater( mDeviceHandle, false ); } } @@ -484,7 +539,7 @@ public class E4KTunerController extends RTL2832TunerController if( controlI2CRepeater ) { - enableI2CRepeater( mUSBDevice, true ); + enableI2CRepeater( mDeviceHandle, true ); } /* Capture current gain settings to reapply at the end */ @@ -548,7 +603,7 @@ public class E4KTunerController extends RTL2832TunerController if( controlI2CRepeater ) { - enableI2CRepeater( mUSBDevice, false ); + enableI2CRepeater( mDeviceHandle, false ); } } @@ -584,7 +639,7 @@ public class E4KTunerController extends RTL2832TunerController { if( controlI2CRepeater ) { - enableI2CRepeater( mUSBDevice, true ); + enableI2CRepeater( mDeviceHandle, true ); } if( gain == E4KLNAGain.AUTOMATIC ) @@ -610,7 +665,7 @@ public class E4KTunerController extends RTL2832TunerController if( controlI2CRepeater ) { - enableI2CRepeater( mUSBDevice, false ); + enableI2CRepeater( mDeviceHandle, false ); } } @@ -661,7 +716,7 @@ public class E4KTunerController extends RTL2832TunerController { if( controlI2CRepeater ) { - enableI2CRepeater( mUSBDevice, true ); + enableI2CRepeater( mDeviceHandle, true ); } boolean localI2CRepeaterControl = false; @@ -689,7 +744,7 @@ public class E4KTunerController extends RTL2832TunerController if( controlI2CRepeater ) { - enableI2CRepeater( mUSBDevice, false ); + enableI2CRepeater( mDeviceHandle, false ); } } @@ -810,7 +865,7 @@ public class E4KTunerController extends RTL2832TunerController } public void setMixerFilter( MixerFilter filter, - boolean controlI2CRepeater ) throws UsbException + boolean controlI2CRepeater ) throws LibUsbException { writeMaskedE4KRegister( MixerFilter.getRegister(), MixerFilter.getMask(), @@ -828,7 +883,7 @@ public class E4KTunerController extends RTL2832TunerController } public void setRCFilter( RCFilter filter, - boolean controlI2CRepeater ) throws UsbException + boolean controlI2CRepeater ) throws LibUsbException { writeMaskedE4KRegister( RCFilter.getRegister(), RCFilter.getMask(), @@ -844,7 +899,7 @@ public class E4KTunerController extends RTL2832TunerController } public void setChannelFilter( ChannelFilter filter, - boolean controlI2CRepeater ) throws UsbException + boolean controlI2CRepeater ) throws LibUsbException { writeMaskedE4KRegister( ChannelFilter.getRegister(), ChannelFilter.getMask(), @@ -885,7 +940,7 @@ public class E4KTunerController extends RTL2832TunerController { if( controlI2CRepeater ) { - enableI2CRepeater( mUSBDevice, true ); + enableI2CRepeater( mDeviceHandle, true ); } Band band = Band.fromFrequency( frequency ); @@ -914,7 +969,7 @@ public class E4KTunerController extends RTL2832TunerController if( controlI2CRepeater ) { - enableI2CRepeater( mUSBDevice, false ); + enableI2CRepeater( mDeviceHandle, false ); } } @@ -946,7 +1001,7 @@ public class E4KTunerController extends RTL2832TunerController { if( controlI2CRepeater ) { - enableI2CRepeater( mUSBDevice, true ); + enableI2CRepeater( mDeviceHandle, true ); } boolean i2CRepeaterControl = false; @@ -957,7 +1012,7 @@ public class E4KTunerController extends RTL2832TunerController if( controlI2CRepeater ) { - enableI2CRepeater( mUSBDevice, false ); + enableI2CRepeater( mDeviceHandle, false ); } } } @@ -969,7 +1024,7 @@ public class E4KTunerController extends RTL2832TunerController { if( controlI2CRepeater ) { - enableI2CRepeater( mUSBDevice, true ); + enableI2CRepeater( mDeviceHandle, true ); } writeE4KRegister( Register.MAGIC_1, (byte)0x01, false ); @@ -983,7 +1038,7 @@ public class E4KTunerController extends RTL2832TunerController if( controlI2CRepeater ) { - enableI2CRepeater( mUSBDevice, false ); + enableI2CRepeater( mDeviceHandle, false ); } } @@ -999,7 +1054,7 @@ public class E4KTunerController extends RTL2832TunerController private void writeMaskedE4KRegister( Register register, byte mask, byte value, - boolean controlI2CRepeater ) throws UsbException + boolean controlI2CRepeater ) throws LibUsbException { int temp = readE4KRegister( register, controlI2CRepeater ); @@ -1009,22 +1064,24 @@ public class E4KTunerController extends RTL2832TunerController writeE4KRegister( register, (byte)( ( temp & ~mask ) | ( value & mask ) ), controlI2CRepeater ); + + int temp2 = readE4KRegister( register, controlI2CRepeater ); } } private int readE4KRegister( Register register, - boolean controlI2CRepeater ) throws UsbException + boolean controlI2CRepeater ) throws LibUsbException { - return readI2CRegister( mUSBDevice, Register.I2C_REGISTER.getValue(), + return readI2CRegister( mDeviceHandle, Register.I2C_REGISTER.getValue(), register.getValue(), controlI2CRepeater ); } private void writeE4KRegister( Register register, byte value, - boolean controlI2CRepeater ) throws UsbException + boolean controlI2CRepeater ) throws LibUsbException { - writeI2CRegister( mUSBDevice, Register.I2C_REGISTER.getValue(), + writeI2CRegister( mDeviceHandle, Register.I2C_REGISTER.getValue(), register.getValue(), value, controlI2CRepeater ); } diff --git a/src/source/tuner/rtl/r820t/R820TTunerConfigurationPanel.java b/src/source/tuner/rtl/r820t/R820TTunerConfigurationPanel.java index 0fe7ce29..c80af5ab 100644 --- a/src/source/tuner/rtl/r820t/R820TTunerConfigurationPanel.java +++ b/src/source/tuner/rtl/r820t/R820TTunerConfigurationPanel.java @@ -46,6 +46,7 @@ import net.miginfocom.swing.MigLayout; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.usb4java.LibUsbException; import source.SourceException; import source.tuner.TunerConfiguration; @@ -252,7 +253,7 @@ public class R820TTunerConfigurationPanel extends JPanel mSelectedConfig.setSampleRate( sampleRate ); save(); } - catch ( SourceException | UsbException eSampleRate ) + catch ( SourceException | LibUsbException eSampleRate ) { JOptionPane.showMessageDialog( R820TTunerConfigurationPanel.this, @@ -308,7 +309,7 @@ public class R820TTunerConfigurationPanel extends JPanel { mController.setSampleRateFrequencyCorrection( value ); } - catch ( SourceException | UsbException e1 ) + catch ( SourceException | LibUsbException e1 ) { JOptionPane.showMessageDialog( R820TTunerConfigurationPanel.this, diff --git a/src/source/tuner/rtl/r820t/R820TTunerController.java b/src/source/tuner/rtl/r820t/R820TTunerController.java index e4852814..375a79b2 100644 --- a/src/source/tuner/rtl/r820t/R820TTunerController.java +++ b/src/source/tuner/rtl/r820t/R820TTunerController.java @@ -22,17 +22,21 @@ ******************************************************************************/ package source.tuner.rtl.r820t; +import java.nio.ByteBuffer; + import javax.swing.JPanel; import javax.usb.UsbException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.usb4java.Device; +import org.usb4java.DeviceDescriptor; +import org.usb4java.LibUsbException; import source.SourceException; import source.tuner.TunerConfiguration; import source.tuner.TunerType; import source.tuner.rtl.RTL2832TunerController; -import source.tuner.usb.USBTunerDevice; import controller.ResourceManager; public class R820TTunerController extends RTL2832TunerController @@ -68,9 +72,11 @@ public class R820TTunerController extends RTL2832TunerController private JPanel mEditor; - public R820TTunerController( USBTunerDevice device ) throws SourceException + public R820TTunerController( Device device, + DeviceDescriptor deviceDescriptor ) + throws SourceException { - super( device, MIN_FREQUENCY, MAX_FREQUENCY ); + super( device, deviceDescriptor, MIN_FREQUENCY, MAX_FREQUENCY ); } @Override @@ -80,7 +86,7 @@ public class R820TTunerController extends RTL2832TunerController } @Override - public void setSampleRateFilters( int sampleRate ) throws UsbException + public void setSampleRateFilters( int sampleRate ) throws LibUsbException { //TODO: why is this being forced as an abstract method on sub classes? } @@ -155,7 +161,7 @@ public class R820TTunerController extends RTL2832TunerController { try { - enableI2CRepeater( mUSBDevice, true ); + enableI2CRepeater( mDeviceHandle, true ); boolean controlI2C = false; @@ -165,7 +171,7 @@ public class R820TTunerController extends RTL2832TunerController setPLL( offsetFrequency, controlI2C ); - enableI2CRepeater( mUSBDevice, false ); + enableI2CRepeater( mDeviceHandle, false ); } catch( UsbException e ) { @@ -179,7 +185,7 @@ public class R820TTunerController extends RTL2832TunerController * Overrides the same method from the RTL2832 tuner controller to apply * settings specific to the R820T tuner. */ - public void setSamplingMode( SampleMode mode ) throws UsbException + public void setSamplingMode( SampleMode mode ) throws LibUsbException { switch( mode ) { @@ -188,14 +194,14 @@ public class R820TTunerController extends RTL2832TunerController setIFFrequency( R820T_IF_FREQUENCY ); /* Enable spectrum inversion */ - writeDemodRegister( mUSBDevice, + writeDemodRegister( mDeviceHandle, Page.ONE, (short)0x15, (short)0x01, 1 ); /* Set default i/q path */ - writeDemodRegister( mUSBDevice, + writeDemodRegister( mDeviceHandle, Page.ZERO, (short)0x06, (short)0x80, @@ -239,18 +245,16 @@ public class R820TTunerController extends RTL2832TunerController */ public void init() throws SourceException { + /* Initialize the super class to open and claim the usb interface*/ + super.init(); + try { - mLog.debug( "testing USB interface" ); - /* Dummy write to test USB interface */ - writeRegister( mUSBDevice, Block.USB, - Address.USB_SYSCTL.getAddress(), (short)0x09, 1 ); - mLog.debug( "initializing RTL2832 tuner baseband" ); - initBaseband( mUSBDevice ); + initBaseband( mDeviceHandle ); mLog.debug( "enabling I2C repeater" ); - enableI2CRepeater( mUSBDevice, true ); + enableI2CRepeater( mDeviceHandle, true ); boolean i2CRepeaterControl = false; @@ -258,11 +262,9 @@ public class R820TTunerController extends RTL2832TunerController initTuner( i2CRepeaterControl ); mLog.debug( "disabling I2C repeater" ); - enableI2CRepeater( mUSBDevice, false ); + enableI2CRepeater( mDeviceHandle, false ); mLog.debug( "initializing RTL2832 tuner controller super class" ); - /* Initialize the super class */ - super.init(); } catch( UsbException e ) { @@ -276,14 +278,14 @@ public class R820TTunerController extends RTL2832TunerController public void initTuner( boolean controlI2C ) throws UsbException { /* Disable zero IF mode */ - writeDemodRegister( mUSBDevice, + writeDemodRegister( mDeviceHandle, Page.ONE, (short)0xB1, (short)0x1A, 1 ); /* Only enable in-phase ADC input */ - writeDemodRegister( mUSBDevice, + writeDemodRegister( mDeviceHandle, Page.ZERO, (short)0x08, (short)0x4D, @@ -293,7 +295,7 @@ public class R820TTunerController extends RTL2832TunerController setIFFrequency( R820T_IF_FREQUENCY ); /* Enable spectrum inversion */ - writeDemodRegister( mUSBDevice, + writeDemodRegister( mDeviceHandle, Page.ONE, (short)0x15, (short)0x01, @@ -570,7 +572,7 @@ public class R820TTunerController extends RTL2832TunerController { for( int x = 5; x < mShadowRegister.length; x++ ) { - writeI2CRegister( mUSBDevice, + writeI2CRegister( mDeviceHandle, mI2CAddress, (byte)x, (byte)mShadowRegister[ x ], @@ -583,11 +585,11 @@ public class R820TTunerController extends RTL2832TunerController */ private int getStatusRegister( int register, boolean controlI2C ) throws UsbException { - byte[] data = new byte[ 5 ]; + ByteBuffer buffer = ByteBuffer.allocateDirect( 5 ); - byte[] statusRegisters = read( mUSBDevice, Block.IIC, mI2CAddress, data ); + read( mDeviceHandle, mI2CAddress, Block.I2C, buffer ); - return bitReverse( statusRegisters[ register ] & 0xFF ); + return bitReverse( buffer.get( register ) & 0xFF ); } /** @@ -615,7 +617,7 @@ public class R820TTunerController extends RTL2832TunerController ( value & register.getMask() ) ); } - writeI2CRegister( mUSBDevice, mI2CAddress, + writeI2CRegister( mDeviceHandle, mI2CAddress, (byte)register.getRegister(), value, controlI2C ); mShadowRegister[ register.getRegister() ] = value; @@ -631,7 +633,7 @@ public class R820TTunerController extends RTL2832TunerController public int readR820TRegister( Register register, boolean controlI2C ) throws UsbException { - int value = readI2CRegister( mUSBDevice, + int value = readI2CRegister( mDeviceHandle, mI2CAddress, (byte)register.getRegister(), controlI2C );