diff --git a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKSymbolEvaluator.java b/src/main/java/io/github/dsheirer/dsp/psk/DQPSKSymbolEvaluator.java
index 16b9018d..cab0fd22 100644
--- a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKSymbolEvaluator.java
+++ b/src/main/java/io/github/dsheirer/dsp/psk/DQPSKSymbolEvaluator.java
@@ -32,7 +32,7 @@ public class DQPSKSymbolEvaluator implements IDQPSKSymbolEvaluator
private Dibit mSymbolDecision = Dibit.D00_PLUS_1;
/**
- * Data-directed symbol phase and timing error detector and symbol decision slicer.
+ * Decision-directed symbol phase and timing error detector and symbol decision slicer.
*
* Symbol decision is based on the closest reference quadrant for the sampled symbol.
*
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKSymbolPhaseErrorCalculator.java b/src/main/java/io/github/dsheirer/dsp/psk/DQPSKSymbolPhaseErrorCalculator.java
deleted file mode 100644
index 7eafb69a..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKSymbolPhaseErrorCalculator.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*******************************************************************************
- * sdr-trunk
- * Copyright (C) 2014-2018 Dennis Sheirer
- *
- * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with this program.
- * If not, see
- *
- ******************************************************************************/
-package io.github.dsheirer.dsp.psk;
-
-import io.github.dsheirer.sample.complex.Complex;
-
-public class DQPSKSymbolPhaseErrorCalculator extends QPSKSymbolPhaseErrorCalculator
-{
- //45 degrees rotation to orient the symbol to a polar axis to make error calculation easy/efficient
- public static final Complex DIFFERENTIAL_OFFSET = Complex.fromAngle(Math.PI / 4.0d);
- private Complex mSymbol = new Complex(0, 0);
-
- public DQPSKSymbolPhaseErrorCalculator()
- {
- }
-
- @Override
- public float getPhaseError(Complex symbol)
- {
- mSymbol.setValues(symbol);
- mSymbol.multiply(DIFFERENTIAL_OFFSET);
- return super.getPhaseError(mSymbol);
- }
-}
diff --git a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKTimingErrorDetector.java b/src/main/java/io/github/dsheirer/dsp/psk/DQPSKTimingErrorDetector.java
deleted file mode 100644
index 929e2b06..00000000
--- a/src/main/java/io/github/dsheirer/dsp/psk/DQPSKTimingErrorDetector.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*******************************************************************************
- * sdr-trunk
- * Copyright (C) 2014-2018 Dennis Sheirer
- *
- * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with this program.
- * If not, see
- *
- ******************************************************************************/
-package io.github.dsheirer.dsp.psk;
-
-import io.github.dsheirer.sample.complex.Complex;
-
-public class DQPSKTimingErrorDetector
-{
- private static final float PI_4_ROTATION = (float)(Math.PI / 4.0);
-
- /**
- * Custom early/late symbol timing error detector designed to optimize the sample timing point such that the
- * current symbol's inphase and quadrature approach the optimal 45 degree (.707) sampling instant.
- */
- public DQPSKTimingErrorDetector()
- {
- }
-
- /**
- * Calculates a symbol sampling time error by comparing the current complex sample against a normal QPSK or
- * Pi/4 rotated four symbol constellation. The error signal (advance/retard) is determined by the slope
- * of each of the inphase and quadrature legs as detected by comparing an immediately preceding sample against
- * the current sample and then calculating the error distance of the sampled symbol from the ideal Pi/4 sampling
- * location.
- *
- * Note: both the preceding and the current symbols MUST be normalized (ie symbol.normalize()) to the unit circle
- * prior to invoking this method.
- *
- * @param precedingSymbol
- * @param currentSymbol
- * @return timing error signal used to advance (positive) or retard (negative) the sampling point
- */
- public float getError(Complex precedingSymbol, Complex currentSymbol)
- {
- return getError(precedingSymbol.inphase(), currentSymbol.inphase()) +
- getError(precedingSymbol.quadrature(), currentSymbol.quadrature());
- }
-
- /**
- * Calculates timing error of current value relative to an ideal 45 degree or Pi/4 radians (.707) value.
- *
- * @param early sample that closely precedes the current sampling instant - used to determine slope
- * @param current sampling value
- * @return error as the distance of the current value from an ideal value and the sign (advance/retard)
- * appropriate for the detected slope
- */
- private float getError(float early, float current)
- {
- if(early < current) //Ascending slope
- {
- if(current > 0.0)
- {
- //Positive quadrature hemisphere, ascending slope
- return PI_4_ROTATION - current;
- }
- else
- {
- //Negative quadrature hemisphere, ascending slope
- return -PI_4_ROTATION - current;
- }
- }
- else //Descending slope
- {
- if(current > 0.0)
- {
- //Positive quadrature hemisphere, descending slope
- return current - PI_4_ROTATION;
- }
- else
- {
- //Negative quadrature hemisphere, descending slope
- return current + PI_4_ROTATION;
- }
- }
- }
-}
diff --git a/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/P25Phase1Pane.java b/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/P25Phase1Pane.java
index 1b3f31d9..526d3e7f 100644
--- a/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/P25Phase1Pane.java
+++ b/src/main/java/io/github/dsheirer/instrument/gui/viewer/decoder/P25Phase1Pane.java
@@ -22,7 +22,7 @@ import io.github.dsheirer.instrument.gui.viewer.chart.PhaseLineChart;
import io.github.dsheirer.instrument.gui.viewer.chart.SymbolChart;
import io.github.dsheirer.message.Message;
import io.github.dsheirer.module.decode.DecoderType;
-import io.github.dsheirer.module.decode.p25.P25_C4FMDecoder2Instrumented;
+import io.github.dsheirer.module.decode.p25.P25_C4FMDecoderInstrumented;
import io.github.dsheirer.sample.Broadcaster;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.ComplexBuffer;
@@ -44,7 +44,7 @@ public class P25Phase1Pane extends DecoderPane
private DoubleLineChart mPLLFrequencyLineChart;
private DoubleLineChart mSamplesPerSymbolLineChart;
private Broadcaster mFilteredBufferBroadcaster = new Broadcaster<>();
- private P25_C4FMDecoder2Instrumented mDecoder = new P25_C4FMDecoder2Instrumented(null);
+ private P25_C4FMDecoderInstrumented mDecoder = new P25_C4FMDecoderInstrumented(null);
public P25Phase1Pane()
{
@@ -90,7 +90,7 @@ public class P25Phase1Pane extends DecoderPane
getSampleLineChart().setSamplesPerSymbol((int)samplesPerSymbol);
}
- private P25_C4FMDecoder2Instrumented getDecoder()
+ private P25_C4FMDecoderInstrumented getDecoder()
{
return mDecoder;
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java b/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java
index 29dbcf5b..94ec4ae7 100644
--- a/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java
+++ b/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java
@@ -246,9 +246,7 @@ public class DecoderFactory
switch(modulation)
{
case C4FM:
- modules.add(new FMDemodulatorModule(P25_C4FM_IQ_FILTER));
- modules.add(new DemodulatedAudioFilterModule(P25_C4FM_DEMOD_FILTER, 1.0f));
- modules.add(new P25_C4FMDecoder(aliasList, decodeConfig.getAFCMaximumCorrection()));
+ modules.add(new P25_C4FMDecoder(aliasList));
modules.add(new P25DecoderState(aliasList, channelType, P25Decoder.Modulation.C4FM,
p25Config.getIgnoreDataCalls()));
break;
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25MessageFramer.java b/src/main/java/io/github/dsheirer/module/decode/p25/P25MessageFramer.java
index 4d38ed79..54047262 100644
--- a/src/main/java/io/github/dsheirer/module/decode/p25/P25MessageFramer.java
+++ b/src/main/java/io/github/dsheirer/module/decode/p25/P25MessageFramer.java
@@ -698,8 +698,7 @@ public class P25MessageFramer implements Listener
@Override
public void syncDetected()
{
- mLog.warn("Phase Inversion SYNC detected - applying correction: " + mCorrection);
-// mPhaseLockedLoop.correctInversion(mCorrection);
+ mPhaseLockedLoop.correctInversion(mCorrection);
/* Since we detected a sync pattern, start a message assembler */
for(P25MessageAssembler assembler : mAssemblers)
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoder.java b/src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoder.java
index c51a7adf..6923bc37 100644
--- a/src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoder.java
+++ b/src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoder.java
@@ -1,153 +1,200 @@
/*******************************************************************************
- * sdrtrunk
- * Copyright (C) 2014-2017 Dennis Sheirer
+ * sdr-trunk
+ * Copyright (C) 2014-2018 Dennis Sheirer
*
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see
*
******************************************************************************/
package io.github.dsheirer.module.decode.p25;
import io.github.dsheirer.alias.AliasList;
-import io.github.dsheirer.instrument.tap.TapGroup;
+import io.github.dsheirer.dsp.filter.FilterFactory;
+import io.github.dsheirer.dsp.filter.design.FilterDesignException;
+import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
+import io.github.dsheirer.dsp.filter.fir.complex.ComplexFIRFilter;
+import io.github.dsheirer.dsp.psk.DQPSKDemodulator;
+import io.github.dsheirer.dsp.psk.InterpolatingSampleBuffer;
+import io.github.dsheirer.dsp.psk.InterpolatingSampleBufferInstrumented;
+import io.github.dsheirer.dsp.psk.pll.CostasLoop;
import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.real.IFilteredRealBufferListener;
-import io.github.dsheirer.sample.real.RealBuffer;
+import io.github.dsheirer.sample.complex.ComplexBuffer;
+import io.github.dsheirer.sample.complex.IComplexBufferListener;
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
-public class P25_C4FMDecoder extends P25Decoder implements IFilteredRealBufferListener
+public class P25_C4FMDecoder extends P25Decoder implements IComplexBufferListener, Listener
{
- private final static Logger mLog = LoggerFactory.getLogger( P25_C4FMDecoder.class );
-
- /* Instrumentation Taps */
- private static final String INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT = "Tap Point: Symbol Filter Output";
- private static final String INSTRUMENT_C4FM_SLICER_OUTPUT = "Tap Point: C4FM Slicer Output";
+ private final static Logger mLog = LoggerFactory.getLogger(P25_C4FMDecoder.class);
+ protected static final double SYMBOL_RATE = 4800;
+ protected InterpolatingSampleBuffer mInterpolatingSampleBuffer;
+ protected DQPSKDemodulator mQPSKDemodulator;
+ protected CostasLoop mCostasLoop;
+ protected P25MessageFramer mMessageFramer;
+ protected double mSampleRate;
+ private Map mBasebandFilters = new HashMap<>();
+ private ComplexFIRFilter mBasebandFilter;
- private List mAvailableTaps;
- private C4FMSymbolFilter mSymbolFilter;
- private C4FMSlicer mC4FMSlicer;
- private P25MessageFramer mMessageFramer;
-
- /**
- * P25 Phase 1 C4FM Decoder processes real buffers of un-filtered,
- * demodulated audio and produces decoded P25 Phase 1 Messages.
- *
- * Provides Frequency Control to steer external tuner source and incorporates
- * internal gain control.
- *
- * Note: use the P25AudioModule to convert the decoded messages into audio.
- *
- * @param aliasList - optional (can be null) list of alias values for network
- * infrastructure and subscriber identities that will be included in each
- * decoded message
- */
- public P25_C4FMDecoder(AliasList aliasList, int frequencyCorrectionMaximum )
- {
- super( aliasList );
-
- /* Shape gain and frequency offsets to optimize sample stream */
- mSymbolFilter = new C4FMSymbolFilter( frequencyCorrectionMaximum );
+ public P25_C4FMDecoder(AliasList aliasList)
+ {
+ super(aliasList);
+ setSampleRate(48000.0);
+ }
- /* Convert samples to symbols */
- mC4FMSlicer = new C4FMSlicer();
- mSymbolFilter.setListener( mC4FMSlicer );
+ public void setSampleRate(double sampleRate)
+ {
+ if(sampleRate <= SYMBOL_RATE * 2)
+ {
+ throw new IllegalArgumentException("Sample rate must be at least twice the symbol rate [4800]");
+ }
- /* Sync pattern detection and message construction */
- mMessageFramer = new P25MessageFramer( aliasList );
- mC4FMSlicer.addListener( mMessageFramer );
-
- /* Process and broadcast messages */
- mMessageFramer.setListener( getMessageProcessor() );
- }
+ mSampleRate = sampleRate;
+ mBasebandFilter = new ComplexFIRFilter(getBasebandFilter(), 1.0f);
- @Override
- public void dispose()
- {
- super.dispose();
-
- mSymbolFilter.dispose();
- mSymbolFilter = null;
-
- mMessageFramer.dispose();
- mMessageFramer = null;
+ mCostasLoop = new CostasLoop(mSampleRate, SYMBOL_RATE);
- mC4FMSlicer.dispose();
- mC4FMSlicer = null;
- }
-
- public Modulation getModulation()
- {
- return Modulation.C4FM;
- }
-
- @Override
- public Listener getFilteredRealBufferListener()
- {
- return mSymbolFilter;
- }
-
- @Override
- public void reset()
- {
- // TODO Auto-generated method stub
-
- }
+ mInterpolatingSampleBuffer = new InterpolatingSampleBufferInstrumented((float)(sampleRate / SYMBOL_RATE));
+ mQPSKDemodulator = new DQPSKDemodulator(mCostasLoop, mInterpolatingSampleBuffer);
- @Override
- public void start( ScheduledExecutorService executor )
- {
- // TODO Auto-generated method stub
-
- }
+ //Message framer can trigger a symbol-inversion correction to the PLL when detected
+ mMessageFramer = new P25MessageFramer(getAliasList(), mCostasLoop);
+ mMessageFramer.setListener(getMessageProcessor());
+ mQPSKDemodulator.setDibitListener(mMessageFramer);
+ }
- @Override
- public void stop()
- {
- // TODO Auto-generated method stub
-
- }
+ @Override
+ public void receive(ComplexBuffer complexBuffer)
+ {
+ ComplexBuffer filtered = filter(complexBuffer);
+ mQPSKDemodulator.receive(filtered);
+ }
- @Override
- public void setFrequencyChangeListener( Listener listener )
- {
- if( mSymbolFilter != null )
- {
- mSymbolFilter.setFrequencyChangeListener( listener );
- }
- }
+ protected ComplexBuffer filter(ComplexBuffer complexBuffer)
+ {
+ return mBasebandFilter.filter(complexBuffer);
+ }
- @Override
- public void removeFrequencyChangeListener()
- {
- if( mSymbolFilter != null )
- {
- mSymbolFilter.setFrequencyChangeListener( null );
- }
- }
+ private double getSampleRate()
+ {
+ return mSampleRate;
+ }
- @Override
- public Listener getFrequencyChangeListener()
- {
- if( mSymbolFilter != null )
- {
- return mSymbolFilter.getFrequencyChangeListener();
- }
-
- return null;
- }
+ private float[] getBasebandFilter()
+ {
+ float[] filter = mBasebandFilters.get(getSampleRate());
+
+ if(filter == null)
+ {
+ FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
+ .sampleRate((int)getSampleRate())
+ .passBandCutoff(5100)
+ .passBandAmplitude(1.0)
+ .passBandRipple(0.01)
+ .stopBandAmplitude(0.0)
+ .stopBandStart(6500)
+ .stopBandRipple(0.01)
+ .build();
+
+ try
+ {
+ filter = FilterFactory.getTaps(specification);
+
+ }
+ catch(FilterDesignException fde)
+ {
+ mLog.error("Couldn't design low pass baseband filter for sample rate: " + getSampleRate());
+ }
+ if(filter != null)
+ {
+ mBasebandFilters.put(getSampleRate(), filter);
+ }
+ else
+ {
+ throw new IllegalStateException("Couldn't design a C4FM symbol filter for sample rate: " + mSampleRate);
+ }
+ }
+
+ return filter;
+ }
+
+ public void dispose()
+ {
+ super.dispose();
+
+ mBasebandFilter.dispose();
+ mBasebandFilter = null;
+
+ mMessageFramer.dispose();
+ mMessageFramer = null;
+ }
+
+ @Override
+ public void setFrequencyChangeListener(Listener listener)
+ {
+ }
+
+ @Override
+ public void removeFrequencyChangeListener()
+ {
+ }
+
+ @Override
+ public Listener getFrequencyChangeListener()
+ {
+ return new Listener()
+ {
+ @Override
+ public void receive(FrequencyChangeEvent frequencyChangeEvent)
+ {
+ switch(frequencyChangeEvent.getEvent())
+ {
+ case NOTIFICATION_FREQUENCY_CHANGE:
+ case NOTIFICATION_FREQUENCY_CORRECTION_CHANGE:
+ case NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
+ case NOTIFICATION_SAMPLE_RATE_CHANGE:
+ mCostasLoop.reset();
+ break;
+ }
+ }
+ };
+ }
+
+ @Override
+ public Listener getComplexBufferListener()
+ {
+ return P25_C4FMDecoder.this;
+ }
+
+ public Modulation getModulation()
+ {
+ return Modulation.C4FM;
+ }
+
+ @Override
+ public void reset()
+ {
+ mCostasLoop.reset();
+ }
+
+ @Override
+ public void start(ScheduledExecutorService executor)
+ {
+ }
+
+ @Override
+ public void stop()
+ {
+ }
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoder2.java b/src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoder2.java
deleted file mode 100644
index dbd56609..00000000
--- a/src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoder2.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*******************************************************************************
- * sdr-trunk
- * Copyright (C) 2014-2018 Dennis Sheirer
- *
- * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with this program.
- * If not, see
- *
- ******************************************************************************/
-package io.github.dsheirer.module.decode.p25;
-
-import io.github.dsheirer.alias.AliasList;
-import io.github.dsheirer.dsp.filter.FilterFactory;
-import io.github.dsheirer.dsp.filter.design.FilterDesignException;
-import io.github.dsheirer.dsp.filter.fir.FIRFilterSpecification;
-import io.github.dsheirer.dsp.filter.fir.complex.ComplexFIRFilter;
-import io.github.dsheirer.dsp.psk.DQPSKDemodulator;
-import io.github.dsheirer.dsp.psk.InterpolatingSampleBuffer;
-import io.github.dsheirer.dsp.psk.InterpolatingSampleBufferInstrumented;
-import io.github.dsheirer.dsp.psk.pll.CostasLoop;
-import io.github.dsheirer.sample.Listener;
-import io.github.dsheirer.sample.complex.ComplexBuffer;
-import io.github.dsheirer.sample.complex.IComplexBufferListener;
-import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ScheduledExecutorService;
-
-public class P25_C4FMDecoder2 extends P25Decoder implements IComplexBufferListener, Listener
-{
- private final static Logger mLog = LoggerFactory.getLogger(P25_C4FMDecoder2.class);
- protected static final double SYMBOL_RATE = 4800;
- protected InterpolatingSampleBuffer mInterpolatingSampleBuffer;
- protected DQPSKDemodulator mQPSKDemodulator;
- protected CostasLoop mCostasLoop;
- protected P25MessageFramer mMessageFramer;
- protected double mSampleRate;
- private Map mBasebandFilters = new HashMap<>();
- private ComplexFIRFilter mBasebandFilter;
-
- public P25_C4FMDecoder2(AliasList aliasList)
- {
- super(aliasList);
- setSampleRate(48000.0);
- }
-
- public void setSampleRate(double sampleRate)
- {
- if(sampleRate <= SYMBOL_RATE * 2)
- {
- throw new IllegalArgumentException("Sample rate must be at least twice the symbol rate [4800]");
- }
-
- mSampleRate = sampleRate;
- mBasebandFilter = new ComplexFIRFilter(getBasebandFilter(), 1.0f);
-
- mCostasLoop = new CostasLoop(mSampleRate, SYMBOL_RATE);
-
- mInterpolatingSampleBuffer = new InterpolatingSampleBufferInstrumented((float)(sampleRate / SYMBOL_RATE));
- mQPSKDemodulator = new DQPSKDemodulator(mCostasLoop, mInterpolatingSampleBuffer);
-
- //Message framer can trigger a symbol-inversion correction to the PLL when detected
- mMessageFramer = new P25MessageFramer(getAliasList(), mCostasLoop);
- mMessageFramer.setListener(getMessageProcessor());
- mQPSKDemodulator.setDibitListener(mMessageFramer);
- }
-
- @Override
- public void receive(ComplexBuffer complexBuffer)
- {
- ComplexBuffer filtered = filter(complexBuffer);
- mQPSKDemodulator.receive(filtered);
- }
-
- protected ComplexBuffer filter(ComplexBuffer complexBuffer)
- {
- return mBasebandFilter.filter(complexBuffer);
- }
-
- private double getSampleRate()
- {
- return mSampleRate;
- }
-
- private float[] getBasebandFilter()
- {
- float[] filter = mBasebandFilters.get(getSampleRate());
-
- if(filter == null)
- {
- FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder()
- .sampleRate((int)getSampleRate())
- .passBandCutoff(5100)
- .passBandAmplitude(1.0)
- .passBandRipple(0.01)
- .stopBandAmplitude(0.0)
- .stopBandStart(6500)
- .stopBandRipple(0.01)
- .build();
-
- try
- {
- filter = FilterFactory.getTaps(specification);
-
- }
- catch(FilterDesignException fde)
- {
- mLog.error("Couldn't design low pass baseband filter for sample rate: " + getSampleRate());
- }
- if(filter != null)
- {
- mBasebandFilters.put(getSampleRate(), filter);
- }
- else
- {
- throw new IllegalStateException("Couldn't design a C4FM symbol filter for sample rate: " + mSampleRate);
- }
- }
-
- return filter;
- }
-
- public void dispose()
- {
- super.dispose();
-
- mBasebandFilter.dispose();
- mBasebandFilter = null;
-
- mMessageFramer.dispose();
- mMessageFramer = null;
- }
-
- @Override
- public void setFrequencyChangeListener(Listener listener)
- {
- }
-
- @Override
- public void removeFrequencyChangeListener()
- {
- }
-
- @Override
- public Listener getFrequencyChangeListener()
- {
- return new Listener()
- {
- @Override
- public void receive(FrequencyChangeEvent frequencyChangeEvent)
- {
- switch(frequencyChangeEvent.getEvent())
- {
- case NOTIFICATION_FREQUENCY_CHANGE:
- case NOTIFICATION_FREQUENCY_CORRECTION_CHANGE:
- case NOTIFICATION_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
- case NOTIFICATION_SAMPLE_RATE_CHANGE:
- mCostasLoop.reset();
- break;
- }
- }
- };
- }
-
- @Override
- public Listener getComplexBufferListener()
- {
- return P25_C4FMDecoder2.this;
- }
-
- public Modulation getModulation()
- {
- return Modulation.C4FM;
- }
-
- @Override
- public void reset()
- {
- mCostasLoop.reset();
- }
-
- @Override
- public void start(ScheduledExecutorService executor)
- {
- }
-
- @Override
- public void stop()
- {
- }
-}
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoder2Instrumented.java b/src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoderInstrumented.java
similarity index 97%
rename from src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoder2Instrumented.java
rename to src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoderInstrumented.java
index 4877261f..903396a7 100644
--- a/src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoder2Instrumented.java
+++ b/src/main/java/io/github/dsheirer/module/decode/p25/P25_C4FMDecoderInstrumented.java
@@ -23,7 +23,7 @@ import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.Complex;
import io.github.dsheirer.sample.complex.ComplexBuffer;
-public class P25_C4FMDecoder2Instrumented extends P25_C4FMDecoder2
+public class P25_C4FMDecoderInstrumented extends P25_C4FMDecoder
{
private Listener mPLLPhaseErrorListener;
private Listener mPLLFrequencyListener;
@@ -32,7 +32,7 @@ public class P25_C4FMDecoder2Instrumented extends P25_C4FMDecoder2
private Listener mFilteredSymbolListener;
private Listener mSymbolDecisionDataListener;
- public P25_C4FMDecoder2Instrumented(AliasList aliasList)
+ public P25_C4FMDecoderInstrumented(AliasList aliasList)
{
super(aliasList);
}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerChannelSource.java b/src/main/java/io/github/dsheirer/source/tuner/TunerChannelSource.java
index c577789e..6804d8d7 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/TunerChannelSource.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/TunerChannelSource.java
@@ -469,6 +469,7 @@ public class TunerChannelSource extends ComplexSource implements IFrequencyChang
{
//Frequency correction requests are the only change requests supported from downstream components
case REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE:
+ mLog.debug("Got a freq corr change request: " + event.getValue().intValue());
setFrequencyCorrection(event.getValue().intValue());
break;
}