diff --git a/src/source/tuner/rtl/RTL2832TunerController.java b/src/source/tuner/rtl/RTL2832TunerController.java index 3beba1bd..4341e301 100644 --- a/src/source/tuner/rtl/RTL2832TunerController.java +++ b/src/source/tuner/rtl/RTL2832TunerController.java @@ -265,9 +265,6 @@ public abstract class RTL2832TunerController extends TunerController switch( mode ) { case QUADRATURE: -// /* Initialize the tuner */ -// initTuner(); - /* Set intermediate frequency to 0 Hz */ setIFFrequency( 0 ); @@ -1335,14 +1332,13 @@ public abstract class RTL2832TunerController extends TunerController /* Note: sample rates below 1.0MHz are subject to aliasing */ RATE_0_240MHZ( 0x0DFC, 0x0000, 240000, "0.240 MHz" ), RATE_0_288MHZ( 0x08FC, 0x0000, 288000, "0.288 MHz" ), - RATE_0_912MHZ( 0x07E6, 0x0000, 912000, "0.912 MHz" ), - RATE_0_960MHZ( 0x0780, 0x0000, 960000, "0.960 MHz" ), + RATE_0_960MHZ( 0x077A, 0x0000, 960000, "0.960 MHz" ), RATE_1_200MHZ( 0x05F4, 0x0000, 1200000, "1.200 MHz" ), RATE_1_440MHZ( 0x0500, 0x0000, 1440000, "1.440 MHz" ), RATE_1_680MHZ( 0x044A, 0x0000, 1680000, "1.680 MHz" ), RATE_1_824MHZ( 0x03F3, 0x0000, 1824000, "1.824 MHz" ), - RATE_2_016MHZ( 0x038E, 0x0000, 2016000, "2.016 MHz" ); + RATE_2_016MHZ( 0x0387, 0x0000, 2016000, "2.016 MHz" ); /* Note: usb4java library buffer processing scheme doesn't seem capable * of supporting these rates */ diff --git a/src/source/tuner/rtl/r820t/R820TTunerConfigurationPanel.java b/src/source/tuner/rtl/r820t/R820TTunerConfigurationPanel.java index e3ae5d24..1ce639eb 100644 --- a/src/source/tuner/rtl/r820t/R820TTunerConfigurationPanel.java +++ b/src/source/tuner/rtl/r820t/R820TTunerConfigurationPanel.java @@ -288,17 +288,14 @@ public class R820TTunerConfigurationPanel extends JPanel if( gain == R820TGain.MANUAL ) { - mComboMixerGain.setSelectedItem( - mController.getMixerGain( true ) ); + mComboMixerGain.setSelectedItem( gain.getMixerGain() ); mComboMixerGain.setEnabled( true ); - mComboLNAGain.setSelectedItem( - mController.getLNAGain( true ) ); + mComboLNAGain.setSelectedItem( gain.getLNAGain() ); mComboLNAGain.setEnabled( true ); + mComboVGAGain.setSelectedItem( gain.getVGAGain() ); mComboVGAGain.setEnabled( true ); - mComboVGAGain.setSelectedItem( - mController.getVGAGain( true ) ); } else { diff --git a/src/source/tuner/rtl/r820t/R820TTunerController.java b/src/source/tuner/rtl/r820t/R820TTunerController.java index a0b55cd8..ad3cd08f 100644 --- a/src/source/tuner/rtl/r820t/R820TTunerController.java +++ b/src/source/tuner/rtl/r820t/R820TTunerController.java @@ -30,8 +30,6 @@ import source.SourceException; import source.tuner.TunerConfiguration; import source.tuner.TunerType; import source.tuner.rtl.RTL2832TunerController; -import source.tuner.rtl.RTL2832TunerController.Address; -import source.tuner.rtl.RTL2832TunerController.Block; import source.tuner.usb.USBTunerDevice; import controller.ResourceManager; @@ -39,21 +37,32 @@ public class R820TTunerController extends RTL2832TunerController { public static final int MIN_FREQUENCY = 24000000; public static final int MAX_FREQUENCY = 1766000000; + public static final int R820T_IF_FREQUENCY = 3570000; public static final byte VERSION = (byte)49; - private byte mI2CAddress = (byte)0x34; - - /* Shadow register is used to keep a cached copy of all registers, so that - * we don't have to read a full byte from a register in order to apply a - * masked value and then re-write the full byte. With the shadow register, - * we can apply the masked value to the cached value, and then just write - * the masked byte, skipping the need to read the byte first. */ + public static final byte[] BIT_REV_LOOKUP_TABLE = + { (byte)0x0, (byte)0x8, (byte)0x4, (byte)0xC, + (byte)0x2, (byte)0xA, (byte)0x6, (byte)0xE, + (byte)0x1, (byte)0x9, (byte)0x5, (byte)0xD, + (byte)0x3, (byte)0xB, (byte)0x7, (byte)0xF }; + + /* R820T I2C address */ + private byte mI2CAddress = (byte)0x34; + + /* Shadow register is used to keep a cached (in-memory) copy of all + * registers, so that we don't have to read a full byte from a register in + * order to apply a masked value and then re-write the full byte. With the + * shadow register, we can apply the masked value to the cached value, and + * then just write the masked byte, skipping the need to read the byte + * first. */ private int[] mShadowRegister = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x32, 0x75, 0xC0, 0x40, 0xD6, 0x6C, 0xF5, 0x63, 0x75, 0x68, 0x6C, 0x83, 0x80, 0x00, 0x0F, 0x00, 0xC0, 0x30, 0x48, 0xCC, 0x60, 0x00, 0x54, 0xAE, 0x4A, 0xC0 }; + private JPanel mEditor; + public R820TTunerController( USBTunerDevice device ) throws SourceException { super( device, MIN_FREQUENCY, MAX_FREQUENCY ); @@ -68,7 +77,7 @@ public class R820TTunerController extends RTL2832TunerController @Override public void setSampleRateFilters( int sampleRate ) throws UsbException { - //TODO: why is this being forced as an abstract method? + //TODO: why is this being forced as an abstract method on sub classes? } @Override @@ -110,21 +119,35 @@ public class R820TTunerController extends RTL2832TunerController } } + /** + * Controller gui editor component for this tuner + */ public JPanel getEditor( ResourceManager resourceManager ) { - return new R820TTunerEditorPanel( this, resourceManager ); + if( mEditor == null ) + { + mEditor = new R820TTunerEditorPanel( this, resourceManager ); + } + + return mEditor; } - + + /** + * Not implemented. + */ @Override public int getTunedFrequency() throws SourceException { return 0; } + /** + * Sets the center frequency. Setting the frequency is a two-part process + * of setting the multiplexer and then setting the Oscillator (PLL). + */ @Override public void setTunedFrequency( int frequency ) throws SourceException { - Log.info( "R820T - setting frequency to " + frequency ); try { enableI2CRepeater( mUSBDevice, true ); @@ -143,9 +166,43 @@ public class R820TTunerController extends RTL2832TunerController + "while setting frequency [" + frequency + "] - " + e.getLocalizedMessage() ); } - } - + + /** + * Overrides the same method from the RTL2832 tuner controller to apply + * settings specific to the R820T tuner. + */ + public void setSamplingMode( SampleMode mode ) throws UsbException + { + switch( mode ) + { + case QUADRATURE: + /* Set intermediate frequency to R820T IF frequency */ + setIFFrequency( R820T_IF_FREQUENCY ); + + /* Enable spectrum inversion */ + writeDemodRegister( mUSBDevice, + Page.ONE, + (short)0x15, + (short)0x01, + 1 ); + + /* Set default i/q path */ + writeDemodRegister( mUSBDevice, + Page.ZERO, + (short)0x06, + (short)0x80, + 1 ); + break; + default: + break; + + } + } + + /** + * Sets the multiplexer for the desired center frequency. + */ private void setMux( int frequency, boolean controlI2C ) throws UsbException { FrequencyRange range = FrequencyRange.getRangeForFrequency( frequency ); @@ -169,7 +226,10 @@ public class R820TTunerController extends RTL2832TunerController /* Register 9 - what is it? */ writeR820TRegister( Register.UNKNOWN_REGISTER_9, (byte)0x00, controlI2C ); } - + + /** + * Initializes the tuner for use. + */ public void init() throws SourceException { try @@ -198,16 +258,41 @@ public class R820TTunerController extends RTL2832TunerController + "init()", e ); } } - + + /** + * Initializes the tuner section. + */ public void initTuner( boolean controlI2C ) throws UsbException { + /* Disable zero IF mode */ + writeDemodRegister( mUSBDevice, + Page.ONE, + (short)0xB1, + (short)0x1A, + 1 ); + + /* Only enable in-phase ADC input */ + writeDemodRegister( mUSBDevice, + Page.ZERO, + (short)0x08, + (short)0x4D, + 1 ); + + /* Set intermediate frequency to R820T IF frequency (3.57 MHz) */ + setIFFrequency( R820T_IF_FREQUENCY ); + + /* Enable spectrum inversion */ + writeDemodRegister( mUSBDevice, + Page.ONE, + (short)0x15, + (short)0x01, + 1 ); + initializeRegisters( controlI2C ); setTVStandard( controlI2C ); systemFrequencySelect( 0, controlI2C ); - - getGain(); } /** @@ -216,7 +301,6 @@ public class R820TTunerController extends RTL2832TunerController */ private void setTVStandard( boolean controlI2C ) throws UsbException { - Log.info( "Setting TV Standard" ); /* Init Flag & Xtal check Result */ writeR820TRegister( Register.XTAL_CHECK, (byte)0x00, controlI2C ); @@ -239,7 +323,7 @@ public class R820TTunerController extends RTL2832TunerController /* XTAL capacitor 0pF for PLL */ writeR820TRegister( Register.PLL_XTAL_CAPACITOR, (byte)0x00, controlI2C ); - setPLL( 5600 * 1000, controlI2C ); + setPLL( 56000 * 1000, controlI2C ); /* Start trigger */ writeR820TRegister( Register.CALIBRATION_TRIGGER, (byte)0x10, controlI2C ); @@ -252,16 +336,9 @@ public class R820TTunerController extends RTL2832TunerController calibrationCode = getCalibrationCode( controlI2C ); - if( calibrationSuccessful( calibrationCode ) ) + if( !calibrationSuccessful( calibrationCode ) ) { - Log.info( "Calibration successful!!" ); - - - break; - } - else - { - Log.info( "Calibration NOT successful!!" ); + Log.error( "Calibration NOT successful!!" ); } } @@ -271,6 +348,9 @@ public class R820TTunerController extends RTL2832TunerController } /* Write calibration code */ + byte filt_q = 0x10; + calibrationCode = calibrationCode | filt_q; + writeR820TRegister( Register.FILTER_CALIBRATION_CODE, (byte)calibrationCode, controlI2C ); @@ -298,28 +378,32 @@ public class R820TTunerController extends RTL2832TunerController /* RF poly filter current */ writeR820TRegister( Register.RF_POLY_FILTER_CURRENT, (byte)0x60, controlI2C ); - - Log.info( "Done Setting TV Standard" ); } - + + /** + * Indicates if a calibration request was successful. + */ private boolean calibrationSuccessful( int calibrationCode ) { return calibrationCode != 0 && calibrationCode != 0x0F; } - + + /** + * Returns the calibration code resulting from a calibration request. + */ private int getCalibrationCode( boolean controlI2C ) throws UsbException { return getStatusRegister( 4, controlI2C ) & 0x0F; } - + + /** + * Sets the system IF frequency + */ private void systemFrequencySelect( int frequency, boolean controlI2C ) throws UsbException { - /* Set pre_detect to off */ - writeR820TRegister( Register.PRE_DETECT, (byte)0x00, controlI2C ); - /* LNA top? */ - writeR820TRegister( Register.LNA_TOP, (byte)0xE5, controlI2C ); + writeR820TRegister( Register.LNA_TOP2, (byte)0xE5, controlI2C ); byte mixer_top; byte cp_cur; @@ -344,7 +428,7 @@ public class R820TTunerController extends RTL2832TunerController writeR820TRegister( Register.LNA_VTH_L, (byte)0x53, controlI2C ); - writeR820TRegister( Register.MIXER_VTH_L, (byte)0x76, controlI2C ); + writeR820TRegister( Register.MIXER_VTH_L, (byte)0x75, controlI2C ); /* Air-In only for Astrometa */ writeR820TRegister( Register.AIR_CABLE1_INPUT_SELECTOR, (byte)0x00, controlI2C ); @@ -356,25 +440,40 @@ public class R820TTunerController extends RTL2832TunerController writeR820TRegister( Register.DIVIDER_BUFFER_CURRENT, div_buf_cur, controlI2C ); writeR820TRegister( Register.FILTER_CURRENT, (byte)0x40, controlI2C ); + + /* if( type != TUNER_ANALOG_TV ) ... */ - /* Set LNA - omitted, because this is redundant to first 2 writes */ + writeR820TRegister( Register.LNA_TOP, (byte)0x00, controlI2C ); + + writeR820TRegister( Register.MIXER_TOP2, (byte)0x00, controlI2C ); - /* Write discharge mode */ + writeR820TRegister( Register.PRE_DETECT, (byte)0x00, controlI2C ); + + writeR820TRegister( Register.AGC_CLOCK, (byte)0x30, controlI2C ); + + writeR820TRegister( Register.LNA_TOP, (byte)0x18, controlI2C ); + writeR820TRegister( Register.MIXER_TOP2, mixer_top, controlI2C ); - + /* LNA discharge current */ writeR820TRegister( Register.LNA_DISCHARGE_CURRENT, (byte)0x14, controlI2C ); /* AGC clock 1 khz, external det1 cap 1u */ - writeR820TRegister( Register.AGC_CLOCK, (byte)0x00, controlI2C ); - - writeR820TRegister( Register.UNKNOWN_REGISTER_10, (byte)0x00, controlI2C ); + writeR820TRegister( Register.AGC_CLOCK, (byte)0x20, controlI2C ); } + /** + * Sets the tuner's Phase-Locked-Loop (PLL) oscillator used for frequency + * (tuning) control + * + * @param frequency - desired center frequency + * @param controlI2C - control the I2C repeater locally + * @throws UsbException - if unable to set any of the R820T registers + */ private void setPLL( int frequency, boolean controlI2C ) throws UsbException { /* Set reference divider to 0 */ - writeR820TRegister( Register.PLL_XTAL_CAPACITOR, (byte)0x00, controlI2C ); + writeR820TRegister( Register.REFERENCE_DIVIDER_2, (byte)0x00, controlI2C ); /* Set PLL autotune to 128kHz */ writeR820TRegister( Register.PLL_AUTOTUNE, (byte)0x00, controlI2C ); @@ -382,8 +481,7 @@ public class R820TTunerController extends RTL2832TunerController /* Set VCO current to 100 */ writeR820TRegister( Register.VCO_CURRENT, (byte)0x80, controlI2C ); - /* Calculate divider */ - int mix_div =2; + int mix_div = 2; int div_buf = 0; int div_num = 0; int vco_min = 1770000; @@ -392,7 +490,6 @@ public class R820TTunerController extends RTL2832TunerController int freq_khz = (int)( ( frequency + 500 ) / 1000 ); int pll_ref = mOscillatorFrequency; - int pll_ref_khz = ( mOscillatorFrequency + 500 ) / 1000; while( mix_div <= 64 ) { @@ -407,17 +504,17 @@ public class R820TTunerController extends RTL2832TunerController div_buf = div_buf >> 1; div_num++; } - break; + break; } mix_div = mix_div << 1; } int statusRegister4 = getStatusRegister( 4, controlI2C ); - + int vco_fine_tune = ( statusRegister4 & 0x30 ) >> 4; - + if( vco_fine_tune > vco_power_ref ) { div_num--; @@ -430,52 +527,61 @@ public class R820TTunerController extends RTL2832TunerController writeR820TRegister( Register.DIVIDER, (byte)( div_num << 5 ), controlI2C ); long vco_freq = (long)frequency * (long)mix_div; - - int nint = (int)( vco_freq / ( 2 * pll_ref ) ); - int vco_fra = (int)( ( vco_freq - ( 2 * pll_ref * nint ) ) / 1000 ); + int nint = (int)( vco_freq / ( 2L * (long)pll_ref ) ); + + long integral = 2l * (long)pll_ref * (long)nint; + + int vco_fra = (int)( ( vco_freq - integral ) / 1000 ); if( nint > (( 128 / vco_power_ref ) - 1 ) ) { - Log.error( "R820T Tuner Controller - no valid PLL value for frequency [" + frequency + "]" ); + Log.error( "R820T Tuner Controller - no valid PLL value for " + + "frequency [" + frequency + "]" ); } int ni = ( nint - 13 ) / 4; - int si = nint - ( 4 * ni ) - 13; - - writeR820TRegister( Register.UNKNOWN_REGISTER_14, (byte)ni, controlI2C ); - /* PW_SDM */ - if( vco_fra > 0 ) + /* Note: this deviates from the original by adding 1 to the si value. + * Testing (wireshark USB packet captures) indicated that this driver + * was setting the si value one lower than what the c++ version was + * setting ... an error introduced through primitive casting I think. */ + int si = ( nint - ( 4 * ni ) - 13 ) + 1; + + int register14 = ni + ( si << 6 ); + + writeR820TRegister( Register.PLL, (byte)register14, controlI2C ); + + /** + * Sigma-Delta Modulator - fractional PLL + * + * The sdm value represents the leftover or fractional part of a + * divided mixer unit ( 2 * XTAL frequency in kHz = 57600 ) that + * remains after we set the number of integral divided mixer units in + * register 14. + */ + + if( vco_fra == 0 ) /* Do we need fractional PLL? */ { - writeR820TRegister( Register.PW_SDM, (byte)0x08, controlI2C ); + /* Turn off sigma-delta modulator */ + writeR820TRegister( Register.SIGMA_DELTA_MODULATOR_POWER, + (byte)0x08, controlI2C ); } else { - writeR820TRegister( Register.PW_SDM, (byte)0x00, controlI2C ); + /* Turn on sigma-delta modulator */ + writeR820TRegister( Register.SIGMA_DELTA_MODULATOR_POWER, + (byte)0x00, controlI2C ); } - /* sdm calculator */ - int n_sdm = 2; - int sdm = 0; + /* Sigma-delta modulator fractional PLL setting */ + int sdm = (int)( ( ( ( (long)vco_freq << 16 ) + (long)pll_ref ) / + (long)( 2 * pll_ref ) ) & 0xFFFF ); - while( vco_fra > 1 ) - { - if( vco_fra > ( 2 * pll_ref_khz / n_sdm ) ) - { - sdm+= 32768 / ( n_sdm / 2 ); - vco_fra -= 2 * pll_ref_khz / n_sdm; - if( n_sdm >= 0x8000 ) - { - break; - } - } - - n_sdm <<= 1; - } - - writeR820TRegister( Register.SDM_MSB, (byte)( sdm >> 8 ), controlI2C ); - writeR820TRegister( Register.SDM_LSB, (byte)( sdm & 0xFF ), controlI2C ); + writeR820TRegister( Register.SIGMA_DELTA_MODULATOR_MSB, + (byte)( ( sdm >> 8 ) & 0xFF ), controlI2C ); + writeR820TRegister( Register.SIGMA_DELTA_MODULATOR_LSB, + (byte)( sdm & 0xFF ), controlI2C ); if( !isPLLLocked( controlI2C ) ) { @@ -490,12 +596,13 @@ public class R820TTunerController extends RTL2832TunerController } /* set pll autotune to 8kHz */ - writeR820TRegister( Register.PLL_AUTOTUNE, (byte)0x08, controlI2C ); + writeR820TRegister( Register.PLL_AUTOTUNE_VARIANT, (byte)0x08, controlI2C ); } /** - * Indicates if the Phase Locked Loop (PLL) is locked. Checks status - * register 2 to see if the PLL locked indicator bit is set. + * Indicates if the Phase Locked Loop (PLL) oscillator is locked following + * a change in the tuned center frequency. Checks status register 2 to see + * if the PLL locked indicator bit is set. */ private boolean isPLLLocked( boolean controlI2C ) throws UsbException { @@ -521,20 +628,32 @@ public class R820TTunerController extends RTL2832TunerController controlI2C ); } } - + + /** + * Returns the contents of status registers 0 through 4 + */ private int getStatusRegister( int register, boolean controlI2C ) throws UsbException { - if( 0 <= register && register <= 4 ) - { - return readI2CRegister( mUSBDevice, mI2CAddress, (byte)register, controlI2C ); - } - else - { - throw new IllegalArgumentException( "R820T Tuner Controller - " - + "attempt to read unknown status register #" + register ); - } + byte[] data = new byte[ 5 ]; + + byte[] statusRegisters = read( mUSBDevice, Block.IIC, mI2CAddress, data ); + + return bitReverse( statusRegisters[ register ] & 0xFF ); } + /** + * Assumes value is a byte value and reverses the bits in the byte. + */ + private static int bitReverse( int value ) + { + return BIT_REV_LOOKUP_TABLE[ value & 0x0F ] << 4 | + BIT_REV_LOOKUP_TABLE[ ( value & 0xF0 ) >> 4 ]; + } + + /** + * Writes the byte value to the specified register, optionally controlling + * the I2C repeater as needed. + */ public void writeR820TRegister( Register register, byte value, boolean controlI2C ) throws UsbException @@ -549,30 +668,28 @@ public class R820TTunerController extends RTL2832TunerController writeI2CRegister( mUSBDevice, mI2CAddress, (byte)register.getRegister(), value, controlI2C ); - + mShadowRegister[ register.getRegister() ] = value; } - + + /** + * Reads the specified register, optionally controlling the I2C repeater + */ public int readR820TRegister( Register register, boolean controlI2C ) throws UsbException { - return readI2CRegister( mUSBDevice, + int value = readI2CRegister( mUSBDevice, mI2CAddress, (byte)register.getRegister(), controlI2C ); + + return value; } - private void getGain() throws UsbException - { - int gain = getStatusRegister( 3, true ); - - Log.info( "Gain original value is [" + gain + "]" ); - - int converted = ( ( gain & 0x0F ) << 1 ) + ( ( gain & 0xF0 ) >> 4 ); - - Log.info( "Gain converted value is [" + converted + "]" ); - } - + /** + * Sets master gain by applying gain component values to LNA, Mixer and + * VGA gain registers. + */ public void setGain( R820TGain gain, boolean controlI2C ) throws UsbException { setLNAGain( gain.getLNAGain(), controlI2C ); @@ -580,36 +697,33 @@ public class R820TTunerController extends RTL2832TunerController setVGAGain( gain.getVGAGain(), controlI2C ); } + /** + * Sets LNA gain + */ public void setLNAGain( R820TLNAGain gain, boolean controlI2C ) throws UsbException { writeR820TRegister( Register.LNA_GAIN, gain.getSetting(), controlI2C ); } - - public R820TLNAGain getLNAGain( boolean controlI2C ) throws UsbException - { - return null; - } - + + /** + * Sets Mixer gain + */ public void setMixerGain( R820TMixerGain gain, boolean controlI2C ) throws UsbException { writeR820TRegister( Register.MIXER_GAIN, gain.getSetting(), controlI2C ); } - - public R820TMixerGain getMixerGain( boolean controlI2C ) throws UsbException - { - return null; - } - + + /** + * Sets VGA gain + */ public void setVGAGain( R820TVGAGain gain, boolean controlI2C ) throws UsbException { writeR820TRegister( Register.VGA_GAIN, gain.getSetting(), controlI2C ); } - public R820TVGAGain getVGAGain( boolean controlI2C ) throws UsbException - { - return null; - } - + /** + * R820T VGA gain settings + */ public enum R820TVGAGain { GAIN_0( "0", 0x00 ), @@ -648,7 +762,10 @@ public class R820TTunerController extends RTL2832TunerController return (byte)mSetting; } } - + + /** + * R820T Low Noise Amplifier gain settings + */ public enum R820TLNAGain { AUTOMATIC( "Automatic", 0x00 ), @@ -689,6 +806,9 @@ public class R820TTunerController extends RTL2832TunerController } } + /** + * R820T mixer gain settings + */ public enum R820TMixerGain { AUTOMATIC( "Automatic", 0x10 ), @@ -729,10 +849,13 @@ public class R820TTunerController extends RTL2832TunerController } } + /** + * R820T Master gain settings + */ public enum R820TGain { AUTOMATIC( "Automatic", R820TVGAGain.GAIN_312, R820TLNAGain.AUTOMATIC, R820TMixerGain.AUTOMATIC ), - MANUAL( "Manual", R820TVGAGain.GAIN_210, R820TLNAGain.GAIN_112, R820TMixerGain.GAIN_105 ), + MANUAL( "Manual", R820TVGAGain.GAIN_210, R820TLNAGain.GAIN_248, R820TMixerGain.GAIN_123 ), GAIN_0( "0", R820TVGAGain.GAIN_210, R820TLNAGain.GAIN_0, R820TMixerGain.GAIN_0 ), GAIN_9( "9", R820TVGAGain.GAIN_210, R820TLNAGain.GAIN_9, R820TMixerGain.GAIN_0 ), GAIN_14( "14", R820TVGAGain.GAIN_210, R820TLNAGain.GAIN_9, R820TMixerGain.GAIN_5 ), @@ -798,7 +921,9 @@ public class R820TTunerController extends RTL2832TunerController } } - + /** + * R820T tuner registers and register mask values + */ public enum Register { LNA_GAIN( 0x05, 0x1F ), @@ -829,16 +954,17 @@ public class R820TTunerController extends RTL2832TunerController CAPACITOR_SELECTOR( 0x10, 0x1B ), DIVIDER( 0x10, 0xE0 ), CP_CUR( 0x11, 0x38 ), - PW_SDM( 0x12, 0x08 ), + SIGMA_DELTA_MODULATOR_POWER( 0x12, 0x08 ), VCO_CURRENT( 0x12, 0xE0 ), VERSION( 0x13, 0x3F ), - UNKNOWN_REGISTER_14( 0x14, 0x0 ), - SDM_LSB( 0x15, 0x0 ), - SDM_MSB( 0x16, 0x0 ), + PLL( 0x14, 0x0 ), + SIGMA_DELTA_MODULATOR_LSB( 0x15, 0x0 ), + SIGMA_DELTA_MODULATOR_MSB( 0x16, 0x0 ), DRAIN( 0x17, 0x08 ), DIVIDER_BUFFER_CURRENT( 0x17, 0x30 ), RF_POLY_FILTER_CURRENT( 0x19, 0x60 ), PLL_AUTOTUNE( 0x1A, 0x0C ), + PLL_AUTOTUNE_VARIANT( 0x1A, 0x08 ), AGC_CLOCK( 0x1A, 0x30 ), RF_POLY_MUX( 0x1A, 0xC3 ), TF_BAND( 0x1B, 0x0 ), @@ -985,8 +1111,112 @@ public class R820TTunerController extends RTL2832TunerController public byte getXTALHighCap0P() { - return (byte)0x10; + return (byte)0x00; } } + /** + * Frequency Divider Values: + * + * div_num mix_div min - max + * 0 2 885.0000 - 1770.0000 MHz + * 1 4 442.5000 - 885.9999 MHz + * 2 8 221.2500 - 442.4999 MHz + * 3 16 110.6250 - 221.2499 MHz + * 4 32 55.3125 - 110.6249 MHz + * 5 64 27.65625 - 55.31249 MHz + */ + public enum FrequencyDivider + { + DIVIDER_0( 0, 2, 885000000, 1770000000, 0x00 ), + DIVIDER_1( 1, 4, 442500000, 884999999, 0x20 ), + DIVIDER_2( 2, 8, 221250000, 442499999, 0x40 ), + DIVIDER_3( 3, 16, 110625000, 221249999, 0x60 ), + DIVIDER_4( 4, 32, 55312500, 110624999, 0x80 ), + DIVIDER_5( 5, 64, 24000000, 55312499, 0xA0 ); + + private int mDividerNumber; + private int mMixerDivider; + private int mMinimumFrequency; + private int mMaximumFrequency; + private int mRegisterSetting; + private static final int mVCOPowerReference = 2; + + private FrequencyDivider( int dividerNumber, + int mixerDivider, + int minimumFrequency, + int maximumFrequency, + int registerSetting ) + { + mDividerNumber = dividerNumber; + mMixerDivider = mixerDivider; + mMinimumFrequency = minimumFrequency; + mMaximumFrequency = maximumFrequency; + mRegisterSetting = registerSetting; + } + + public int getDividerNumber( int vcoFineTune ) + { + if( vcoFineTune == mVCOPowerReference ) + { + return mDividerNumber; + } + else if( vcoFineTune < mVCOPowerReference ) + { + return mDividerNumber - 1; + } + else if( vcoFineTune > mVCOPowerReference ) + { + return mDividerNumber + 1; + } + + return mDividerNumber; + } + + public int getMixerDivider() + { + return mMixerDivider; + } + + public int getMinimumFrequency() + { + return mMinimumFrequency; + } + + public int getMaximumFrequency() + { + return mMaximumFrequency; + } + + public byte getRegisterSetting() + { + return (byte)mRegisterSetting; + } + + public boolean contains( int frequency ) + { + return mMinimumFrequency <= frequency && + frequency <= mMaximumFrequency; + } + + /** + * Returns the correct frequency divider for the specified frequency, + * or returns divider #5, if the frequency is outside of the specified + * frequency ranges. + * @param frequency - desired frequency + * @return - FrequencyDivider to use for the specified frequency + */ + public static FrequencyDivider fromFrequency( int frequency ) + { + for( FrequencyDivider divider: FrequencyDivider.values() ) + { + if( divider.contains( frequency ) ) + { + return divider; + } + } + + return FrequencyDivider.DIVIDER_5; + } + } }